{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Introduction to topaz\n",
    "\n",
    "This tutorial tries to give the user a first idea about the features of the `topaz` application of `polymake`. We take a look at a variety of small examples.\n",
    "\n",
    "First, we have to make `topaz` the current application. For this you can either start `polymake` with the option `-A topaz`,\n",
    "\n",
    "    \n",
    "    polymake -A topaz\n",
    "\n",
    "or, if you've already started `polymake`, type\n",
    "\n",
    "    \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "application 'topaz';"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "in the `polymake` shell.\n",
    "\n",
    "### Simplicial complexes\n",
    "\n",
    "The most important object of the `topaz` application is the simplicial complex. There are several ways of obtaining one.\n",
    "\n",
    "#### From faces\n",
    "\n",
    "For example, you can specify some faces of the complex. You can pass them as an `Array< Set<Int> >`, or `Array< Array<Int> >`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "# $s = new SimplicialComplex(INPUT_FACES=>[new Set(0), new Set(0,1), new Set(1,2,3)]);\n",
    "$s = new SimplicialComplex(INPUT_FACES=>[[0],[0,1],[1,2,3]]);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As you can see, redundancies are allowed -- `[0]` is not a facet of the complex, and thus not necessary for encoding `$s`. You can compute the inclusion maximal faces like this:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{0 1}\n",
       "{1 2 3}\n"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "print $s->FACETS;"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can also pass the `FACETS` to the constructor, but be aware that in that case the vertices must be numbered increasingly starting with `0` and redundancies are prohibited.\n",
    "\n",
    "Take a look at your complex using"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<!--\n",
       "polymake for knusper\n",
       "Thu Aug 27 10:41:00 2020\n",
       "s\n",
       "-->\n",
       "\n",
       "\n",
       "<html>\n",
       "   <head>\n",
       "      <meta charset=utf-8>\n",
       "      <title>s</title>\n",
       "      <style>\n",
       "/*\n",
       "// COMMON_CODE_BLOCK_BEGIN\n",
       "*/\n",
       "         html {overflow: scroll;}\n",
       "         strong{font-size: 18px;}\n",
       "         canvas { z-index: 8; }\n",
       "         input[type='radio'] {margin-left:0;}\n",
       "         input[type='checkbox'] {margin-right:7px; margin-left: 0px; padding-left:0px;}\n",
       "         .group{padding-bottom: 15px;}\n",
       "         .settings * {z-index: 11; }\n",
       "         .settings{z-index: 10; font-family: Arial, Helvetica, sans-serif; margin-left: 30px; visibility: hidden; width: 14em; height: 96%; border: solid 1px silver; padding: 2px; overflow-y: scroll; box-sizing: border-box; background-color: white; position: absolute;}\n",
       "         .indented{margin-left: 20px; margin-top: 10px; padding-bottom: 0px;} \n",
       "         .shownObjectsList{overflow: auto; max-width: 150px; max-height: 150px;}\n",
       "         .showSettingsButton{visibility: visible; z-index: 12; position: absolute }\n",
       "         .hideSettingsButton{visibility: hidden; z-index: 12; position: absolute; opacity: 0.5}\n",
       "         button{margin-left: 0; margin-top: 10px}\n",
       "         img{cursor: pointer;}\n",
       "         .suboption{padding-top: 15px;}\n",
       "         #model60529989966 { width: 100%; height: 100%; }\n",
       "         .threejs_container { width: 100%; height: 75vh;}\n",
       "         .settings{max-height: 74vh} \n",
       "         input[type=range] {\n",
       "           -webkit-appearance: none;\n",
       "           padding:0; \n",
       "           width:90%; \n",
       "           margin-left: auto;\n",
       "           margin-right: auto;\n",
       "           margin-top: 15px;\n",
       "           margin-bottom: 15px;\n",
       "           display: block;\t\n",
       "         }\n",
       "         input[type=range]:focus {\n",
       "           outline: none;\n",
       "         }\n",
       "         input[type=range]::-webkit-slider-runnable-track {\n",
       "           height: 4px;\n",
       "           cursor: pointer;\n",
       "           animate: 0.2s;\n",
       "           box-shadow: 0px 0px 0px #000000;\n",
       "           background: #E3E3E3;\n",
       "           border-radius: 0px;\n",
       "           border: 0px solid #000000;\n",
       "         }\n",
       "         input[type=range]::-webkit-slider-thumb {\n",
       "           box-shadow: 1px 1px 2px #B8B8B8;\n",
       "           border: 1px solid #ABABAB;\n",
       "           height: 13px;\n",
       "           width: 25px;\n",
       "           border-radius: 20px;\n",
       "           background: #E0E0E0;\n",
       "           cursor: pointer;\n",
       "           -webkit-appearance: none;\n",
       "           margin-top: -5px;\n",
       "         }\n",
       "         input[type=range]:focus::-webkit-slider-runnable-track {\n",
       "           background: #E3E3E3;\n",
       "         }\n",
       "         input[type=range]::-moz-range-track {\n",
       "           height: 4px;\n",
       "           cursor: pointer;\n",
       "           animate: 0.2s;\n",
       "           box-shadow: 0px 0px 0px #000000;\n",
       "           background: #E3E3E3;\n",
       "           border-radius: 0px;\n",
       "           border: 0px solid #000000;\n",
       "         }\n",
       "         input[type=range]::-moz-range-thumb {\n",
       "           box-shadow: 1px 1px 2px #B8B8B8;\n",
       "           border: 1px solid #ABABAB;\n",
       "           height: 13px;\n",
       "           width: 25px;\n",
       "           border-radius: 20px;\n",
       "           background: #E0E0E0;\n",
       "           cursor: pointer;\n",
       "         }\n",
       "         input[type=range]::-ms-track {\n",
       "           height: 4px;\n",
       "           cursor: pointer;\n",
       "           animate: 0.2s;\n",
       "           background: transparent;\n",
       "           border-color: transparent;\n",
       "           color: transparent;\n",
       "         }\n",
       "         input[type=range]::-ms-fill-lower {\n",
       "           background: #E3E3E3;\n",
       "           border: 0px solid #000000;\n",
       "           border-radius: 0px;\n",
       "           box-shadow: 0px 0px 0px #000000;\n",
       "         }\n",
       "         input[type=range]::-ms-fill-upper {\n",
       "           background: #E3E3E3;\n",
       "           border: 0px solid #000000;\n",
       "           border-radius: 0px;\n",
       "           box-shadow: 0px 0px 0px #000000;\n",
       "         }\n",
       "         input[type=range]::-ms-thumb {\n",
       "           box-shadow: 1px 1px 2px #B8B8B8;\n",
       "           border: 1px solid #ABABAB;\n",
       "           height: 13px;\n",
       "           width: 25px;\n",
       "           border-radius: 20px;\n",
       "           background: #E0E0E0;\n",
       "           cursor: pointer;\n",
       "         }\n",
       "         input[type=range]:focus::-ms-fill-lower {\n",
       "           background: #E3E3E3;\n",
       "         }\n",
       "         input[type=range]:focus::-ms-fill-upper {\n",
       "           background: #E3E3E3;\n",
       "         }\n",
       "/*\n",
       "// COMMON_CODE_BLOCK_END\n",
       "*/\n",
       "\t\t</style>\n",
       "   </head>\n",
       "<body>\n",
       "   <div class='threejs_container'>\n",
       "\t\t<div id='settings_0' class='settings'>\n",
       "\t\t\t<div class=group id='explode_0'>\n",
       "\t\t\t\t<strong>Explode</strong>\n",
       "\t\t\t\t<input id='explodeRange_0' type='range' min=0 max=6 step=0.01 value=0>\n",
       "\t\t\t\t<div class=indented><input id='explodeCheckbox_0' type='checkbox'>Automatic explosion</div>\n",
       "\t\t\t\t<div class=suboption>Exploding speed</div>\n",
       "\t\t\t\t<input id='explodingSpeedRange_0' type='range' min=0 max=0.5 step=0.001 value=0.05>\n",
       "\t\t\t</div>\n",
       "\t\n",
       "\t\t\t<div class=group id='transparency_0' class='transparency'>\n",
       "\t\t\t\t<strong>Transparency</strong>\n",
       "\t\t\t\t<input id='transparencyRange_0' type='range' min=0 max=1 step=0.01 value=0>\n",
       "\t\t\t</div>\n",
       "\t\t\t\n",
       "\t\t\t<div class=group id='rotation_0'>\n",
       "\t\t\t\t<strong>Rotation</strong>\n",
       "\t\t\t\t<div class=indented>\n",
       "\t\t\t\t\t<div><input type='checkbox' id='changeRotationX_0'> x-axis</div>\n",
       "\t\t\t\t\t<div><input type='checkbox' id='changeRotationY_0'> y-axis</div>\n",
       "\t\t\t\t\t<div><input type='checkbox' id='changeRotationZ_0'> z-axis</div>\n",
       "\t\t\t\t\t<button id='resetButton_0'>Reset</button>\n",
       "\t\t\t\t</div>\n",
       "\n",
       "\t\t\t\t<div class=suboption>Rotation speed</div>\n",
       "\t\t\t\t<input id='rotationSpeedRange_0' type='range' min=0 max=5 step=0.01 value=2>\n",
       "\t\t\t</div>\n",
       "\n",
       "\n",
       "\t\t\t<div class=group id='display_0'>\n",
       "\t\t\t\t<strong>Display</strong>\n",
       "\t\t\t\t<div class=indented>\n",
       "\t\t\t\t\t<div id='shownObjectTypesList_0' class='shownObjectsList'></div>\n",
       "\t\t\t\t</div>\n",
       "\t\t\t\t<div class=suboption>Objects</div>\n",
       "\t\t\t\t<div class=indented>\n",
       "\t\t\t\t   <div id='shownObjectsList_0' class='shownObjectsList'></div>\n",
       "\t\t\t\t</div>\n",
       "\t\t\t</div>\n",
       "         \n",
       "         <div class=group id='camera_0'>\n",
       "            <strong>Camera</strong>\n",
       "            <div class=indented>\n",
       "               <form>\n",
       "                  <select id=\"cameraType_0\">\n",
       "                     <option value='perspective' selected> Perspective<br></option>\n",
       "                     <option value='orthographic' > Orthographic<br></option>\n",
       "                  </select>\n",
       "               </form>\n",
       "            </div>\n",
       "         </div>\n",
       "\n",
       "\t\t\t<div class=group id='svg_0'>\n",
       "\t\t\t\t<strong>SVG</strong>\n",
       "\t\t\t\t<div class=indented>\n",
       "\t\t\t\t\t<form>\n",
       "\t\t\t\t\t\t<input type=\"radio\" name='screenshotMode' value='download' id='download_0' checked> Download<br>\n",
       "\t\t\t\t\t\t<input type=\"radio\" name='screenshotMode' value='tab' id='tab_0' > New tab<br>\n",
       "\t\t\t\t\t</form>\n",
       "\t\t\t\t\t<button id='takeScreenshot_0'>Screenshot</button>\n",
       "\t\t\t\t</div>\n",
       "\t\t\t</div>\n",
       "\n",
       "\t\t</div>\t<!-- end of settings -->\n",
       "\t\t<img id='hideSettingsButton_0' class='hideSettingsButton' src='/kernelspecs/polymake/close.svg' width=20px\">\n",
       "\t\t<img id='showSettingsButton_0' class='showSettingsButton' src='/kernelspecs/polymake/menu.svg' width=20px\">\n",
       "<div id=\"model60529989966\"></div>\n",
       "</div>\n",
       "   <script>\n",
       "    requirejs.config({\n",
       "      paths: {\n",
       "        three: '/kernelspecs/polymake/three',\n",
       "        TrackballControls: '/kernelspecs/polymake/TrackballControls',\n",
       "        OrbitControls: '/kernelspecs/polymake/OrbitControls',\n",
       "        Projector: '/kernelspecs/polymake/Projector',\n",
       "        SVGRenderer: '/kernelspecs/polymake/SVGRenderer',\n",
       "        WEBGL: '/kernelspecs/polymake/WebGL',\n",
       "      },\n",
       "      shim: {\n",
       "        'three': { exports: 'THREE'},\n",
       "        'SVGRenderer': { deps: [ 'three' ], exports: 'THREE.SVGRenderer' },\n",
       "        'WEBGL': { deps: [ 'three' ], exports: 'THREE.WEBGL' },\n",
       "        'Projector': { deps: [ 'three' ], exports: 'THREE.Projector' },\n",
       "        'TrackballControls': { deps: [ 'three' ], exports: 'THREE.TrackballControls' },\n",
       "        'OrbitControls': { deps: [ 'three' ], exports: 'THREE.OrbitControls' },\n",
       "      }\n",
       "    });\n",
       "    \n",
       "    require(['three'],function(THREE){\n",
       "        window.THREE = THREE;\n",
       "      require(['TrackballControls', 'OrbitControls', 'Projector', 'SVGRenderer', 'WEBGL'],\n",
       "               function(TrackballControls, OrbitControls, Projector, SVGRenderer, WEBGL) {\n",
       "    THREE.TrackballControls = TrackballControls;\n",
       "    THREE.OrbitControls = OrbitControls;\n",
       "    THREE.Projector = Projector;\n",
       "    THREE.SVGRenderer = SVGRenderer;\n",
       "    THREE.WEBGL = WEBGL;\n",
       "\n",
       "// COMMON_CODE_BLOCK_BEGIN\n",
       "\n",
       "const intervalLength = 25; // for automatic animations\n",
       "const explodableModel = true; \n",
       "const modelContains = { points: false, pointlabels: false, lines: false, edgelabels: false, faces: false, arrowheads: false };\n",
       "const foldables = [];\n",
       "\n",
       "var three = document.getElementById(\"model60529989966\");\n",
       "var scene = new THREE.Scene();\n",
       "var renderer = new THREE.WebGLRenderer( { antialias: true } );\n",
       "var svgRenderer = new THREE.SVGRenderer( { antialias: true } );\n",
       "renderer.setPixelRatio( window.devicePixelRatio );\n",
       "renderer.setClearColor(0xFFFFFF, 1);\n",
       "svgRenderer.setClearColor(0xFFFFFF, 1);\n",
       "three.appendChild(renderer.domElement);\n",
       "\n",
       "var frustumSize = 4;\n",
       "var cameras = [new THREE.PerspectiveCamera(75, 1, 0.1, 1000), new THREE.OrthographicCamera()];\n",
       "cameras.forEach(function(cam) {\n",
       "    cam.position.set(0, 0, 5);\n",
       "    cam.lookAt(0, 0, 0);  \n",
       "    cam.up.set(0, 1, 0);         \n",
       "});\n",
       "var controls = [new THREE.TrackballControls(cameras[0], three), new THREE.OrbitControls(cameras[1], three)];\n",
       "var camera, control;\n",
       "\n",
       "controls[0].zoomSpeed = 0.2;\n",
       "controls[0].rotateSpeed = 4;\n",
       "\n",
       "\n",
       "// class to allow move points together with labels and spheres\n",
       "var PMPoint = function (x,y,z) {\n",
       "   this.vector = new THREE.Vector3(x,y,z);\n",
       "   this.sprite = null;\n",
       "   this.sphere = null;\n",
       "}\n",
       "PMPoint.prototype.addLabel = function(labelsprite) {\n",
       "   this.sprite = labelsprite;\n",
       "   this.sprite.position.copy(this.vector);\n",
       "}\n",
       "PMPoint.prototype.addSphere = function(spheremesh) {\n",
       "   this.sphere = spheremesh;\n",
       "   this.sphere.position.copy(this.vector);\n",
       "}\n",
       "PMPoint.prototype.set = function(x,y,z) {\n",
       "   this.vector.set(x,y,z);\n",
       "   if (this.sprite) {\n",
       "      this.sprite.position.copy(this.vector);\n",
       "   }\n",
       "   if (this.sphere) {\n",
       "      this.sphere.position.copy(this.vector);\n",
       "   }\n",
       "}\n",
       "PMPoint.prototype.radius = function() {\n",
       "   if (this.sphere) {\n",
       "      return this.sphere.geometry.parameters.radius;\n",
       "   } else {\n",
       "      return 0;\n",
       "   }\n",
       "};\n",
       "// select the target node\n",
       "var target = document.querySelector('#model60529989966');\n",
       "\n",
       "// create an observer instance\n",
       "var observer = new MutationObserver(function(mutations) {\n",
       "   mutations.forEach(function(mutation) {\n",
       "      if (mutation.removedNodes && mutation.removedNodes.length > 0) {\n",
       "         cancelAnimationFrame(renderId);\n",
       "         observer.disconnect();\n",
       "         console.log(\"cancelled frame \"+renderId);\n",
       "      }\n",
       "   });\n",
       "});\n",
       "\n",
       "// configuration of the observer:\n",
       "var config = { childList: true, characterData: true }\n",
       "\n",
       "// pass in the target node, as well as the observer options\n",
       "while (target) {\n",
       "   if (target.className==\"output\") {\n",
       "      observer.observe(target, config);\n",
       "      break;\n",
       "   }\n",
       "   target = target.parentNode;\n",
       "}\n",
       "\n",
       "// COMMON_CODE_BLOCK_END\n",
       "\n",
       "var obj0 = new THREE.Object3D();\n",
       "obj0.name = \"GRAPH of s\";\n",
       "obj0.userData.explodable = 1;\n",
       "obj0.userData.points = [];\n",
       "obj0.userData.points.push(new PMPoint(1.66248, -1.75901, 0.708625));\n",
       "obj0.userData.points.push(new PMPoint(0.152738, -0.16166, 0.0650532));\n",
       "obj0.userData.points.push(new PMPoint(-0.811113, 1.19867, -0.0208203));\n",
       "obj0.userData.points.push(new PMPoint(-1.00411, 0.721995, -0.752858));\n",
       "\n",
       "obj0.userData.pointradii = 0.02;\n",
       "   <!-- Vertex style -->\n",
       "obj0.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0x000000, side: THREE.DoubleSide, transparent: false } );\n",
       "obj0.userData.pointlabels = [\"0\", \"1\", \"2\", \"3\"];\n",
       "obj0.userData.edgeindices = [1, 0, 2, 1, 3, 1, 3, 2];\n",
       "   <!-- Edge style -->\n",
       "obj0.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, depthTest: true, linewidth: 1.5, transparent: false } );\n",
       "init_object(obj0);\n",
       "scene.add(obj0);\n",
       "\n",
       "var obj1 = new THREE.Object3D();\n",
       "obj1.name = \"0 1\";\n",
       "obj1.userData.explodable = 1;\n",
       "obj1.userData.points = [];\n",
       "obj1.userData.points.push(new PMPoint(1.66248, -1.75901, 0.708625));\n",
       "obj1.userData.points.push(new PMPoint(0.152738, -0.16166, 0.0650532));\n",
       "\n",
       "obj1.userData.pointradii = 0.02;\n",
       "   <!-- Vertex style -->\n",
       "obj1.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } );\n",
       "obj1.userData.pointlabels = [\"0\", \"1\"];\n",
       "obj1.userData.edgeindices = [1, 0];\n",
       "   <!-- Edge style -->\n",
       "obj1.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, depthTest: true, linewidth: 1.5, transparent: false } );\n",
       "init_object(obj1);\n",
       "scene.add(obj1);\n",
       "\n",
       "var obj2 = new THREE.Object3D();\n",
       "obj2.name = \"1 2 3\";\n",
       "obj2.userData.explodable = 1;\n",
       "obj2.userData.points = [];\n",
       "obj2.userData.points.push(new PMPoint(0.152738, -0.16166, 0.0650532));\n",
       "obj2.userData.points.push(new PMPoint(-0.811113, 1.19867, -0.0208203));\n",
       "obj2.userData.points.push(new PMPoint(-1.00411, 0.721995, -0.752858));\n",
       "\n",
       "obj2.userData.pointradii = 0.02;\n",
       "   <!-- Vertex style -->\n",
       "obj2.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } );\n",
       "obj2.userData.pointlabels = [\"1\", \"2\", \"3\"];\n",
       "obj2.userData.edgeindices = [0, 1, 0, 2, 1, 2];\n",
       "   <!-- Edge style -->\n",
       "obj2.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, depthTest: true, linewidth: 1.5, transparent: false } );\n",
       "obj2.userData.facets = [[0, 1, 2]];\n",
       "   <!-- Facet style -->\n",
       "obj2.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } );\n",
       "init_object(obj2);\n",
       "scene.add(obj2);\n",
       "\n",
       "// COMMON_CODE_BLOCK_BEGIN\n",
       "function textSpriteMaterial(message, parameters) {\n",
       "    if ( parameters === undefined ) parameters = {};\n",
       "    var fontface = \"Helvetica\";\n",
       "    var fontsize = parameters.hasOwnProperty(\"fontsize\") ? parameters[\"fontsize\"] : 15;\n",
       "    fontsize = fontsize*10;\n",
       "    var lines = message.split('\\\\n');\n",
       "    var size = 512;\n",
       "    for(var i = 0; i<lines.length; i++){\n",
       "        var tmp = lines[i].length;\n",
       "        while(tmp*fontsize > size){\n",
       "           fontsize--;\n",
       "        }\n",
       "    }\n",
       "    \n",
       "    var canvas = document.createElement('canvas');\n",
       "    canvas.width = size;\n",
       "    canvas.height = size;\n",
       "    var context = canvas.getContext('2d');\n",
       "    context.fillStyle = \"rgba(255, 255, 255, 0)\";\n",
       "    context.fill();\n",
       "    context.font = fontsize + \"px \" + fontface;\n",
       "    \n",
       "    // text color\n",
       "    context.fillStyle = \"rgba(0, 0, 0, 1.0)\";\n",
       "     for(var i = 0; i<lines.length; i++){\n",
       "        context.fillText(lines[i], size/2, size/2+i*fontsize);\n",
       "     }\n",
       "    \n",
       "    // canvas contents will be used for a texture\n",
       "    var texture = new THREE.Texture(canvas);\n",
       "    texture.needsUpdate = true;\n",
       "    \n",
       "    var spriteMaterial = new THREE.SpriteMaterial({map: texture, depthTest: true, depthWrite: false, polygonOffset: true, polygonOffsetFactor: -1, polygonOffsetUnits: 1 });\n",
       "    return spriteMaterial;\n",
       "}\n",
       "\n",
       "\n",
       "// ---------------------- INITIALIZING OBJECTS--------------------------------------\n",
       "// ---------------------------------------------------------------------------------\n",
       "\n",
       "function init_object(obj) {\n",
       "    if (obj.userData.hasOwnProperty(\"pointmaterial\")) {\n",
       "        init_points(obj);\n",
       "        modelContains.points = true;\n",
       "    }\n",
       "    if (obj.userData.hasOwnProperty(\"pointlabels\")) {\n",
       "        init_pointlabels(obj);\n",
       "        modelContains.pointlabels = true;\n",
       "    }\n",
       "    if (obj.userData.hasOwnProperty(\"edgematerial\")) {\n",
       "        init_lines(obj);\n",
       "        modelContains.lines = true;\n",
       "    }\n",
       "    if (obj.userData.hasOwnProperty(\"edgelabels\")) {\n",
       "        init_edgelabels(obj);\n",
       "        modelContains.edgelabels = true;\n",
       "    }\n",
       "    if (obj.userData.hasOwnProperty(\"arrowstyle\")) {\n",
       "        init_arrowheads(obj);\n",
       "        modelContains.arrowheads = true;\n",
       "    }\n",
       "    if (obj.userData.hasOwnProperty(\"facetmaterial\")) {\n",
       "        init_faces(obj);\n",
       "        modelContains.faces = true;\n",
       "    }\n",
       "}\n",
       "\n",
       "function init_points(obj) {\n",
       "    var pointgroup = new THREE.Group();\n",
       "    pointgroup.name = \"points\";\n",
       "    var points = obj.userData.points;\n",
       "    var radii = obj.userData.pointradii;\n",
       "    var materials = obj.userData.pointmaterial;\n",
       "    var geometry,material;\n",
       "    if (!Array.isArray(radii)) {\n",
       "        geometry = new THREE.SphereBufferGeometry(radii);  \n",
       "    }\n",
       "    if (!Array.isArray(materials)) {\n",
       "        material = materials;\n",
       "    }\n",
       "    for (var i=0; i<points.length; i++) {\n",
       "        var point = points[i];\n",
       "        if (Array.isArray(radii)) {\n",
       "            if (radii[i] == 0) {\n",
       "                continue;\n",
       "            }\n",
       "            geometry = new THREE.SphereBufferGeometry(radii[i]);  \n",
       "        } \n",
       "        if (Array.isArray(materials)) {\n",
       "            material = materials[i];     \n",
       "        } \n",
       "        var sphere = new THREE.Mesh(geometry, material);\n",
       "        point.addSphere(sphere);\n",
       "        pointgroup.add(sphere);\n",
       "    }\n",
       "    obj.add(pointgroup);\n",
       "}\n",
       "\n",
       "function init_pointlabels(obj) {\n",
       "    var points = obj.userData.points;\n",
       "    var labels = obj.userData.pointlabels;\n",
       "    var pointlabels = new THREE.Group();\n",
       "    pointlabels.name = \"pointlabels\";\n",
       "    if (Array.isArray(labels)) {\n",
       "        for (var i=0; i<points.length; i++) {\n",
       "            var point = points[i];\n",
       "            var spriteMaterial = textSpriteMaterial( labels[i] );\n",
       "\t        var sprite = new THREE.Sprite(spriteMaterial);\n",
       "            point.addLabel(sprite);\n",
       "            pointlabels.add(sprite);\n",
       "        }\n",
       "    } else {\n",
       "        var spriteMaterial = textSpriteMaterial( labels );\n",
       "        for (var i=0; i<points.length; i++) {\n",
       "            var point = points[i];\n",
       "\t        var sprite = new THREE.Sprite(spriteMaterial);\n",
       "            point.addLabel(sprite);\n",
       "            pointlabels.add(sprite);\n",
       "        }\n",
       "    }\n",
       "    obj.add(pointlabels);\n",
       "}\n",
       "\n",
       "function init_lines(obj) {\n",
       "    var edgeindices = obj.userData.edgeindices;\n",
       "    var points = obj.userData.points;\n",
       "    var materials = obj.userData.edgematerial;\n",
       "    var geometry = new THREE.BufferGeometry();\n",
       "    var bufarr = new Float32Array( obj.userData.edgeindices.length * 3 );\n",
       "    var bufattr = new THREE.Float32BufferAttribute( bufarr, 3 );\n",
       "    var geometry = new THREE.BufferGeometry();\n",
       "    geometry.setAttribute('position', bufattr);\n",
       "    if (Array.isArray(materials)) {     \n",
       "        for (var i=0; i<materials.length; i++) {\n",
       "            geometry.addGroup(2*i,2,i);\n",
       "        }\n",
       "    }\n",
       "    var lines = new THREE.LineSegments(geometry, materials);\n",
       "    lines.name = \"lines\";\n",
       "    obj.add(lines);\n",
       "    updateEdgesPosition(obj);\n",
       "}\n",
       "\n",
       "function init_edgelabels(obj) {\n",
       "    var points = obj.userData.points;\n",
       "    var edgeindices = obj.userData.edgeindices;\n",
       "    var labels = obj.userData.edgelabels;\n",
       "    var edgelabels = new THREE.Group();\n",
       "    edgelabels.name = \"edgelabels\";\n",
       "    if (Array.isArray(labels)) {\n",
       "        for (var i=0; i<edgeindices.length; i=i+2) {\n",
       "            var point = points[i];\n",
       "            var spriteMaterial = textSpriteMaterial( labels[i] );\n",
       "            var sprite = new THREE.Sprite(spriteMaterial);\n",
       "            sprite.position.copy(new THREE.Vector3().addVectors(points[edgeindices[i]].vector,points[edgeindices[i+1]].vector).multiplyScalar(0.5));\n",
       "            edgelabels.add(sprite);\n",
       "        }\n",
       "    } else {\n",
       "        var spriteMaterial = textSpriteMaterial( labels );\n",
       "        for (var i=0; i<points.length; i++) {\n",
       "            var point = points[i];\n",
       "            var sprite = new THREE.Sprite(spriteMaterial);\n",
       "            sprite.position.copy(new THREE.Vector3().addVectors(points[edgeindices[i]].vector,points[edgeindices[i+1]].vector).multiplyScalar(0.5));\n",
       "            pointlabels.add(sprite);\n",
       "        }\n",
       "    }\n",
       "    obj.add(edgelabels);\n",
       "}\n",
       "\n",
       "function init_arrowheads(obj) {\n",
       "    var arrowheads = new THREE.Group();\n",
       "    arrowheads.name = \"arrowheads\";\n",
       "    var arrowstyle = obj.userData.arrowstyle;\n",
       "    var edgeindices = obj.userData.edgeindices;\n",
       "    var edgematerials = obj.userData.edgematerial;\n",
       "    var points = obj.userData.points;\n",
       "    var material;\n",
       "    if (!Array.isArray(edgematerials)) {\n",
       "        material = new THREE.MeshBasicMaterial( {color: edgematerials.color} );\n",
       "    }\n",
       "\n",
       "    for (var i=0; i<edgeindices.length; i=i+2) {\n",
       "        var start = points[edgeindices[i]];\n",
       "        var end = points[edgeindices[i+1]];\n",
       "        var dist = start.vector.distanceTo( end.vector ) - start.radius() - end.radius();\n",
       "        if (dist <= 0) {\n",
       "            continue;\n",
       "        }\n",
       "        var dir = new THREE.Vector3().subVectors(end.vector,start.vector);\n",
       "        dir.normalize();\n",
       "        var axis = new THREE.Vector3().set(dir.z,0,-dir.x);\n",
       "        axis.normalize();\n",
       "        var radians = Math.acos( dir.y );\n",
       "        var radius = dist/25;\n",
       "        var height = dist/5;\n",
       "        var geometry = new THREE.ConeBufferGeometry(radius,height);\n",
       "        var position = new THREE.Vector3().addVectors(start.vector,dir.clone().multiplyScalar(start.radius()+dist-height/2));\n",
       "        if (Array.isArray(edgematerials)) {\n",
       "            material = new THREE.MeshBasicMaterial( {color: edgematerials[i].color} );\n",
       "        }\n",
       "        var cone = new THREE.Mesh( geometry, material );\n",
       "        cone.quaternion.setFromAxisAngle(axis,radians);;\n",
       "        cone.position.copy(position);;\n",
       "        arrowheads.add(cone);\n",
       "    }\n",
       "    obj.add(arrowheads);\n",
       "}\n",
       "\n",
       "function init_faces(obj) {\n",
       "    var points = obj.userData.points;\n",
       "    var facets = obj.userData.facets;\n",
       "    obj.userData.triangleindices = [];\n",
       "    for (var i=0; i<facets.length; i++) {\n",
       "        facet = facets[i];\n",
       "        for (var t=0; t<facet.length-2; t++) {\n",
       "            obj.userData.triangleindices.push(facet[0],facet[t+1],facet[t+2]);  \n",
       "        }\n",
       "    }\n",
       "    var bufarr = new Float32Array( obj.userData.triangleindices.length * 3 );\n",
       "    var bufattr = new THREE.Float32BufferAttribute(bufarr,3);\n",
       "    \n",
       "    var materials = obj.userData.facetmaterial;\n",
       "    var geometry = new THREE.BufferGeometry();\n",
       "    geometry.setAttribute('position',bufattr);\n",
       "    if (Array.isArray(materials)) {\n",
       "        var tricount = 0;\n",
       "        var facet;\n",
       "        for (var i=0; i<facets.length; i++) {\n",
       "            facet = facets[i];\n",
       "            geometry.addGroup(tricount,(facet.length-2)*3,i);\n",
       "            tricount += (facet.length-2)*3;\n",
       "        }\n",
       "    }\n",
       "    var mesh = new THREE.Mesh(geometry, materials);\n",
       "    mesh.name = \"faces\";\n",
       "    obj.add(mesh); \n",
       "    updateFacesPosition(obj);\n",
       "}\n",
       "// //INITIALIZING\n",
       "\n",
       "\n",
       "function updateFacesPosition(obj) {\n",
       "    var points = obj.userData.points;\n",
       "    var indices = obj.userData.triangleindices;\n",
       "    var faces = obj.getObjectByName(\"faces\");\n",
       "    var ba = faces.geometry.getAttribute(\"position\");\n",
       "    for (var i=0; i<indices.length; i++) {\n",
       "        ba.setXYZ(i, points[indices[i]].vector.x, points[indices[i]].vector.y ,points[indices[i]].vector.z); \n",
       "    }\n",
       "    faces.geometry.attributes.position.needsUpdate = true;\n",
       "    \n",
       "}\n",
       "\n",
       "function updateEdgesPosition(obj) {\n",
       "    var points = obj.userData.points;\n",
       "    var indices = obj.userData.edgeindices;\n",
       "    var lines = obj.getObjectByName(\"lines\");\n",
       "    var ba = lines.geometry.getAttribute(\"position\"); \n",
       "    for (var i=0; i<indices.length; i++) {\n",
       "        ba.setXYZ(i, points[indices[i]].vector.x, points[indices[i]].vector.y ,points[indices[i]].vector.z); \n",
       "    }\n",
       "    lines.geometry.attributes.position.needsUpdate = true;\n",
       "}\n",
       "\n",
       "function onWindowResize() {\n",
       "    renderer.setSize( three.clientWidth, three.clientHeight );\n",
       "    svgRenderer.setSize( three.clientWidth, three.clientHeight );\n",
       "    updateCamera();\n",
       "}\n",
       "\n",
       "function updateCamera() {\n",
       "    var width = three.clientWidth;\n",
       "    var height = three.clientHeight;\n",
       "    var aspect = width / height;\n",
       "    if (camera.type == \"OrthographicCamera\") {\n",
       "        camera.left = frustumSize * aspect / - 2;\n",
       "        camera.right = frustumSize * aspect / 2;\n",
       "        camera.top = frustumSize / 2;\n",
       "        camera.bottom = - frustumSize / 2;\n",
       "    } else if (camera.type == \"PerspectiveCamera\") {\n",
       "        camera.aspect = aspect;\n",
       "    }\n",
       "    camera.updateProjectionMatrix();\n",
       "}\n",
       "\n",
       "function changeCamera(event) {\n",
       "    var selindex = event.currentTarget.selectedIndex;\n",
       "    camera = cameras[selindex];\n",
       "    control = controls[selindex];\n",
       "    control.enabled = true; \n",
       "    for (var i=0; i<controls.length; i++) {\n",
       "        if (i!=selindex) {\n",
       "            controls[i].enabled = false;\n",
       "        }\n",
       "    }\n",
       "    updateCamera();\n",
       "}\n",
       "\n",
       "var camtypenode = document.getElementById('cameraType_0');\n",
       "camtypenode.onchange = changeCamera;\n",
       "camtypenode.dispatchEvent(new Event('change'));\n",
       "\n",
       "onWindowResize();\n",
       "window.addEventListener('resize', onWindowResize);\t\n",
       "\n",
       "\n",
       "var xRotationEnabled = false;\n",
       "var yRotationEnabled = false;\n",
       "var zRotationEnabled = false;\n",
       "var rotationSpeedFactor = 1;\n",
       "var settingsShown = false;\n",
       "var labelsShown = true;\n",
       "var intervals = [];\n",
       "var timeouts = [];\n",
       "var explodingSpeed = 0.05;\n",
       "var explodeScale = 0;\n",
       "var XMLS = new XMLSerializer();\n",
       "var svgElement;\n",
       "var renderId;\n",
       "\n",
       "var render = function () {\n",
       "\n",
       "\trenderId = requestAnimationFrame(render);\n",
       "\n",
       "//\tcomment in for automatic explosion\n",
       "//\texplode(updateFactor());\n",
       "\n",
       "    var phi = 0.02 * rotationSpeedFactor;\n",
       "\n",
       "    if (xRotationEnabled) {\n",
       "        scene.rotation.x += phi;\n",
       "    }\n",
       "    if (yRotationEnabled) {\n",
       "        scene.rotation.y += phi;\n",
       "    }\n",
       "    if (zRotationEnabled) {\n",
       "        scene.rotation.z += phi;\n",
       "    }\n",
       "\n",
       "    control.update();\n",
       "    renderer.render(scene, camera);\n",
       "};\n",
       "\n",
       "if ( THREE.WEBGL.isWebGLAvailable() ) {\n",
       "\trender();\n",
       "} else {\n",
       "\tvar warning = WEBGL.getWebGLErrorMessage();\n",
       "\tthree.appendChild( warning );\n",
       "}\n",
       "    \n",
       "function changeTransparency() {\n",
       "    var opacity = 1-Number(event.currentTarget.value);\n",
       "    for (var i=0; i<scene.children.length; i++) {\n",
       "        child = scene.children[i];\n",
       "        if ( child.userData.hasOwnProperty(\"facetmaterial\") ) {\n",
       "            if (Array.isArray(child.userData.facetmaterial)) {\n",
       "                for (var j=0; j<child.userData.facetmaterial.length; j++) {\n",
       "                    child.userData.facetmaterial[j].opacity = opacity;\n",
       "                }\n",
       "            } else {\n",
       "                child.userData.facetmaterial.opacity = opacity;\n",
       "            }    \n",
       "        }\n",
       "    }\n",
       "}\n",
       "\n",
       "function changeRotationX(event){\n",
       "    xRotationEnabled = event.currentTarget.checked;\n",
       "}\t\n",
       "\n",
       "function changeRotationY(event){\n",
       "    yRotationEnabled = event.currentTarget.checked;\n",
       "}\t\n",
       "\n",
       "function changeRotationZ(event){\n",
       "    zRotationEnabled = event.currentTarget.checked;\n",
       "}\t\n",
       "\n",
       "\n",
       "function changeRotationSpeedFactor(event){\n",
       "    rotationSpeedFactor = Number(event.currentTarget.value);\n",
       "}\n",
       "\n",
       "function resetScene(){\n",
       "    scene.rotation.set(0,0,0);\n",
       "    camera.position.set(0,0,5);\n",
       "    camera.up.set(0,1,0);\n",
       "}\n",
       "\n",
       "function showSettings(event){\n",
       "    document.getElementById('settings_0').style.visibility = 'visible';\n",
       "    document.getElementById('showSettingsButton_0').style.visibility = 'hidden';\n",
       "    document.getElementById('hideSettingsButton_0').style.visibility = 'visible';\n",
       "    settingsShown = true;\n",
       "}\n",
       "\n",
       "function hideSettings(event){\n",
       "    document.getElementById('settings_0').style.visibility = 'hidden';\n",
       "    document.getElementById('showSettingsButton_0').style.visibility = 'visible';\n",
       "    document.getElementById('hideSettingsButton_0').style.visibility = 'hidden';\n",
       "    settingsShown = false;\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "var pos = 150* Math.PI;\n",
       "\n",
       "function updateFactor() {\n",
       "    pos++;\n",
       "    return Math.sin(.01*pos)+1;\n",
       "}\n",
       "\n",
       "// ------------------------ FOLDING ------------------------------------------------\n",
       "// ---------------------------------------------------------------------------------\n",
       "// rotate point p around axis defined by points p1 and p2 by given angle\n",
       "function rotate(p, p1, p2, angle ){   \n",
       "    angle = -angle;\n",
       "    var x = p.x, y = p.y, z = p.z, \n",
       "    a = p1.x, b = p1.y, c = p1.z, \n",
       "    u = p2.x-p1.x, v = p2.y-p1.y, w = p2.z-p1.z;\n",
       "    var result = [];\n",
       "    var L = u*u + v*v + w*w;\n",
       "    var sqrt = Math.sqrt;\n",
       "    var cos = Math.cos;\n",
       "    var sin = Math.sin;\n",
       "\n",
       "    result[0] = ((a*(v*v+w*w)-u*(b*v+c*w-u*x-v*y-w*z))*(1-cos(angle))+L*x*cos(angle)+sqrt(L)*(-c*v+b*w-w*y+v*z)*sin(angle))/L;\n",
       "    result[1] = ((b*(u*u+w*w)-v*(a*u+c*w-u*x-v*y-w*z))*(1-cos(angle))+L*y*cos(angle)+sqrt(L)*(c*u-a*w+w*x-u*z)*sin(angle))/L;\n",
       "    result[2] = ((c*(u*u+v*v)-w*(a*u+b*v-u*x-v*y-w*z))*(1-cos(angle))+L*z*cos(angle)+sqrt(L)*(-b*u+a*v-v*x+u*y)*sin(angle))/L;\n",
       "\n",
       "    return result;\n",
       "}\n",
       "\n",
       "var fold = function(event){\n",
       "    var obj = foldables[Number(event.currentTarget.name)];\n",
       "    var foldvalue = Number(event.currentTarget.value);\n",
       "    var scale = foldvalue - obj.userData.oldscale;\n",
       "\n",
       "    for (var j=0; j<obj.userData.axes.length; j++) {\n",
       "        rotateVertices(obj, j, scale);\n",
       "    }\n",
       "    update(obj);\n",
       "    obj.userData.oldscale += scale;\n",
       "    lookAtBarycenter(obj);\n",
       "}\n",
       "\n",
       "function lookAtBarycenter(obj){\n",
       "    control.target = barycenter(obj);\n",
       "}\n",
       "\n",
       "function barycenter(obj) {\n",
       "    var center = new THREE.Vector3(0,0,0);\n",
       "    var points = obj.userData.points;\n",
       "    for (var i=0; i<points.length; i++){\n",
       "        center.add(points[i].vector);\n",
       "    }\n",
       "    center.divideScalar(points.length);\n",
       "    return center;\n",
       "}\n",
       "\n",
       "function rotateVertices(obj, edge, scale) {\n",
       "    var axes = obj.userData.axes;\n",
       "    var subtrees = obj.userData.subtrees;\n",
       "    var points = obj.userData.points;\n",
       "    var angles = obj.userData.angles;\n",
       "    if (edge < axes.length){\n",
       "        for (var j=0; j<subtrees[edge].length; j++){\n",
       "            var rotP = rotate(points[subtrees[edge][j]].vector, points[axes[edge][0]].vector,points[axes[edge][1]].vector, scale * (Math.PI - angles[edge]));\n",
       "            points[subtrees[edge][j]].set(rotP[0],rotP[1],rotP[2]);\n",
       "        }\n",
       "    }\n",
       "}\n",
       "\n",
       "function update(obj) {\n",
       "   updateFacesPosition(obj);\n",
       "   updateEdgesPosition(obj);\n",
       "}\n",
       "\n",
       "if (foldables.length) {\n",
       "    var settings = document.getElementById('settings_0');\n",
       "    var foldDiv = document.createElement('div');\n",
       "    foldDiv.id = 'fold_0';\n",
       "    var title = document.createElement('strong');\n",
       "    title.innerHTML = 'Fold';\n",
       "    foldDiv.appendChild(title);\n",
       "    foldDiv.className = 'group';\n",
       "    for (var i=0; i<foldables.length; i++) {\n",
       "        var range = document.createElement('input');\n",
       "        range.type = 'range';\n",
       "        range.min = 0;\n",
       "        range.max = 1;\n",
       "        range.value = 0;\n",
       "        range.step = 0.001;\n",
       "        range.name = String(i);\n",
       "        range.oninput = fold;\n",
       "        foldDiv.appendChild(range);\n",
       "    }\n",
       "    lookAtBarycenter(foldables[0]);\n",
       "    settings.insertBefore(foldDiv,settings.childNodes[0]);\n",
       "}\n",
       "\n",
       "    \n",
       "// ---------------------- EXPLOSION ------------------------------------------------\n",
       "// ---------------------------------------------------------------------------------\n",
       "\n",
       "if (explodableModel) {\n",
       "    for (var i=0; i<scene.children.length; i++) {\n",
       "        obj = scene.children[i];\n",
       "        if ( obj.userData.explodable ) {\n",
       "            computeCentroid(obj);\n",
       "        }\n",
       "    }\n",
       "    document.getElementById('explodeRange_0').oninput = triggerExplode;\n",
       "    document.getElementById('explodeCheckbox_0').onchange = triggerAutomaticExplode;\n",
       "    document.getElementById('explodingSpeedRange_0').oninput = setExplodingSpeed;\n",
       "}\n",
       "\n",
       "function computeCentroid(obj) {\n",
       "    centroid = new THREE.Vector3();\n",
       "    obj.userData.points.forEach(function(pmpoint) {\n",
       "        centroid.add(pmpoint.vector);\t\t\t\n",
       "    });\n",
       "    centroid.divideScalar(obj.userData.points.length);\n",
       "    obj.userData.centroid = centroid;\n",
       "}\n",
       "\n",
       "function explode(factor) {\n",
       "    for (var i=0; i<scene.children.length; i++) {\n",
       "        var obj = scene.children[i];\n",
       "        if (obj.userData.hasOwnProperty(\"centroid\")) { \n",
       "            var c = obj.userData.centroid;\n",
       "            obj.position.set(c.x*factor, c.y*factor, c.z*factor);\n",
       "        }\n",
       "    }\t\n",
       "}\n",
       "\n",
       "function triggerExplode(event){\n",
       "    explodeScale = Number(event.currentTarget.value);\n",
       "    explode(explodeScale);\n",
       "}\n",
       "\n",
       "function setExplodingSpeed(event){\n",
       "    explodingSpeed = Number(event.currentTarget.value);\n",
       "}\n",
       "\n",
       "function triggerAutomaticExplode(event){\n",
       "    if (event.currentTarget.checked){\n",
       "        startExploding();\n",
       "    } else {\n",
       "        clearIntervals();\n",
       "    }\t\n",
       "}\n",
       "\n",
       "function startExploding(){\n",
       "    intervals.push(setInterval(explodingInterval, 25));\n",
       "}\n",
       "\n",
       "\n",
       "function explodingInterval(){\n",
       "    explodeScale += explodingSpeed;\n",
       "    if (explodeScale <= 6){ \n",
       "        explode(explodeScale);\n",
       "    }\n",
       "    else{\n",
       "        explode(6);\n",
       "        explodeScale = 6;\n",
       "        clearIntervals();\n",
       "        timeouts.push(setTimeout(startUnexploding, 3000));\n",
       "    }\n",
       "    document.getElementById('explodeRange_0').value = explodeScale;\n",
       "}\n",
       "\n",
       "\n",
       "function startUnexploding(){\n",
       "    intervals.push(setInterval(unexplodingInterval, 25));\n",
       "}\n",
       "\n",
       "function unexplodingInterval(){\n",
       "    explodeScale -= explodingSpeed;\n",
       "    if (explodeScale >= 0){\t\n",
       "        explode(explodeScale);\n",
       "    }\n",
       "    else {\n",
       "        explode(0);\n",
       "        explodeScale = 0;\n",
       "        clearIntervals();\n",
       "        timeouts.push(setTimeout(startExploding, 3000));\n",
       "    }\n",
       "    document.getElementById('explodeRange_0').value = explodeScale;\n",
       "}\n",
       "\n",
       "function clearIntervals(){\n",
       "    intervals.forEach(function(interval){\n",
       "        clearInterval(interval);\n",
       "    });\n",
       "    intervals = [];\n",
       "    timeouts.forEach(function(timeout){\n",
       "        clearTimeout(timeout);\n",
       "    });\n",
       "    timeouts = [];\n",
       "}\n",
       "\n",
       "// ---------------------- DISPLAY --------------------------------------------------\n",
       "// ---------------------------------------------------------------------------------\n",
       "\n",
       "const objectTypeInnerHTMLs = { points: \"Points\", pointlabels: \"Point labels\", lines: \"Edges\", edgelabels: \"Edge labels\", faces: \"Faces\", arrowheads: \"Arrow heads\" };\n",
       "const objectTypeVisible = {};\n",
       "Object.assign(objectTypeVisible,modelContains);\n",
       "const sortedObjectTypeKeys = Object.keys(objectTypeInnerHTMLs).sort();\n",
       "const shownObjectTypesList = document.getElementById('shownObjectTypesList_0');\n",
       "\n",
       "function setVisibility(bool,objname) {\n",
       "    for (var i=0; i<scene.children.length; i++){\n",
       "        var obj = scene.children[i].getObjectByName(objname);\n",
       "        if (obj) {\n",
       "            obj.visible = bool;\n",
       "        }\n",
       "    }\n",
       "}\n",
       "\n",
       "function toggleObjectTypeVisibility(event){\n",
       "    var name = event.currentTarget.name;\n",
       "    var checked = event.currentTarget.checked;\n",
       "    objectTypeVisible[name] = checked;\n",
       "    setVisibility(checked,name);\n",
       "}\n",
       "\n",
       "for (var i=0; i<sortedObjectTypeKeys.length; i++){\n",
       "    var key = sortedObjectTypeKeys[i];\n",
       "    if (modelContains[key]) {\n",
       "        var objTypeNode = document.createElement('span');\n",
       "        objTypeNode.innerHTML = objectTypeInnerHTMLs[key] + '<br>';\n",
       "        var checkbox = document.createElement('input');\n",
       "        checkbox.type = 'checkbox';\n",
       "        checkbox.checked = true;\n",
       "        checkbox.name = key;\n",
       "        checkbox.onchange = toggleObjectTypeVisibility;\n",
       "        shownObjectTypesList.appendChild(checkbox);\n",
       "        shownObjectTypesList.appendChild(objTypeNode);\n",
       "    }\n",
       "}\n",
       "\n",
       "// ------------------------------------------------------\n",
       "\n",
       "function toggleObjectVisibility(event){\n",
       "    var nr = Number(event.currentTarget.name);\n",
       "    scene.children[nr].visible = event.currentTarget.checked;\n",
       "}\n",
       "\n",
       "// append checkboxes for displaying or hiding objects\n",
       "var shownObjectsList = document.getElementById('shownObjectsList_0');\n",
       "for (var i=0; i<scene.children.length; i++){\n",
       "    obj = scene.children[i];\n",
       "    var objNode = document.createElement('span');\n",
       "    objNode.innerHTML = obj.name + '<br>';\n",
       "    var checkbox = document.createElement('input');\n",
       "    checkbox.type = 'checkbox';\n",
       "    checkbox.checked = true;\n",
       "    checkbox.name = String(i);\n",
       "    checkbox.onchange = toggleObjectVisibility;\n",
       "    shownObjectsList.appendChild(checkbox);\n",
       "    shownObjectsList.appendChild(objNode);\n",
       "}\n",
       "\n",
       "// ---------------------- SVG ------------------------------------------------------\n",
       "// ---------------------------------------------------------------------------------\n",
       "\n",
       "function takeSvgScreenshot() {\n",
       "    if (objectTypeVisible[\"pointlabels\"]) {\n",
       "        setVisibility(false,\"pointlabels\");\n",
       "    }\n",
       "    if (objectTypeVisible[\"edgelabels\"]) {\n",
       "        setVisibility(false,\"edgelabels\");\n",
       "    }\n",
       "    svgRenderer.render(scene,camera);\n",
       "    svgElement = XMLS.serializeToString(svgRenderer.domElement);\n",
       "    \n",
       "    if (objectTypeVisible[\"pointlabels\"]) {\n",
       "        setVisibility(true,\"pointlabels\");\n",
       "    }\n",
       "    if (objectTypeVisible[\"edgelabels\"]) {\n",
       "        setVisibility(true,\"edgelabels\");\n",
       "    }\n",
       "\n",
       "    if (document.getElementById('tab_0').checked){\n",
       "        //show in new tab\n",
       "        var myWindow = window.open(\"\",\"\");\n",
       "        myWindow.document.body.innerHTML = svgElement;\n",
       "    } else{\n",
       "        // download svg file \n",
       "        download(\"screenshot.svg\", svgElement);\n",
       "    }\n",
       "}\n",
       "\n",
       "function download(filename, text) {\n",
       "    var element = document.createElement('a');\n",
       "    element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));\n",
       "    element.setAttribute('download', filename);\n",
       "\n",
       "    element.style.display = 'none';\n",
       "    document.body.appendChild(element);\n",
       "\n",
       "    element.click();\n",
       "\n",
       "    document.body.removeChild(element);\n",
       "}\n",
       "\n",
       "\n",
       "document.getElementById('transparencyRange_0').oninput = changeTransparency;\n",
       "document.getElementById('changeRotationX_0').onchange = changeRotationX;\n",
       "document.getElementById('changeRotationY_0').onchange = changeRotationY;\n",
       "document.getElementById('changeRotationZ_0').onchange = changeRotationZ;\n",
       "document.getElementById('resetButton_0').onclick = resetScene;\n",
       "document.getElementById('rotationSpeedRange_0').oninput = changeRotationSpeedFactor;\n",
       "document.getElementById('takeScreenshot_0').onclick = takeSvgScreenshot;\n",
       "document.getElementById('showSettingsButton_0').onclick = showSettings;\n",
       "document.getElementById('hideSettingsButton_0').onclick = hideSettings;\n",
       "\n",
       "\n",
       "// ------------------ SHORTCUTS --------------------------------------------\n",
       "// -------------------------------------------------------------------------\n",
       "\n",
       "/**\n",
       " * http://www.openjs.com/scripts/events/keyboard_shortcuts/\n",
       " * Version : 2.01.B\n",
       " * By Binny V A\n",
       " * License : BSD\n",
       " */\n",
       "shortcut = {\n",
       "\t'all_shortcuts':{},//All the shortcuts are stored in this array\n",
       "\t'add': function(shortcut_combination,callback,opt) {\n",
       "\t\t//Provide a set of default options\n",
       "\t\tvar default_options = {\n",
       "\t\t\t'type':'keydown',\n",
       "\t\t\t'propagate':false,\n",
       "\t\t\t'disable_in_input':false,\n",
       "\t\t\t'target':document,\n",
       "\t\t\t'keycode':false\n",
       "\t\t}\n",
       "\t\tif(!opt) opt = default_options;\n",
       "\t\telse {\n",
       "\t\t\tfor(var dfo in default_options) {\n",
       "\t\t\t\tif(typeof opt[dfo] == 'undefined') opt[dfo] = default_options[dfo];\n",
       "\t\t\t}\n",
       "\t\t}\n",
       "\n",
       "\t\tvar ele = opt.target;\n",
       "\t\tif(typeof opt.target == 'string') ele = document.getElementById(opt.target);\n",
       "\t\tvar ths = this;\n",
       "\t\tshortcut_combination = shortcut_combination.toLowerCase();\n",
       "\n",
       "\t\t//The function to be called at keypress\n",
       "\t\tvar func = function(e) {\n",
       "\t\t\te = e || window.event;\n",
       "\t\t\t\n",
       "\t\t\tif(opt['disable_in_input']) { //Don't enable shortcut keys in Input, Textarea fields\n",
       "\t\t\t\tvar element;\n",
       "\t\t\t\tif(e.target) element=e.target;\n",
       "\t\t\t\telse if(e.srcElement) element=e.srcElement;\n",
       "\t\t\t\tif(element.nodeType==3) element=element.parentNode;\n",
       "\n",
       "\t\t\t\tif(element.tagName == 'INPUT' || element.tagName == 'TEXTAREA') return;\n",
       "\t\t\t}\n",
       "\t\n",
       "\t\t\t//Find Which key is pressed\n",
       "\t\t\tif (e.keyCode) code = e.keyCode;\n",
       "\t\t\telse if (e.which) code = e.which;\n",
       "\t\t\tvar character = String.fromCharCode(code).toLowerCase();\n",
       "\t\t\t\n",
       "\t\t\tif(code == 188) character=\",\"; //If the user presses , when the type is onkeydown\n",
       "\t\t\tif(code == 190) character=\".\"; //If the user presses , when the type is onkeydown\n",
       "\n",
       "\t\t\tvar keys = shortcut_combination.split(\"+\");\n",
       "\t\t\t//Key Pressed - counts the number of valid keypresses - if it is same as the number of keys, the shortcut function is invoked\n",
       "\t\t\tvar kp = 0;\n",
       "\t\t\t\n",
       "\t\t\t//Work around for stupid Shift key bug created by using lowercase - as a result the shift+num combination was broken\n",
       "\t\t\tvar shift_nums = {\n",
       "\t\t\t\t\"`\":\"~\",\n",
       "\t\t\t\t\"1\":\"!\",\n",
       "\t\t\t\t\"2\":\"@\",\n",
       "\t\t\t\t\"3\":\"#\",\n",
       "\t\t\t\t\"4\":\"$\",\n",
       "\t\t\t\t\"5\":\"%\",\n",
       "\t\t\t\t\"6\":\"^\",\n",
       "\t\t\t\t\"7\":\"&\",\n",
       "\t\t\t\t\"8\":\"*\",\n",
       "\t\t\t\t\"9\":\"(\",\n",
       "\t\t\t\t\"0\":\")\",\n",
       "\t\t\t\t\"-\":\"_\",\n",
       "\t\t\t\t\"=\":\"+\",\n",
       "\t\t\t\t\";\":\":\",\n",
       "\t\t\t\t\"'\":\"\\\"\",\n",
       "\t\t\t\t\",\":\"<\",\n",
       "\t\t\t\t\".\":\">\",\n",
       "\t\t\t\t\"/\":\"?\",\n",
       "\t\t\t\t\"\\\\\":\"|\"\n",
       "\t\t\t}\n",
       "\t\t\t//Special Keys - and their codes\n",
       "\t\t\tvar special_keys = {\n",
       "\t\t\t\t'esc':27,\n",
       "\t\t\t\t'escape':27,\n",
       "\t\t\t\t'tab':9,\n",
       "\t\t\t\t'space':32,\n",
       "\t\t\t\t'return':13,\n",
       "\t\t\t\t'enter':13,\n",
       "\t\t\t\t'backspace':8,\n",
       "\t\n",
       "\t\t\t\t'scrolllock':145,\n",
       "\t\t\t\t'scroll_lock':145,\n",
       "\t\t\t\t'scroll':145,\n",
       "\t\t\t\t'capslock':20,\n",
       "\t\t\t\t'caps_lock':20,\n",
       "\t\t\t\t'caps':20,\n",
       "\t\t\t\t'numlock':144,\n",
       "\t\t\t\t'num_lock':144,\n",
       "\t\t\t\t'num':144,\n",
       "\t\t\t\t\n",
       "\t\t\t\t'pause':19,\n",
       "\t\t\t\t'break':19,\n",
       "\t\t\t\t\n",
       "\t\t\t\t'insert':45,\n",
       "\t\t\t\t'home':36,\n",
       "\t\t\t\t'delete':46,\n",
       "\t\t\t\t'end':35,\n",
       "\t\t\t\t\n",
       "\t\t\t\t'pageup':33,\n",
       "\t\t\t\t'page_up':33,\n",
       "\t\t\t\t'pu':33,\n",
       "\t\n",
       "\t\t\t\t'pagedown':34,\n",
       "\t\t\t\t'page_down':34,\n",
       "\t\t\t\t'pd':34,\n",
       "\t\n",
       "\t\t\t\t'left':37,\n",
       "\t\t\t\t'up':38,\n",
       "\t\t\t\t'right':39,\n",
       "\t\t\t\t'down':40,\n",
       "\t\n",
       "\t\t\t\t'f1':112,\n",
       "\t\t\t\t'f2':113,\n",
       "\t\t\t\t'f3':114,\n",
       "\t\t\t\t'f4':115,\n",
       "\t\t\t\t'f5':116,\n",
       "\t\t\t\t'f6':117,\n",
       "\t\t\t\t'f7':118,\n",
       "\t\t\t\t'f8':119,\n",
       "\t\t\t\t'f9':120,\n",
       "\t\t\t\t'f10':121,\n",
       "\t\t\t\t'f11':122,\n",
       "\t\t\t\t'f12':123\n",
       "\t\t\t}\n",
       "\t\n",
       "\t\t\tvar modifiers = { \n",
       "\t\t\t\tshift: { wanted:false, pressed:false},\n",
       "\t\t\t\tctrl : { wanted:false, pressed:false},\n",
       "\t\t\t\talt  : { wanted:false, pressed:false},\n",
       "\t\t\t\tmeta : { wanted:false, pressed:false}\t//Meta is Mac specific\n",
       "\t\t\t};\n",
       "                        \n",
       "\t\t\tif(e.ctrlKey)\tmodifiers.ctrl.pressed = true;\n",
       "\t\t\tif(e.shiftKey)\tmodifiers.shift.pressed = true;\n",
       "\t\t\tif(e.altKey)\tmodifiers.alt.pressed = true;\n",
       "\t\t\tif(e.metaKey)   modifiers.meta.pressed = true;\n",
       "                        \n",
       "\t\t\tfor(var i=0; k=keys[i],i<keys.length; i++) {\n",
       "\t\t\t\t//Modifiers\n",
       "\t\t\t\tif(k == 'ctrl' || k == 'control') {\n",
       "\t\t\t\t\tkp++;\n",
       "\t\t\t\t\tmodifiers.ctrl.wanted = true;\n",
       "\n",
       "\t\t\t\t} else if(k == 'shift') {\n",
       "\t\t\t\t\tkp++;\n",
       "\t\t\t\t\tmodifiers.shift.wanted = true;\n",
       "\n",
       "\t\t\t\t} else if(k == 'alt') {\n",
       "\t\t\t\t\tkp++;\n",
       "\t\t\t\t\tmodifiers.alt.wanted = true;\n",
       "\t\t\t\t} else if(k == 'meta') {\n",
       "\t\t\t\t\tkp++;\n",
       "\t\t\t\t\tmodifiers.meta.wanted = true;\n",
       "\t\t\t\t} else if(k.length > 1) { //If it is a special key\n",
       "\t\t\t\t\tif(special_keys[k] == code) kp++;\n",
       "\t\t\t\t\t\n",
       "\t\t\t\t} else if(opt['keycode']) {\n",
       "\t\t\t\t\tif(opt['keycode'] == code) kp++;\n",
       "\n",
       "\t\t\t\t} else { //The special keys did not match\n",
       "\t\t\t\t\tif(character == k) kp++;\n",
       "\t\t\t\t\telse {\n",
       "\t\t\t\t\t\tif(shift_nums[character] && e.shiftKey) { //Stupid Shift key bug created by using lowercase\n",
       "\t\t\t\t\t\t\tcharacter = shift_nums[character]; \n",
       "\t\t\t\t\t\t\tif(character == k) kp++;\n",
       "\t\t\t\t\t\t}\n",
       "\t\t\t\t\t}\n",
       "\t\t\t\t}\n",
       "\t\t\t}\n",
       "\t\t\t\n",
       "\t\t\tif(kp == keys.length && \n",
       "\t\t\t\t\t\tmodifiers.ctrl.pressed == modifiers.ctrl.wanted &&\n",
       "\t\t\t\t\t\tmodifiers.shift.pressed == modifiers.shift.wanted &&\n",
       "\t\t\t\t\t\tmodifiers.alt.pressed == modifiers.alt.wanted &&\n",
       "\t\t\t\t\t\tmodifiers.meta.pressed == modifiers.meta.wanted) {\n",
       "\t\t\t\tcallback(e);\n",
       "\t\n",
       "\t\t\t\tif(!opt['propagate']) { //Stop the event\n",
       "\t\t\t\t\t//e.cancelBubble is supported by IE - this will kill the bubbling process.\n",
       "\t\t\t\t\te.cancelBubble = true;\n",
       "\t\t\t\t\te.returnValue = false;\n",
       "\t\n",
       "\t\t\t\t\t//e.stopPropagation works in Firefox.\n",
       "\t\t\t\t\tif (e.stopPropagation) {\n",
       "\t\t\t\t\t\te.stopPropagation();\n",
       "\t\t\t\t\t\te.preventDefault();\n",
       "\t\t\t\t\t}\n",
       "\t\t\t\t\treturn false;\n",
       "\t\t\t\t}\n",
       "\t\t\t}\n",
       "\t\t}\n",
       "\t\tthis.all_shortcuts[shortcut_combination] = {\n",
       "\t\t\t'callback':func, \n",
       "\t\t\t'target':ele, \n",
       "\t\t\t'event': opt['type']\n",
       "\t\t};\n",
       "\t\t//Attach the function with the event\n",
       "\t\tif(ele.addEventListener) ele.addEventListener(opt['type'], func, false);\n",
       "\t\telse if(ele.attachEvent) ele.attachEvent('on'+opt['type'], func);\n",
       "\t\telse ele['on'+opt['type']] = func;\n",
       "\t},\n",
       "\n",
       "\t//Remove the shortcut - just specify the shortcut and I will remove the binding\n",
       "\t'remove':function(shortcut_combination) {\n",
       "\t\tshortcut_combination = shortcut_combination.toLowerCase();\n",
       "\t\tvar binding = this.all_shortcuts[shortcut_combination];\n",
       "\t\tdelete(this.all_shortcuts[shortcut_combination])\n",
       "\t\tif(!binding) return;\n",
       "\t\tvar type = binding['event'];\n",
       "\t\tvar ele = binding['target'];\n",
       "\t\tvar callback = binding['callback'];\n",
       "\n",
       "\t\tif(ele.detachEvent) ele.detachEvent('on'+type, callback);\n",
       "\t\telse if(ele.removeEventListener) ele.removeEventListener(type, callback, false);\n",
       "\t\telse ele['on'+type] = false;\n",
       "\t}\n",
       "}\n",
       "\n",
       "shortcut.add(\"Alt+Left\",function() {\n",
       "\tvar event = new Event('click');\n",
       "\tif (settingsShown){\n",
       "\t\tdocument.getElementById('hideSettingsButton_0').dispatchEvent(event);\n",
       "\t} else {\n",
       "\t\tdocument.getElementById('showSettingsButton_0').dispatchEvent(event);\n",
       "\t}\n",
       "});\n",
       "\n",
       "\n",
       "// COMMON_CODE_BLOCK_END\n",
       "\n",
       "});});\n",
       "      </script>\n",
       "   </body>\n",
       "</html>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<details><summary><pre style=\"display:inline\"><small>Click here for additional output</small></pre></summary>\n",
       "<pre>\n",
       "polymake: used package threejs\n",
       "   Three.js is a lightweight cross-browser JavaScript library/API used to create and display animated 3D computer graphics on a Web browser.\n",
       "   See http://github.com/mrdoob for the source code.\n",
       "\n",
       "</pre>\n",
       "</details>\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "$s->VISUAL;"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "For more information on visualizing simplicial complex, see the section below.\n",
    "\n",
    "`polymake` can compute the Hasse diagram of a simplicial complex (watch out, this gets really large for large complexes!). To print all the faces of the complex together with their rank in the face lattice, do this:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "({-1} 4)\n",
       "({0 1} 2)\n",
       "({1 2 3} 3)\n",
       "({0} 1)\n",
       "({1} 1)\n",
       "({1 2} 2)\n",
       "({1 3} 2)\n",
       "({2 3} 2)\n",
       "({} 0)\n",
       "({2} 1)\n",
       "({3} 1)\n"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "print $s->HASSE_DIAGRAM->DECORATION;"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The first entry of each pair denotes the face, the second is the rank. The `{-1}`-node is a dummy representing the whole complex. the `{}`-node is the empty face. If you want to look at a pretty graph representation, try the visualization:\n",
    "\n",
    "    \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n",
       "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.0//EN\" \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n",
       "<svg height=\"841pt\" id=\"document\" viewBox=\"0 -824 570 824\" width=\"595pt\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:svg=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
       "\t<title id=\"document_title\">Face lattice of s</title>\n",
       "\t<line stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"496.25\" x2=\"297.5\" y1=\"-420.5\" y2=\"-774.5\" />\n",
       "\t<line stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"236.346153846154\" x2=\"297.5\" y1=\"-597.5\" y2=\"-774.5\" />\n",
       "\t<line stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"456.5\" x2=\"496.25\" y1=\"-243.5\" y2=\"-420.5\" />\n",
       "\t<line stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"358.653846153846\" x2=\"496.25\" y1=\"-243.5\" y2=\"-420.5\" />\n",
       "\t<line stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"358.653846153846\" x2=\"363.75\" y1=\"-243.5\" y2=\"-420.5\" />\n",
       "\t<line stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"358.653846153846\" x2=\"231.25\" y1=\"-243.5\" y2=\"-420.5\" />\n",
       "\t<line stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"363.75\" x2=\"236.346153846154\" y1=\"-420.5\" y2=\"-597.5\" />\n",
       "\t<line stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"231.25\" x2=\"236.346153846154\" y1=\"-420.5\" y2=\"-597.5\" />\n",
       "\t<line stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"98.75\" x2=\"236.346153846154\" y1=\"-420.5\" y2=\"-597.5\" />\n",
       "\t<line stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"297.5\" x2=\"456.5\" y1=\"-66.5\" y2=\"-243.5\" />\n",
       "\t<line stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"297.5\" x2=\"358.653846153846\" y1=\"-66.5\" y2=\"-243.5\" />\n",
       "\t<line stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"297.5\" x2=\"246.796911018903\" y1=\"-66.5\" y2=\"-243.5\" />\n",
       "\t<line stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"297.5\" x2=\"179.722222222222\" y1=\"-66.5\" y2=\"-243.5\" />\n",
       "\t<line stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"246.796911018903\" x2=\"363.75\" y1=\"-243.5\" y2=\"-420.5\" />\n",
       "\t<line stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"246.796911018903\" x2=\"98.75\" y1=\"-243.5\" y2=\"-420.5\" />\n",
       "\t<line stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"179.722222222222\" x2=\"231.25\" y1=\"-243.5\" y2=\"-420.5\" />\n",
       "\t<line stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"179.722222222222\" x2=\"98.75\" y1=\"-243.5\" y2=\"-420.5\" />\n",
       "\t<rect height=\"13.5\" rx=\"0\" ry=\"0\" style=\"fill: rgb(0,0,0); stroke: rgb(0,0,0); stroke-width: 1\" width=\"14.52\" x=\"290.24\" y=\"-782.5\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"10\" text-anchor=\"middle\" x=\"297.5\" y=\"-772\"> </text>\n",
       "\t<rect height=\"13.5\" rx=\"0\" ry=\"0\" style=\"fill: rgb(255,255,255); stroke: rgb(0,0,0); stroke-width: 1\" width=\"19.28\" x=\"486.61\" y=\"-428.5\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"10\" text-anchor=\"middle\" x=\"496.25\" y=\"-418\">0 1</text>\n",
       "\t<rect height=\"13.5\" rx=\"0\" ry=\"0\" style=\"fill: rgb(255,255,255); stroke: rgb(0,0,0); stroke-width: 1\" width=\"28.8\" x=\"221.946153846154\" y=\"-605.5\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"10\" text-anchor=\"middle\" x=\"236.346153846154\" y=\"-595\">1 2 3</text>\n",
       "\t<rect height=\"13.5\" rx=\"0\" ry=\"0\" style=\"fill: rgb(255,255,255); stroke: rgb(0,0,0); stroke-width: 1\" width=\"9.76\" x=\"451.62\" y=\"-251.5\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"10\" text-anchor=\"middle\" x=\"456.5\" y=\"-241\">0</text>\n",
       "\t<rect height=\"13.5\" rx=\"0\" ry=\"0\" style=\"fill: rgb(255,255,255); stroke: rgb(0,0,0); stroke-width: 1\" width=\"9.76\" x=\"353.773846153846\" y=\"-251.5\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"10\" text-anchor=\"middle\" x=\"358.653846153846\" y=\"-241\">1</text>\n",
       "\t<rect height=\"13.5\" rx=\"0\" ry=\"0\" style=\"fill: rgb(255,255,255); stroke: rgb(0,0,0); stroke-width: 1\" width=\"19.28\" x=\"354.11\" y=\"-428.5\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"10\" text-anchor=\"middle\" x=\"363.75\" y=\"-418\">1 2</text>\n",
       "\t<rect height=\"13.5\" rx=\"0\" ry=\"0\" style=\"fill: rgb(255,255,255); stroke: rgb(0,0,0); stroke-width: 1\" width=\"19.28\" x=\"221.61\" y=\"-428.5\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"10\" text-anchor=\"middle\" x=\"231.25\" y=\"-418\">1 3</text>\n",
       "\t<rect height=\"13.5\" rx=\"0\" ry=\"0\" style=\"fill: rgb(255,255,255); stroke: rgb(0,0,0); stroke-width: 1\" width=\"19.28\" x=\"89.11\" y=\"-428.5\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"10\" text-anchor=\"middle\" x=\"98.75\" y=\"-418\">2 3</text>\n",
       "\t<rect height=\"13.5\" rx=\"0\" ry=\"0\" style=\"fill: rgb(255,255,255); stroke: rgb(0,0,0); stroke-width: 1\" width=\"14.52\" x=\"290.24\" y=\"-74.5\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"10\" text-anchor=\"middle\" x=\"297.5\" y=\"-64\"> </text>\n",
       "\t<rect height=\"13.5\" rx=\"0\" ry=\"0\" style=\"fill: rgb(255,255,255); stroke: rgb(0,0,0); stroke-width: 1\" width=\"9.76\" x=\"241.916911018903\" y=\"-251.5\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"10\" text-anchor=\"middle\" x=\"246.796911018903\" y=\"-241\">2</text>\n",
       "\t<rect height=\"13.5\" rx=\"0\" ry=\"0\" style=\"fill: rgb(255,255,255); stroke: rgb(0,0,0); stroke-width: 1\" width=\"9.76\" x=\"174.842222222222\" y=\"-251.5\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"10\" text-anchor=\"middle\" x=\"179.722222222222\" y=\"-241\">3</text>\n",
       "\t<!--\n",
       "\tGenerated using the Perl SVG Module V2.84\n",
       "\tby Ronan Oger\n",
       "\tInfo: http://www.roitsystems.com/\n",
       "\t-->\n",
       "</svg>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "$s->VISUAL_FACE_LATTICE;"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "\n",
    "#### Using clients\n",
    "\n",
    "There are several clients that construct common simplicial complexes (for a comprehensive list, see the [topaz documentation](https://polymake.org/doku.php/documentation/latest/topaz)). An example is the torus client:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "$t = torus();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "Of course, `polymake` can compute the reduced integer homology groups of a simplicial complex, so we can convice ourselves this is a torus:\n",
    "\n",
    "    \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "true"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "print $t->MANIFOLD;"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "({} 0)\n",
       "({} 2)\n",
       "({} 1)\n"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "print $t->HOMOLOGY;"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The `i`-th line represents the $i$-th homology module. The curly braces contain torsion coefficients with multiplicity, the second pair entry denotes the Betti number. The empty curly braces indicate that `$t` is torsion-free. You can see a non-empty torsion group here (using the `rows_numbered` client for a pretty print with the corresponding dimensions):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0:{} 0\n",
       "1:{(2 1)} 0\n",
       "2:{} 0\n"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "print rows_numbered( real_projective_plane()->HOMOLOGY );"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As expected, the first homology group has torsion coefficient `2` with multiplicity `1` and all Betti numbers are zero.\n",
    "\n",
    "#### As boundary complex\n",
    "\n",
    "If your complex is a pseudo-manifold, you can obtain a new complex from its boundary. For example, this produces a triangulation of the $2$-sphere:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "true"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "$bs = simplex(3)->BOUNDARY;\n",
    "print $bs->SPHERE;"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "#### Triangulating polytopes\n",
    "\n",
    "The triangulation of a polytope is a simplicial complex, too. The `TRIANGULATION` gets stored in a property of the polytope. We use the `cube` client from the `polytope` application to demonstrate:\n",
    "\n",
    "    \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{0 1 2 4}\n",
       "{1 2 3 4}\n",
       "{1 3 4 5}\n",
       "{2 3 4 6}\n",
       "{3 4 5 6}\n",
       "{3 5 6 7}\n"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "$c = polytope::cube(3);\n",
    "$tc = $c->TRIANGULATION;\n",
    "print $tc->FACETS;"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "### Geometric realizations\n",
    "\n",
    "The `topaz` application is primarily designed to deal with abstract simplicial complexes that do not come with coordinates for an embedding in euclidean space. There is a special object subtype named `GeometricSimplicialComplex` that has extra properties for dealing with coodinates.\n",
    "\n",
    "You can pass the coordinates to the constructor. Take care to choose an embedding without crossings!\n",
    "\n",
    "    \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "$s = new GeometricSimplicialComplex(INPUT_FACES=>[[0],[0,1],[1,2,3]], COORDINATES=>[[1,0],[1,1],[0,2],[2,2]]);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "\n",
    "Some clients produce complexes with geometric realization...\n",
    "\n",
    "    \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0 0 0\n",
       "1 0 0\n",
       "0 1 0\n",
       "0 0 1\n"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "$b = ball(3);\n",
    "# print a dense representation of the sparse matrix\n",
    "print dense( $b->COORDINATES );"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "...some others provide the option `geometric_realization` so you can decide whether to invest the extra computing time.\n",
    "\n",
    "    \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "$bs = barycentric_subdivision($b,geometric_realization=>1);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "Again, see the [topaz documentation](https://polymake.org/doku.php/documentation/latest/topaz) for a comprehensive list.\n",
    "\n",
    "\n",
    "### Visualization\n",
    "\n",
    "Visualization of simplicial complexes uses the `VISUAL` property. Check out\n",
    "\n",
    "    \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "VISUAL(Options) -> Visual::SimplicialComplex\n",
       "\n",
       " Visualizes the complex.\n",
       "\n",
       " If \u001b[4mG_DIM\u001b[24m < 4, the \u001b[4mGRAPH\u001b[24m and the facets\n",
       " are visualized using the \u001b[4mCOORDINATES\u001b[24m.\n",
       "\n",
       " Otherwise, the spring embedder and the \u001b[4mGRAPH\u001b[24m are used to\n",
       " produce coordinates for the visualization.\n",
       "\n",
       " If \u001b[4mJavaView\u001b[24m is used to visualize the complex, all faces of\n",
       " one facet build a geometry in the jvx-file, so you may use\n",
       " \u001b[4mMethod -> Effect -> Explode Group of Geometries\u001b[24m in the JavaView menu.\n",
       "\n",
       "Options: \n",
       "  \u001b[4mmixed_graph\u001b[24m => Bool use the \u001b[4mMIXED_GRAPH\u001b[24m for the spring embedder\n",
       "  \u001b[4mseed\u001b[24m => Int random seed value for the string embedder\n",
       "\n",
       "Options:  Attributes modifying the appearance of filled polygons.\n",
       "  \u001b[4mFacetColor\u001b[24m => Color filling color of the polygon\n",
       "  \u001b[4mFacetTransparency\u001b[24m => Float transparency factor of the polygon between 0 (opaque) and 1 (completely translucent)\n",
       "  \u001b[4mFacetStyle\u001b[24m => String if set to \"hidden\", the inner area of the polygon is not rendered\n",
       "  \u001b[4mEdgeColor\u001b[24m => Color color of the boundary lines\n",
       "  \u001b[4mEdgeThickness\u001b[24m => Float scaling factor for the thickness of the boundary lines\n",
       "  \u001b[4mEdgeStyle\u001b[24m => String if set to \"hidden\", the boundary lines are not rendered\n",
       "  \u001b[4mTitle\u001b[24m => String the name of the drawing\n",
       "  \u001b[4mName\u001b[24m => String the name of this visual object in the drawing\n",
       "  \u001b[4mHidden\u001b[24m => Bool if set to true, the visual object is not rendered\n",
       "    (useful for interactive visualization programs allowing for switching details on and off)\n",
       "  \u001b[4mPointLabels\u001b[24m => String if set to \"hidden\", no point labels are displayed\n",
       "  \u001b[4mVertexLabels\u001b[24m => String alias for PointLabels\n",
       "  \u001b[4mPointColor\u001b[24m => Flexible<Color> color of the spheres or rectangles representing the points\n",
       "  \u001b[4mVertexColor\u001b[24m => Flexible<Color> alias for PointColor\n",
       "  \u001b[4mPointThickness\u001b[24m => Flexible<Float> scaling factor for the size of the spheres or rectangles representing the points\n",
       "  \u001b[4mVertexThickness\u001b[24m => Flexible<Float> alias for PointThickness\n",
       "  \u001b[4mPointBorderColor\u001b[24m => Flexible<Color> color of the border line of rectangles representing the points\n",
       "  \u001b[4mVertexBorderColor\u001b[24m => Flexible<Float> alias for PointBorderColor\n",
       "  \u001b[4mPointBorderThickness\u001b[24m => Flexible<Float> scaling factor for the thickness of the border line of rectangles representing the points\n",
       "  \u001b[4mVertexBorderThickness\u001b[24m => Flexible<Float> alias for PointBorderThickness\n",
       "  \u001b[4mPointStyle\u001b[24m => Flexible<String> if set to \"hidden\", neither point nor its label is rendered\n",
       "  \u001b[4mVertexStyle\u001b[24m => Flexible<String> alias for PointStyle\n",
       "  \u001b[4mViewPoint\u001b[24m => Vector<Float> ViewPoint for Sketch visualization\n",
       "  \u001b[4mViewDirection\u001b[24m => Vector<Float> ViewDirection for Sketch visualization\n",
       "  \u001b[4mViewUp\u001b[24m => Vector<Float> ViewUp for Sketch visualization\n",
       "  \u001b[4mScale\u001b[24m => Float scale for Sketch visualization\n",
       "  \u001b[4mLabelAlignment\u001b[24m => Flexible<String> Defines the alignment of the vertex labels: left, right or center\n",
       "\n",
       "Options:  Attributes modifying the appearance of graphs\n",
       "  \u001b[4mCoord\u001b[24m => Matrix<Float> 2-d or 3-d coordinates of the nodes.\n",
       "    If not specified, a random embedding is generated using a pseudo-physical spring model\n",
       "  \u001b[4mNodeColor\u001b[24m => Flexible<RGB> alias for PointColor\n",
       "  \u001b[4mNodeThickness\u001b[24m => Flexible<Float> alias for PointThickness\n",
       "  \u001b[4mNodeBorderColor\u001b[24m => Flexible<RGB> alias for PointBorderColor\n",
       "  \u001b[4mNodeBorderThickness\u001b[24m => Flexible<Float> alias for PointBorderThickness\n",
       "  \u001b[4mNodeStyle\u001b[24m => Flexible<String> alias for PointStyle\n",
       "  \u001b[4mNodeLabels\u001b[24m => String alias for PointLabels\n",
       "  \u001b[4mArrowStyle\u001b[24m => Flexible<Int> How to draw directed edges: 0 (like undirected), 1 (with an arrow pointing towards the edge),\n",
       "    or -1 (with an arrow pointing against the edge).  Default is 1 for directed graphs and lattices.\n",
       "  \u001b[4mEdgeColor\u001b[24m => Flexible<Color> color of the lines representing the edges\n",
       "  \u001b[4mEdgeThickness\u001b[24m => Flexible<Float> scaling factor for the thickness of the lines representing the edges\n",
       "  \u001b[4mEdgeLabels\u001b[24m => EdgeMap<String> textual labels to be placed along the edges\n",
       "  \u001b[4mEdgeStyle\u001b[24m => Flexible<String> if set to \"hidden\", neither the edge nor its label is rendered\n",
       "  \u001b[4mTitle\u001b[24m => String the name of the drawing\n",
       "  \u001b[4mName\u001b[24m => String the name of this visual object in the drawing\n",
       "  \u001b[4mHidden\u001b[24m => Bool if set to true, the visual object is not rendered\n",
       "    (useful for interactive visualization programs allowing for switching details on and off)\n",
       "  \u001b[4mPointLabels\u001b[24m => String if set to \"hidden\", no point labels are displayed\n",
       "  \u001b[4mVertexLabels\u001b[24m => String alias for PointLabels\n",
       "  \u001b[4mPointColor\u001b[24m => Flexible<Color> color of the spheres or rectangles representing the points\n",
       "  \u001b[4mVertexColor\u001b[24m => Flexible<Color> alias for PointColor\n",
       "  \u001b[4mPointThickness\u001b[24m => Flexible<Float> scaling factor for the size of the spheres or rectangles representing the points\n",
       "  \u001b[4mVertexThickness\u001b[24m => Flexible<Float> alias for PointThickness\n",
       "  \u001b[4mPointBorderColor\u001b[24m => Flexible<Color> color of the border line of rectangles representing the points\n",
       "  \u001b[4mVertexBorderColor\u001b[24m => Flexible<Float> alias for PointBorderColor\n",
       "  \u001b[4mPointBorderThickness\u001b[24m => Flexible<Float> scaling factor for the thickness of the border line of rectangles representing the points\n",
       "  \u001b[4mVertexBorderThickness\u001b[24m => Flexible<Float> alias for PointBorderThickness\n",
       "  \u001b[4mPointStyle\u001b[24m => Flexible<String> if set to \"hidden\", neither point nor its label is rendered\n",
       "  \u001b[4mVertexStyle\u001b[24m => Flexible<String> alias for PointStyle\n",
       "  \u001b[4mViewPoint\u001b[24m => Vector<Float> ViewPoint for Sketch visualization\n",
       "  \u001b[4mViewDirection\u001b[24m => Vector<Float> ViewDirection for Sketch visualization\n",
       "  \u001b[4mViewUp\u001b[24m => Vector<Float> ViewUp for Sketch visualization\n",
       "  \u001b[4mScale\u001b[24m => Float scale for Sketch visualization\n",
       "  \u001b[4mLabelAlignment\u001b[24m => Flexible<String> Defines the alignment of the vertex labels: left, right or center\n",
       "\n",
       "Returns Visual::SimplicialComplex \n",
       "\n"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "help 'objects/SimplicialComplex/methods/Visualization/VISUAL';"
   ]
  },
  {
   "attachments": {
    "ball_triang.png": {
     "image/png": "[encoded data, 85032 characters]"
    }
   },
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "![](attachment:ball_triang.png)\n",
    "for a list of available options and this [tutorial](visual_tutorial.ipynb) for a general intro to visualization in polymake.\n",
    "\n",
    "If your complex is of dimension three or lower, you can visualize a geometric realization together with the `GRAPH` of the complex using the `VISUAL` property. Note that if your complex is not a `GeometricSimplicialComplex`, `polymake` will use the spring embedder to find an embedding of the graph of the complex, which is not guaranteed to result in an intersection-free visualization.\n",
    "\n",
    "    \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<!--\n",
       "polymake for knusper\n",
       "Thu Aug 27 10:41:00 2020\n",
       "bs\n",
       "-->\n",
       "\n",
       "\n",
       "<html>\n",
       "   <head>\n",
       "      <meta charset=utf-8>\n",
       "      <title>bs</title>\n",
       "      <style>\n",
       "/*\n",
       "// COMMON_CODE_BLOCK_BEGIN\n",
       "*/\n",
       "         html {overflow: scroll;}\n",
       "         strong{font-size: 18px;}\n",
       "         canvas { z-index: 8; }\n",
       "         input[type='radio'] {margin-left:0;}\n",
       "         input[type='checkbox'] {margin-right:7px; margin-left: 0px; padding-left:0px;}\n",
       "         .group{padding-bottom: 15px;}\n",
       "         .settings * {z-index: 11; }\n",
       "         .settings{z-index: 10; font-family: Arial, Helvetica, sans-serif; margin-left: 30px; visibility: hidden; width: 14em; height: 96%; border: solid 1px silver; padding: 2px; overflow-y: scroll; box-sizing: border-box; background-color: white; position: absolute;}\n",
       "         .indented{margin-left: 20px; margin-top: 10px; padding-bottom: 0px;} \n",
       "         .shownObjectsList{overflow: auto; max-width: 150px; max-height: 150px;}\n",
       "         .showSettingsButton{visibility: visible; z-index: 12; position: absolute }\n",
       "         .hideSettingsButton{visibility: hidden; z-index: 12; position: absolute; opacity: 0.5}\n",
       "         button{margin-left: 0; margin-top: 10px}\n",
       "         img{cursor: pointer;}\n",
       "         .suboption{padding-top: 15px;}\n",
       "         #model92388142887 { width: 100%; height: 100%; }\n",
       "         .threejs_container { width: 100%; height: 75vh;}\n",
       "         .settings{max-height: 74vh} \n",
       "         input[type=range] {\n",
       "           -webkit-appearance: none;\n",
       "           padding:0; \n",
       "           width:90%; \n",
       "           margin-left: auto;\n",
       "           margin-right: auto;\n",
       "           margin-top: 15px;\n",
       "           margin-bottom: 15px;\n",
       "           display: block;\t\n",
       "         }\n",
       "         input[type=range]:focus {\n",
       "           outline: none;\n",
       "         }\n",
       "         input[type=range]::-webkit-slider-runnable-track {\n",
       "           height: 4px;\n",
       "           cursor: pointer;\n",
       "           animate: 0.2s;\n",
       "           box-shadow: 0px 0px 0px #000000;\n",
       "           background: #E3E3E3;\n",
       "           border-radius: 0px;\n",
       "           border: 0px solid #000000;\n",
       "         }\n",
       "         input[type=range]::-webkit-slider-thumb {\n",
       "           box-shadow: 1px 1px 2px #B8B8B8;\n",
       "           border: 1px solid #ABABAB;\n",
       "           height: 13px;\n",
       "           width: 25px;\n",
       "           border-radius: 20px;\n",
       "           background: #E0E0E0;\n",
       "           cursor: pointer;\n",
       "           -webkit-appearance: none;\n",
       "           margin-top: -5px;\n",
       "         }\n",
       "         input[type=range]:focus::-webkit-slider-runnable-track {\n",
       "           background: #E3E3E3;\n",
       "         }\n",
       "         input[type=range]::-moz-range-track {\n",
       "           height: 4px;\n",
       "           cursor: pointer;\n",
       "           animate: 0.2s;\n",
       "           box-shadow: 0px 0px 0px #000000;\n",
       "           background: #E3E3E3;\n",
       "           border-radius: 0px;\n",
       "           border: 0px solid #000000;\n",
       "         }\n",
       "         input[type=range]::-moz-range-thumb {\n",
       "           box-shadow: 1px 1px 2px #B8B8B8;\n",
       "           border: 1px solid #ABABAB;\n",
       "           height: 13px;\n",
       "           width: 25px;\n",
       "           border-radius: 20px;\n",
       "           background: #E0E0E0;\n",
       "           cursor: pointer;\n",
       "         }\n",
       "         input[type=range]::-ms-track {\n",
       "           height: 4px;\n",
       "           cursor: pointer;\n",
       "           animate: 0.2s;\n",
       "           background: transparent;\n",
       "           border-color: transparent;\n",
       "           color: transparent;\n",
       "         }\n",
       "         input[type=range]::-ms-fill-lower {\n",
       "           background: #E3E3E3;\n",
       "           border: 0px solid #000000;\n",
       "           border-radius: 0px;\n",
       "           box-shadow: 0px 0px 0px #000000;\n",
       "         }\n",
       "         input[type=range]::-ms-fill-upper {\n",
       "           background: #E3E3E3;\n",
       "           border: 0px solid #000000;\n",
       "           border-radius: 0px;\n",
       "           box-shadow: 0px 0px 0px #000000;\n",
       "         }\n",
       "         input[type=range]::-ms-thumb {\n",
       "           box-shadow: 1px 1px 2px #B8B8B8;\n",
       "           border: 1px solid #ABABAB;\n",
       "           height: 13px;\n",
       "           width: 25px;\n",
       "           border-radius: 20px;\n",
       "           background: #E0E0E0;\n",
       "           cursor: pointer;\n",
       "         }\n",
       "         input[type=range]:focus::-ms-fill-lower {\n",
       "           background: #E3E3E3;\n",
       "         }\n",
       "         input[type=range]:focus::-ms-fill-upper {\n",
       "           background: #E3E3E3;\n",
       "         }\n",
       "/*\n",
       "// COMMON_CODE_BLOCK_END\n",
       "*/\n",
       "\t\t</style>\n",
       "   </head>\n",
       "<body>\n",
       "   <div class='threejs_container'>\n",
       "\t\t<div id='settings_1' class='settings'>\n",
       "\t\t\t<div class=group id='explode_1'>\n",
       "\t\t\t\t<strong>Explode</strong>\n",
       "\t\t\t\t<input id='explodeRange_1' type='range' min=0 max=6 step=0.01 value=0>\n",
       "\t\t\t\t<div class=indented><input id='explodeCheckbox_1' type='checkbox'>Automatic explosion</div>\n",
       "\t\t\t\t<div class=suboption>Exploding speed</div>\n",
       "\t\t\t\t<input id='explodingSpeedRange_1' type='range' min=0 max=0.5 step=0.001 value=0.05>\n",
       "\t\t\t</div>\n",
       "\t\n",
       "\t\t\t<div class=group id='transparency_1' class='transparency'>\n",
       "\t\t\t\t<strong>Transparency</strong>\n",
       "\t\t\t\t<input id='transparencyRange_1' type='range' min=0 max=1 step=0.01 value=0>\n",
       "\t\t\t</div>\n",
       "\t\t\t\n",
       "\t\t\t<div class=group id='rotation_1'>\n",
       "\t\t\t\t<strong>Rotation</strong>\n",
       "\t\t\t\t<div class=indented>\n",
       "\t\t\t\t\t<div><input type='checkbox' id='changeRotationX_1'> x-axis</div>\n",
       "\t\t\t\t\t<div><input type='checkbox' id='changeRotationY_1'> y-axis</div>\n",
       "\t\t\t\t\t<div><input type='checkbox' id='changeRotationZ_1'> z-axis</div>\n",
       "\t\t\t\t\t<button id='resetButton_1'>Reset</button>\n",
       "\t\t\t\t</div>\n",
       "\n",
       "\t\t\t\t<div class=suboption>Rotation speed</div>\n",
       "\t\t\t\t<input id='rotationSpeedRange_1' type='range' min=0 max=5 step=0.01 value=2>\n",
       "\t\t\t</div>\n",
       "\n",
       "\n",
       "\t\t\t<div class=group id='display_1'>\n",
       "\t\t\t\t<strong>Display</strong>\n",
       "\t\t\t\t<div class=indented>\n",
       "\t\t\t\t\t<div id='shownObjectTypesList_1' class='shownObjectsList'></div>\n",
       "\t\t\t\t</div>\n",
       "\t\t\t\t<div class=suboption>Objects</div>\n",
       "\t\t\t\t<div class=indented>\n",
       "\t\t\t\t   <div id='shownObjectsList_1' class='shownObjectsList'></div>\n",
       "\t\t\t\t</div>\n",
       "\t\t\t</div>\n",
       "         \n",
       "         <div class=group id='camera_1'>\n",
       "            <strong>Camera</strong>\n",
       "            <div class=indented>\n",
       "               <form>\n",
       "                  <select id=\"cameraType_1\">\n",
       "                     <option value='perspective' selected> Perspective<br></option>\n",
       "                     <option value='orthographic' > Orthographic<br></option>\n",
       "                  </select>\n",
       "               </form>\n",
       "            </div>\n",
       "         </div>\n",
       "\n",
       "\t\t\t<div class=group id='svg_1'>\n",
       "\t\t\t\t<strong>SVG</strong>\n",
       "\t\t\t\t<div class=indented>\n",
       "\t\t\t\t\t<form>\n",
       "\t\t\t\t\t\t<input type=\"radio\" name='screenshotMode' value='download' id='download_1' checked> Download<br>\n",
       "\t\t\t\t\t\t<input type=\"radio\" name='screenshotMode' value='tab' id='tab_1' > New tab<br>\n",
       "\t\t\t\t\t</form>\n",
       "\t\t\t\t\t<button id='takeScreenshot_1'>Screenshot</button>\n",
       "\t\t\t\t</div>\n",
       "\t\t\t</div>\n",
       "\n",
       "\t\t</div>\t<!-- end of settings -->\n",
       "\t\t<img id='hideSettingsButton_1' class='hideSettingsButton' src='/kernelspecs/polymake/close.svg' width=20px\">\n",
       "\t\t<img id='showSettingsButton_1' class='showSettingsButton' src='/kernelspecs/polymake/menu.svg' width=20px\">\n",
       "<div id=\"model92388142887\"></div>\n",
       "</div>\n",
       "   <script>\n",
       "    requirejs.config({\n",
       "      paths: {\n",
       "        three: '/kernelspecs/polymake/three',\n",
       "        TrackballControls: '/kernelspecs/polymake/TrackballControls',\n",
       "        OrbitControls: '/kernelspecs/polymake/OrbitControls',\n",
       "        Projector: '/kernelspecs/polymake/Projector',\n",
       "        SVGRenderer: '/kernelspecs/polymake/SVGRenderer',\n",
       "        WEBGL: '/kernelspecs/polymake/WebGL',\n",
       "      },\n",
       "      shim: {\n",
       "        'three': { exports: 'THREE'},\n",
       "        'SVGRenderer': { deps: [ 'three' ], exports: 'THREE.SVGRenderer' },\n",
       "        'WEBGL': { deps: [ 'three' ], exports: 'THREE.WEBGL' },\n",
       "        'Projector': { deps: [ 'three' ], exports: 'THREE.Projector' },\n",
       "        'TrackballControls': { deps: [ 'three' ], exports: 'THREE.TrackballControls' },\n",
       "        'OrbitControls': { deps: [ 'three' ], exports: 'THREE.OrbitControls' },\n",
       "      }\n",
       "    });\n",
       "    \n",
       "    require(['three'],function(THREE){\n",
       "        window.THREE = THREE;\n",
       "      require(['TrackballControls', 'OrbitControls', 'Projector', 'SVGRenderer', 'WEBGL'],\n",
       "               function(TrackballControls, OrbitControls, Projector, SVGRenderer, WEBGL) {\n",
       "    THREE.TrackballControls = TrackballControls;\n",
       "    THREE.OrbitControls = OrbitControls;\n",
       "    THREE.Projector = Projector;\n",
       "    THREE.SVGRenderer = SVGRenderer;\n",
       "    THREE.WEBGL = WEBGL;\n",
       "\n",
       "// COMMON_CODE_BLOCK_BEGIN\n",
       "\n",
       "const intervalLength = 25; // for automatic animations\n",
       "const explodableModel = true; \n",
       "const modelContains = { points: false, pointlabels: false, lines: false, edgelabels: false, faces: false, arrowheads: false };\n",
       "const foldables = [];\n",
       "\n",
       "var three = document.getElementById(\"model92388142887\");\n",
       "var scene = new THREE.Scene();\n",
       "var renderer = new THREE.WebGLRenderer( { antialias: true } );\n",
       "var svgRenderer = new THREE.SVGRenderer( { antialias: true } );\n",
       "renderer.setPixelRatio( window.devicePixelRatio );\n",
       "renderer.setClearColor(0xFFFFFF, 1);\n",
       "svgRenderer.setClearColor(0xFFFFFF, 1);\n",
       "three.appendChild(renderer.domElement);\n",
       "\n",
       "var frustumSize = 4;\n",
       "var cameras = [new THREE.PerspectiveCamera(75, 1, 0.1, 1000), new THREE.OrthographicCamera()];\n",
       "cameras.forEach(function(cam) {\n",
       "    cam.position.set(0, 0, 5);\n",
       "    cam.lookAt(0, 0, 0);  \n",
       "    cam.up.set(0, 1, 0);         \n",
       "});\n",
       "var controls = [new THREE.TrackballControls(cameras[0], three), new THREE.OrbitControls(cameras[1], three)];\n",
       "var camera, control;\n",
       "\n",
       "controls[0].zoomSpeed = 0.2;\n",
       "controls[0].rotateSpeed = 4;\n",
       "\n",
       "\n",
       "// class to allow move points together with labels and spheres\n",
       "var PMPoint = function (x,y,z) {\n",
       "   this.vector = new THREE.Vector3(x,y,z);\n",
       "   this.sprite = null;\n",
       "   this.sphere = null;\n",
       "}\n",
       "PMPoint.prototype.addLabel = function(labelsprite) {\n",
       "   this.sprite = labelsprite;\n",
       "   this.sprite.position.copy(this.vector);\n",
       "}\n",
       "PMPoint.prototype.addSphere = function(spheremesh) {\n",
       "   this.sphere = spheremesh;\n",
       "   this.sphere.position.copy(this.vector);\n",
       "}\n",
       "PMPoint.prototype.set = function(x,y,z) {\n",
       "   this.vector.set(x,y,z);\n",
       "   if (this.sprite) {\n",
       "      this.sprite.position.copy(this.vector);\n",
       "   }\n",
       "   if (this.sphere) {\n",
       "      this.sphere.position.copy(this.vector);\n",
       "   }\n",
       "}\n",
       "PMPoint.prototype.radius = function() {\n",
       "   if (this.sphere) {\n",
       "      return this.sphere.geometry.parameters.radius;\n",
       "   } else {\n",
       "      return 0;\n",
       "   }\n",
       "};\n",
       "// select the target node\n",
       "var target = document.querySelector('#model92388142887');\n",
       "\n",
       "// create an observer instance\n",
       "var observer = new MutationObserver(function(mutations) {\n",
       "   mutations.forEach(function(mutation) {\n",
       "      if (mutation.removedNodes && mutation.removedNodes.length > 0) {\n",
       "         cancelAnimationFrame(renderId);\n",
       "         observer.disconnect();\n",
       "         console.log(\"cancelled frame \"+renderId);\n",
       "      }\n",
       "   });\n",
       "});\n",
       "\n",
       "// configuration of the observer:\n",
       "var config = { childList: true, characterData: true }\n",
       "\n",
       "// pass in the target node, as well as the observer options\n",
       "while (target) {\n",
       "   if (target.className==\"output\") {\n",
       "      observer.observe(target, config);\n",
       "      break;\n",
       "   }\n",
       "   target = target.parentNode;\n",
       "}\n",
       "\n",
       "// COMMON_CODE_BLOCK_END\n",
       "\n",
       "var obj0 = new THREE.Object3D();\n",
       "obj0.name = \"GRAPH of bs\";\n",
       "obj0.userData.explodable = 1;\n",
       "obj0.userData.points = [];\n",
       "obj0.userData.points.push(new PMPoint(0.25, 0.25, 0.25));\n",
       "obj0.userData.points.push(new PMPoint(0.333333, 0.333333, 0));\n",
       "obj0.userData.points.push(new PMPoint(0.333333, 0, 0.333333));\n",
       "obj0.userData.points.push(new PMPoint(0, 0.333333, 0.333333));\n",
       "obj0.userData.points.push(new PMPoint(0.333333, 0.333333, 0.333333));\n",
       "obj0.userData.points.push(new PMPoint(0.5, 0, 0));\n",
       "obj0.userData.points.push(new PMPoint(0, 0.5, 0));\n",
       "obj0.userData.points.push(new PMPoint(0.5, 0.5, 0));\n",
       "obj0.userData.points.push(new PMPoint(0, 0, 0.5));\n",
       "obj0.userData.points.push(new PMPoint(0.5, 0, 0.5));\n",
       "obj0.userData.points.push(new PMPoint(0, 0.5, 0.5));\n",
       "obj0.userData.points.push(new PMPoint(0, 0, 0));\n",
       "obj0.userData.points.push(new PMPoint(1, 0, 0));\n",
       "obj0.userData.points.push(new PMPoint(0, 1, 0));\n",
       "obj0.userData.points.push(new PMPoint(0, 0, 1));\n",
       "\n",
       "obj0.userData.pointradii = 0.02;\n",
       "   <!-- Vertex style -->\n",
       "obj0.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0x000000, side: THREE.DoubleSide, transparent: false } );\n",
       "obj0.userData.pointlabels = [\"{0 1 2 3}\", \"{0 1 2}\", \"{0 1 3}\", \"{0 2 3}\", \"{1 2 3}\", \"{0 1}\", \"{0 2}\", \"{1 2}\", \"{0 3}\", \"{1 3}\", \"{2 3}\", \"{0}\", \"{1}\", \"{2}\", \"{3}\"];\n",
       "obj0.userData.edgeindices = [1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 5, 1, 5, 2, 6, 0, 6, 1, 6, 3, 7, 0, 7, 1, 7, 4, 8, 0, 8, 2, 8, 3, 9, 0, 9, 2, 9, 4, 10, 0, 10, 3, 10, 4, 11, 0, 11, 1, 11, 2, 11, 3, 11, 5, 11, 6, 11, 8, 12, 0, 12, 1, 12, 2, 12, 4, 12, 5, 12, 7, 12, 9, 13, 0, 13, 1, 13, 3, 13, 4, 13, 6, 13, 7, 13, 10, 14, 0, 14, 2, 14, 3, 14, 4, 14, 8, 14, 9, 14, 10];\n",
       "   <!-- Edge style -->\n",
       "obj0.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, depthTest: true, linewidth: 1.5, transparent: false } );\n",
       "init_object(obj0);\n",
       "scene.add(obj0);\n",
       "\n",
       "var obj1 = new THREE.Object3D();\n",
       "obj1.name = \"{0 1 2 3} {0 1 2} {0 1} {0}\";\n",
       "obj1.userData.explodable = 1;\n",
       "obj1.userData.points = [];\n",
       "obj1.userData.points.push(new PMPoint(0.25, 0.25, 0.25));\n",
       "obj1.userData.points.push(new PMPoint(0.333333, 0.333333, 0));\n",
       "obj1.userData.points.push(new PMPoint(0.5, 0, 0));\n",
       "obj1.userData.points.push(new PMPoint(0, 0, 0));\n",
       "\n",
       "obj1.userData.pointradii = 0.02;\n",
       "   <!-- Vertex style -->\n",
       "obj1.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } );\n",
       "obj1.userData.pointlabels = [\"{0 1 2 3}\", \"{0 1 2}\", \"{0 1}\", \"{0}\"];\n",
       "obj1.userData.edgeindices = [0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3];\n",
       "   <!-- Edge style -->\n",
       "obj1.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, depthTest: true, linewidth: 1.5, transparent: false } );\n",
       "obj1.userData.facets = [[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3]];\n",
       "   <!-- Facet style -->\n",
       "obj1.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } );\n",
       "init_object(obj1);\n",
       "scene.add(obj1);\n",
       "\n",
       "var obj2 = new THREE.Object3D();\n",
       "obj2.name = \"{0 1 2 3} {0 1 3} {0 1} {0}\";\n",
       "obj2.userData.explodable = 1;\n",
       "obj2.userData.points = [];\n",
       "obj2.userData.points.push(new PMPoint(0.25, 0.25, 0.25));\n",
       "obj2.userData.points.push(new PMPoint(0.333333, 0, 0.333333));\n",
       "obj2.userData.points.push(new PMPoint(0.5, 0, 0));\n",
       "obj2.userData.points.push(new PMPoint(0, 0, 0));\n",
       "\n",
       "obj2.userData.pointradii = 0.02;\n",
       "   <!-- Vertex style -->\n",
       "obj2.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } );\n",
       "obj2.userData.pointlabels = [\"{0 1 2 3}\", \"{0 1 3}\", \"{0 1}\", \"{0}\"];\n",
       "obj2.userData.edgeindices = [0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3];\n",
       "   <!-- Edge style -->\n",
       "obj2.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, depthTest: true, linewidth: 1.5, transparent: false } );\n",
       "obj2.userData.facets = [[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3]];\n",
       "   <!-- Facet style -->\n",
       "obj2.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } );\n",
       "init_object(obj2);\n",
       "scene.add(obj2);\n",
       "\n",
       "var obj3 = new THREE.Object3D();\n",
       "obj3.name = \"{0 1 2 3} {0 1 2} {0 2} {0}\";\n",
       "obj3.userData.explodable = 1;\n",
       "obj3.userData.points = [];\n",
       "obj3.userData.points.push(new PMPoint(0.25, 0.25, 0.25));\n",
       "obj3.userData.points.push(new PMPoint(0.333333, 0.333333, 0));\n",
       "obj3.userData.points.push(new PMPoint(0, 0.5, 0));\n",
       "obj3.userData.points.push(new PMPoint(0, 0, 0));\n",
       "\n",
       "obj3.userData.pointradii = 0.02;\n",
       "   <!-- Vertex style -->\n",
       "obj3.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } );\n",
       "obj3.userData.pointlabels = [\"{0 1 2 3}\", \"{0 1 2}\", \"{0 2}\", \"{0}\"];\n",
       "obj3.userData.edgeindices = [0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3];\n",
       "   <!-- Edge style -->\n",
       "obj3.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, depthTest: true, linewidth: 1.5, transparent: false } );\n",
       "obj3.userData.facets = [[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3]];\n",
       "   <!-- Facet style -->\n",
       "obj3.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } );\n",
       "init_object(obj3);\n",
       "scene.add(obj3);\n",
       "\n",
       "var obj4 = new THREE.Object3D();\n",
       "obj4.name = \"{0 1 2 3} {0 2 3} {0 2} {0}\";\n",
       "obj4.userData.explodable = 1;\n",
       "obj4.userData.points = [];\n",
       "obj4.userData.points.push(new PMPoint(0.25, 0.25, 0.25));\n",
       "obj4.userData.points.push(new PMPoint(0, 0.333333, 0.333333));\n",
       "obj4.userData.points.push(new PMPoint(0, 0.5, 0));\n",
       "obj4.userData.points.push(new PMPoint(0, 0, 0));\n",
       "\n",
       "obj4.userData.pointradii = 0.02;\n",
       "   <!-- Vertex style -->\n",
       "obj4.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } );\n",
       "obj4.userData.pointlabels = [\"{0 1 2 3}\", \"{0 2 3}\", \"{0 2}\", \"{0}\"];\n",
       "obj4.userData.edgeindices = [0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3];\n",
       "   <!-- Edge style -->\n",
       "obj4.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, depthTest: true, linewidth: 1.5, transparent: false } );\n",
       "obj4.userData.facets = [[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3]];\n",
       "   <!-- Facet style -->\n",
       "obj4.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } );\n",
       "init_object(obj4);\n",
       "scene.add(obj4);\n",
       "\n",
       "var obj5 = new THREE.Object3D();\n",
       "obj5.name = \"{0 1 2 3} {0 1 3} {0 3} {0}\";\n",
       "obj5.userData.explodable = 1;\n",
       "obj5.userData.points = [];\n",
       "obj5.userData.points.push(new PMPoint(0.25, 0.25, 0.25));\n",
       "obj5.userData.points.push(new PMPoint(0.333333, 0, 0.333333));\n",
       "obj5.userData.points.push(new PMPoint(0, 0, 0.5));\n",
       "obj5.userData.points.push(new PMPoint(0, 0, 0));\n",
       "\n",
       "obj5.userData.pointradii = 0.02;\n",
       "   <!-- Vertex style -->\n",
       "obj5.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } );\n",
       "obj5.userData.pointlabels = [\"{0 1 2 3}\", \"{0 1 3}\", \"{0 3}\", \"{0}\"];\n",
       "obj5.userData.edgeindices = [0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3];\n",
       "   <!-- Edge style -->\n",
       "obj5.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, depthTest: true, linewidth: 1.5, transparent: false } );\n",
       "obj5.userData.facets = [[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3]];\n",
       "   <!-- Facet style -->\n",
       "obj5.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } );\n",
       "init_object(obj5);\n",
       "scene.add(obj5);\n",
       "\n",
       "var obj6 = new THREE.Object3D();\n",
       "obj6.name = \"{0 1 2 3} {0 2 3} {0 3} {0}\";\n",
       "obj6.userData.explodable = 1;\n",
       "obj6.userData.points = [];\n",
       "obj6.userData.points.push(new PMPoint(0.25, 0.25, 0.25));\n",
       "obj6.userData.points.push(new PMPoint(0, 0.333333, 0.333333));\n",
       "obj6.userData.points.push(new PMPoint(0, 0, 0.5));\n",
       "obj6.userData.points.push(new PMPoint(0, 0, 0));\n",
       "\n",
       "obj6.userData.pointradii = 0.02;\n",
       "   <!-- Vertex style -->\n",
       "obj6.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } );\n",
       "obj6.userData.pointlabels = [\"{0 1 2 3}\", \"{0 2 3}\", \"{0 3}\", \"{0}\"];\n",
       "obj6.userData.edgeindices = [0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3];\n",
       "   <!-- Edge style -->\n",
       "obj6.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, depthTest: true, linewidth: 1.5, transparent: false } );\n",
       "obj6.userData.facets = [[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3]];\n",
       "   <!-- Facet style -->\n",
       "obj6.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } );\n",
       "init_object(obj6);\n",
       "scene.add(obj6);\n",
       "\n",
       "var obj7 = new THREE.Object3D();\n",
       "obj7.name = \"{0 1 2 3} {0 1 2} {0 1} {1}\";\n",
       "obj7.userData.explodable = 1;\n",
       "obj7.userData.points = [];\n",
       "obj7.userData.points.push(new PMPoint(0.25, 0.25, 0.25));\n",
       "obj7.userData.points.push(new PMPoint(0.333333, 0.333333, 0));\n",
       "obj7.userData.points.push(new PMPoint(0.5, 0, 0));\n",
       "obj7.userData.points.push(new PMPoint(1, 0, 0));\n",
       "\n",
       "obj7.userData.pointradii = 0.02;\n",
       "   <!-- Vertex style -->\n",
       "obj7.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } );\n",
       "obj7.userData.pointlabels = [\"{0 1 2 3}\", \"{0 1 2}\", \"{0 1}\", \"{1}\"];\n",
       "obj7.userData.edgeindices = [0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3];\n",
       "   <!-- Edge style -->\n",
       "obj7.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, depthTest: true, linewidth: 1.5, transparent: false } );\n",
       "obj7.userData.facets = [[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3]];\n",
       "   <!-- Facet style -->\n",
       "obj7.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } );\n",
       "init_object(obj7);\n",
       "scene.add(obj7);\n",
       "\n",
       "var obj8 = new THREE.Object3D();\n",
       "obj8.name = \"{0 1 2 3} {0 1 3} {0 1} {1}\";\n",
       "obj8.userData.explodable = 1;\n",
       "obj8.userData.points = [];\n",
       "obj8.userData.points.push(new PMPoint(0.25, 0.25, 0.25));\n",
       "obj8.userData.points.push(new PMPoint(0.333333, 0, 0.333333));\n",
       "obj8.userData.points.push(new PMPoint(0.5, 0, 0));\n",
       "obj8.userData.points.push(new PMPoint(1, 0, 0));\n",
       "\n",
       "obj8.userData.pointradii = 0.02;\n",
       "   <!-- Vertex style -->\n",
       "obj8.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } );\n",
       "obj8.userData.pointlabels = [\"{0 1 2 3}\", \"{0 1 3}\", \"{0 1}\", \"{1}\"];\n",
       "obj8.userData.edgeindices = [0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3];\n",
       "   <!-- Edge style -->\n",
       "obj8.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, depthTest: true, linewidth: 1.5, transparent: false } );\n",
       "obj8.userData.facets = [[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3]];\n",
       "   <!-- Facet style -->\n",
       "obj8.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } );\n",
       "init_object(obj8);\n",
       "scene.add(obj8);\n",
       "\n",
       "var obj9 = new THREE.Object3D();\n",
       "obj9.name = \"{0 1 2 3} {0 1 2} {1 2} {1}\";\n",
       "obj9.userData.explodable = 1;\n",
       "obj9.userData.points = [];\n",
       "obj9.userData.points.push(new PMPoint(0.25, 0.25, 0.25));\n",
       "obj9.userData.points.push(new PMPoint(0.333333, 0.333333, 0));\n",
       "obj9.userData.points.push(new PMPoint(0.5, 0.5, 0));\n",
       "obj9.userData.points.push(new PMPoint(1, 0, 0));\n",
       "\n",
       "obj9.userData.pointradii = 0.02;\n",
       "   <!-- Vertex style -->\n",
       "obj9.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } );\n",
       "obj9.userData.pointlabels = [\"{0 1 2 3}\", \"{0 1 2}\", \"{1 2}\", \"{1}\"];\n",
       "obj9.userData.edgeindices = [0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3];\n",
       "   <!-- Edge style -->\n",
       "obj9.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, depthTest: true, linewidth: 1.5, transparent: false } );\n",
       "obj9.userData.facets = [[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3]];\n",
       "   <!-- Facet style -->\n",
       "obj9.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } );\n",
       "init_object(obj9);\n",
       "scene.add(obj9);\n",
       "\n",
       "var obj10 = new THREE.Object3D();\n",
       "obj10.name = \"{0 1 2 3} {1 2 3} {1 2} {1}\";\n",
       "obj10.userData.explodable = 1;\n",
       "obj10.userData.points = [];\n",
       "obj10.userData.points.push(new PMPoint(0.25, 0.25, 0.25));\n",
       "obj10.userData.points.push(new PMPoint(0.333333, 0.333333, 0.333333));\n",
       "obj10.userData.points.push(new PMPoint(0.5, 0.5, 0));\n",
       "obj10.userData.points.push(new PMPoint(1, 0, 0));\n",
       "\n",
       "obj10.userData.pointradii = 0.02;\n",
       "   <!-- Vertex style -->\n",
       "obj10.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } );\n",
       "obj10.userData.pointlabels = [\"{0 1 2 3}\", \"{1 2 3}\", \"{1 2}\", \"{1}\"];\n",
       "obj10.userData.edgeindices = [0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3];\n",
       "   <!-- Edge style -->\n",
       "obj10.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, depthTest: true, linewidth: 1.5, transparent: false } );\n",
       "obj10.userData.facets = [[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3]];\n",
       "   <!-- Facet style -->\n",
       "obj10.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } );\n",
       "init_object(obj10);\n",
       "scene.add(obj10);\n",
       "\n",
       "var obj11 = new THREE.Object3D();\n",
       "obj11.name = \"{0 1 2 3} {0 1 3} {1 3} {1}\";\n",
       "obj11.userData.explodable = 1;\n",
       "obj11.userData.points = [];\n",
       "obj11.userData.points.push(new PMPoint(0.25, 0.25, 0.25));\n",
       "obj11.userData.points.push(new PMPoint(0.333333, 0, 0.333333));\n",
       "obj11.userData.points.push(new PMPoint(0.5, 0, 0.5));\n",
       "obj11.userData.points.push(new PMPoint(1, 0, 0));\n",
       "\n",
       "obj11.userData.pointradii = 0.02;\n",
       "   <!-- Vertex style -->\n",
       "obj11.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } );\n",
       "obj11.userData.pointlabels = [\"{0 1 2 3}\", \"{0 1 3}\", \"{1 3}\", \"{1}\"];\n",
       "obj11.userData.edgeindices = [0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3];\n",
       "   <!-- Edge style -->\n",
       "obj11.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, depthTest: true, linewidth: 1.5, transparent: false } );\n",
       "obj11.userData.facets = [[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3]];\n",
       "   <!-- Facet style -->\n",
       "obj11.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } );\n",
       "init_object(obj11);\n",
       "scene.add(obj11);\n",
       "\n",
       "var obj12 = new THREE.Object3D();\n",
       "obj12.name = \"{0 1 2 3} {1 2 3} {1 3} {1}\";\n",
       "obj12.userData.explodable = 1;\n",
       "obj12.userData.points = [];\n",
       "obj12.userData.points.push(new PMPoint(0.25, 0.25, 0.25));\n",
       "obj12.userData.points.push(new PMPoint(0.333333, 0.333333, 0.333333));\n",
       "obj12.userData.points.push(new PMPoint(0.5, 0, 0.5));\n",
       "obj12.userData.points.push(new PMPoint(1, 0, 0));\n",
       "\n",
       "obj12.userData.pointradii = 0.02;\n",
       "   <!-- Vertex style -->\n",
       "obj12.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } );\n",
       "obj12.userData.pointlabels = [\"{0 1 2 3}\", \"{1 2 3}\", \"{1 3}\", \"{1}\"];\n",
       "obj12.userData.edgeindices = [0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3];\n",
       "   <!-- Edge style -->\n",
       "obj12.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, depthTest: true, linewidth: 1.5, transparent: false } );\n",
       "obj12.userData.facets = [[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3]];\n",
       "   <!-- Facet style -->\n",
       "obj12.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } );\n",
       "init_object(obj12);\n",
       "scene.add(obj12);\n",
       "\n",
       "var obj13 = new THREE.Object3D();\n",
       "obj13.name = \"{0 1 2 3} {0 1 2} {0 2} {2}\";\n",
       "obj13.userData.explodable = 1;\n",
       "obj13.userData.points = [];\n",
       "obj13.userData.points.push(new PMPoint(0.25, 0.25, 0.25));\n",
       "obj13.userData.points.push(new PMPoint(0.333333, 0.333333, 0));\n",
       "obj13.userData.points.push(new PMPoint(0, 0.5, 0));\n",
       "obj13.userData.points.push(new PMPoint(0, 1, 0));\n",
       "\n",
       "obj13.userData.pointradii = 0.02;\n",
       "   <!-- Vertex style -->\n",
       "obj13.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } );\n",
       "obj13.userData.pointlabels = [\"{0 1 2 3}\", \"{0 1 2}\", \"{0 2}\", \"{2}\"];\n",
       "obj13.userData.edgeindices = [0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3];\n",
       "   <!-- Edge style -->\n",
       "obj13.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, depthTest: true, linewidth: 1.5, transparent: false } );\n",
       "obj13.userData.facets = [[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3]];\n",
       "   <!-- Facet style -->\n",
       "obj13.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } );\n",
       "init_object(obj13);\n",
       "scene.add(obj13);\n",
       "\n",
       "var obj14 = new THREE.Object3D();\n",
       "obj14.name = \"{0 1 2 3} {0 2 3} {0 2} {2}\";\n",
       "obj14.userData.explodable = 1;\n",
       "obj14.userData.points = [];\n",
       "obj14.userData.points.push(new PMPoint(0.25, 0.25, 0.25));\n",
       "obj14.userData.points.push(new PMPoint(0, 0.333333, 0.333333));\n",
       "obj14.userData.points.push(new PMPoint(0, 0.5, 0));\n",
       "obj14.userData.points.push(new PMPoint(0, 1, 0));\n",
       "\n",
       "obj14.userData.pointradii = 0.02;\n",
       "   <!-- Vertex style -->\n",
       "obj14.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } );\n",
       "obj14.userData.pointlabels = [\"{0 1 2 3}\", \"{0 2 3}\", \"{0 2}\", \"{2}\"];\n",
       "obj14.userData.edgeindices = [0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3];\n",
       "   <!-- Edge style -->\n",
       "obj14.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, depthTest: true, linewidth: 1.5, transparent: false } );\n",
       "obj14.userData.facets = [[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3]];\n",
       "   <!-- Facet style -->\n",
       "obj14.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } );\n",
       "init_object(obj14);\n",
       "scene.add(obj14);\n",
       "\n",
       "var obj15 = new THREE.Object3D();\n",
       "obj15.name = \"{0 1 2 3} {0 1 2} {1 2} {2}\";\n",
       "obj15.userData.explodable = 1;\n",
       "obj15.userData.points = [];\n",
       "obj15.userData.points.push(new PMPoint(0.25, 0.25, 0.25));\n",
       "obj15.userData.points.push(new PMPoint(0.333333, 0.333333, 0));\n",
       "obj15.userData.points.push(new PMPoint(0.5, 0.5, 0));\n",
       "obj15.userData.points.push(new PMPoint(0, 1, 0));\n",
       "\n",
       "obj15.userData.pointradii = 0.02;\n",
       "   <!-- Vertex style -->\n",
       "obj15.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } );\n",
       "obj15.userData.pointlabels = [\"{0 1 2 3}\", \"{0 1 2}\", \"{1 2}\", \"{2}\"];\n",
       "obj15.userData.edgeindices = [0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3];\n",
       "   <!-- Edge style -->\n",
       "obj15.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, depthTest: true, linewidth: 1.5, transparent: false } );\n",
       "obj15.userData.facets = [[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3]];\n",
       "   <!-- Facet style -->\n",
       "obj15.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } );\n",
       "init_object(obj15);\n",
       "scene.add(obj15);\n",
       "\n",
       "var obj16 = new THREE.Object3D();\n",
       "obj16.name = \"{0 1 2 3} {1 2 3} {1 2} {2}\";\n",
       "obj16.userData.explodable = 1;\n",
       "obj16.userData.points = [];\n",
       "obj16.userData.points.push(new PMPoint(0.25, 0.25, 0.25));\n",
       "obj16.userData.points.push(new PMPoint(0.333333, 0.333333, 0.333333));\n",
       "obj16.userData.points.push(new PMPoint(0.5, 0.5, 0));\n",
       "obj16.userData.points.push(new PMPoint(0, 1, 0));\n",
       "\n",
       "obj16.userData.pointradii = 0.02;\n",
       "   <!-- Vertex style -->\n",
       "obj16.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } );\n",
       "obj16.userData.pointlabels = [\"{0 1 2 3}\", \"{1 2 3}\", \"{1 2}\", \"{2}\"];\n",
       "obj16.userData.edgeindices = [0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3];\n",
       "   <!-- Edge style -->\n",
       "obj16.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, depthTest: true, linewidth: 1.5, transparent: false } );\n",
       "obj16.userData.facets = [[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3]];\n",
       "   <!-- Facet style -->\n",
       "obj16.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } );\n",
       "init_object(obj16);\n",
       "scene.add(obj16);\n",
       "\n",
       "var obj17 = new THREE.Object3D();\n",
       "obj17.name = \"{0 1 2 3} {0 2 3} {2 3} {2}\";\n",
       "obj17.userData.explodable = 1;\n",
       "obj17.userData.points = [];\n",
       "obj17.userData.points.push(new PMPoint(0.25, 0.25, 0.25));\n",
       "obj17.userData.points.push(new PMPoint(0, 0.333333, 0.333333));\n",
       "obj17.userData.points.push(new PMPoint(0, 0.5, 0.5));\n",
       "obj17.userData.points.push(new PMPoint(0, 1, 0));\n",
       "\n",
       "obj17.userData.pointradii = 0.02;\n",
       "   <!-- Vertex style -->\n",
       "obj17.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } );\n",
       "obj17.userData.pointlabels = [\"{0 1 2 3}\", \"{0 2 3}\", \"{2 3}\", \"{2}\"];\n",
       "obj17.userData.edgeindices = [0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3];\n",
       "   <!-- Edge style -->\n",
       "obj17.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, depthTest: true, linewidth: 1.5, transparent: false } );\n",
       "obj17.userData.facets = [[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3]];\n",
       "   <!-- Facet style -->\n",
       "obj17.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } );\n",
       "init_object(obj17);\n",
       "scene.add(obj17);\n",
       "\n",
       "var obj18 = new THREE.Object3D();\n",
       "obj18.name = \"{0 1 2 3} {1 2 3} {2 3} {2}\";\n",
       "obj18.userData.explodable = 1;\n",
       "obj18.userData.points = [];\n",
       "obj18.userData.points.push(new PMPoint(0.25, 0.25, 0.25));\n",
       "obj18.userData.points.push(new PMPoint(0.333333, 0.333333, 0.333333));\n",
       "obj18.userData.points.push(new PMPoint(0, 0.5, 0.5));\n",
       "obj18.userData.points.push(new PMPoint(0, 1, 0));\n",
       "\n",
       "obj18.userData.pointradii = 0.02;\n",
       "   <!-- Vertex style -->\n",
       "obj18.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } );\n",
       "obj18.userData.pointlabels = [\"{0 1 2 3}\", \"{1 2 3}\", \"{2 3}\", \"{2}\"];\n",
       "obj18.userData.edgeindices = [0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3];\n",
       "   <!-- Edge style -->\n",
       "obj18.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, depthTest: true, linewidth: 1.5, transparent: false } );\n",
       "obj18.userData.facets = [[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3]];\n",
       "   <!-- Facet style -->\n",
       "obj18.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } );\n",
       "init_object(obj18);\n",
       "scene.add(obj18);\n",
       "\n",
       "var obj19 = new THREE.Object3D();\n",
       "obj19.name = \"{0 1 2 3} {0 1 3} {0 3} {3}\";\n",
       "obj19.userData.explodable = 1;\n",
       "obj19.userData.points = [];\n",
       "obj19.userData.points.push(new PMPoint(0.25, 0.25, 0.25));\n",
       "obj19.userData.points.push(new PMPoint(0.333333, 0, 0.333333));\n",
       "obj19.userData.points.push(new PMPoint(0, 0, 0.5));\n",
       "obj19.userData.points.push(new PMPoint(0, 0, 1));\n",
       "\n",
       "obj19.userData.pointradii = 0.02;\n",
       "   <!-- Vertex style -->\n",
       "obj19.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } );\n",
       "obj19.userData.pointlabels = [\"{0 1 2 3}\", \"{0 1 3}\", \"{0 3}\", \"{3}\"];\n",
       "obj19.userData.edgeindices = [0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3];\n",
       "   <!-- Edge style -->\n",
       "obj19.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, depthTest: true, linewidth: 1.5, transparent: false } );\n",
       "obj19.userData.facets = [[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3]];\n",
       "   <!-- Facet style -->\n",
       "obj19.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } );\n",
       "init_object(obj19);\n",
       "scene.add(obj19);\n",
       "\n",
       "var obj20 = new THREE.Object3D();\n",
       "obj20.name = \"{0 1 2 3} {0 2 3} {0 3} {3}\";\n",
       "obj20.userData.explodable = 1;\n",
       "obj20.userData.points = [];\n",
       "obj20.userData.points.push(new PMPoint(0.25, 0.25, 0.25));\n",
       "obj20.userData.points.push(new PMPoint(0, 0.333333, 0.333333));\n",
       "obj20.userData.points.push(new PMPoint(0, 0, 0.5));\n",
       "obj20.userData.points.push(new PMPoint(0, 0, 1));\n",
       "\n",
       "obj20.userData.pointradii = 0.02;\n",
       "   <!-- Vertex style -->\n",
       "obj20.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } );\n",
       "obj20.userData.pointlabels = [\"{0 1 2 3}\", \"{0 2 3}\", \"{0 3}\", \"{3}\"];\n",
       "obj20.userData.edgeindices = [0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3];\n",
       "   <!-- Edge style -->\n",
       "obj20.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, depthTest: true, linewidth: 1.5, transparent: false } );\n",
       "obj20.userData.facets = [[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3]];\n",
       "   <!-- Facet style -->\n",
       "obj20.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } );\n",
       "init_object(obj20);\n",
       "scene.add(obj20);\n",
       "\n",
       "var obj21 = new THREE.Object3D();\n",
       "obj21.name = \"{0 1 2 3} {0 1 3} {1 3} {3}\";\n",
       "obj21.userData.explodable = 1;\n",
       "obj21.userData.points = [];\n",
       "obj21.userData.points.push(new PMPoint(0.25, 0.25, 0.25));\n",
       "obj21.userData.points.push(new PMPoint(0.333333, 0, 0.333333));\n",
       "obj21.userData.points.push(new PMPoint(0.5, 0, 0.5));\n",
       "obj21.userData.points.push(new PMPoint(0, 0, 1));\n",
       "\n",
       "obj21.userData.pointradii = 0.02;\n",
       "   <!-- Vertex style -->\n",
       "obj21.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } );\n",
       "obj21.userData.pointlabels = [\"{0 1 2 3}\", \"{0 1 3}\", \"{1 3}\", \"{3}\"];\n",
       "obj21.userData.edgeindices = [0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3];\n",
       "   <!-- Edge style -->\n",
       "obj21.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, depthTest: true, linewidth: 1.5, transparent: false } );\n",
       "obj21.userData.facets = [[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3]];\n",
       "   <!-- Facet style -->\n",
       "obj21.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } );\n",
       "init_object(obj21);\n",
       "scene.add(obj21);\n",
       "\n",
       "var obj22 = new THREE.Object3D();\n",
       "obj22.name = \"{0 1 2 3} {1 2 3} {1 3} {3}\";\n",
       "obj22.userData.explodable = 1;\n",
       "obj22.userData.points = [];\n",
       "obj22.userData.points.push(new PMPoint(0.25, 0.25, 0.25));\n",
       "obj22.userData.points.push(new PMPoint(0.333333, 0.333333, 0.333333));\n",
       "obj22.userData.points.push(new PMPoint(0.5, 0, 0.5));\n",
       "obj22.userData.points.push(new PMPoint(0, 0, 1));\n",
       "\n",
       "obj22.userData.pointradii = 0.02;\n",
       "   <!-- Vertex style -->\n",
       "obj22.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } );\n",
       "obj22.userData.pointlabels = [\"{0 1 2 3}\", \"{1 2 3}\", \"{1 3}\", \"{3}\"];\n",
       "obj22.userData.edgeindices = [0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3];\n",
       "   <!-- Edge style -->\n",
       "obj22.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, depthTest: true, linewidth: 1.5, transparent: false } );\n",
       "obj22.userData.facets = [[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3]];\n",
       "   <!-- Facet style -->\n",
       "obj22.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } );\n",
       "init_object(obj22);\n",
       "scene.add(obj22);\n",
       "\n",
       "var obj23 = new THREE.Object3D();\n",
       "obj23.name = \"{0 1 2 3} {0 2 3} {2 3} {3}\";\n",
       "obj23.userData.explodable = 1;\n",
       "obj23.userData.points = [];\n",
       "obj23.userData.points.push(new PMPoint(0.25, 0.25, 0.25));\n",
       "obj23.userData.points.push(new PMPoint(0, 0.333333, 0.333333));\n",
       "obj23.userData.points.push(new PMPoint(0, 0.5, 0.5));\n",
       "obj23.userData.points.push(new PMPoint(0, 0, 1));\n",
       "\n",
       "obj23.userData.pointradii = 0.02;\n",
       "   <!-- Vertex style -->\n",
       "obj23.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } );\n",
       "obj23.userData.pointlabels = [\"{0 1 2 3}\", \"{0 2 3}\", \"{2 3}\", \"{3}\"];\n",
       "obj23.userData.edgeindices = [0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3];\n",
       "   <!-- Edge style -->\n",
       "obj23.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, depthTest: true, linewidth: 1.5, transparent: false } );\n",
       "obj23.userData.facets = [[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3]];\n",
       "   <!-- Facet style -->\n",
       "obj23.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } );\n",
       "init_object(obj23);\n",
       "scene.add(obj23);\n",
       "\n",
       "var obj24 = new THREE.Object3D();\n",
       "obj24.name = \"{0 1 2 3} {1 2 3} {2 3} {3}\";\n",
       "obj24.userData.explodable = 1;\n",
       "obj24.userData.points = [];\n",
       "obj24.userData.points.push(new PMPoint(0.25, 0.25, 0.25));\n",
       "obj24.userData.points.push(new PMPoint(0.333333, 0.333333, 0.333333));\n",
       "obj24.userData.points.push(new PMPoint(0, 0.5, 0.5));\n",
       "obj24.userData.points.push(new PMPoint(0, 0, 1));\n",
       "\n",
       "obj24.userData.pointradii = 0.02;\n",
       "   <!-- Vertex style -->\n",
       "obj24.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } );\n",
       "obj24.userData.pointlabels = [\"{0 1 2 3}\", \"{1 2 3}\", \"{2 3}\", \"{3}\"];\n",
       "obj24.userData.edgeindices = [0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3];\n",
       "   <!-- Edge style -->\n",
       "obj24.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, depthTest: true, linewidth: 1.5, transparent: false } );\n",
       "obj24.userData.facets = [[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3]];\n",
       "   <!-- Facet style -->\n",
       "obj24.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } );\n",
       "init_object(obj24);\n",
       "scene.add(obj24);\n",
       "\n",
       "// COMMON_CODE_BLOCK_BEGIN\n",
       "function textSpriteMaterial(message, parameters) {\n",
       "    if ( parameters === undefined ) parameters = {};\n",
       "    var fontface = \"Helvetica\";\n",
       "    var fontsize = parameters.hasOwnProperty(\"fontsize\") ? parameters[\"fontsize\"] : 15;\n",
       "    fontsize = fontsize*10;\n",
       "    var lines = message.split('\\\\n');\n",
       "    var size = 512;\n",
       "    for(var i = 0; i<lines.length; i++){\n",
       "        var tmp = lines[i].length;\n",
       "        while(tmp*fontsize > size){\n",
       "           fontsize--;\n",
       "        }\n",
       "    }\n",
       "    \n",
       "    var canvas = document.createElement('canvas');\n",
       "    canvas.width = size;\n",
       "    canvas.height = size;\n",
       "    var context = canvas.getContext('2d');\n",
       "    context.fillStyle = \"rgba(255, 255, 255, 0)\";\n",
       "    context.fill();\n",
       "    context.font = fontsize + \"px \" + fontface;\n",
       "    \n",
       "    // text color\n",
       "    context.fillStyle = \"rgba(0, 0, 0, 1.0)\";\n",
       "     for(var i = 0; i<lines.length; i++){\n",
       "        context.fillText(lines[i], size/2, size/2+i*fontsize);\n",
       "     }\n",
       "    \n",
       "    // canvas contents will be used for a texture\n",
       "    var texture = new THREE.Texture(canvas);\n",
       "    texture.needsUpdate = true;\n",
       "    \n",
       "    var spriteMaterial = new THREE.SpriteMaterial({map: texture, depthTest: true, depthWrite: false, polygonOffset: true, polygonOffsetFactor: -1, polygonOffsetUnits: 1 });\n",
       "    return spriteMaterial;\n",
       "}\n",
       "\n",
       "\n",
       "// ---------------------- INITIALIZING OBJECTS--------------------------------------\n",
       "// ---------------------------------------------------------------------------------\n",
       "\n",
       "function init_object(obj) {\n",
       "    if (obj.userData.hasOwnProperty(\"pointmaterial\")) {\n",
       "        init_points(obj);\n",
       "        modelContains.points = true;\n",
       "    }\n",
       "    if (obj.userData.hasOwnProperty(\"pointlabels\")) {\n",
       "        init_pointlabels(obj);\n",
       "        modelContains.pointlabels = true;\n",
       "    }\n",
       "    if (obj.userData.hasOwnProperty(\"edgematerial\")) {\n",
       "        init_lines(obj);\n",
       "        modelContains.lines = true;\n",
       "    }\n",
       "    if (obj.userData.hasOwnProperty(\"edgelabels\")) {\n",
       "        init_edgelabels(obj);\n",
       "        modelContains.edgelabels = true;\n",
       "    }\n",
       "    if (obj.userData.hasOwnProperty(\"arrowstyle\")) {\n",
       "        init_arrowheads(obj);\n",
       "        modelContains.arrowheads = true;\n",
       "    }\n",
       "    if (obj.userData.hasOwnProperty(\"facetmaterial\")) {\n",
       "        init_faces(obj);\n",
       "        modelContains.faces = true;\n",
       "    }\n",
       "}\n",
       "\n",
       "function init_points(obj) {\n",
       "    var pointgroup = new THREE.Group();\n",
       "    pointgroup.name = \"points\";\n",
       "    var points = obj.userData.points;\n",
       "    var radii = obj.userData.pointradii;\n",
       "    var materials = obj.userData.pointmaterial;\n",
       "    var geometry,material;\n",
       "    if (!Array.isArray(radii)) {\n",
       "        geometry = new THREE.SphereBufferGeometry(radii);  \n",
       "    }\n",
       "    if (!Array.isArray(materials)) {\n",
       "        material = materials;\n",
       "    }\n",
       "    for (var i=0; i<points.length; i++) {\n",
       "        var point = points[i];\n",
       "        if (Array.isArray(radii)) {\n",
       "            if (radii[i] == 0) {\n",
       "                continue;\n",
       "            }\n",
       "            geometry = new THREE.SphereBufferGeometry(radii[i]);  \n",
       "        } \n",
       "        if (Array.isArray(materials)) {\n",
       "            material = materials[i];     \n",
       "        } \n",
       "        var sphere = new THREE.Mesh(geometry, material);\n",
       "        point.addSphere(sphere);\n",
       "        pointgroup.add(sphere);\n",
       "    }\n",
       "    obj.add(pointgroup);\n",
       "}\n",
       "\n",
       "function init_pointlabels(obj) {\n",
       "    var points = obj.userData.points;\n",
       "    var labels = obj.userData.pointlabels;\n",
       "    var pointlabels = new THREE.Group();\n",
       "    pointlabels.name = \"pointlabels\";\n",
       "    if (Array.isArray(labels)) {\n",
       "        for (var i=0; i<points.length; i++) {\n",
       "            var point = points[i];\n",
       "            var spriteMaterial = textSpriteMaterial( labels[i] );\n",
       "\t        var sprite = new THREE.Sprite(spriteMaterial);\n",
       "            point.addLabel(sprite);\n",
       "            pointlabels.add(sprite);\n",
       "        }\n",
       "    } else {\n",
       "        var spriteMaterial = textSpriteMaterial( labels );\n",
       "        for (var i=0; i<points.length; i++) {\n",
       "            var point = points[i];\n",
       "\t        var sprite = new THREE.Sprite(spriteMaterial);\n",
       "            point.addLabel(sprite);\n",
       "            pointlabels.add(sprite);\n",
       "        }\n",
       "    }\n",
       "    obj.add(pointlabels);\n",
       "}\n",
       "\n",
       "function init_lines(obj) {\n",
       "    var edgeindices = obj.userData.edgeindices;\n",
       "    var points = obj.userData.points;\n",
       "    var materials = obj.userData.edgematerial;\n",
       "    var geometry = new THREE.BufferGeometry();\n",
       "    var bufarr = new Float32Array( obj.userData.edgeindices.length * 3 );\n",
       "    var bufattr = new THREE.Float32BufferAttribute( bufarr, 3 );\n",
       "    var geometry = new THREE.BufferGeometry();\n",
       "    geometry.setAttribute('position', bufattr);\n",
       "    if (Array.isArray(materials)) {     \n",
       "        for (var i=0; i<materials.length; i++) {\n",
       "            geometry.addGroup(2*i,2,i);\n",
       "        }\n",
       "    }\n",
       "    var lines = new THREE.LineSegments(geometry, materials);\n",
       "    lines.name = \"lines\";\n",
       "    obj.add(lines);\n",
       "    updateEdgesPosition(obj);\n",
       "}\n",
       "\n",
       "function init_edgelabels(obj) {\n",
       "    var points = obj.userData.points;\n",
       "    var edgeindices = obj.userData.edgeindices;\n",
       "    var labels = obj.userData.edgelabels;\n",
       "    var edgelabels = new THREE.Group();\n",
       "    edgelabels.name = \"edgelabels\";\n",
       "    if (Array.isArray(labels)) {\n",
       "        for (var i=0; i<edgeindices.length; i=i+2) {\n",
       "            var point = points[i];\n",
       "            var spriteMaterial = textSpriteMaterial( labels[i] );\n",
       "            var sprite = new THREE.Sprite(spriteMaterial);\n",
       "            sprite.position.copy(new THREE.Vector3().addVectors(points[edgeindices[i]].vector,points[edgeindices[i+1]].vector).multiplyScalar(0.5));\n",
       "            edgelabels.add(sprite);\n",
       "        }\n",
       "    } else {\n",
       "        var spriteMaterial = textSpriteMaterial( labels );\n",
       "        for (var i=0; i<points.length; i++) {\n",
       "            var point = points[i];\n",
       "            var sprite = new THREE.Sprite(spriteMaterial);\n",
       "            sprite.position.copy(new THREE.Vector3().addVectors(points[edgeindices[i]].vector,points[edgeindices[i+1]].vector).multiplyScalar(0.5));\n",
       "            pointlabels.add(sprite);\n",
       "        }\n",
       "    }\n",
       "    obj.add(edgelabels);\n",
       "}\n",
       "\n",
       "function init_arrowheads(obj) {\n",
       "    var arrowheads = new THREE.Group();\n",
       "    arrowheads.name = \"arrowheads\";\n",
       "    var arrowstyle = obj.userData.arrowstyle;\n",
       "    var edgeindices = obj.userData.edgeindices;\n",
       "    var edgematerials = obj.userData.edgematerial;\n",
       "    var points = obj.userData.points;\n",
       "    var material;\n",
       "    if (!Array.isArray(edgematerials)) {\n",
       "        material = new THREE.MeshBasicMaterial( {color: edgematerials.color} );\n",
       "    }\n",
       "\n",
       "    for (var i=0; i<edgeindices.length; i=i+2) {\n",
       "        var start = points[edgeindices[i]];\n",
       "        var end = points[edgeindices[i+1]];\n",
       "        var dist = start.vector.distanceTo( end.vector ) - start.radius() - end.radius();\n",
       "        if (dist <= 0) {\n",
       "            continue;\n",
       "        }\n",
       "        var dir = new THREE.Vector3().subVectors(end.vector,start.vector);\n",
       "        dir.normalize();\n",
       "        var axis = new THREE.Vector3().set(dir.z,0,-dir.x);\n",
       "        axis.normalize();\n",
       "        var radians = Math.acos( dir.y );\n",
       "        var radius = dist/25;\n",
       "        var height = dist/5;\n",
       "        var geometry = new THREE.ConeBufferGeometry(radius,height);\n",
       "        var position = new THREE.Vector3().addVectors(start.vector,dir.clone().multiplyScalar(start.radius()+dist-height/2));\n",
       "        if (Array.isArray(edgematerials)) {\n",
       "            material = new THREE.MeshBasicMaterial( {color: edgematerials[i].color} );\n",
       "        }\n",
       "        var cone = new THREE.Mesh( geometry, material );\n",
       "        cone.quaternion.setFromAxisAngle(axis,radians);;\n",
       "        cone.position.copy(position);;\n",
       "        arrowheads.add(cone);\n",
       "    }\n",
       "    obj.add(arrowheads);\n",
       "}\n",
       "\n",
       "function init_faces(obj) {\n",
       "    var points = obj.userData.points;\n",
       "    var facets = obj.userData.facets;\n",
       "    obj.userData.triangleindices = [];\n",
       "    for (var i=0; i<facets.length; i++) {\n",
       "        facet = facets[i];\n",
       "        for (var t=0; t<facet.length-2; t++) {\n",
       "            obj.userData.triangleindices.push(facet[0],facet[t+1],facet[t+2]);  \n",
       "        }\n",
       "    }\n",
       "    var bufarr = new Float32Array( obj.userData.triangleindices.length * 3 );\n",
       "    var bufattr = new THREE.Float32BufferAttribute(bufarr,3);\n",
       "    \n",
       "    var materials = obj.userData.facetmaterial;\n",
       "    var geometry = new THREE.BufferGeometry();\n",
       "    geometry.setAttribute('position',bufattr);\n",
       "    if (Array.isArray(materials)) {\n",
       "        var tricount = 0;\n",
       "        var facet;\n",
       "        for (var i=0; i<facets.length; i++) {\n",
       "            facet = facets[i];\n",
       "            geometry.addGroup(tricount,(facet.length-2)*3,i);\n",
       "            tricount += (facet.length-2)*3;\n",
       "        }\n",
       "    }\n",
       "    var mesh = new THREE.Mesh(geometry, materials);\n",
       "    mesh.name = \"faces\";\n",
       "    obj.add(mesh); \n",
       "    updateFacesPosition(obj);\n",
       "}\n",
       "// //INITIALIZING\n",
       "\n",
       "\n",
       "function updateFacesPosition(obj) {\n",
       "    var points = obj.userData.points;\n",
       "    var indices = obj.userData.triangleindices;\n",
       "    var faces = obj.getObjectByName(\"faces\");\n",
       "    var ba = faces.geometry.getAttribute(\"position\");\n",
       "    for (var i=0; i<indices.length; i++) {\n",
       "        ba.setXYZ(i, points[indices[i]].vector.x, points[indices[i]].vector.y ,points[indices[i]].vector.z); \n",
       "    }\n",
       "    faces.geometry.attributes.position.needsUpdate = true;\n",
       "    \n",
       "}\n",
       "\n",
       "function updateEdgesPosition(obj) {\n",
       "    var points = obj.userData.points;\n",
       "    var indices = obj.userData.edgeindices;\n",
       "    var lines = obj.getObjectByName(\"lines\");\n",
       "    var ba = lines.geometry.getAttribute(\"position\"); \n",
       "    for (var i=0; i<indices.length; i++) {\n",
       "        ba.setXYZ(i, points[indices[i]].vector.x, points[indices[i]].vector.y ,points[indices[i]].vector.z); \n",
       "    }\n",
       "    lines.geometry.attributes.position.needsUpdate = true;\n",
       "}\n",
       "\n",
       "function onWindowResize() {\n",
       "    renderer.setSize( three.clientWidth, three.clientHeight );\n",
       "    svgRenderer.setSize( three.clientWidth, three.clientHeight );\n",
       "    updateCamera();\n",
       "}\n",
       "\n",
       "function updateCamera() {\n",
       "    var width = three.clientWidth;\n",
       "    var height = three.clientHeight;\n",
       "    var aspect = width / height;\n",
       "    if (camera.type == \"OrthographicCamera\") {\n",
       "        camera.left = frustumSize * aspect / - 2;\n",
       "        camera.right = frustumSize * aspect / 2;\n",
       "        camera.top = frustumSize / 2;\n",
       "        camera.bottom = - frustumSize / 2;\n",
       "    } else if (camera.type == \"PerspectiveCamera\") {\n",
       "        camera.aspect = aspect;\n",
       "    }\n",
       "    camera.updateProjectionMatrix();\n",
       "}\n",
       "\n",
       "function changeCamera(event) {\n",
       "    var selindex = event.currentTarget.selectedIndex;\n",
       "    camera = cameras[selindex];\n",
       "    control = controls[selindex];\n",
       "    control.enabled = true; \n",
       "    for (var i=0; i<controls.length; i++) {\n",
       "        if (i!=selindex) {\n",
       "            controls[i].enabled = false;\n",
       "        }\n",
       "    }\n",
       "    updateCamera();\n",
       "}\n",
       "\n",
       "var camtypenode = document.getElementById('cameraType_1');\n",
       "camtypenode.onchange = changeCamera;\n",
       "camtypenode.dispatchEvent(new Event('change'));\n",
       "\n",
       "onWindowResize();\n",
       "window.addEventListener('resize', onWindowResize);\t\n",
       "\n",
       "\n",
       "var xRotationEnabled = false;\n",
       "var yRotationEnabled = false;\n",
       "var zRotationEnabled = false;\n",
       "var rotationSpeedFactor = 1;\n",
       "var settingsShown = false;\n",
       "var labelsShown = true;\n",
       "var intervals = [];\n",
       "var timeouts = [];\n",
       "var explodingSpeed = 0.05;\n",
       "var explodeScale = 0;\n",
       "var XMLS = new XMLSerializer();\n",
       "var svgElement;\n",
       "var renderId;\n",
       "\n",
       "var render = function () {\n",
       "\n",
       "\trenderId = requestAnimationFrame(render);\n",
       "\n",
       "//\tcomment in for automatic explosion\n",
       "//\texplode(updateFactor());\n",
       "\n",
       "    var phi = 0.02 * rotationSpeedFactor;\n",
       "\n",
       "    if (xRotationEnabled) {\n",
       "        scene.rotation.x += phi;\n",
       "    }\n",
       "    if (yRotationEnabled) {\n",
       "        scene.rotation.y += phi;\n",
       "    }\n",
       "    if (zRotationEnabled) {\n",
       "        scene.rotation.z += phi;\n",
       "    }\n",
       "\n",
       "    control.update();\n",
       "    renderer.render(scene, camera);\n",
       "};\n",
       "\n",
       "if ( THREE.WEBGL.isWebGLAvailable() ) {\n",
       "\trender();\n",
       "} else {\n",
       "\tvar warning = WEBGL.getWebGLErrorMessage();\n",
       "\tthree.appendChild( warning );\n",
       "}\n",
       "    \n",
       "function changeTransparency() {\n",
       "    var opacity = 1-Number(event.currentTarget.value);\n",
       "    for (var i=0; i<scene.children.length; i++) {\n",
       "        child = scene.children[i];\n",
       "        if ( child.userData.hasOwnProperty(\"facetmaterial\") ) {\n",
       "            if (Array.isArray(child.userData.facetmaterial)) {\n",
       "                for (var j=0; j<child.userData.facetmaterial.length; j++) {\n",
       "                    child.userData.facetmaterial[j].opacity = opacity;\n",
       "                }\n",
       "            } else {\n",
       "                child.userData.facetmaterial.opacity = opacity;\n",
       "            }    \n",
       "        }\n",
       "    }\n",
       "}\n",
       "\n",
       "function changeRotationX(event){\n",
       "    xRotationEnabled = event.currentTarget.checked;\n",
       "}\t\n",
       "\n",
       "function changeRotationY(event){\n",
       "    yRotationEnabled = event.currentTarget.checked;\n",
       "}\t\n",
       "\n",
       "function changeRotationZ(event){\n",
       "    zRotationEnabled = event.currentTarget.checked;\n",
       "}\t\n",
       "\n",
       "\n",
       "function changeRotationSpeedFactor(event){\n",
       "    rotationSpeedFactor = Number(event.currentTarget.value);\n",
       "}\n",
       "\n",
       "function resetScene(){\n",
       "    scene.rotation.set(0,0,0);\n",
       "    camera.position.set(0,0,5);\n",
       "    camera.up.set(0,1,0);\n",
       "}\n",
       "\n",
       "function showSettings(event){\n",
       "    document.getElementById('settings_1').style.visibility = 'visible';\n",
       "    document.getElementById('showSettingsButton_1').style.visibility = 'hidden';\n",
       "    document.getElementById('hideSettingsButton_1').style.visibility = 'visible';\n",
       "    settingsShown = true;\n",
       "}\n",
       "\n",
       "function hideSettings(event){\n",
       "    document.getElementById('settings_1').style.visibility = 'hidden';\n",
       "    document.getElementById('showSettingsButton_1').style.visibility = 'visible';\n",
       "    document.getElementById('hideSettingsButton_1').style.visibility = 'hidden';\n",
       "    settingsShown = false;\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "var pos = 150* Math.PI;\n",
       "\n",
       "function updateFactor() {\n",
       "    pos++;\n",
       "    return Math.sin(.01*pos)+1;\n",
       "}\n",
       "\n",
       "// ------------------------ FOLDING ------------------------------------------------\n",
       "// ---------------------------------------------------------------------------------\n",
       "// rotate point p around axis defined by points p1 and p2 by given angle\n",
       "function rotate(p, p1, p2, angle ){   \n",
       "    angle = -angle;\n",
       "    var x = p.x, y = p.y, z = p.z, \n",
       "    a = p1.x, b = p1.y, c = p1.z, \n",
       "    u = p2.x-p1.x, v = p2.y-p1.y, w = p2.z-p1.z;\n",
       "    var result = [];\n",
       "    var L = u*u + v*v + w*w;\n",
       "    var sqrt = Math.sqrt;\n",
       "    var cos = Math.cos;\n",
       "    var sin = Math.sin;\n",
       "\n",
       "    result[0] = ((a*(v*v+w*w)-u*(b*v+c*w-u*x-v*y-w*z))*(1-cos(angle))+L*x*cos(angle)+sqrt(L)*(-c*v+b*w-w*y+v*z)*sin(angle))/L;\n",
       "    result[1] = ((b*(u*u+w*w)-v*(a*u+c*w-u*x-v*y-w*z))*(1-cos(angle))+L*y*cos(angle)+sqrt(L)*(c*u-a*w+w*x-u*z)*sin(angle))/L;\n",
       "    result[2] = ((c*(u*u+v*v)-w*(a*u+b*v-u*x-v*y-w*z))*(1-cos(angle))+L*z*cos(angle)+sqrt(L)*(-b*u+a*v-v*x+u*y)*sin(angle))/L;\n",
       "\n",
       "    return result;\n",
       "}\n",
       "\n",
       "var fold = function(event){\n",
       "    var obj = foldables[Number(event.currentTarget.name)];\n",
       "    var foldvalue = Number(event.currentTarget.value);\n",
       "    var scale = foldvalue - obj.userData.oldscale;\n",
       "\n",
       "    for (var j=0; j<obj.userData.axes.length; j++) {\n",
       "        rotateVertices(obj, j, scale);\n",
       "    }\n",
       "    update(obj);\n",
       "    obj.userData.oldscale += scale;\n",
       "    lookAtBarycenter(obj);\n",
       "}\n",
       "\n",
       "function lookAtBarycenter(obj){\n",
       "    control.target = barycenter(obj);\n",
       "}\n",
       "\n",
       "function barycenter(obj) {\n",
       "    var center = new THREE.Vector3(0,0,0);\n",
       "    var points = obj.userData.points;\n",
       "    for (var i=0; i<points.length; i++){\n",
       "        center.add(points[i].vector);\n",
       "    }\n",
       "    center.divideScalar(points.length);\n",
       "    return center;\n",
       "}\n",
       "\n",
       "function rotateVertices(obj, edge, scale) {\n",
       "    var axes = obj.userData.axes;\n",
       "    var subtrees = obj.userData.subtrees;\n",
       "    var points = obj.userData.points;\n",
       "    var angles = obj.userData.angles;\n",
       "    if (edge < axes.length){\n",
       "        for (var j=0; j<subtrees[edge].length; j++){\n",
       "            var rotP = rotate(points[subtrees[edge][j]].vector, points[axes[edge][0]].vector,points[axes[edge][1]].vector, scale * (Math.PI - angles[edge]));\n",
       "            points[subtrees[edge][j]].set(rotP[0],rotP[1],rotP[2]);\n",
       "        }\n",
       "    }\n",
       "}\n",
       "\n",
       "function update(obj) {\n",
       "   updateFacesPosition(obj);\n",
       "   updateEdgesPosition(obj);\n",
       "}\n",
       "\n",
       "if (foldables.length) {\n",
       "    var settings = document.getElementById('settings_1');\n",
       "    var foldDiv = document.createElement('div');\n",
       "    foldDiv.id = 'fold_1';\n",
       "    var title = document.createElement('strong');\n",
       "    title.innerHTML = 'Fold';\n",
       "    foldDiv.appendChild(title);\n",
       "    foldDiv.className = 'group';\n",
       "    for (var i=0; i<foldables.length; i++) {\n",
       "        var range = document.createElement('input');\n",
       "        range.type = 'range';\n",
       "        range.min = 0;\n",
       "        range.max = 1;\n",
       "        range.value = 0;\n",
       "        range.step = 0.001;\n",
       "        range.name = String(i);\n",
       "        range.oninput = fold;\n",
       "        foldDiv.appendChild(range);\n",
       "    }\n",
       "    lookAtBarycenter(foldables[0]);\n",
       "    settings.insertBefore(foldDiv,settings.childNodes[0]);\n",
       "}\n",
       "\n",
       "    \n",
       "// ---------------------- EXPLOSION ------------------------------------------------\n",
       "// ---------------------------------------------------------------------------------\n",
       "\n",
       "if (explodableModel) {\n",
       "    for (var i=0; i<scene.children.length; i++) {\n",
       "        obj = scene.children[i];\n",
       "        if ( obj.userData.explodable ) {\n",
       "            computeCentroid(obj);\n",
       "        }\n",
       "    }\n",
       "    document.getElementById('explodeRange_1').oninput = triggerExplode;\n",
       "    document.getElementById('explodeCheckbox_1').onchange = triggerAutomaticExplode;\n",
       "    document.getElementById('explodingSpeedRange_1').oninput = setExplodingSpeed;\n",
       "}\n",
       "\n",
       "function computeCentroid(obj) {\n",
       "    centroid = new THREE.Vector3();\n",
       "    obj.userData.points.forEach(function(pmpoint) {\n",
       "        centroid.add(pmpoint.vector);\t\t\t\n",
       "    });\n",
       "    centroid.divideScalar(obj.userData.points.length);\n",
       "    obj.userData.centroid = centroid;\n",
       "}\n",
       "\n",
       "function explode(factor) {\n",
       "    for (var i=0; i<scene.children.length; i++) {\n",
       "        var obj = scene.children[i];\n",
       "        if (obj.userData.hasOwnProperty(\"centroid\")) { \n",
       "            var c = obj.userData.centroid;\n",
       "            obj.position.set(c.x*factor, c.y*factor, c.z*factor);\n",
       "        }\n",
       "    }\t\n",
       "}\n",
       "\n",
       "function triggerExplode(event){\n",
       "    explodeScale = Number(event.currentTarget.value);\n",
       "    explode(explodeScale);\n",
       "}\n",
       "\n",
       "function setExplodingSpeed(event){\n",
       "    explodingSpeed = Number(event.currentTarget.value);\n",
       "}\n",
       "\n",
       "function triggerAutomaticExplode(event){\n",
       "    if (event.currentTarget.checked){\n",
       "        startExploding();\n",
       "    } else {\n",
       "        clearIntervals();\n",
       "    }\t\n",
       "}\n",
       "\n",
       "function startExploding(){\n",
       "    intervals.push(setInterval(explodingInterval, 25));\n",
       "}\n",
       "\n",
       "\n",
       "function explodingInterval(){\n",
       "    explodeScale += explodingSpeed;\n",
       "    if (explodeScale <= 6){ \n",
       "        explode(explodeScale);\n",
       "    }\n",
       "    else{\n",
       "        explode(6);\n",
       "        explodeScale = 6;\n",
       "        clearIntervals();\n",
       "        timeouts.push(setTimeout(startUnexploding, 3000));\n",
       "    }\n",
       "    document.getElementById('explodeRange_1').value = explodeScale;\n",
       "}\n",
       "\n",
       "\n",
       "function startUnexploding(){\n",
       "    intervals.push(setInterval(unexplodingInterval, 25));\n",
       "}\n",
       "\n",
       "function unexplodingInterval(){\n",
       "    explodeScale -= explodingSpeed;\n",
       "    if (explodeScale >= 0){\t\n",
       "        explode(explodeScale);\n",
       "    }\n",
       "    else {\n",
       "        explode(0);\n",
       "        explodeScale = 0;\n",
       "        clearIntervals();\n",
       "        timeouts.push(setTimeout(startExploding, 3000));\n",
       "    }\n",
       "    document.getElementById('explodeRange_1').value = explodeScale;\n",
       "}\n",
       "\n",
       "function clearIntervals(){\n",
       "    intervals.forEach(function(interval){\n",
       "        clearInterval(interval);\n",
       "    });\n",
       "    intervals = [];\n",
       "    timeouts.forEach(function(timeout){\n",
       "        clearTimeout(timeout);\n",
       "    });\n",
       "    timeouts = [];\n",
       "}\n",
       "\n",
       "// ---------------------- DISPLAY --------------------------------------------------\n",
       "// ---------------------------------------------------------------------------------\n",
       "\n",
       "const objectTypeInnerHTMLs = { points: \"Points\", pointlabels: \"Point labels\", lines: \"Edges\", edgelabels: \"Edge labels\", faces: \"Faces\", arrowheads: \"Arrow heads\" };\n",
       "const objectTypeVisible = {};\n",
       "Object.assign(objectTypeVisible,modelContains);\n",
       "const sortedObjectTypeKeys = Object.keys(objectTypeInnerHTMLs).sort();\n",
       "const shownObjectTypesList = document.getElementById('shownObjectTypesList_1');\n",
       "\n",
       "function setVisibility(bool,objname) {\n",
       "    for (var i=0; i<scene.children.length; i++){\n",
       "        var obj = scene.children[i].getObjectByName(objname);\n",
       "        if (obj) {\n",
       "            obj.visible = bool;\n",
       "        }\n",
       "    }\n",
       "}\n",
       "\n",
       "function toggleObjectTypeVisibility(event){\n",
       "    var name = event.currentTarget.name;\n",
       "    var checked = event.currentTarget.checked;\n",
       "    objectTypeVisible[name] = checked;\n",
       "    setVisibility(checked,name);\n",
       "}\n",
       "\n",
       "for (var i=0; i<sortedObjectTypeKeys.length; i++){\n",
       "    var key = sortedObjectTypeKeys[i];\n",
       "    if (modelContains[key]) {\n",
       "        var objTypeNode = document.createElement('span');\n",
       "        objTypeNode.innerHTML = objectTypeInnerHTMLs[key] + '<br>';\n",
       "        var checkbox = document.createElement('input');\n",
       "        checkbox.type = 'checkbox';\n",
       "        checkbox.checked = true;\n",
       "        checkbox.name = key;\n",
       "        checkbox.onchange = toggleObjectTypeVisibility;\n",
       "        shownObjectTypesList.appendChild(checkbox);\n",
       "        shownObjectTypesList.appendChild(objTypeNode);\n",
       "    }\n",
       "}\n",
       "\n",
       "// ------------------------------------------------------\n",
       "\n",
       "function toggleObjectVisibility(event){\n",
       "    var nr = Number(event.currentTarget.name);\n",
       "    scene.children[nr].visible = event.currentTarget.checked;\n",
       "}\n",
       "\n",
       "// append checkboxes for displaying or hiding objects\n",
       "var shownObjectsList = document.getElementById('shownObjectsList_1');\n",
       "for (var i=0; i<scene.children.length; i++){\n",
       "    obj = scene.children[i];\n",
       "    var objNode = document.createElement('span');\n",
       "    objNode.innerHTML = obj.name + '<br>';\n",
       "    var checkbox = document.createElement('input');\n",
       "    checkbox.type = 'checkbox';\n",
       "    checkbox.checked = true;\n",
       "    checkbox.name = String(i);\n",
       "    checkbox.onchange = toggleObjectVisibility;\n",
       "    shownObjectsList.appendChild(checkbox);\n",
       "    shownObjectsList.appendChild(objNode);\n",
       "}\n",
       "\n",
       "// ---------------------- SVG ------------------------------------------------------\n",
       "// ---------------------------------------------------------------------------------\n",
       "\n",
       "function takeSvgScreenshot() {\n",
       "    if (objectTypeVisible[\"pointlabels\"]) {\n",
       "        setVisibility(false,\"pointlabels\");\n",
       "    }\n",
       "    if (objectTypeVisible[\"edgelabels\"]) {\n",
       "        setVisibility(false,\"edgelabels\");\n",
       "    }\n",
       "    svgRenderer.render(scene,camera);\n",
       "    svgElement = XMLS.serializeToString(svgRenderer.domElement);\n",
       "    \n",
       "    if (objectTypeVisible[\"pointlabels\"]) {\n",
       "        setVisibility(true,\"pointlabels\");\n",
       "    }\n",
       "    if (objectTypeVisible[\"edgelabels\"]) {\n",
       "        setVisibility(true,\"edgelabels\");\n",
       "    }\n",
       "\n",
       "    if (document.getElementById('tab_1').checked){\n",
       "        //show in new tab\n",
       "        var myWindow = window.open(\"\",\"\");\n",
       "        myWindow.document.body.innerHTML = svgElement;\n",
       "    } else{\n",
       "        // download svg file \n",
       "        download(\"screenshot.svg\", svgElement);\n",
       "    }\n",
       "}\n",
       "\n",
       "function download(filename, text) {\n",
       "    var element = document.createElement('a');\n",
       "    element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));\n",
       "    element.setAttribute('download', filename);\n",
       "\n",
       "    element.style.display = 'none';\n",
       "    document.body.appendChild(element);\n",
       "\n",
       "    element.click();\n",
       "\n",
       "    document.body.removeChild(element);\n",
       "}\n",
       "\n",
       "\n",
       "document.getElementById('transparencyRange_1').oninput = changeTransparency;\n",
       "document.getElementById('changeRotationX_1').onchange = changeRotationX;\n",
       "document.getElementById('changeRotationY_1').onchange = changeRotationY;\n",
       "document.getElementById('changeRotationZ_1').onchange = changeRotationZ;\n",
       "document.getElementById('resetButton_1').onclick = resetScene;\n",
       "document.getElementById('rotationSpeedRange_1').oninput = changeRotationSpeedFactor;\n",
       "document.getElementById('takeScreenshot_1').onclick = takeSvgScreenshot;\n",
       "document.getElementById('showSettingsButton_1').onclick = showSettings;\n",
       "document.getElementById('hideSettingsButton_1').onclick = hideSettings;\n",
       "\n",
       "\n",
       "// ------------------ SHORTCUTS --------------------------------------------\n",
       "// -------------------------------------------------------------------------\n",
       "\n",
       "/**\n",
       " * http://www.openjs.com/scripts/events/keyboard_shortcuts/\n",
       " * Version : 2.01.B\n",
       " * By Binny V A\n",
       " * License : BSD\n",
       " */\n",
       "shortcut = {\n",
       "\t'all_shortcuts':{},//All the shortcuts are stored in this array\n",
       "\t'add': function(shortcut_combination,callback,opt) {\n",
       "\t\t//Provide a set of default options\n",
       "\t\tvar default_options = {\n",
       "\t\t\t'type':'keydown',\n",
       "\t\t\t'propagate':false,\n",
       "\t\t\t'disable_in_input':false,\n",
       "\t\t\t'target':document,\n",
       "\t\t\t'keycode':false\n",
       "\t\t}\n",
       "\t\tif(!opt) opt = default_options;\n",
       "\t\telse {\n",
       "\t\t\tfor(var dfo in default_options) {\n",
       "\t\t\t\tif(typeof opt[dfo] == 'undefined') opt[dfo] = default_options[dfo];\n",
       "\t\t\t}\n",
       "\t\t}\n",
       "\n",
       "\t\tvar ele = opt.target;\n",
       "\t\tif(typeof opt.target == 'string') ele = document.getElementById(opt.target);\n",
       "\t\tvar ths = this;\n",
       "\t\tshortcut_combination = shortcut_combination.toLowerCase();\n",
       "\n",
       "\t\t//The function to be called at keypress\n",
       "\t\tvar func = function(e) {\n",
       "\t\t\te = e || window.event;\n",
       "\t\t\t\n",
       "\t\t\tif(opt['disable_in_input']) { //Don't enable shortcut keys in Input, Textarea fields\n",
       "\t\t\t\tvar element;\n",
       "\t\t\t\tif(e.target) element=e.target;\n",
       "\t\t\t\telse if(e.srcElement) element=e.srcElement;\n",
       "\t\t\t\tif(element.nodeType==3) element=element.parentNode;\n",
       "\n",
       "\t\t\t\tif(element.tagName == 'INPUT' || element.tagName == 'TEXTAREA') return;\n",
       "\t\t\t}\n",
       "\t\n",
       "\t\t\t//Find Which key is pressed\n",
       "\t\t\tif (e.keyCode) code = e.keyCode;\n",
       "\t\t\telse if (e.which) code = e.which;\n",
       "\t\t\tvar character = String.fromCharCode(code).toLowerCase();\n",
       "\t\t\t\n",
       "\t\t\tif(code == 188) character=\",\"; //If the user presses , when the type is onkeydown\n",
       "\t\t\tif(code == 190) character=\".\"; //If the user presses , when the type is onkeydown\n",
       "\n",
       "\t\t\tvar keys = shortcut_combination.split(\"+\");\n",
       "\t\t\t//Key Pressed - counts the number of valid keypresses - if it is same as the number of keys, the shortcut function is invoked\n",
       "\t\t\tvar kp = 0;\n",
       "\t\t\t\n",
       "\t\t\t//Work around for stupid Shift key bug created by using lowercase - as a result the shift+num combination was broken\n",
       "\t\t\tvar shift_nums = {\n",
       "\t\t\t\t\"`\":\"~\",\n",
       "\t\t\t\t\"1\":\"!\",\n",
       "\t\t\t\t\"2\":\"@\",\n",
       "\t\t\t\t\"3\":\"#\",\n",
       "\t\t\t\t\"4\":\"$\",\n",
       "\t\t\t\t\"5\":\"%\",\n",
       "\t\t\t\t\"6\":\"^\",\n",
       "\t\t\t\t\"7\":\"&\",\n",
       "\t\t\t\t\"8\":\"*\",\n",
       "\t\t\t\t\"9\":\"(\",\n",
       "\t\t\t\t\"0\":\")\",\n",
       "\t\t\t\t\"-\":\"_\",\n",
       "\t\t\t\t\"=\":\"+\",\n",
       "\t\t\t\t\";\":\":\",\n",
       "\t\t\t\t\"'\":\"\\\"\",\n",
       "\t\t\t\t\",\":\"<\",\n",
       "\t\t\t\t\".\":\">\",\n",
       "\t\t\t\t\"/\":\"?\",\n",
       "\t\t\t\t\"\\\\\":\"|\"\n",
       "\t\t\t}\n",
       "\t\t\t//Special Keys - and their codes\n",
       "\t\t\tvar special_keys = {\n",
       "\t\t\t\t'esc':27,\n",
       "\t\t\t\t'escape':27,\n",
       "\t\t\t\t'tab':9,\n",
       "\t\t\t\t'space':32,\n",
       "\t\t\t\t'return':13,\n",
       "\t\t\t\t'enter':13,\n",
       "\t\t\t\t'backspace':8,\n",
       "\t\n",
       "\t\t\t\t'scrolllock':145,\n",
       "\t\t\t\t'scroll_lock':145,\n",
       "\t\t\t\t'scroll':145,\n",
       "\t\t\t\t'capslock':20,\n",
       "\t\t\t\t'caps_lock':20,\n",
       "\t\t\t\t'caps':20,\n",
       "\t\t\t\t'numlock':144,\n",
       "\t\t\t\t'num_lock':144,\n",
       "\t\t\t\t'num':144,\n",
       "\t\t\t\t\n",
       "\t\t\t\t'pause':19,\n",
       "\t\t\t\t'break':19,\n",
       "\t\t\t\t\n",
       "\t\t\t\t'insert':45,\n",
       "\t\t\t\t'home':36,\n",
       "\t\t\t\t'delete':46,\n",
       "\t\t\t\t'end':35,\n",
       "\t\t\t\t\n",
       "\t\t\t\t'pageup':33,\n",
       "\t\t\t\t'page_up':33,\n",
       "\t\t\t\t'pu':33,\n",
       "\t\n",
       "\t\t\t\t'pagedown':34,\n",
       "\t\t\t\t'page_down':34,\n",
       "\t\t\t\t'pd':34,\n",
       "\t\n",
       "\t\t\t\t'left':37,\n",
       "\t\t\t\t'up':38,\n",
       "\t\t\t\t'right':39,\n",
       "\t\t\t\t'down':40,\n",
       "\t\n",
       "\t\t\t\t'f1':112,\n",
       "\t\t\t\t'f2':113,\n",
       "\t\t\t\t'f3':114,\n",
       "\t\t\t\t'f4':115,\n",
       "\t\t\t\t'f5':116,\n",
       "\t\t\t\t'f6':117,\n",
       "\t\t\t\t'f7':118,\n",
       "\t\t\t\t'f8':119,\n",
       "\t\t\t\t'f9':120,\n",
       "\t\t\t\t'f10':121,\n",
       "\t\t\t\t'f11':122,\n",
       "\t\t\t\t'f12':123\n",
       "\t\t\t}\n",
       "\t\n",
       "\t\t\tvar modifiers = { \n",
       "\t\t\t\tshift: { wanted:false, pressed:false},\n",
       "\t\t\t\tctrl : { wanted:false, pressed:false},\n",
       "\t\t\t\talt  : { wanted:false, pressed:false},\n",
       "\t\t\t\tmeta : { wanted:false, pressed:false}\t//Meta is Mac specific\n",
       "\t\t\t};\n",
       "                        \n",
       "\t\t\tif(e.ctrlKey)\tmodifiers.ctrl.pressed = true;\n",
       "\t\t\tif(e.shiftKey)\tmodifiers.shift.pressed = true;\n",
       "\t\t\tif(e.altKey)\tmodifiers.alt.pressed = true;\n",
       "\t\t\tif(e.metaKey)   modifiers.meta.pressed = true;\n",
       "                        \n",
       "\t\t\tfor(var i=0; k=keys[i],i<keys.length; i++) {\n",
       "\t\t\t\t//Modifiers\n",
       "\t\t\t\tif(k == 'ctrl' || k == 'control') {\n",
       "\t\t\t\t\tkp++;\n",
       "\t\t\t\t\tmodifiers.ctrl.wanted = true;\n",
       "\n",
       "\t\t\t\t} else if(k == 'shift') {\n",
       "\t\t\t\t\tkp++;\n",
       "\t\t\t\t\tmodifiers.shift.wanted = true;\n",
       "\n",
       "\t\t\t\t} else if(k == 'alt') {\n",
       "\t\t\t\t\tkp++;\n",
       "\t\t\t\t\tmodifiers.alt.wanted = true;\n",
       "\t\t\t\t} else if(k == 'meta') {\n",
       "\t\t\t\t\tkp++;\n",
       "\t\t\t\t\tmodifiers.meta.wanted = true;\n",
       "\t\t\t\t} else if(k.length > 1) { //If it is a special key\n",
       "\t\t\t\t\tif(special_keys[k] == code) kp++;\n",
       "\t\t\t\t\t\n",
       "\t\t\t\t} else if(opt['keycode']) {\n",
       "\t\t\t\t\tif(opt['keycode'] == code) kp++;\n",
       "\n",
       "\t\t\t\t} else { //The special keys did not match\n",
       "\t\t\t\t\tif(character == k) kp++;\n",
       "\t\t\t\t\telse {\n",
       "\t\t\t\t\t\tif(shift_nums[character] && e.shiftKey) { //Stupid Shift key bug created by using lowercase\n",
       "\t\t\t\t\t\t\tcharacter = shift_nums[character]; \n",
       "\t\t\t\t\t\t\tif(character == k) kp++;\n",
       "\t\t\t\t\t\t}\n",
       "\t\t\t\t\t}\n",
       "\t\t\t\t}\n",
       "\t\t\t}\n",
       "\t\t\t\n",
       "\t\t\tif(kp == keys.length && \n",
       "\t\t\t\t\t\tmodifiers.ctrl.pressed == modifiers.ctrl.wanted &&\n",
       "\t\t\t\t\t\tmodifiers.shift.pressed == modifiers.shift.wanted &&\n",
       "\t\t\t\t\t\tmodifiers.alt.pressed == modifiers.alt.wanted &&\n",
       "\t\t\t\t\t\tmodifiers.meta.pressed == modifiers.meta.wanted) {\n",
       "\t\t\t\tcallback(e);\n",
       "\t\n",
       "\t\t\t\tif(!opt['propagate']) { //Stop the event\n",
       "\t\t\t\t\t//e.cancelBubble is supported by IE - this will kill the bubbling process.\n",
       "\t\t\t\t\te.cancelBubble = true;\n",
       "\t\t\t\t\te.returnValue = false;\n",
       "\t\n",
       "\t\t\t\t\t//e.stopPropagation works in Firefox.\n",
       "\t\t\t\t\tif (e.stopPropagation) {\n",
       "\t\t\t\t\t\te.stopPropagation();\n",
       "\t\t\t\t\t\te.preventDefault();\n",
       "\t\t\t\t\t}\n",
       "\t\t\t\t\treturn false;\n",
       "\t\t\t\t}\n",
       "\t\t\t}\n",
       "\t\t}\n",
       "\t\tthis.all_shortcuts[shortcut_combination] = {\n",
       "\t\t\t'callback':func, \n",
       "\t\t\t'target':ele, \n",
       "\t\t\t'event': opt['type']\n",
       "\t\t};\n",
       "\t\t//Attach the function with the event\n",
       "\t\tif(ele.addEventListener) ele.addEventListener(opt['type'], func, false);\n",
       "\t\telse if(ele.attachEvent) ele.attachEvent('on'+opt['type'], func);\n",
       "\t\telse ele['on'+opt['type']] = func;\n",
       "\t},\n",
       "\n",
       "\t//Remove the shortcut - just specify the shortcut and I will remove the binding\n",
       "\t'remove':function(shortcut_combination) {\n",
       "\t\tshortcut_combination = shortcut_combination.toLowerCase();\n",
       "\t\tvar binding = this.all_shortcuts[shortcut_combination];\n",
       "\t\tdelete(this.all_shortcuts[shortcut_combination])\n",
       "\t\tif(!binding) return;\n",
       "\t\tvar type = binding['event'];\n",
       "\t\tvar ele = binding['target'];\n",
       "\t\tvar callback = binding['callback'];\n",
       "\n",
       "\t\tif(ele.detachEvent) ele.detachEvent('on'+type, callback);\n",
       "\t\telse if(ele.removeEventListener) ele.removeEventListener(type, callback, false);\n",
       "\t\telse ele['on'+type] = false;\n",
       "\t}\n",
       "}\n",
       "\n",
       "shortcut.add(\"Alt+Left\",function() {\n",
       "\tvar event = new Event('click');\n",
       "\tif (settingsShown){\n",
       "\t\tdocument.getElementById('hideSettingsButton_1').dispatchEvent(event);\n",
       "\t} else {\n",
       "\t\tdocument.getElementById('showSettingsButton_1').dispatchEvent(event);\n",
       "\t}\n",
       "});\n",
       "\n",
       "\n",
       "// COMMON_CODE_BLOCK_END\n",
       "\n",
       "});});\n",
       "      </script>\n",
       "   </body>\n",
       "</html>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "$bs->VISUAL;"
   ]
  },
  {
   "attachments": {
    "ball_triang_pink.png": {
     "image/png": "[encoded data, 47904 characters]"
    }
   },
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "You should give the `explode` feature of jReality a try -- it gives a good (and pretty!) overview of the object. You can find it in the left slot of the jReality interface.\n",
    "\n",
    "![](attachment:ball_triang_pink.png) \n",
    "`topaz` may also visualize distinguished subcomplexes or just sets of faces with different decorations (colors, styles, etc.). For example, to highlight the fourth facet of `$bs` in pink, do this:\n",
    "\n",
    "    \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<!--\n",
       "polymake for knusper\n",
       "Thu Aug 27 10:41:00 2020\n",
       "bs\n",
       "-->\n",
       "\n",
       "\n",
       "<html>\n",
       "   <head>\n",
       "      <meta charset=utf-8>\n",
       "      <title>bs</title>\n",
       "      <style>\n",
       "/*\n",
       "// COMMON_CODE_BLOCK_BEGIN\n",
       "*/\n",
       "         html {overflow: scroll;}\n",
       "         strong{font-size: 18px;}\n",
       "         canvas { z-index: 8; }\n",
       "         input[type='radio'] {margin-left:0;}\n",
       "         input[type='checkbox'] {margin-right:7px; margin-left: 0px; padding-left:0px;}\n",
       "         .group{padding-bottom: 15px;}\n",
       "         .settings * {z-index: 11; }\n",
       "         .settings{z-index: 10; font-family: Arial, Helvetica, sans-serif; margin-left: 30px; visibility: hidden; width: 14em; height: 96%; border: solid 1px silver; padding: 2px; overflow-y: scroll; box-sizing: border-box; background-color: white; position: absolute;}\n",
       "         .indented{margin-left: 20px; margin-top: 10px; padding-bottom: 0px;} \n",
       "         .shownObjectsList{overflow: auto; max-width: 150px; max-height: 150px;}\n",
       "         .showSettingsButton{visibility: visible; z-index: 12; position: absolute }\n",
       "         .hideSettingsButton{visibility: hidden; z-index: 12; position: absolute; opacity: 0.5}\n",
       "         button{margin-left: 0; margin-top: 10px}\n",
       "         img{cursor: pointer;}\n",
       "         .suboption{padding-top: 15px;}\n",
       "         #model71730599789 { width: 100%; height: 100%; }\n",
       "         .threejs_container { width: 100%; height: 75vh;}\n",
       "         .settings{max-height: 74vh} \n",
       "         input[type=range] {\n",
       "           -webkit-appearance: none;\n",
       "           padding:0; \n",
       "           width:90%; \n",
       "           margin-left: auto;\n",
       "           margin-right: auto;\n",
       "           margin-top: 15px;\n",
       "           margin-bottom: 15px;\n",
       "           display: block;\t\n",
       "         }\n",
       "         input[type=range]:focus {\n",
       "           outline: none;\n",
       "         }\n",
       "         input[type=range]::-webkit-slider-runnable-track {\n",
       "           height: 4px;\n",
       "           cursor: pointer;\n",
       "           animate: 0.2s;\n",
       "           box-shadow: 0px 0px 0px #000000;\n",
       "           background: #E3E3E3;\n",
       "           border-radius: 0px;\n",
       "           border: 0px solid #000000;\n",
       "         }\n",
       "         input[type=range]::-webkit-slider-thumb {\n",
       "           box-shadow: 1px 1px 2px #B8B8B8;\n",
       "           border: 1px solid #ABABAB;\n",
       "           height: 13px;\n",
       "           width: 25px;\n",
       "           border-radius: 20px;\n",
       "           background: #E0E0E0;\n",
       "           cursor: pointer;\n",
       "           -webkit-appearance: none;\n",
       "           margin-top: -5px;\n",
       "         }\n",
       "         input[type=range]:focus::-webkit-slider-runnable-track {\n",
       "           background: #E3E3E3;\n",
       "         }\n",
       "         input[type=range]::-moz-range-track {\n",
       "           height: 4px;\n",
       "           cursor: pointer;\n",
       "           animate: 0.2s;\n",
       "           box-shadow: 0px 0px 0px #000000;\n",
       "           background: #E3E3E3;\n",
       "           border-radius: 0px;\n",
       "           border: 0px solid #000000;\n",
       "         }\n",
       "         input[type=range]::-moz-range-thumb {\n",
       "           box-shadow: 1px 1px 2px #B8B8B8;\n",
       "           border: 1px solid #ABABAB;\n",
       "           height: 13px;\n",
       "           width: 25px;\n",
       "           border-radius: 20px;\n",
       "           background: #E0E0E0;\n",
       "           cursor: pointer;\n",
       "         }\n",
       "         input[type=range]::-ms-track {\n",
       "           height: 4px;\n",
       "           cursor: pointer;\n",
       "           animate: 0.2s;\n",
       "           background: transparent;\n",
       "           border-color: transparent;\n",
       "           color: transparent;\n",
       "         }\n",
       "         input[type=range]::-ms-fill-lower {\n",
       "           background: #E3E3E3;\n",
       "           border: 0px solid #000000;\n",
       "           border-radius: 0px;\n",
       "           box-shadow: 0px 0px 0px #000000;\n",
       "         }\n",
       "         input[type=range]::-ms-fill-upper {\n",
       "           background: #E3E3E3;\n",
       "           border: 0px solid #000000;\n",
       "           border-radius: 0px;\n",
       "           box-shadow: 0px 0px 0px #000000;\n",
       "         }\n",
       "         input[type=range]::-ms-thumb {\n",
       "           box-shadow: 1px 1px 2px #B8B8B8;\n",
       "           border: 1px solid #ABABAB;\n",
       "           height: 13px;\n",
       "           width: 25px;\n",
       "           border-radius: 20px;\n",
       "           background: #E0E0E0;\n",
       "           cursor: pointer;\n",
       "         }\n",
       "         input[type=range]:focus::-ms-fill-lower {\n",
       "           background: #E3E3E3;\n",
       "         }\n",
       "         input[type=range]:focus::-ms-fill-upper {\n",
       "           background: #E3E3E3;\n",
       "         }\n",
       "/*\n",
       "// COMMON_CODE_BLOCK_END\n",
       "*/\n",
       "\t\t</style>\n",
       "   </head>\n",
       "<body>\n",
       "   <div class='threejs_container'>\n",
       "\t\t<div id='settings_2' class='settings'>\n",
       "\t\t\t<div class=group id='explode_2'>\n",
       "\t\t\t\t<strong>Explode</strong>\n",
       "\t\t\t\t<input id='explodeRange_2' type='range' min=0 max=6 step=0.01 value=0>\n",
       "\t\t\t\t<div class=indented><input id='explodeCheckbox_2' type='checkbox'>Automatic explosion</div>\n",
       "\t\t\t\t<div class=suboption>Exploding speed</div>\n",
       "\t\t\t\t<input id='explodingSpeedRange_2' type='range' min=0 max=0.5 step=0.001 value=0.05>\n",
       "\t\t\t</div>\n",
       "\t\n",
       "\t\t\t<div class=group id='transparency_2' class='transparency'>\n",
       "\t\t\t\t<strong>Transparency</strong>\n",
       "\t\t\t\t<input id='transparencyRange_2' type='range' min=0 max=1 step=0.01 value=0>\n",
       "\t\t\t</div>\n",
       "\t\t\t\n",
       "\t\t\t<div class=group id='rotation_2'>\n",
       "\t\t\t\t<strong>Rotation</strong>\n",
       "\t\t\t\t<div class=indented>\n",
       "\t\t\t\t\t<div><input type='checkbox' id='changeRotationX_2'> x-axis</div>\n",
       "\t\t\t\t\t<div><input type='checkbox' id='changeRotationY_2'> y-axis</div>\n",
       "\t\t\t\t\t<div><input type='checkbox' id='changeRotationZ_2'> z-axis</div>\n",
       "\t\t\t\t\t<button id='resetButton_2'>Reset</button>\n",
       "\t\t\t\t</div>\n",
       "\n",
       "\t\t\t\t<div class=suboption>Rotation speed</div>\n",
       "\t\t\t\t<input id='rotationSpeedRange_2' type='range' min=0 max=5 step=0.01 value=2>\n",
       "\t\t\t</div>\n",
       "\n",
       "\n",
       "\t\t\t<div class=group id='display_2'>\n",
       "\t\t\t\t<strong>Display</strong>\n",
       "\t\t\t\t<div class=indented>\n",
       "\t\t\t\t\t<div id='shownObjectTypesList_2' class='shownObjectsList'></div>\n",
       "\t\t\t\t</div>\n",
       "\t\t\t\t<div class=suboption>Objects</div>\n",
       "\t\t\t\t<div class=indented>\n",
       "\t\t\t\t   <div id='shownObjectsList_2' class='shownObjectsList'></div>\n",
       "\t\t\t\t</div>\n",
       "\t\t\t</div>\n",
       "         \n",
       "         <div class=group id='camera_2'>\n",
       "            <strong>Camera</strong>\n",
       "            <div class=indented>\n",
       "               <form>\n",
       "                  <select id=\"cameraType_2\">\n",
       "                     <option value='perspective' selected> Perspective<br></option>\n",
       "                     <option value='orthographic' > Orthographic<br></option>\n",
       "                  </select>\n",
       "               </form>\n",
       "            </div>\n",
       "         </div>\n",
       "\n",
       "\t\t\t<div class=group id='svg_2'>\n",
       "\t\t\t\t<strong>SVG</strong>\n",
       "\t\t\t\t<div class=indented>\n",
       "\t\t\t\t\t<form>\n",
       "\t\t\t\t\t\t<input type=\"radio\" name='screenshotMode' value='download' id='download_2' checked> Download<br>\n",
       "\t\t\t\t\t\t<input type=\"radio\" name='screenshotMode' value='tab' id='tab_2' > New tab<br>\n",
       "\t\t\t\t\t</form>\n",
       "\t\t\t\t\t<button id='takeScreenshot_2'>Screenshot</button>\n",
       "\t\t\t\t</div>\n",
       "\t\t\t</div>\n",
       "\n",
       "\t\t</div>\t<!-- end of settings -->\n",
       "\t\t<img id='hideSettingsButton_2' class='hideSettingsButton' src='/kernelspecs/polymake/close.svg' width=20px\">\n",
       "\t\t<img id='showSettingsButton_2' class='showSettingsButton' src='/kernelspecs/polymake/menu.svg' width=20px\">\n",
       "<div id=\"model71730599789\"></div>\n",
       "</div>\n",
       "   <script>\n",
       "    requirejs.config({\n",
       "      paths: {\n",
       "        three: '/kernelspecs/polymake/three',\n",
       "        TrackballControls: '/kernelspecs/polymake/TrackballControls',\n",
       "        OrbitControls: '/kernelspecs/polymake/OrbitControls',\n",
       "        Projector: '/kernelspecs/polymake/Projector',\n",
       "        SVGRenderer: '/kernelspecs/polymake/SVGRenderer',\n",
       "        WEBGL: '/kernelspecs/polymake/WebGL',\n",
       "      },\n",
       "      shim: {\n",
       "        'three': { exports: 'THREE'},\n",
       "        'SVGRenderer': { deps: [ 'three' ], exports: 'THREE.SVGRenderer' },\n",
       "        'WEBGL': { deps: [ 'three' ], exports: 'THREE.WEBGL' },\n",
       "        'Projector': { deps: [ 'three' ], exports: 'THREE.Projector' },\n",
       "        'TrackballControls': { deps: [ 'three' ], exports: 'THREE.TrackballControls' },\n",
       "        'OrbitControls': { deps: [ 'three' ], exports: 'THREE.OrbitControls' },\n",
       "      }\n",
       "    });\n",
       "    \n",
       "    require(['three'],function(THREE){\n",
       "        window.THREE = THREE;\n",
       "      require(['TrackballControls', 'OrbitControls', 'Projector', 'SVGRenderer', 'WEBGL'],\n",
       "               function(TrackballControls, OrbitControls, Projector, SVGRenderer, WEBGL) {\n",
       "    THREE.TrackballControls = TrackballControls;\n",
       "    THREE.OrbitControls = OrbitControls;\n",
       "    THREE.Projector = Projector;\n",
       "    THREE.SVGRenderer = SVGRenderer;\n",
       "    THREE.WEBGL = WEBGL;\n",
       "\n",
       "// COMMON_CODE_BLOCK_BEGIN\n",
       "\n",
       "const intervalLength = 25; // for automatic animations\n",
       "const explodableModel = true; \n",
       "const modelContains = { points: false, pointlabels: false, lines: false, edgelabels: false, faces: false, arrowheads: false };\n",
       "const foldables = [];\n",
       "\n",
       "var three = document.getElementById(\"model71730599789\");\n",
       "var scene = new THREE.Scene();\n",
       "var renderer = new THREE.WebGLRenderer( { antialias: true } );\n",
       "var svgRenderer = new THREE.SVGRenderer( { antialias: true } );\n",
       "renderer.setPixelRatio( window.devicePixelRatio );\n",
       "renderer.setClearColor(0xFFFFFF, 1);\n",
       "svgRenderer.setClearColor(0xFFFFFF, 1);\n",
       "three.appendChild(renderer.domElement);\n",
       "\n",
       "var frustumSize = 4;\n",
       "var cameras = [new THREE.PerspectiveCamera(75, 1, 0.1, 1000), new THREE.OrthographicCamera()];\n",
       "cameras.forEach(function(cam) {\n",
       "    cam.position.set(0, 0, 5);\n",
       "    cam.lookAt(0, 0, 0);  \n",
       "    cam.up.set(0, 1, 0);         \n",
       "});\n",
       "var controls = [new THREE.TrackballControls(cameras[0], three), new THREE.OrbitControls(cameras[1], three)];\n",
       "var camera, control;\n",
       "\n",
       "controls[0].zoomSpeed = 0.2;\n",
       "controls[0].rotateSpeed = 4;\n",
       "\n",
       "\n",
       "// class to allow move points together with labels and spheres\n",
       "var PMPoint = function (x,y,z) {\n",
       "   this.vector = new THREE.Vector3(x,y,z);\n",
       "   this.sprite = null;\n",
       "   this.sphere = null;\n",
       "}\n",
       "PMPoint.prototype.addLabel = function(labelsprite) {\n",
       "   this.sprite = labelsprite;\n",
       "   this.sprite.position.copy(this.vector);\n",
       "}\n",
       "PMPoint.prototype.addSphere = function(spheremesh) {\n",
       "   this.sphere = spheremesh;\n",
       "   this.sphere.position.copy(this.vector);\n",
       "}\n",
       "PMPoint.prototype.set = function(x,y,z) {\n",
       "   this.vector.set(x,y,z);\n",
       "   if (this.sprite) {\n",
       "      this.sprite.position.copy(this.vector);\n",
       "   }\n",
       "   if (this.sphere) {\n",
       "      this.sphere.position.copy(this.vector);\n",
       "   }\n",
       "}\n",
       "PMPoint.prototype.radius = function() {\n",
       "   if (this.sphere) {\n",
       "      return this.sphere.geometry.parameters.radius;\n",
       "   } else {\n",
       "      return 0;\n",
       "   }\n",
       "};\n",
       "// select the target node\n",
       "var target = document.querySelector('#model71730599789');\n",
       "\n",
       "// create an observer instance\n",
       "var observer = new MutationObserver(function(mutations) {\n",
       "   mutations.forEach(function(mutation) {\n",
       "      if (mutation.removedNodes && mutation.removedNodes.length > 0) {\n",
       "         cancelAnimationFrame(renderId);\n",
       "         observer.disconnect();\n",
       "         console.log(\"cancelled frame \"+renderId);\n",
       "      }\n",
       "   });\n",
       "});\n",
       "\n",
       "// configuration of the observer:\n",
       "var config = { childList: true, characterData: true }\n",
       "\n",
       "// pass in the target node, as well as the observer options\n",
       "while (target) {\n",
       "   if (target.className==\"output\") {\n",
       "      observer.observe(target, config);\n",
       "      break;\n",
       "   }\n",
       "   target = target.parentNode;\n",
       "}\n",
       "\n",
       "// COMMON_CODE_BLOCK_END\n",
       "\n",
       "var obj0 = new THREE.Object3D();\n",
       "obj0.name = \"GRAPH of bs\";\n",
       "obj0.userData.explodable = 1;\n",
       "obj0.userData.points = [];\n",
       "obj0.userData.points.push(new PMPoint(0.25, 0.25, 0.25));\n",
       "obj0.userData.points.push(new PMPoint(0.333333, 0.333333, 0));\n",
       "obj0.userData.points.push(new PMPoint(0.333333, 0, 0.333333));\n",
       "obj0.userData.points.push(new PMPoint(0, 0.333333, 0.333333));\n",
       "obj0.userData.points.push(new PMPoint(0.333333, 0.333333, 0.333333));\n",
       "obj0.userData.points.push(new PMPoint(0.5, 0, 0));\n",
       "obj0.userData.points.push(new PMPoint(0, 0.5, 0));\n",
       "obj0.userData.points.push(new PMPoint(0.5, 0.5, 0));\n",
       "obj0.userData.points.push(new PMPoint(0, 0, 0.5));\n",
       "obj0.userData.points.push(new PMPoint(0.5, 0, 0.5));\n",
       "obj0.userData.points.push(new PMPoint(0, 0.5, 0.5));\n",
       "obj0.userData.points.push(new PMPoint(0, 0, 0));\n",
       "obj0.userData.points.push(new PMPoint(1, 0, 0));\n",
       "obj0.userData.points.push(new PMPoint(0, 1, 0));\n",
       "obj0.userData.points.push(new PMPoint(0, 0, 1));\n",
       "\n",
       "obj0.userData.pointradii = 0.02;\n",
       "   <!-- Vertex style -->\n",
       "obj0.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0x000000, side: THREE.DoubleSide, transparent: false } );\n",
       "obj0.userData.pointlabels = [\"{0 1 2 3}\", \"{0 1 2}\", \"{0 1 3}\", \"{0 2 3}\", \"{1 2 3}\", \"{0 1}\", \"{0 2}\", \"{1 2}\", \"{0 3}\", \"{1 3}\", \"{2 3}\", \"{0}\", \"{1}\", \"{2}\", \"{3}\"];\n",
       "obj0.userData.edgeindices = [1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 5, 1, 5, 2, 6, 0, 6, 1, 6, 3, 7, 0, 7, 1, 7, 4, 8, 0, 8, 2, 8, 3, 9, 0, 9, 2, 9, 4, 10, 0, 10, 3, 10, 4, 11, 0, 11, 1, 11, 2, 11, 3, 11, 5, 11, 6, 11, 8, 12, 0, 12, 1, 12, 2, 12, 4, 12, 5, 12, 7, 12, 9, 13, 0, 13, 1, 13, 3, 13, 4, 13, 6, 13, 7, 13, 10, 14, 0, 14, 2, 14, 3, 14, 4, 14, 8, 14, 9, 14, 10];\n",
       "   <!-- Edge style -->\n",
       "obj0.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, depthTest: true, linewidth: 1.5, transparent: false } );\n",
       "init_object(obj0);\n",
       "scene.add(obj0);\n",
       "\n",
       "var obj1 = new THREE.Object3D();\n",
       "obj1.name = \"{0 1 2 3} {0 1 2} {0 1} {0}\";\n",
       "obj1.userData.explodable = 1;\n",
       "obj1.userData.points = [];\n",
       "obj1.userData.points.push(new PMPoint(0.25, 0.25, 0.25));\n",
       "obj1.userData.points.push(new PMPoint(0.333333, 0.333333, 0));\n",
       "obj1.userData.points.push(new PMPoint(0.5, 0, 0));\n",
       "obj1.userData.points.push(new PMPoint(0, 0, 0));\n",
       "\n",
       "obj1.userData.pointradii = 0.02;\n",
       "   <!-- Vertex style -->\n",
       "obj1.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } );\n",
       "obj1.userData.pointlabels = [\"{0 1 2 3}\", \"{0 1 2}\", \"{0 1}\", \"{0}\"];\n",
       "obj1.userData.edgeindices = [0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3];\n",
       "   <!-- Edge style -->\n",
       "obj1.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, depthTest: true, linewidth: 1.5, transparent: false } );\n",
       "obj1.userData.facets = [[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3]];\n",
       "   <!-- Facet style -->\n",
       "obj1.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } );\n",
       "init_object(obj1);\n",
       "scene.add(obj1);\n",
       "\n",
       "var obj2 = new THREE.Object3D();\n",
       "obj2.name = \"{0 1 2 3} {0 1 3} {0 1} {0}\";\n",
       "obj2.userData.explodable = 1;\n",
       "obj2.userData.points = [];\n",
       "obj2.userData.points.push(new PMPoint(0.25, 0.25, 0.25));\n",
       "obj2.userData.points.push(new PMPoint(0.333333, 0, 0.333333));\n",
       "obj2.userData.points.push(new PMPoint(0.5, 0, 0));\n",
       "obj2.userData.points.push(new PMPoint(0, 0, 0));\n",
       "\n",
       "obj2.userData.pointradii = 0.02;\n",
       "   <!-- Vertex style -->\n",
       "obj2.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } );\n",
       "obj2.userData.pointlabels = [\"{0 1 2 3}\", \"{0 1 3}\", \"{0 1}\", \"{0}\"];\n",
       "obj2.userData.edgeindices = [0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3];\n",
       "   <!-- Edge style -->\n",
       "obj2.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, depthTest: true, linewidth: 1.5, transparent: false } );\n",
       "obj2.userData.facets = [[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3]];\n",
       "   <!-- Facet style -->\n",
       "obj2.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } );\n",
       "init_object(obj2);\n",
       "scene.add(obj2);\n",
       "\n",
       "var obj3 = new THREE.Object3D();\n",
       "obj3.name = \"{0 1 2 3} {0 1 2} {0 2} {0}\";\n",
       "obj3.userData.explodable = 1;\n",
       "obj3.userData.points = [];\n",
       "obj3.userData.points.push(new PMPoint(0.25, 0.25, 0.25));\n",
       "obj3.userData.points.push(new PMPoint(0.333333, 0.333333, 0));\n",
       "obj3.userData.points.push(new PMPoint(0, 0.5, 0));\n",
       "obj3.userData.points.push(new PMPoint(0, 0, 0));\n",
       "\n",
       "obj3.userData.pointradii = 0.02;\n",
       "   <!-- Vertex style -->\n",
       "obj3.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } );\n",
       "obj3.userData.pointlabels = [\"{0 1 2 3}\", \"{0 1 2}\", \"{0 2}\", \"{0}\"];\n",
       "obj3.userData.edgeindices = [0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3];\n",
       "   <!-- Edge style -->\n",
       "obj3.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, depthTest: true, linewidth: 1.5, transparent: false } );\n",
       "obj3.userData.facets = [[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3]];\n",
       "   <!-- Facet style -->\n",
       "obj3.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } );\n",
       "init_object(obj3);\n",
       "scene.add(obj3);\n",
       "\n",
       "var obj4 = new THREE.Object3D();\n",
       "obj4.name = \"{0 1 2 3} {0 2 3} {0 2} {0}\";\n",
       "obj4.userData.explodable = 1;\n",
       "obj4.userData.points = [];\n",
       "obj4.userData.points.push(new PMPoint(0.25, 0.25, 0.25));\n",
       "obj4.userData.points.push(new PMPoint(0, 0.333333, 0.333333));\n",
       "obj4.userData.points.push(new PMPoint(0, 0.5, 0));\n",
       "obj4.userData.points.push(new PMPoint(0, 0, 0));\n",
       "\n",
       "obj4.userData.pointradii = 0.02;\n",
       "   <!-- Vertex style -->\n",
       "obj4.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } );\n",
       "obj4.userData.pointlabels = [\"{0 1 2 3}\", \"{0 2 3}\", \"{0 2}\", \"{0}\"];\n",
       "obj4.userData.edgeindices = [0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3];\n",
       "   <!-- Edge style -->\n",
       "obj4.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, depthTest: true, linewidth: 1.5, transparent: false } );\n",
       "obj4.userData.facets = [[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3]];\n",
       "   <!-- Facet style -->\n",
       "obj4.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } );\n",
       "init_object(obj4);\n",
       "scene.add(obj4);\n",
       "\n",
       "var obj5 = new THREE.Object3D();\n",
       "obj5.name = \"{0 1 2 3} {0 1 3} {0 3} {0}\";\n",
       "obj5.userData.explodable = 1;\n",
       "obj5.userData.points = [];\n",
       "obj5.userData.points.push(new PMPoint(0.25, 0.25, 0.25));\n",
       "obj5.userData.points.push(new PMPoint(0.333333, 0, 0.333333));\n",
       "obj5.userData.points.push(new PMPoint(0, 0, 0.5));\n",
       "obj5.userData.points.push(new PMPoint(0, 0, 0));\n",
       "\n",
       "obj5.userData.pointradii = 0.02;\n",
       "   <!-- Vertex style -->\n",
       "obj5.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } );\n",
       "obj5.userData.pointlabels = [\"{0 1 2 3}\", \"{0 1 3}\", \"{0 3}\", \"{0}\"];\n",
       "obj5.userData.edgeindices = [0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3];\n",
       "   <!-- Edge style -->\n",
       "obj5.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, depthTest: true, linewidth: 1.5, transparent: false } );\n",
       "obj5.userData.facets = [[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3]];\n",
       "   <!-- Facet style -->\n",
       "obj5.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } );\n",
       "init_object(obj5);\n",
       "scene.add(obj5);\n",
       "\n",
       "var obj6 = new THREE.Object3D();\n",
       "obj6.name = \"{0 1 2 3} {0 2 3} {0 3} {0}\";\n",
       "obj6.userData.explodable = 1;\n",
       "obj6.userData.points = [];\n",
       "obj6.userData.points.push(new PMPoint(0.25, 0.25, 0.25));\n",
       "obj6.userData.points.push(new PMPoint(0, 0.333333, 0.333333));\n",
       "obj6.userData.points.push(new PMPoint(0, 0, 0.5));\n",
       "obj6.userData.points.push(new PMPoint(0, 0, 0));\n",
       "\n",
       "obj6.userData.pointradii = 0.02;\n",
       "   <!-- Vertex style -->\n",
       "obj6.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } );\n",
       "obj6.userData.pointlabels = [\"{0 1 2 3}\", \"{0 2 3}\", \"{0 3}\", \"{0}\"];\n",
       "obj6.userData.edgeindices = [0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3];\n",
       "   <!-- Edge style -->\n",
       "obj6.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, depthTest: true, linewidth: 1.5, transparent: false } );\n",
       "obj6.userData.facets = [[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3]];\n",
       "   <!-- Facet style -->\n",
       "obj6.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } );\n",
       "init_object(obj6);\n",
       "scene.add(obj6);\n",
       "\n",
       "var obj7 = new THREE.Object3D();\n",
       "obj7.name = \"{0 1 2 3} {0 1 2} {0 1} {1}\";\n",
       "obj7.userData.explodable = 1;\n",
       "obj7.userData.points = [];\n",
       "obj7.userData.points.push(new PMPoint(0.25, 0.25, 0.25));\n",
       "obj7.userData.points.push(new PMPoint(0.333333, 0.333333, 0));\n",
       "obj7.userData.points.push(new PMPoint(0.5, 0, 0));\n",
       "obj7.userData.points.push(new PMPoint(1, 0, 0));\n",
       "\n",
       "obj7.userData.pointradii = 0.02;\n",
       "   <!-- Vertex style -->\n",
       "obj7.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } );\n",
       "obj7.userData.pointlabels = [\"{0 1 2 3}\", \"{0 1 2}\", \"{0 1}\", \"{1}\"];\n",
       "obj7.userData.edgeindices = [0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3];\n",
       "   <!-- Edge style -->\n",
       "obj7.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, depthTest: true, linewidth: 1.5, transparent: false } );\n",
       "obj7.userData.facets = [[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3]];\n",
       "   <!-- Facet style -->\n",
       "obj7.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } );\n",
       "init_object(obj7);\n",
       "scene.add(obj7);\n",
       "\n",
       "var obj8 = new THREE.Object3D();\n",
       "obj8.name = \"{0 1 2 3} {0 1 3} {0 1} {1}\";\n",
       "obj8.userData.explodable = 1;\n",
       "obj8.userData.points = [];\n",
       "obj8.userData.points.push(new PMPoint(0.25, 0.25, 0.25));\n",
       "obj8.userData.points.push(new PMPoint(0.333333, 0, 0.333333));\n",
       "obj8.userData.points.push(new PMPoint(0.5, 0, 0));\n",
       "obj8.userData.points.push(new PMPoint(1, 0, 0));\n",
       "\n",
       "obj8.userData.pointradii = 0.02;\n",
       "   <!-- Vertex style -->\n",
       "obj8.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } );\n",
       "obj8.userData.pointlabels = [\"{0 1 2 3}\", \"{0 1 3}\", \"{0 1}\", \"{1}\"];\n",
       "obj8.userData.edgeindices = [0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3];\n",
       "   <!-- Edge style -->\n",
       "obj8.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, depthTest: true, linewidth: 1.5, transparent: false } );\n",
       "obj8.userData.facets = [[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3]];\n",
       "   <!-- Facet style -->\n",
       "obj8.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } );\n",
       "init_object(obj8);\n",
       "scene.add(obj8);\n",
       "\n",
       "var obj9 = new THREE.Object3D();\n",
       "obj9.name = \"{0 1 2 3} {0 1 2} {1 2} {1}\";\n",
       "obj9.userData.explodable = 1;\n",
       "obj9.userData.points = [];\n",
       "obj9.userData.points.push(new PMPoint(0.25, 0.25, 0.25));\n",
       "obj9.userData.points.push(new PMPoint(0.333333, 0.333333, 0));\n",
       "obj9.userData.points.push(new PMPoint(0.5, 0.5, 0));\n",
       "obj9.userData.points.push(new PMPoint(1, 0, 0));\n",
       "\n",
       "obj9.userData.pointradii = 0.02;\n",
       "   <!-- Vertex style -->\n",
       "obj9.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } );\n",
       "obj9.userData.pointlabels = [\"{0 1 2 3}\", \"{0 1 2}\", \"{1 2}\", \"{1}\"];\n",
       "obj9.userData.edgeindices = [0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3];\n",
       "   <!-- Edge style -->\n",
       "obj9.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, depthTest: true, linewidth: 1.5, transparent: false } );\n",
       "obj9.userData.facets = [[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3]];\n",
       "   <!-- Facet style -->\n",
       "obj9.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } );\n",
       "init_object(obj9);\n",
       "scene.add(obj9);\n",
       "\n",
       "var obj10 = new THREE.Object3D();\n",
       "obj10.name = \"{0 1 2 3} {1 2 3} {1 2} {1}\";\n",
       "obj10.userData.explodable = 1;\n",
       "obj10.userData.points = [];\n",
       "obj10.userData.points.push(new PMPoint(0.25, 0.25, 0.25));\n",
       "obj10.userData.points.push(new PMPoint(0.333333, 0.333333, 0.333333));\n",
       "obj10.userData.points.push(new PMPoint(0.5, 0.5, 0));\n",
       "obj10.userData.points.push(new PMPoint(1, 0, 0));\n",
       "\n",
       "obj10.userData.pointradii = 0.02;\n",
       "   <!-- Vertex style -->\n",
       "obj10.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } );\n",
       "obj10.userData.pointlabels = [\"{0 1 2 3}\", \"{1 2 3}\", \"{1 2}\", \"{1}\"];\n",
       "obj10.userData.edgeindices = [0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3];\n",
       "   <!-- Edge style -->\n",
       "obj10.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, depthTest: true, linewidth: 1.5, transparent: false } );\n",
       "obj10.userData.facets = [[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3]];\n",
       "   <!-- Facet style -->\n",
       "obj10.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } );\n",
       "init_object(obj10);\n",
       "scene.add(obj10);\n",
       "\n",
       "var obj11 = new THREE.Object3D();\n",
       "obj11.name = \"{0 1 2 3} {0 1 3} {1 3} {1}\";\n",
       "obj11.userData.explodable = 1;\n",
       "obj11.userData.points = [];\n",
       "obj11.userData.points.push(new PMPoint(0.25, 0.25, 0.25));\n",
       "obj11.userData.points.push(new PMPoint(0.333333, 0, 0.333333));\n",
       "obj11.userData.points.push(new PMPoint(0.5, 0, 0.5));\n",
       "obj11.userData.points.push(new PMPoint(1, 0, 0));\n",
       "\n",
       "obj11.userData.pointradii = 0.02;\n",
       "   <!-- Vertex style -->\n",
       "obj11.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } );\n",
       "obj11.userData.pointlabels = [\"{0 1 2 3}\", \"{0 1 3}\", \"{1 3}\", \"{1}\"];\n",
       "obj11.userData.edgeindices = [0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3];\n",
       "   <!-- Edge style -->\n",
       "obj11.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, depthTest: true, linewidth: 1.5, transparent: false } );\n",
       "obj11.userData.facets = [[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3]];\n",
       "   <!-- Facet style -->\n",
       "obj11.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } );\n",
       "init_object(obj11);\n",
       "scene.add(obj11);\n",
       "\n",
       "var obj12 = new THREE.Object3D();\n",
       "obj12.name = \"{0 1 2 3} {1 2 3} {1 3} {1}\";\n",
       "obj12.userData.explodable = 1;\n",
       "obj12.userData.points = [];\n",
       "obj12.userData.points.push(new PMPoint(0.25, 0.25, 0.25));\n",
       "obj12.userData.points.push(new PMPoint(0.333333, 0.333333, 0.333333));\n",
       "obj12.userData.points.push(new PMPoint(0.5, 0, 0.5));\n",
       "obj12.userData.points.push(new PMPoint(1, 0, 0));\n",
       "\n",
       "obj12.userData.pointradii = 0.02;\n",
       "   <!-- Vertex style -->\n",
       "obj12.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } );\n",
       "obj12.userData.pointlabels = [\"{0 1 2 3}\", \"{1 2 3}\", \"{1 3}\", \"{1}\"];\n",
       "obj12.userData.edgeindices = [0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3];\n",
       "   <!-- Edge style -->\n",
       "obj12.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, depthTest: true, linewidth: 1.5, transparent: false } );\n",
       "obj12.userData.facets = [[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3]];\n",
       "   <!-- Facet style -->\n",
       "obj12.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } );\n",
       "init_object(obj12);\n",
       "scene.add(obj12);\n",
       "\n",
       "var obj13 = new THREE.Object3D();\n",
       "obj13.name = \"{0 1 2 3} {0 1 2} {0 2} {2}\";\n",
       "obj13.userData.explodable = 1;\n",
       "obj13.userData.points = [];\n",
       "obj13.userData.points.push(new PMPoint(0.25, 0.25, 0.25));\n",
       "obj13.userData.points.push(new PMPoint(0.333333, 0.333333, 0));\n",
       "obj13.userData.points.push(new PMPoint(0, 0.5, 0));\n",
       "obj13.userData.points.push(new PMPoint(0, 1, 0));\n",
       "\n",
       "obj13.userData.pointradii = 0.02;\n",
       "   <!-- Vertex style -->\n",
       "obj13.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } );\n",
       "obj13.userData.pointlabels = [\"{0 1 2 3}\", \"{0 1 2}\", \"{0 2}\", \"{2}\"];\n",
       "obj13.userData.edgeindices = [0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3];\n",
       "   <!-- Edge style -->\n",
       "obj13.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, depthTest: true, linewidth: 1.5, transparent: false } );\n",
       "obj13.userData.facets = [[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3]];\n",
       "   <!-- Facet style -->\n",
       "obj13.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } );\n",
       "init_object(obj13);\n",
       "scene.add(obj13);\n",
       "\n",
       "var obj14 = new THREE.Object3D();\n",
       "obj14.name = \"{0 1 2 3} {0 2 3} {0 2} {2}\";\n",
       "obj14.userData.explodable = 1;\n",
       "obj14.userData.points = [];\n",
       "obj14.userData.points.push(new PMPoint(0.25, 0.25, 0.25));\n",
       "obj14.userData.points.push(new PMPoint(0, 0.333333, 0.333333));\n",
       "obj14.userData.points.push(new PMPoint(0, 0.5, 0));\n",
       "obj14.userData.points.push(new PMPoint(0, 1, 0));\n",
       "\n",
       "obj14.userData.pointradii = 0.02;\n",
       "   <!-- Vertex style -->\n",
       "obj14.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } );\n",
       "obj14.userData.pointlabels = [\"{0 1 2 3}\", \"{0 2 3}\", \"{0 2}\", \"{2}\"];\n",
       "obj14.userData.edgeindices = [0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3];\n",
       "   <!-- Edge style -->\n",
       "obj14.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, depthTest: true, linewidth: 1.5, transparent: false } );\n",
       "obj14.userData.facets = [[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3]];\n",
       "   <!-- Facet style -->\n",
       "obj14.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } );\n",
       "init_object(obj14);\n",
       "scene.add(obj14);\n",
       "\n",
       "var obj15 = new THREE.Object3D();\n",
       "obj15.name = \"{0 1 2 3} {0 1 2} {1 2} {2}\";\n",
       "obj15.userData.explodable = 1;\n",
       "obj15.userData.points = [];\n",
       "obj15.userData.points.push(new PMPoint(0.25, 0.25, 0.25));\n",
       "obj15.userData.points.push(new PMPoint(0.333333, 0.333333, 0));\n",
       "obj15.userData.points.push(new PMPoint(0.5, 0.5, 0));\n",
       "obj15.userData.points.push(new PMPoint(0, 1, 0));\n",
       "\n",
       "obj15.userData.pointradii = 0.02;\n",
       "   <!-- Vertex style -->\n",
       "obj15.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } );\n",
       "obj15.userData.pointlabels = [\"{0 1 2 3}\", \"{0 1 2}\", \"{1 2}\", \"{2}\"];\n",
       "obj15.userData.edgeindices = [0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3];\n",
       "   <!-- Edge style -->\n",
       "obj15.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, depthTest: true, linewidth: 1.5, transparent: false } );\n",
       "obj15.userData.facets = [[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3]];\n",
       "   <!-- Facet style -->\n",
       "obj15.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } );\n",
       "init_object(obj15);\n",
       "scene.add(obj15);\n",
       "\n",
       "var obj16 = new THREE.Object3D();\n",
       "obj16.name = \"{0 1 2 3} {1 2 3} {1 2} {2}\";\n",
       "obj16.userData.explodable = 1;\n",
       "obj16.userData.points = [];\n",
       "obj16.userData.points.push(new PMPoint(0.25, 0.25, 0.25));\n",
       "obj16.userData.points.push(new PMPoint(0.333333, 0.333333, 0.333333));\n",
       "obj16.userData.points.push(new PMPoint(0.5, 0.5, 0));\n",
       "obj16.userData.points.push(new PMPoint(0, 1, 0));\n",
       "\n",
       "obj16.userData.pointradii = 0.02;\n",
       "   <!-- Vertex style -->\n",
       "obj16.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } );\n",
       "obj16.userData.pointlabels = [\"{0 1 2 3}\", \"{1 2 3}\", \"{1 2}\", \"{2}\"];\n",
       "obj16.userData.edgeindices = [0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3];\n",
       "   <!-- Edge style -->\n",
       "obj16.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, depthTest: true, linewidth: 1.5, transparent: false } );\n",
       "obj16.userData.facets = [[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3]];\n",
       "   <!-- Facet style -->\n",
       "obj16.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } );\n",
       "init_object(obj16);\n",
       "scene.add(obj16);\n",
       "\n",
       "var obj17 = new THREE.Object3D();\n",
       "obj17.name = \"{0 1 2 3} {0 2 3} {2 3} {2}\";\n",
       "obj17.userData.explodable = 1;\n",
       "obj17.userData.points = [];\n",
       "obj17.userData.points.push(new PMPoint(0.25, 0.25, 0.25));\n",
       "obj17.userData.points.push(new PMPoint(0, 0.333333, 0.333333));\n",
       "obj17.userData.points.push(new PMPoint(0, 0.5, 0.5));\n",
       "obj17.userData.points.push(new PMPoint(0, 1, 0));\n",
       "\n",
       "obj17.userData.pointradii = 0.02;\n",
       "   <!-- Vertex style -->\n",
       "obj17.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } );\n",
       "obj17.userData.pointlabels = [\"{0 1 2 3}\", \"{0 2 3}\", \"{2 3}\", \"{2}\"];\n",
       "obj17.userData.edgeindices = [0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3];\n",
       "   <!-- Edge style -->\n",
       "obj17.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, depthTest: true, linewidth: 1.5, transparent: false } );\n",
       "obj17.userData.facets = [[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3]];\n",
       "   <!-- Facet style -->\n",
       "obj17.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } );\n",
       "init_object(obj17);\n",
       "scene.add(obj17);\n",
       "\n",
       "var obj18 = new THREE.Object3D();\n",
       "obj18.name = \"{0 1 2 3} {1 2 3} {2 3} {2}\";\n",
       "obj18.userData.explodable = 1;\n",
       "obj18.userData.points = [];\n",
       "obj18.userData.points.push(new PMPoint(0.25, 0.25, 0.25));\n",
       "obj18.userData.points.push(new PMPoint(0.333333, 0.333333, 0.333333));\n",
       "obj18.userData.points.push(new PMPoint(0, 0.5, 0.5));\n",
       "obj18.userData.points.push(new PMPoint(0, 1, 0));\n",
       "\n",
       "obj18.userData.pointradii = 0.02;\n",
       "   <!-- Vertex style -->\n",
       "obj18.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } );\n",
       "obj18.userData.pointlabels = [\"{0 1 2 3}\", \"{1 2 3}\", \"{2 3}\", \"{2}\"];\n",
       "obj18.userData.edgeindices = [0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3];\n",
       "   <!-- Edge style -->\n",
       "obj18.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, depthTest: true, linewidth: 1.5, transparent: false } );\n",
       "obj18.userData.facets = [[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3]];\n",
       "   <!-- Facet style -->\n",
       "obj18.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } );\n",
       "init_object(obj18);\n",
       "scene.add(obj18);\n",
       "\n",
       "var obj19 = new THREE.Object3D();\n",
       "obj19.name = \"{0 1 2 3} {0 1 3} {0 3} {3}\";\n",
       "obj19.userData.explodable = 1;\n",
       "obj19.userData.points = [];\n",
       "obj19.userData.points.push(new PMPoint(0.25, 0.25, 0.25));\n",
       "obj19.userData.points.push(new PMPoint(0.333333, 0, 0.333333));\n",
       "obj19.userData.points.push(new PMPoint(0, 0, 0.5));\n",
       "obj19.userData.points.push(new PMPoint(0, 0, 1));\n",
       "\n",
       "obj19.userData.pointradii = 0.02;\n",
       "   <!-- Vertex style -->\n",
       "obj19.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } );\n",
       "obj19.userData.pointlabels = [\"{0 1 2 3}\", \"{0 1 3}\", \"{0 3}\", \"{3}\"];\n",
       "obj19.userData.edgeindices = [0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3];\n",
       "   <!-- Edge style -->\n",
       "obj19.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, depthTest: true, linewidth: 1.5, transparent: false } );\n",
       "obj19.userData.facets = [[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3]];\n",
       "   <!-- Facet style -->\n",
       "obj19.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } );\n",
       "init_object(obj19);\n",
       "scene.add(obj19);\n",
       "\n",
       "var obj20 = new THREE.Object3D();\n",
       "obj20.name = \"{0 1 2 3} {0 2 3} {0 3} {3}\";\n",
       "obj20.userData.explodable = 1;\n",
       "obj20.userData.points = [];\n",
       "obj20.userData.points.push(new PMPoint(0.25, 0.25, 0.25));\n",
       "obj20.userData.points.push(new PMPoint(0, 0.333333, 0.333333));\n",
       "obj20.userData.points.push(new PMPoint(0, 0, 0.5));\n",
       "obj20.userData.points.push(new PMPoint(0, 0, 1));\n",
       "\n",
       "obj20.userData.pointradii = 0.02;\n",
       "   <!-- Vertex style -->\n",
       "obj20.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } );\n",
       "obj20.userData.pointlabels = [\"{0 1 2 3}\", \"{0 2 3}\", \"{0 3}\", \"{3}\"];\n",
       "obj20.userData.edgeindices = [0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3];\n",
       "   <!-- Edge style -->\n",
       "obj20.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, depthTest: true, linewidth: 1.5, transparent: false } );\n",
       "obj20.userData.facets = [[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3]];\n",
       "   <!-- Facet style -->\n",
       "obj20.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } );\n",
       "init_object(obj20);\n",
       "scene.add(obj20);\n",
       "\n",
       "var obj21 = new THREE.Object3D();\n",
       "obj21.name = \"{0 1 2 3} {0 1 3} {1 3} {3}\";\n",
       "obj21.userData.explodable = 1;\n",
       "obj21.userData.points = [];\n",
       "obj21.userData.points.push(new PMPoint(0.25, 0.25, 0.25));\n",
       "obj21.userData.points.push(new PMPoint(0.333333, 0, 0.333333));\n",
       "obj21.userData.points.push(new PMPoint(0.5, 0, 0.5));\n",
       "obj21.userData.points.push(new PMPoint(0, 0, 1));\n",
       "\n",
       "obj21.userData.pointradii = 0.02;\n",
       "   <!-- Vertex style -->\n",
       "obj21.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } );\n",
       "obj21.userData.pointlabels = [\"{0 1 2 3}\", \"{0 1 3}\", \"{1 3}\", \"{3}\"];\n",
       "obj21.userData.edgeindices = [0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3];\n",
       "   <!-- Edge style -->\n",
       "obj21.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, depthTest: true, linewidth: 1.5, transparent: false } );\n",
       "obj21.userData.facets = [[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3]];\n",
       "   <!-- Facet style -->\n",
       "obj21.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } );\n",
       "init_object(obj21);\n",
       "scene.add(obj21);\n",
       "\n",
       "var obj22 = new THREE.Object3D();\n",
       "obj22.name = \"{0 1 2 3} {1 2 3} {1 3} {3}\";\n",
       "obj22.userData.explodable = 1;\n",
       "obj22.userData.points = [];\n",
       "obj22.userData.points.push(new PMPoint(0.25, 0.25, 0.25));\n",
       "obj22.userData.points.push(new PMPoint(0.333333, 0.333333, 0.333333));\n",
       "obj22.userData.points.push(new PMPoint(0.5, 0, 0.5));\n",
       "obj22.userData.points.push(new PMPoint(0, 0, 1));\n",
       "\n",
       "obj22.userData.pointradii = 0.02;\n",
       "   <!-- Vertex style -->\n",
       "obj22.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } );\n",
       "obj22.userData.pointlabels = [\"{0 1 2 3}\", \"{1 2 3}\", \"{1 3}\", \"{3}\"];\n",
       "obj22.userData.edgeindices = [0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3];\n",
       "   <!-- Edge style -->\n",
       "obj22.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, depthTest: true, linewidth: 1.5, transparent: false } );\n",
       "obj22.userData.facets = [[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3]];\n",
       "   <!-- Facet style -->\n",
       "obj22.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } );\n",
       "init_object(obj22);\n",
       "scene.add(obj22);\n",
       "\n",
       "var obj23 = new THREE.Object3D();\n",
       "obj23.name = \"{0 1 2 3} {0 2 3} {2 3} {3}\";\n",
       "obj23.userData.explodable = 1;\n",
       "obj23.userData.points = [];\n",
       "obj23.userData.points.push(new PMPoint(0.25, 0.25, 0.25));\n",
       "obj23.userData.points.push(new PMPoint(0, 0.333333, 0.333333));\n",
       "obj23.userData.points.push(new PMPoint(0, 0.5, 0.5));\n",
       "obj23.userData.points.push(new PMPoint(0, 0, 1));\n",
       "\n",
       "obj23.userData.pointradii = 0.02;\n",
       "   <!-- Vertex style -->\n",
       "obj23.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } );\n",
       "obj23.userData.pointlabels = [\"{0 1 2 3}\", \"{0 2 3}\", \"{2 3}\", \"{3}\"];\n",
       "obj23.userData.edgeindices = [0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3];\n",
       "   <!-- Edge style -->\n",
       "obj23.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, depthTest: true, linewidth: 1.5, transparent: false } );\n",
       "obj23.userData.facets = [[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3]];\n",
       "   <!-- Facet style -->\n",
       "obj23.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } );\n",
       "init_object(obj23);\n",
       "scene.add(obj23);\n",
       "\n",
       "var obj24 = new THREE.Object3D();\n",
       "obj24.name = \"{0 1 2 3} {1 2 3} {2 3} {3}\";\n",
       "obj24.userData.explodable = 1;\n",
       "obj24.userData.points = [];\n",
       "obj24.userData.points.push(new PMPoint(0.25, 0.25, 0.25));\n",
       "obj24.userData.points.push(new PMPoint(0.333333, 0.333333, 0.333333));\n",
       "obj24.userData.points.push(new PMPoint(0, 0.5, 0.5));\n",
       "obj24.userData.points.push(new PMPoint(0, 0, 1));\n",
       "\n",
       "obj24.userData.pointradii = 0.02;\n",
       "   <!-- Vertex style -->\n",
       "obj24.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFF0000, side: THREE.DoubleSide, transparent: false } );\n",
       "obj24.userData.pointlabels = [\"{0 1 2 3}\", \"{1 2 3}\", \"{2 3}\", \"{3}\"];\n",
       "obj24.userData.edgeindices = [0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3];\n",
       "   <!-- Edge style -->\n",
       "obj24.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, depthTest: true, linewidth: 1.5, transparent: false } );\n",
       "obj24.userData.facets = [[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3]];\n",
       "   <!-- Facet style -->\n",
       "obj24.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0x77EC9E, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } );\n",
       "init_object(obj24);\n",
       "scene.add(obj24);\n",
       "\n",
       "var obj25 = new THREE.Object3D();\n",
       "obj25.name = \"{0 1 2 3} {0 1 3} {0 3} {0}\";\n",
       "obj25.userData.explodable = 1;\n",
       "obj25.userData.points = [];\n",
       "obj25.userData.points.push(new PMPoint(0.25, 0.25, 0.25));\n",
       "obj25.userData.points.push(new PMPoint(0.333333, 0, 0.333333));\n",
       "obj25.userData.points.push(new PMPoint(0, 0, 0.5));\n",
       "obj25.userData.points.push(new PMPoint(0, 0, 0));\n",
       "\n",
       "obj25.userData.edgeindices = [0, 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3];\n",
       "obj25.userData.facets = [[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3]];\n",
       "   <!-- Facet style -->\n",
       "obj25.userData.facetmaterial = new THREE.MeshBasicMaterial( { color: 0xFFC0CB, depthFunc: THREE.LessDepth, opacity: 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.5, side: THREE.DoubleSide, transparent: true } );\n",
       "init_object(obj25);\n",
       "scene.add(obj25);\n",
       "\n",
       "// COMMON_CODE_BLOCK_BEGIN\n",
       "function textSpriteMaterial(message, parameters) {\n",
       "    if ( parameters === undefined ) parameters = {};\n",
       "    var fontface = \"Helvetica\";\n",
       "    var fontsize = parameters.hasOwnProperty(\"fontsize\") ? parameters[\"fontsize\"] : 15;\n",
       "    fontsize = fontsize*10;\n",
       "    var lines = message.split('\\\\n');\n",
       "    var size = 512;\n",
       "    for(var i = 0; i<lines.length; i++){\n",
       "        var tmp = lines[i].length;\n",
       "        while(tmp*fontsize > size){\n",
       "           fontsize--;\n",
       "        }\n",
       "    }\n",
       "    \n",
       "    var canvas = document.createElement('canvas');\n",
       "    canvas.width = size;\n",
       "    canvas.height = size;\n",
       "    var context = canvas.getContext('2d');\n",
       "    context.fillStyle = \"rgba(255, 255, 255, 0)\";\n",
       "    context.fill();\n",
       "    context.font = fontsize + \"px \" + fontface;\n",
       "    \n",
       "    // text color\n",
       "    context.fillStyle = \"rgba(0, 0, 0, 1.0)\";\n",
       "     for(var i = 0; i<lines.length; i++){\n",
       "        context.fillText(lines[i], size/2, size/2+i*fontsize);\n",
       "     }\n",
       "    \n",
       "    // canvas contents will be used for a texture\n",
       "    var texture = new THREE.Texture(canvas);\n",
       "    texture.needsUpdate = true;\n",
       "    \n",
       "    var spriteMaterial = new THREE.SpriteMaterial({map: texture, depthTest: true, depthWrite: false, polygonOffset: true, polygonOffsetFactor: -1, polygonOffsetUnits: 1 });\n",
       "    return spriteMaterial;\n",
       "}\n",
       "\n",
       "\n",
       "// ---------------------- INITIALIZING OBJECTS--------------------------------------\n",
       "// ---------------------------------------------------------------------------------\n",
       "\n",
       "function init_object(obj) {\n",
       "    if (obj.userData.hasOwnProperty(\"pointmaterial\")) {\n",
       "        init_points(obj);\n",
       "        modelContains.points = true;\n",
       "    }\n",
       "    if (obj.userData.hasOwnProperty(\"pointlabels\")) {\n",
       "        init_pointlabels(obj);\n",
       "        modelContains.pointlabels = true;\n",
       "    }\n",
       "    if (obj.userData.hasOwnProperty(\"edgematerial\")) {\n",
       "        init_lines(obj);\n",
       "        modelContains.lines = true;\n",
       "    }\n",
       "    if (obj.userData.hasOwnProperty(\"edgelabels\")) {\n",
       "        init_edgelabels(obj);\n",
       "        modelContains.edgelabels = true;\n",
       "    }\n",
       "    if (obj.userData.hasOwnProperty(\"arrowstyle\")) {\n",
       "        init_arrowheads(obj);\n",
       "        modelContains.arrowheads = true;\n",
       "    }\n",
       "    if (obj.userData.hasOwnProperty(\"facetmaterial\")) {\n",
       "        init_faces(obj);\n",
       "        modelContains.faces = true;\n",
       "    }\n",
       "}\n",
       "\n",
       "function init_points(obj) {\n",
       "    var pointgroup = new THREE.Group();\n",
       "    pointgroup.name = \"points\";\n",
       "    var points = obj.userData.points;\n",
       "    var radii = obj.userData.pointradii;\n",
       "    var materials = obj.userData.pointmaterial;\n",
       "    var geometry,material;\n",
       "    if (!Array.isArray(radii)) {\n",
       "        geometry = new THREE.SphereBufferGeometry(radii);  \n",
       "    }\n",
       "    if (!Array.isArray(materials)) {\n",
       "        material = materials;\n",
       "    }\n",
       "    for (var i=0; i<points.length; i++) {\n",
       "        var point = points[i];\n",
       "        if (Array.isArray(radii)) {\n",
       "            if (radii[i] == 0) {\n",
       "                continue;\n",
       "            }\n",
       "            geometry = new THREE.SphereBufferGeometry(radii[i]);  \n",
       "        } \n",
       "        if (Array.isArray(materials)) {\n",
       "            material = materials[i];     \n",
       "        } \n",
       "        var sphere = new THREE.Mesh(geometry, material);\n",
       "        point.addSphere(sphere);\n",
       "        pointgroup.add(sphere);\n",
       "    }\n",
       "    obj.add(pointgroup);\n",
       "}\n",
       "\n",
       "function init_pointlabels(obj) {\n",
       "    var points = obj.userData.points;\n",
       "    var labels = obj.userData.pointlabels;\n",
       "    var pointlabels = new THREE.Group();\n",
       "    pointlabels.name = \"pointlabels\";\n",
       "    if (Array.isArray(labels)) {\n",
       "        for (var i=0; i<points.length; i++) {\n",
       "            var point = points[i];\n",
       "            var spriteMaterial = textSpriteMaterial( labels[i] );\n",
       "\t        var sprite = new THREE.Sprite(spriteMaterial);\n",
       "            point.addLabel(sprite);\n",
       "            pointlabels.add(sprite);\n",
       "        }\n",
       "    } else {\n",
       "        var spriteMaterial = textSpriteMaterial( labels );\n",
       "        for (var i=0; i<points.length; i++) {\n",
       "            var point = points[i];\n",
       "\t        var sprite = new THREE.Sprite(spriteMaterial);\n",
       "            point.addLabel(sprite);\n",
       "            pointlabels.add(sprite);\n",
       "        }\n",
       "    }\n",
       "    obj.add(pointlabels);\n",
       "}\n",
       "\n",
       "function init_lines(obj) {\n",
       "    var edgeindices = obj.userData.edgeindices;\n",
       "    var points = obj.userData.points;\n",
       "    var materials = obj.userData.edgematerial;\n",
       "    var geometry = new THREE.BufferGeometry();\n",
       "    var bufarr = new Float32Array( obj.userData.edgeindices.length * 3 );\n",
       "    var bufattr = new THREE.Float32BufferAttribute( bufarr, 3 );\n",
       "    var geometry = new THREE.BufferGeometry();\n",
       "    geometry.setAttribute('position', bufattr);\n",
       "    if (Array.isArray(materials)) {     \n",
       "        for (var i=0; i<materials.length; i++) {\n",
       "            geometry.addGroup(2*i,2,i);\n",
       "        }\n",
       "    }\n",
       "    var lines = new THREE.LineSegments(geometry, materials);\n",
       "    lines.name = \"lines\";\n",
       "    obj.add(lines);\n",
       "    updateEdgesPosition(obj);\n",
       "}\n",
       "\n",
       "function init_edgelabels(obj) {\n",
       "    var points = obj.userData.points;\n",
       "    var edgeindices = obj.userData.edgeindices;\n",
       "    var labels = obj.userData.edgelabels;\n",
       "    var edgelabels = new THREE.Group();\n",
       "    edgelabels.name = \"edgelabels\";\n",
       "    if (Array.isArray(labels)) {\n",
       "        for (var i=0; i<edgeindices.length; i=i+2) {\n",
       "            var point = points[i];\n",
       "            var spriteMaterial = textSpriteMaterial( labels[i] );\n",
       "            var sprite = new THREE.Sprite(spriteMaterial);\n",
       "            sprite.position.copy(new THREE.Vector3().addVectors(points[edgeindices[i]].vector,points[edgeindices[i+1]].vector).multiplyScalar(0.5));\n",
       "            edgelabels.add(sprite);\n",
       "        }\n",
       "    } else {\n",
       "        var spriteMaterial = textSpriteMaterial( labels );\n",
       "        for (var i=0; i<points.length; i++) {\n",
       "            var point = points[i];\n",
       "            var sprite = new THREE.Sprite(spriteMaterial);\n",
       "            sprite.position.copy(new THREE.Vector3().addVectors(points[edgeindices[i]].vector,points[edgeindices[i+1]].vector).multiplyScalar(0.5));\n",
       "            pointlabels.add(sprite);\n",
       "        }\n",
       "    }\n",
       "    obj.add(edgelabels);\n",
       "}\n",
       "\n",
       "function init_arrowheads(obj) {\n",
       "    var arrowheads = new THREE.Group();\n",
       "    arrowheads.name = \"arrowheads\";\n",
       "    var arrowstyle = obj.userData.arrowstyle;\n",
       "    var edgeindices = obj.userData.edgeindices;\n",
       "    var edgematerials = obj.userData.edgematerial;\n",
       "    var points = obj.userData.points;\n",
       "    var material;\n",
       "    if (!Array.isArray(edgematerials)) {\n",
       "        material = new THREE.MeshBasicMaterial( {color: edgematerials.color} );\n",
       "    }\n",
       "\n",
       "    for (var i=0; i<edgeindices.length; i=i+2) {\n",
       "        var start = points[edgeindices[i]];\n",
       "        var end = points[edgeindices[i+1]];\n",
       "        var dist = start.vector.distanceTo( end.vector ) - start.radius() - end.radius();\n",
       "        if (dist <= 0) {\n",
       "            continue;\n",
       "        }\n",
       "        var dir = new THREE.Vector3().subVectors(end.vector,start.vector);\n",
       "        dir.normalize();\n",
       "        var axis = new THREE.Vector3().set(dir.z,0,-dir.x);\n",
       "        axis.normalize();\n",
       "        var radians = Math.acos( dir.y );\n",
       "        var radius = dist/25;\n",
       "        var height = dist/5;\n",
       "        var geometry = new THREE.ConeBufferGeometry(radius,height);\n",
       "        var position = new THREE.Vector3().addVectors(start.vector,dir.clone().multiplyScalar(start.radius()+dist-height/2));\n",
       "        if (Array.isArray(edgematerials)) {\n",
       "            material = new THREE.MeshBasicMaterial( {color: edgematerials[i].color} );\n",
       "        }\n",
       "        var cone = new THREE.Mesh( geometry, material );\n",
       "        cone.quaternion.setFromAxisAngle(axis,radians);;\n",
       "        cone.position.copy(position);;\n",
       "        arrowheads.add(cone);\n",
       "    }\n",
       "    obj.add(arrowheads);\n",
       "}\n",
       "\n",
       "function init_faces(obj) {\n",
       "    var points = obj.userData.points;\n",
       "    var facets = obj.userData.facets;\n",
       "    obj.userData.triangleindices = [];\n",
       "    for (var i=0; i<facets.length; i++) {\n",
       "        facet = facets[i];\n",
       "        for (var t=0; t<facet.length-2; t++) {\n",
       "            obj.userData.triangleindices.push(facet[0],facet[t+1],facet[t+2]);  \n",
       "        }\n",
       "    }\n",
       "    var bufarr = new Float32Array( obj.userData.triangleindices.length * 3 );\n",
       "    var bufattr = new THREE.Float32BufferAttribute(bufarr,3);\n",
       "    \n",
       "    var materials = obj.userData.facetmaterial;\n",
       "    var geometry = new THREE.BufferGeometry();\n",
       "    geometry.setAttribute('position',bufattr);\n",
       "    if (Array.isArray(materials)) {\n",
       "        var tricount = 0;\n",
       "        var facet;\n",
       "        for (var i=0; i<facets.length; i++) {\n",
       "            facet = facets[i];\n",
       "            geometry.addGroup(tricount,(facet.length-2)*3,i);\n",
       "            tricount += (facet.length-2)*3;\n",
       "        }\n",
       "    }\n",
       "    var mesh = new THREE.Mesh(geometry, materials);\n",
       "    mesh.name = \"faces\";\n",
       "    obj.add(mesh); \n",
       "    updateFacesPosition(obj);\n",
       "}\n",
       "// //INITIALIZING\n",
       "\n",
       "\n",
       "function updateFacesPosition(obj) {\n",
       "    var points = obj.userData.points;\n",
       "    var indices = obj.userData.triangleindices;\n",
       "    var faces = obj.getObjectByName(\"faces\");\n",
       "    var ba = faces.geometry.getAttribute(\"position\");\n",
       "    for (var i=0; i<indices.length; i++) {\n",
       "        ba.setXYZ(i, points[indices[i]].vector.x, points[indices[i]].vector.y ,points[indices[i]].vector.z); \n",
       "    }\n",
       "    faces.geometry.attributes.position.needsUpdate = true;\n",
       "    \n",
       "}\n",
       "\n",
       "function updateEdgesPosition(obj) {\n",
       "    var points = obj.userData.points;\n",
       "    var indices = obj.userData.edgeindices;\n",
       "    var lines = obj.getObjectByName(\"lines\");\n",
       "    var ba = lines.geometry.getAttribute(\"position\"); \n",
       "    for (var i=0; i<indices.length; i++) {\n",
       "        ba.setXYZ(i, points[indices[i]].vector.x, points[indices[i]].vector.y ,points[indices[i]].vector.z); \n",
       "    }\n",
       "    lines.geometry.attributes.position.needsUpdate = true;\n",
       "}\n",
       "\n",
       "function onWindowResize() {\n",
       "    renderer.setSize( three.clientWidth, three.clientHeight );\n",
       "    svgRenderer.setSize( three.clientWidth, three.clientHeight );\n",
       "    updateCamera();\n",
       "}\n",
       "\n",
       "function updateCamera() {\n",
       "    var width = three.clientWidth;\n",
       "    var height = three.clientHeight;\n",
       "    var aspect = width / height;\n",
       "    if (camera.type == \"OrthographicCamera\") {\n",
       "        camera.left = frustumSize * aspect / - 2;\n",
       "        camera.right = frustumSize * aspect / 2;\n",
       "        camera.top = frustumSize / 2;\n",
       "        camera.bottom = - frustumSize / 2;\n",
       "    } else if (camera.type == \"PerspectiveCamera\") {\n",
       "        camera.aspect = aspect;\n",
       "    }\n",
       "    camera.updateProjectionMatrix();\n",
       "}\n",
       "\n",
       "function changeCamera(event) {\n",
       "    var selindex = event.currentTarget.selectedIndex;\n",
       "    camera = cameras[selindex];\n",
       "    control = controls[selindex];\n",
       "    control.enabled = true; \n",
       "    for (var i=0; i<controls.length; i++) {\n",
       "        if (i!=selindex) {\n",
       "            controls[i].enabled = false;\n",
       "        }\n",
       "    }\n",
       "    updateCamera();\n",
       "}\n",
       "\n",
       "var camtypenode = document.getElementById('cameraType_2');\n",
       "camtypenode.onchange = changeCamera;\n",
       "camtypenode.dispatchEvent(new Event('change'));\n",
       "\n",
       "onWindowResize();\n",
       "window.addEventListener('resize', onWindowResize);\t\n",
       "\n",
       "\n",
       "var xRotationEnabled = false;\n",
       "var yRotationEnabled = false;\n",
       "var zRotationEnabled = false;\n",
       "var rotationSpeedFactor = 1;\n",
       "var settingsShown = false;\n",
       "var labelsShown = true;\n",
       "var intervals = [];\n",
       "var timeouts = [];\n",
       "var explodingSpeed = 0.05;\n",
       "var explodeScale = 0;\n",
       "var XMLS = new XMLSerializer();\n",
       "var svgElement;\n",
       "var renderId;\n",
       "\n",
       "var render = function () {\n",
       "\n",
       "\trenderId = requestAnimationFrame(render);\n",
       "\n",
       "//\tcomment in for automatic explosion\n",
       "//\texplode(updateFactor());\n",
       "\n",
       "    var phi = 0.02 * rotationSpeedFactor;\n",
       "\n",
       "    if (xRotationEnabled) {\n",
       "        scene.rotation.x += phi;\n",
       "    }\n",
       "    if (yRotationEnabled) {\n",
       "        scene.rotation.y += phi;\n",
       "    }\n",
       "    if (zRotationEnabled) {\n",
       "        scene.rotation.z += phi;\n",
       "    }\n",
       "\n",
       "    control.update();\n",
       "    renderer.render(scene, camera);\n",
       "};\n",
       "\n",
       "if ( THREE.WEBGL.isWebGLAvailable() ) {\n",
       "\trender();\n",
       "} else {\n",
       "\tvar warning = WEBGL.getWebGLErrorMessage();\n",
       "\tthree.appendChild( warning );\n",
       "}\n",
       "    \n",
       "function changeTransparency() {\n",
       "    var opacity = 1-Number(event.currentTarget.value);\n",
       "    for (var i=0; i<scene.children.length; i++) {\n",
       "        child = scene.children[i];\n",
       "        if ( child.userData.hasOwnProperty(\"facetmaterial\") ) {\n",
       "            if (Array.isArray(child.userData.facetmaterial)) {\n",
       "                for (var j=0; j<child.userData.facetmaterial.length; j++) {\n",
       "                    child.userData.facetmaterial[j].opacity = opacity;\n",
       "                }\n",
       "            } else {\n",
       "                child.userData.facetmaterial.opacity = opacity;\n",
       "            }    \n",
       "        }\n",
       "    }\n",
       "}\n",
       "\n",
       "function changeRotationX(event){\n",
       "    xRotationEnabled = event.currentTarget.checked;\n",
       "}\t\n",
       "\n",
       "function changeRotationY(event){\n",
       "    yRotationEnabled = event.currentTarget.checked;\n",
       "}\t\n",
       "\n",
       "function changeRotationZ(event){\n",
       "    zRotationEnabled = event.currentTarget.checked;\n",
       "}\t\n",
       "\n",
       "\n",
       "function changeRotationSpeedFactor(event){\n",
       "    rotationSpeedFactor = Number(event.currentTarget.value);\n",
       "}\n",
       "\n",
       "function resetScene(){\n",
       "    scene.rotation.set(0,0,0);\n",
       "    camera.position.set(0,0,5);\n",
       "    camera.up.set(0,1,0);\n",
       "}\n",
       "\n",
       "function showSettings(event){\n",
       "    document.getElementById('settings_2').style.visibility = 'visible';\n",
       "    document.getElementById('showSettingsButton_2').style.visibility = 'hidden';\n",
       "    document.getElementById('hideSettingsButton_2').style.visibility = 'visible';\n",
       "    settingsShown = true;\n",
       "}\n",
       "\n",
       "function hideSettings(event){\n",
       "    document.getElementById('settings_2').style.visibility = 'hidden';\n",
       "    document.getElementById('showSettingsButton_2').style.visibility = 'visible';\n",
       "    document.getElementById('hideSettingsButton_2').style.visibility = 'hidden';\n",
       "    settingsShown = false;\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "var pos = 150* Math.PI;\n",
       "\n",
       "function updateFactor() {\n",
       "    pos++;\n",
       "    return Math.sin(.01*pos)+1;\n",
       "}\n",
       "\n",
       "// ------------------------ FOLDING ------------------------------------------------\n",
       "// ---------------------------------------------------------------------------------\n",
       "// rotate point p around axis defined by points p1 and p2 by given angle\n",
       "function rotate(p, p1, p2, angle ){   \n",
       "    angle = -angle;\n",
       "    var x = p.x, y = p.y, z = p.z, \n",
       "    a = p1.x, b = p1.y, c = p1.z, \n",
       "    u = p2.x-p1.x, v = p2.y-p1.y, w = p2.z-p1.z;\n",
       "    var result = [];\n",
       "    var L = u*u + v*v + w*w;\n",
       "    var sqrt = Math.sqrt;\n",
       "    var cos = Math.cos;\n",
       "    var sin = Math.sin;\n",
       "\n",
       "    result[0] = ((a*(v*v+w*w)-u*(b*v+c*w-u*x-v*y-w*z))*(1-cos(angle))+L*x*cos(angle)+sqrt(L)*(-c*v+b*w-w*y+v*z)*sin(angle))/L;\n",
       "    result[1] = ((b*(u*u+w*w)-v*(a*u+c*w-u*x-v*y-w*z))*(1-cos(angle))+L*y*cos(angle)+sqrt(L)*(c*u-a*w+w*x-u*z)*sin(angle))/L;\n",
       "    result[2] = ((c*(u*u+v*v)-w*(a*u+b*v-u*x-v*y-w*z))*(1-cos(angle))+L*z*cos(angle)+sqrt(L)*(-b*u+a*v-v*x+u*y)*sin(angle))/L;\n",
       "\n",
       "    return result;\n",
       "}\n",
       "\n",
       "var fold = function(event){\n",
       "    var obj = foldables[Number(event.currentTarget.name)];\n",
       "    var foldvalue = Number(event.currentTarget.value);\n",
       "    var scale = foldvalue - obj.userData.oldscale;\n",
       "\n",
       "    for (var j=0; j<obj.userData.axes.length; j++) {\n",
       "        rotateVertices(obj, j, scale);\n",
       "    }\n",
       "    update(obj);\n",
       "    obj.userData.oldscale += scale;\n",
       "    lookAtBarycenter(obj);\n",
       "}\n",
       "\n",
       "function lookAtBarycenter(obj){\n",
       "    control.target = barycenter(obj);\n",
       "}\n",
       "\n",
       "function barycenter(obj) {\n",
       "    var center = new THREE.Vector3(0,0,0);\n",
       "    var points = obj.userData.points;\n",
       "    for (var i=0; i<points.length; i++){\n",
       "        center.add(points[i].vector);\n",
       "    }\n",
       "    center.divideScalar(points.length);\n",
       "    return center;\n",
       "}\n",
       "\n",
       "function rotateVertices(obj, edge, scale) {\n",
       "    var axes = obj.userData.axes;\n",
       "    var subtrees = obj.userData.subtrees;\n",
       "    var points = obj.userData.points;\n",
       "    var angles = obj.userData.angles;\n",
       "    if (edge < axes.length){\n",
       "        for (var j=0; j<subtrees[edge].length; j++){\n",
       "            var rotP = rotate(points[subtrees[edge][j]].vector, points[axes[edge][0]].vector,points[axes[edge][1]].vector, scale * (Math.PI - angles[edge]));\n",
       "            points[subtrees[edge][j]].set(rotP[0],rotP[1],rotP[2]);\n",
       "        }\n",
       "    }\n",
       "}\n",
       "\n",
       "function update(obj) {\n",
       "   updateFacesPosition(obj);\n",
       "   updateEdgesPosition(obj);\n",
       "}\n",
       "\n",
       "if (foldables.length) {\n",
       "    var settings = document.getElementById('settings_2');\n",
       "    var foldDiv = document.createElement('div');\n",
       "    foldDiv.id = 'fold_2';\n",
       "    var title = document.createElement('strong');\n",
       "    title.innerHTML = 'Fold';\n",
       "    foldDiv.appendChild(title);\n",
       "    foldDiv.className = 'group';\n",
       "    for (var i=0; i<foldables.length; i++) {\n",
       "        var range = document.createElement('input');\n",
       "        range.type = 'range';\n",
       "        range.min = 0;\n",
       "        range.max = 1;\n",
       "        range.value = 0;\n",
       "        range.step = 0.001;\n",
       "        range.name = String(i);\n",
       "        range.oninput = fold;\n",
       "        foldDiv.appendChild(range);\n",
       "    }\n",
       "    lookAtBarycenter(foldables[0]);\n",
       "    settings.insertBefore(foldDiv,settings.childNodes[0]);\n",
       "}\n",
       "\n",
       "    \n",
       "// ---------------------- EXPLOSION ------------------------------------------------\n",
       "// ---------------------------------------------------------------------------------\n",
       "\n",
       "if (explodableModel) {\n",
       "    for (var i=0; i<scene.children.length; i++) {\n",
       "        obj = scene.children[i];\n",
       "        if ( obj.userData.explodable ) {\n",
       "            computeCentroid(obj);\n",
       "        }\n",
       "    }\n",
       "    document.getElementById('explodeRange_2').oninput = triggerExplode;\n",
       "    document.getElementById('explodeCheckbox_2').onchange = triggerAutomaticExplode;\n",
       "    document.getElementById('explodingSpeedRange_2').oninput = setExplodingSpeed;\n",
       "}\n",
       "\n",
       "function computeCentroid(obj) {\n",
       "    centroid = new THREE.Vector3();\n",
       "    obj.userData.points.forEach(function(pmpoint) {\n",
       "        centroid.add(pmpoint.vector);\t\t\t\n",
       "    });\n",
       "    centroid.divideScalar(obj.userData.points.length);\n",
       "    obj.userData.centroid = centroid;\n",
       "}\n",
       "\n",
       "function explode(factor) {\n",
       "    for (var i=0; i<scene.children.length; i++) {\n",
       "        var obj = scene.children[i];\n",
       "        if (obj.userData.hasOwnProperty(\"centroid\")) { \n",
       "            var c = obj.userData.centroid;\n",
       "            obj.position.set(c.x*factor, c.y*factor, c.z*factor);\n",
       "        }\n",
       "    }\t\n",
       "}\n",
       "\n",
       "function triggerExplode(event){\n",
       "    explodeScale = Number(event.currentTarget.value);\n",
       "    explode(explodeScale);\n",
       "}\n",
       "\n",
       "function setExplodingSpeed(event){\n",
       "    explodingSpeed = Number(event.currentTarget.value);\n",
       "}\n",
       "\n",
       "function triggerAutomaticExplode(event){\n",
       "    if (event.currentTarget.checked){\n",
       "        startExploding();\n",
       "    } else {\n",
       "        clearIntervals();\n",
       "    }\t\n",
       "}\n",
       "\n",
       "function startExploding(){\n",
       "    intervals.push(setInterval(explodingInterval, 25));\n",
       "}\n",
       "\n",
       "\n",
       "function explodingInterval(){\n",
       "    explodeScale += explodingSpeed;\n",
       "    if (explodeScale <= 6){ \n",
       "        explode(explodeScale);\n",
       "    }\n",
       "    else{\n",
       "        explode(6);\n",
       "        explodeScale = 6;\n",
       "        clearIntervals();\n",
       "        timeouts.push(setTimeout(startUnexploding, 3000));\n",
       "    }\n",
       "    document.getElementById('explodeRange_2').value = explodeScale;\n",
       "}\n",
       "\n",
       "\n",
       "function startUnexploding(){\n",
       "    intervals.push(setInterval(unexplodingInterval, 25));\n",
       "}\n",
       "\n",
       "function unexplodingInterval(){\n",
       "    explodeScale -= explodingSpeed;\n",
       "    if (explodeScale >= 0){\t\n",
       "        explode(explodeScale);\n",
       "    }\n",
       "    else {\n",
       "        explode(0);\n",
       "        explodeScale = 0;\n",
       "        clearIntervals();\n",
       "        timeouts.push(setTimeout(startExploding, 3000));\n",
       "    }\n",
       "    document.getElementById('explodeRange_2').value = explodeScale;\n",
       "}\n",
       "\n",
       "function clearIntervals(){\n",
       "    intervals.forEach(function(interval){\n",
       "        clearInterval(interval);\n",
       "    });\n",
       "    intervals = [];\n",
       "    timeouts.forEach(function(timeout){\n",
       "        clearTimeout(timeout);\n",
       "    });\n",
       "    timeouts = [];\n",
       "}\n",
       "\n",
       "// ---------------------- DISPLAY --------------------------------------------------\n",
       "// ---------------------------------------------------------------------------------\n",
       "\n",
       "const objectTypeInnerHTMLs = { points: \"Points\", pointlabels: \"Point labels\", lines: \"Edges\", edgelabels: \"Edge labels\", faces: \"Faces\", arrowheads: \"Arrow heads\" };\n",
       "const objectTypeVisible = {};\n",
       "Object.assign(objectTypeVisible,modelContains);\n",
       "const sortedObjectTypeKeys = Object.keys(objectTypeInnerHTMLs).sort();\n",
       "const shownObjectTypesList = document.getElementById('shownObjectTypesList_2');\n",
       "\n",
       "function setVisibility(bool,objname) {\n",
       "    for (var i=0; i<scene.children.length; i++){\n",
       "        var obj = scene.children[i].getObjectByName(objname);\n",
       "        if (obj) {\n",
       "            obj.visible = bool;\n",
       "        }\n",
       "    }\n",
       "}\n",
       "\n",
       "function toggleObjectTypeVisibility(event){\n",
       "    var name = event.currentTarget.name;\n",
       "    var checked = event.currentTarget.checked;\n",
       "    objectTypeVisible[name] = checked;\n",
       "    setVisibility(checked,name);\n",
       "}\n",
       "\n",
       "for (var i=0; i<sortedObjectTypeKeys.length; i++){\n",
       "    var key = sortedObjectTypeKeys[i];\n",
       "    if (modelContains[key]) {\n",
       "        var objTypeNode = document.createElement('span');\n",
       "        objTypeNode.innerHTML = objectTypeInnerHTMLs[key] + '<br>';\n",
       "        var checkbox = document.createElement('input');\n",
       "        checkbox.type = 'checkbox';\n",
       "        checkbox.checked = true;\n",
       "        checkbox.name = key;\n",
       "        checkbox.onchange = toggleObjectTypeVisibility;\n",
       "        shownObjectTypesList.appendChild(checkbox);\n",
       "        shownObjectTypesList.appendChild(objTypeNode);\n",
       "    }\n",
       "}\n",
       "\n",
       "// ------------------------------------------------------\n",
       "\n",
       "function toggleObjectVisibility(event){\n",
       "    var nr = Number(event.currentTarget.name);\n",
       "    scene.children[nr].visible = event.currentTarget.checked;\n",
       "}\n",
       "\n",
       "// append checkboxes for displaying or hiding objects\n",
       "var shownObjectsList = document.getElementById('shownObjectsList_2');\n",
       "for (var i=0; i<scene.children.length; i++){\n",
       "    obj = scene.children[i];\n",
       "    var objNode = document.createElement('span');\n",
       "    objNode.innerHTML = obj.name + '<br>';\n",
       "    var checkbox = document.createElement('input');\n",
       "    checkbox.type = 'checkbox';\n",
       "    checkbox.checked = true;\n",
       "    checkbox.name = String(i);\n",
       "    checkbox.onchange = toggleObjectVisibility;\n",
       "    shownObjectsList.appendChild(checkbox);\n",
       "    shownObjectsList.appendChild(objNode);\n",
       "}\n",
       "\n",
       "// ---------------------- SVG ------------------------------------------------------\n",
       "// ---------------------------------------------------------------------------------\n",
       "\n",
       "function takeSvgScreenshot() {\n",
       "    if (objectTypeVisible[\"pointlabels\"]) {\n",
       "        setVisibility(false,\"pointlabels\");\n",
       "    }\n",
       "    if (objectTypeVisible[\"edgelabels\"]) {\n",
       "        setVisibility(false,\"edgelabels\");\n",
       "    }\n",
       "    svgRenderer.render(scene,camera);\n",
       "    svgElement = XMLS.serializeToString(svgRenderer.domElement);\n",
       "    \n",
       "    if (objectTypeVisible[\"pointlabels\"]) {\n",
       "        setVisibility(true,\"pointlabels\");\n",
       "    }\n",
       "    if (objectTypeVisible[\"edgelabels\"]) {\n",
       "        setVisibility(true,\"edgelabels\");\n",
       "    }\n",
       "\n",
       "    if (document.getElementById('tab_2').checked){\n",
       "        //show in new tab\n",
       "        var myWindow = window.open(\"\",\"\");\n",
       "        myWindow.document.body.innerHTML = svgElement;\n",
       "    } else{\n",
       "        // download svg file \n",
       "        download(\"screenshot.svg\", svgElement);\n",
       "    }\n",
       "}\n",
       "\n",
       "function download(filename, text) {\n",
       "    var element = document.createElement('a');\n",
       "    element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));\n",
       "    element.setAttribute('download', filename);\n",
       "\n",
       "    element.style.display = 'none';\n",
       "    document.body.appendChild(element);\n",
       "\n",
       "    element.click();\n",
       "\n",
       "    document.body.removeChild(element);\n",
       "}\n",
       "\n",
       "\n",
       "document.getElementById('transparencyRange_2').oninput = changeTransparency;\n",
       "document.getElementById('changeRotationX_2').onchange = changeRotationX;\n",
       "document.getElementById('changeRotationY_2').onchange = changeRotationY;\n",
       "document.getElementById('changeRotationZ_2').onchange = changeRotationZ;\n",
       "document.getElementById('resetButton_2').onclick = resetScene;\n",
       "document.getElementById('rotationSpeedRange_2').oninput = changeRotationSpeedFactor;\n",
       "document.getElementById('takeScreenshot_2').onclick = takeSvgScreenshot;\n",
       "document.getElementById('showSettingsButton_2').onclick = showSettings;\n",
       "document.getElementById('hideSettingsButton_2').onclick = hideSettings;\n",
       "\n",
       "\n",
       "// ------------------ SHORTCUTS --------------------------------------------\n",
       "// -------------------------------------------------------------------------\n",
       "\n",
       "/**\n",
       " * http://www.openjs.com/scripts/events/keyboard_shortcuts/\n",
       " * Version : 2.01.B\n",
       " * By Binny V A\n",
       " * License : BSD\n",
       " */\n",
       "shortcut = {\n",
       "\t'all_shortcuts':{},//All the shortcuts are stored in this array\n",
       "\t'add': function(shortcut_combination,callback,opt) {\n",
       "\t\t//Provide a set of default options\n",
       "\t\tvar default_options = {\n",
       "\t\t\t'type':'keydown',\n",
       "\t\t\t'propagate':false,\n",
       "\t\t\t'disable_in_input':false,\n",
       "\t\t\t'target':document,\n",
       "\t\t\t'keycode':false\n",
       "\t\t}\n",
       "\t\tif(!opt) opt = default_options;\n",
       "\t\telse {\n",
       "\t\t\tfor(var dfo in default_options) {\n",
       "\t\t\t\tif(typeof opt[dfo] == 'undefined') opt[dfo] = default_options[dfo];\n",
       "\t\t\t}\n",
       "\t\t}\n",
       "\n",
       "\t\tvar ele = opt.target;\n",
       "\t\tif(typeof opt.target == 'string') ele = document.getElementById(opt.target);\n",
       "\t\tvar ths = this;\n",
       "\t\tshortcut_combination = shortcut_combination.toLowerCase();\n",
       "\n",
       "\t\t//The function to be called at keypress\n",
       "\t\tvar func = function(e) {\n",
       "\t\t\te = e || window.event;\n",
       "\t\t\t\n",
       "\t\t\tif(opt['disable_in_input']) { //Don't enable shortcut keys in Input, Textarea fields\n",
       "\t\t\t\tvar element;\n",
       "\t\t\t\tif(e.target) element=e.target;\n",
       "\t\t\t\telse if(e.srcElement) element=e.srcElement;\n",
       "\t\t\t\tif(element.nodeType==3) element=element.parentNode;\n",
       "\n",
       "\t\t\t\tif(element.tagName == 'INPUT' || element.tagName == 'TEXTAREA') return;\n",
       "\t\t\t}\n",
       "\t\n",
       "\t\t\t//Find Which key is pressed\n",
       "\t\t\tif (e.keyCode) code = e.keyCode;\n",
       "\t\t\telse if (e.which) code = e.which;\n",
       "\t\t\tvar character = String.fromCharCode(code).toLowerCase();\n",
       "\t\t\t\n",
       "\t\t\tif(code == 188) character=\",\"; //If the user presses , when the type is onkeydown\n",
       "\t\t\tif(code == 190) character=\".\"; //If the user presses , when the type is onkeydown\n",
       "\n",
       "\t\t\tvar keys = shortcut_combination.split(\"+\");\n",
       "\t\t\t//Key Pressed - counts the number of valid keypresses - if it is same as the number of keys, the shortcut function is invoked\n",
       "\t\t\tvar kp = 0;\n",
       "\t\t\t\n",
       "\t\t\t//Work around for stupid Shift key bug created by using lowercase - as a result the shift+num combination was broken\n",
       "\t\t\tvar shift_nums = {\n",
       "\t\t\t\t\"`\":\"~\",\n",
       "\t\t\t\t\"1\":\"!\",\n",
       "\t\t\t\t\"2\":\"@\",\n",
       "\t\t\t\t\"3\":\"#\",\n",
       "\t\t\t\t\"4\":\"$\",\n",
       "\t\t\t\t\"5\":\"%\",\n",
       "\t\t\t\t\"6\":\"^\",\n",
       "\t\t\t\t\"7\":\"&\",\n",
       "\t\t\t\t\"8\":\"*\",\n",
       "\t\t\t\t\"9\":\"(\",\n",
       "\t\t\t\t\"0\":\")\",\n",
       "\t\t\t\t\"-\":\"_\",\n",
       "\t\t\t\t\"=\":\"+\",\n",
       "\t\t\t\t\";\":\":\",\n",
       "\t\t\t\t\"'\":\"\\\"\",\n",
       "\t\t\t\t\",\":\"<\",\n",
       "\t\t\t\t\".\":\">\",\n",
       "\t\t\t\t\"/\":\"?\",\n",
       "\t\t\t\t\"\\\\\":\"|\"\n",
       "\t\t\t}\n",
       "\t\t\t//Special Keys - and their codes\n",
       "\t\t\tvar special_keys = {\n",
       "\t\t\t\t'esc':27,\n",
       "\t\t\t\t'escape':27,\n",
       "\t\t\t\t'tab':9,\n",
       "\t\t\t\t'space':32,\n",
       "\t\t\t\t'return':13,\n",
       "\t\t\t\t'enter':13,\n",
       "\t\t\t\t'backspace':8,\n",
       "\t\n",
       "\t\t\t\t'scrolllock':145,\n",
       "\t\t\t\t'scroll_lock':145,\n",
       "\t\t\t\t'scroll':145,\n",
       "\t\t\t\t'capslock':20,\n",
       "\t\t\t\t'caps_lock':20,\n",
       "\t\t\t\t'caps':20,\n",
       "\t\t\t\t'numlock':144,\n",
       "\t\t\t\t'num_lock':144,\n",
       "\t\t\t\t'num':144,\n",
       "\t\t\t\t\n",
       "\t\t\t\t'pause':19,\n",
       "\t\t\t\t'break':19,\n",
       "\t\t\t\t\n",
       "\t\t\t\t'insert':45,\n",
       "\t\t\t\t'home':36,\n",
       "\t\t\t\t'delete':46,\n",
       "\t\t\t\t'end':35,\n",
       "\t\t\t\t\n",
       "\t\t\t\t'pageup':33,\n",
       "\t\t\t\t'page_up':33,\n",
       "\t\t\t\t'pu':33,\n",
       "\t\n",
       "\t\t\t\t'pagedown':34,\n",
       "\t\t\t\t'page_down':34,\n",
       "\t\t\t\t'pd':34,\n",
       "\t\n",
       "\t\t\t\t'left':37,\n",
       "\t\t\t\t'up':38,\n",
       "\t\t\t\t'right':39,\n",
       "\t\t\t\t'down':40,\n",
       "\t\n",
       "\t\t\t\t'f1':112,\n",
       "\t\t\t\t'f2':113,\n",
       "\t\t\t\t'f3':114,\n",
       "\t\t\t\t'f4':115,\n",
       "\t\t\t\t'f5':116,\n",
       "\t\t\t\t'f6':117,\n",
       "\t\t\t\t'f7':118,\n",
       "\t\t\t\t'f8':119,\n",
       "\t\t\t\t'f9':120,\n",
       "\t\t\t\t'f10':121,\n",
       "\t\t\t\t'f11':122,\n",
       "\t\t\t\t'f12':123\n",
       "\t\t\t}\n",
       "\t\n",
       "\t\t\tvar modifiers = { \n",
       "\t\t\t\tshift: { wanted:false, pressed:false},\n",
       "\t\t\t\tctrl : { wanted:false, pressed:false},\n",
       "\t\t\t\talt  : { wanted:false, pressed:false},\n",
       "\t\t\t\tmeta : { wanted:false, pressed:false}\t//Meta is Mac specific\n",
       "\t\t\t};\n",
       "                        \n",
       "\t\t\tif(e.ctrlKey)\tmodifiers.ctrl.pressed = true;\n",
       "\t\t\tif(e.shiftKey)\tmodifiers.shift.pressed = true;\n",
       "\t\t\tif(e.altKey)\tmodifiers.alt.pressed = true;\n",
       "\t\t\tif(e.metaKey)   modifiers.meta.pressed = true;\n",
       "                        \n",
       "\t\t\tfor(var i=0; k=keys[i],i<keys.length; i++) {\n",
       "\t\t\t\t//Modifiers\n",
       "\t\t\t\tif(k == 'ctrl' || k == 'control') {\n",
       "\t\t\t\t\tkp++;\n",
       "\t\t\t\t\tmodifiers.ctrl.wanted = true;\n",
       "\n",
       "\t\t\t\t} else if(k == 'shift') {\n",
       "\t\t\t\t\tkp++;\n",
       "\t\t\t\t\tmodifiers.shift.wanted = true;\n",
       "\n",
       "\t\t\t\t} else if(k == 'alt') {\n",
       "\t\t\t\t\tkp++;\n",
       "\t\t\t\t\tmodifiers.alt.wanted = true;\n",
       "\t\t\t\t} else if(k == 'meta') {\n",
       "\t\t\t\t\tkp++;\n",
       "\t\t\t\t\tmodifiers.meta.wanted = true;\n",
       "\t\t\t\t} else if(k.length > 1) { //If it is a special key\n",
       "\t\t\t\t\tif(special_keys[k] == code) kp++;\n",
       "\t\t\t\t\t\n",
       "\t\t\t\t} else if(opt['keycode']) {\n",
       "\t\t\t\t\tif(opt['keycode'] == code) kp++;\n",
       "\n",
       "\t\t\t\t} else { //The special keys did not match\n",
       "\t\t\t\t\tif(character == k) kp++;\n",
       "\t\t\t\t\telse {\n",
       "\t\t\t\t\t\tif(shift_nums[character] && e.shiftKey) { //Stupid Shift key bug created by using lowercase\n",
       "\t\t\t\t\t\t\tcharacter = shift_nums[character]; \n",
       "\t\t\t\t\t\t\tif(character == k) kp++;\n",
       "\t\t\t\t\t\t}\n",
       "\t\t\t\t\t}\n",
       "\t\t\t\t}\n",
       "\t\t\t}\n",
       "\t\t\t\n",
       "\t\t\tif(kp == keys.length && \n",
       "\t\t\t\t\t\tmodifiers.ctrl.pressed == modifiers.ctrl.wanted &&\n",
       "\t\t\t\t\t\tmodifiers.shift.pressed == modifiers.shift.wanted &&\n",
       "\t\t\t\t\t\tmodifiers.alt.pressed == modifiers.alt.wanted &&\n",
       "\t\t\t\t\t\tmodifiers.meta.pressed == modifiers.meta.wanted) {\n",
       "\t\t\t\tcallback(e);\n",
       "\t\n",
       "\t\t\t\tif(!opt['propagate']) { //Stop the event\n",
       "\t\t\t\t\t//e.cancelBubble is supported by IE - this will kill the bubbling process.\n",
       "\t\t\t\t\te.cancelBubble = true;\n",
       "\t\t\t\t\te.returnValue = false;\n",
       "\t\n",
       "\t\t\t\t\t//e.stopPropagation works in Firefox.\n",
       "\t\t\t\t\tif (e.stopPropagation) {\n",
       "\t\t\t\t\t\te.stopPropagation();\n",
       "\t\t\t\t\t\te.preventDefault();\n",
       "\t\t\t\t\t}\n",
       "\t\t\t\t\treturn false;\n",
       "\t\t\t\t}\n",
       "\t\t\t}\n",
       "\t\t}\n",
       "\t\tthis.all_shortcuts[shortcut_combination] = {\n",
       "\t\t\t'callback':func, \n",
       "\t\t\t'target':ele, \n",
       "\t\t\t'event': opt['type']\n",
       "\t\t};\n",
       "\t\t//Attach the function with the event\n",
       "\t\tif(ele.addEventListener) ele.addEventListener(opt['type'], func, false);\n",
       "\t\telse if(ele.attachEvent) ele.attachEvent('on'+opt['type'], func);\n",
       "\t\telse ele['on'+opt['type']] = func;\n",
       "\t},\n",
       "\n",
       "\t//Remove the shortcut - just specify the shortcut and I will remove the binding\n",
       "\t'remove':function(shortcut_combination) {\n",
       "\t\tshortcut_combination = shortcut_combination.toLowerCase();\n",
       "\t\tvar binding = this.all_shortcuts[shortcut_combination];\n",
       "\t\tdelete(this.all_shortcuts[shortcut_combination])\n",
       "\t\tif(!binding) return;\n",
       "\t\tvar type = binding['event'];\n",
       "\t\tvar ele = binding['target'];\n",
       "\t\tvar callback = binding['callback'];\n",
       "\n",
       "\t\tif(ele.detachEvent) ele.detachEvent('on'+type, callback);\n",
       "\t\telse if(ele.removeEventListener) ele.removeEventListener(type, callback, false);\n",
       "\t\telse ele['on'+type] = false;\n",
       "\t}\n",
       "}\n",
       "\n",
       "shortcut.add(\"Alt+Left\",function() {\n",
       "\tvar event = new Event('click');\n",
       "\tif (settingsShown){\n",
       "\t\tdocument.getElementById('hideSettingsButton_2').dispatchEvent(event);\n",
       "\t} else {\n",
       "\t\tdocument.getElementById('showSettingsButton_2').dispatchEvent(event);\n",
       "\t}\n",
       "});\n",
       "\n",
       "\n",
       "// COMMON_CODE_BLOCK_END\n",
       "\n",
       "});});\n",
       "      </script>\n",
       "   </body>\n",
       "</html>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "$a = new Array<Set<Int>>(1); $a->[0] = $bs->FACETS->[4];\n",
    "$bs->VISUAL->FACES($a, FacetColor => 'pink');"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "\n",
    "The same can be used for the visualization of the face lattice. As an example, we have a look at a `morse matching` of the Klein bottle with its associated critical faces. In order to see the arrowheads in the picture clearly, you ought to use graphviz or svg to vizualize it. \n",
    "\n",
    "    \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n",
       "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.0//EN\" \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n",
       "<svg height=\"841pt\" id=\"document\" viewBox=\"0 -824 570 824\" width=\"595pt\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:svg=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
       "\t<title id=\"document_title\">Face lattice of k</title>\n",
       "\t<defs>\n",
       "\t\t<marker id=\"arrow\" markerHeight=\"10\" markerUnits=\"strokeWidth\" markerWidth=\"15\" orient=\"auto\" refX=\"30\" refY=\"5\">\n",
       "\t\t\t<path d=\"M0,0 L0,10 L15,5z\" fill=\"rgb(0,0,0)\" />\n",
       "\t\t</marker>\n",
       "\t</defs>\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"282.655601659751\" x2=\"297.5\" y1=\"-597.5\" y2=\"-774.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"165.36652835408\" x2=\"297.5\" y1=\"-597.5\" y2=\"-774.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"136.044260027663\" x2=\"297.5\" y1=\"-597.5\" y2=\"-774.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"253.333333333333\" x2=\"297.5\" y1=\"-597.5\" y2=\"-774.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"106.721991701245\" x2=\"297.5\" y1=\"-597.5\" y2=\"-774.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"77.3997233748271\" x2=\"297.5\" y1=\"-597.5\" y2=\"-774.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"224.011065006916\" x2=\"297.5\" y1=\"-597.5\" y2=\"-774.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"48.0774550484094\" x2=\"297.5\" y1=\"-597.5\" y2=\"-774.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"194.688796680498\" x2=\"297.5\" y1=\"-597.5\" y2=\"-774.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"458.955739972338\" x2=\"297.5\" y1=\"-597.5\" y2=\"-774.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"400.311203319502\" x2=\"297.5\" y1=\"-597.5\" y2=\"-774.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"341.666666666667\" x2=\"297.5\" y1=\"-597.5\" y2=\"-774.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"546.922544951591\" x2=\"297.5\" y1=\"-597.5\" y2=\"-774.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"370.988934993084\" x2=\"297.5\" y1=\"-597.5\" y2=\"-774.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"517.600276625173\" x2=\"297.5\" y1=\"-597.5\" y2=\"-774.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"312.344398340249\" x2=\"297.5\" y1=\"-597.5\" y2=\"-774.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"488.278008298755\" x2=\"297.5\" y1=\"-597.5\" y2=\"-774.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"429.63347164592\" x2=\"297.5\" y1=\"-597.5\" y2=\"-774.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"336.759259259259\" x2=\"282.655601659751\" y1=\"-420.5\" y2=\"-597.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"336.759259259259\" x2=\"458.955739972338\" y1=\"-420.5\" y2=\"-597.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"277.87037037037\" x2=\"282.655601659751\" y1=\"-420.5\" y2=\"-597.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"277.87037037037\" x2=\"253.333333333333\" y1=\"-420.5\" y2=\"-597.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"179.722222222222\" x2=\"282.655601659751\" y1=\"-420.5\" y2=\"-597.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(231,0,74)\" stroke-width=\"1\" x1=\"77.3997233748271\" x2=\"179.722222222222\" y1=\"-597.5\" y2=\"-420.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"140.462962962963\" x2=\"165.36652835408\" y1=\"-420.5\" y2=\"-597.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"140.462962962963\" x2=\"136.044260027663\" y1=\"-420.5\" y2=\"-597.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"238.611111111111\" x2=\"165.36652835408\" y1=\"-420.5\" y2=\"-597.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"238.611111111111\" x2=\"253.333333333333\" y1=\"-420.5\" y2=\"-597.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"101.203703703704\" x2=\"165.36652835408\" y1=\"-420.5\" y2=\"-597.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(231,0,74)\" stroke-width=\"1\" x1=\"106.721991701245\" x2=\"101.203703703704\" y1=\"-597.5\" y2=\"-420.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"258.240740740741\" x2=\"136.044260027663\" y1=\"-420.5\" y2=\"-597.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"258.240740740741\" x2=\"341.666666666667\" y1=\"-420.5\" y2=\"-597.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"61.9444444444444\" x2=\"136.044260027663\" y1=\"-420.5\" y2=\"-597.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"61.9444444444444\" x2=\"48.0774550484094\" y1=\"-420.5\" y2=\"-597.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"199.351851851852\" x2=\"253.333333333333\" y1=\"-420.5\" y2=\"-597.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"199.351851851852\" x2=\"194.688796680498\" y1=\"-420.5\" y2=\"-597.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"81.5740740740741\" x2=\"106.721991701245\" y1=\"-420.5\" y2=\"-597.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"81.5740740740741\" x2=\"77.3997233748271\" y1=\"-420.5\" y2=\"-597.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"160.092592592593\" x2=\"106.721991701245\" y1=\"-420.5\" y2=\"-597.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(231,0,74)\" stroke-width=\"1\" x1=\"224.011065006916\" x2=\"160.092592592593\" y1=\"-597.5\" y2=\"-420.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"42.3148148148148\" x2=\"77.3997233748271\" y1=\"-420.5\" y2=\"-597.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(231,0,74)\" stroke-width=\"1\" x1=\"48.0774550484094\" x2=\"42.3148148148148\" y1=\"-597.5\" y2=\"-420.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"297.5\" x2=\"224.011065006916\" y1=\"-420.5\" y2=\"-597.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(231,0,74)\" stroke-width=\"1\" x1=\"312.344398340249\" x2=\"297.5\" y1=\"-597.5\" y2=\"-420.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"218.981481481481\" x2=\"224.011065006916\" y1=\"-420.5\" y2=\"-597.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"218.981481481481\" x2=\"194.688796680498\" y1=\"-420.5\" y2=\"-597.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"120.833333333333\" x2=\"48.0774550484094\" y1=\"-420.5\" y2=\"-597.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(231,0,74)\" stroke-width=\"1\" x1=\"194.688796680498\" x2=\"120.833333333333\" y1=\"-597.5\" y2=\"-420.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"513.425925925926\" x2=\"458.955739972338\" y1=\"-420.5\" y2=\"-597.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"513.425925925926\" x2=\"546.922544951591\" y1=\"-420.5\" y2=\"-597.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"493.796296296296\" x2=\"458.955739972338\" y1=\"-420.5\" y2=\"-597.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(231,0,74)\" stroke-width=\"1\" x1=\"517.600276625173\" x2=\"493.796296296296\" y1=\"-597.5\" y2=\"-420.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"376.018518518518\" x2=\"400.311203319502\" y1=\"-420.5\" y2=\"-597.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"376.018518518518\" x2=\"341.666666666667\" y1=\"-420.5\" y2=\"-597.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"474.166666666667\" x2=\"400.311203319502\" y1=\"-420.5\" y2=\"-597.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"474.166666666667\" x2=\"546.922544951591\" y1=\"-420.5\" y2=\"-597.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"415.277777777778\" x2=\"400.311203319502\" y1=\"-420.5\" y2=\"-597.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(231,0,74)\" stroke-width=\"1\" x1=\"370.988934993084\" x2=\"415.277777777778\" y1=\"-597.5\" y2=\"-420.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"395.648148148148\" x2=\"341.666666666667\" y1=\"-420.5\" y2=\"-597.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"395.648148148148\" x2=\"488.278008298755\" y1=\"-420.5\" y2=\"-597.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"533.055555555555\" x2=\"546.922544951591\" y1=\"-420.5\" y2=\"-597.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"533.055555555555\" x2=\"429.63347164592\" y1=\"-420.5\" y2=\"-597.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"434.907407407407\" x2=\"370.988934993084\" y1=\"-420.5\" y2=\"-597.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"434.907407407407\" x2=\"517.600276625173\" y1=\"-420.5\" y2=\"-597.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"317.12962962963\" x2=\"370.988934993084\" y1=\"-420.5\" y2=\"-597.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"317.12962962963\" x2=\"312.344398340249\" y1=\"-420.5\" y2=\"-597.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"552.685185185185\" x2=\"517.600276625173\" y1=\"-420.5\" y2=\"-597.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(231,0,74)\" stroke-width=\"1\" x1=\"488.278008298755\" x2=\"552.685185185185\" y1=\"-597.5\" y2=\"-420.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"356.388888888889\" x2=\"312.344398340249\" y1=\"-420.5\" y2=\"-597.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(231,0,74)\" stroke-width=\"1\" x1=\"429.63347164592\" x2=\"356.388888888889\" y1=\"-597.5\" y2=\"-420.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"454.537037037037\" x2=\"488.278008298755\" y1=\"-420.5\" y2=\"-597.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"454.537037037037\" x2=\"429.63347164592\" y1=\"-420.5\" y2=\"-597.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"326.808755760369\" x2=\"336.759259259259\" y1=\"-243.5\" y2=\"-420.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"326.808755760369\" x2=\"277.87037037037\" y1=\"-243.5\" y2=\"-420.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"326.808755760369\" x2=\"140.462962962963\" y1=\"-243.5\" y2=\"-420.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"326.808755760369\" x2=\"238.611111111111\" y1=\"-243.5\" y2=\"-420.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"326.808755760369\" x2=\"258.240740740741\" y1=\"-243.5\" y2=\"-420.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"326.808755760369\" x2=\"513.425925925926\" y1=\"-243.5\" y2=\"-420.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"326.808755760369\" x2=\"376.018518518518\" y1=\"-243.5\" y2=\"-420.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"326.808755760369\" x2=\"474.166666666667\" y1=\"-243.5\" y2=\"-420.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(231,0,74)\" stroke-width=\"1\" x1=\"336.759259259259\" x2=\"287.730414746544\" y1=\"-420.5\" y2=\"-243.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"287.730414746544\" x2=\"179.722222222222\" y1=\"-243.5\" y2=\"-420.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"287.730414746544\" x2=\"81.5740740740741\" y1=\"-243.5\" y2=\"-420.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"287.730414746544\" x2=\"160.092592592593\" y1=\"-243.5\" y2=\"-420.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"287.730414746544\" x2=\"297.5\" y1=\"-243.5\" y2=\"-420.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"287.730414746544\" x2=\"493.796296296296\" y1=\"-243.5\" y2=\"-420.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"287.730414746544\" x2=\"434.907407407407\" y1=\"-243.5\" y2=\"-420.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"287.730414746544\" x2=\"317.12962962963\" y1=\"-243.5\" y2=\"-420.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(231,0,74)\" stroke-width=\"1\" x1=\"277.87037037037\" x2=\"165\" y1=\"-420.5\" y2=\"-243.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"165\" x2=\"179.722222222222\" y1=\"-243.5\" y2=\"-420.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"165\" x2=\"199.351851851852\" y1=\"-243.5\" y2=\"-420.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"165\" x2=\"42.3148148148148\" y1=\"-243.5\" y2=\"-420.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"165\" x2=\"120.833333333333\" y1=\"-243.5\" y2=\"-420.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"87.0588235294119\" x2=\"140.462962962963\" y1=\"-243.5\" y2=\"-420.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"87.0588235294119\" x2=\"101.203703703704\" y1=\"-243.5\" y2=\"-420.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"87.0588235294119\" x2=\"61.9444444444444\" y1=\"-243.5\" y2=\"-420.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(231,0,74)\" stroke-width=\"1\" x1=\"81.5740740740741\" x2=\"87.0588235294119\" y1=\"-420.5\" y2=\"-243.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"87.0588235294119\" x2=\"42.3148148148148\" y1=\"-243.5\" y2=\"-420.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"184.485294117647\" x2=\"238.611111111111\" y1=\"-243.5\" y2=\"-420.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"184.485294117647\" x2=\"101.203703703704\" y1=\"-243.5\" y2=\"-420.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(231,0,74)\" stroke-width=\"1\" x1=\"199.351851851852\" x2=\"184.485294117647\" y1=\"-420.5\" y2=\"-243.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"184.485294117647\" x2=\"160.092592592593\" y1=\"-243.5\" y2=\"-420.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"184.485294117647\" x2=\"218.981481481481\" y1=\"-243.5\" y2=\"-420.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"270.633640552995\" x2=\"258.240740740741\" y1=\"-243.5\" y2=\"-420.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"270.633640552995\" x2=\"61.9444444444444\" y1=\"-243.5\" y2=\"-420.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"270.633640552995\" x2=\"297.5\" y1=\"-243.5\" y2=\"-420.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(231,0,74)\" stroke-width=\"1\" x1=\"218.981481481481\" x2=\"270.633640552995\" y1=\"-420.5\" y2=\"-243.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"270.633640552995\" x2=\"120.833333333333\" y1=\"-243.5\" y2=\"-420.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"270.633640552995\" x2=\"395.648148148148\" y1=\"-243.5\" y2=\"-420.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"270.633640552995\" x2=\"356.388888888889\" y1=\"-243.5\" y2=\"-420.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"270.633640552995\" x2=\"454.537037037037\" y1=\"-243.5\" y2=\"-420.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"507.941176470588\" x2=\"513.425925925926\" y1=\"-243.5\" y2=\"-420.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"507.941176470588\" x2=\"493.796296296296\" y1=\"-243.5\" y2=\"-420.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"507.941176470588\" x2=\"533.055555555555\" y1=\"-243.5\" y2=\"-420.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"507.941176470588\" x2=\"552.685185185185\" y1=\"-243.5\" y2=\"-420.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(231,0,74)\" stroke-width=\"1\" x1=\"454.537037037037\" x2=\"507.941176470588\" y1=\"-420.5\" y2=\"-243.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"433.897058823529\" x2=\"376.018518518518\" y1=\"-243.5\" y2=\"-420.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"433.897058823529\" x2=\"415.277777777778\" y1=\"-243.5\" y2=\"-420.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(231,0,74)\" stroke-width=\"1\" x1=\"395.648148148148\" x2=\"433.897058823529\" y1=\"-420.5\" y2=\"-243.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"433.897058823529\" x2=\"434.907407407407\" y1=\"-243.5\" y2=\"-420.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"433.897058823529\" x2=\"552.685185185185\" y1=\"-243.5\" y2=\"-420.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"418.308823529412\" x2=\"474.166666666667\" y1=\"-243.5\" y2=\"-420.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"418.308823529412\" x2=\"415.277777777778\" y1=\"-243.5\" y2=\"-420.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(231,0,74)\" stroke-width=\"1\" x1=\"533.055555555555\" x2=\"418.308823529412\" y1=\"-420.5\" y2=\"-243.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"418.308823529412\" x2=\"317.12962962963\" y1=\"-243.5\" y2=\"-420.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"418.308823529412\" x2=\"356.388888888889\" y1=\"-243.5\" y2=\"-420.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"297.5\" x2=\"326.808755760369\" y1=\"-66.5\" y2=\"-243.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"297.5\" x2=\"287.730414746544\" y1=\"-66.5\" y2=\"-243.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"297.5\" x2=\"165\" y1=\"-66.5\" y2=\"-243.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"297.5\" x2=\"87.0588235294119\" y1=\"-66.5\" y2=\"-243.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"297.5\" x2=\"184.485294117647\" y1=\"-66.5\" y2=\"-243.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"297.5\" x2=\"270.633640552995\" y1=\"-66.5\" y2=\"-243.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"297.5\" x2=\"507.941176470588\" y1=\"-66.5\" y2=\"-243.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"297.5\" x2=\"433.897058823529\" y1=\"-66.5\" y2=\"-243.5\" />\n",
       "\t<line marker-end=\"url(#arrow)\" stroke=\"rgb(0,0,0)\" stroke-width=\"1\" x1=\"297.5\" x2=\"418.308823529412\" y1=\"-66.5\" y2=\"-243.5\" />\n",
       "\t<rect height=\"11.4540110650069\" rx=\"0\" ry=\"0\" style=\"fill: rgb(0,0,0); stroke: rgb(0,0,0); stroke-width: 0.848445264074586\" width=\"12.319425234363\" x=\"291.340287382819\" y=\"-781.287562112597\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"8.48445264074586\" text-anchor=\"middle\" x=\"297.5\" y=\"-772.378886839814\"> </text>\n",
       "\t<rect height=\"11.4540110650069\" rx=\"0\" ry=\"0\" style=\"fill: rgb(231,0,74); stroke: rgb(0,0,0); stroke-width: 0.848445264074586\" width=\"24.4352236053481\" x=\"270.437989857077\" y=\"-604.287562112597\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"8.48445264074586\" text-anchor=\"middle\" x=\"282.655601659751\" y=\"-595.378886839814\">0 1 5</text>\n",
       "\t<rect height=\"11.4540110650069\" rx=\"0\" ry=\"0\" style=\"fill: rgb(231,0,74); stroke: rgb(0,0,0); stroke-width: 0.848445264074586\" width=\"24.4352236053481\" x=\"153.148916551406\" y=\"-604.287562112597\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"8.48445264074586\" text-anchor=\"middle\" x=\"165.36652835408\" y=\"-595.378886839814\">0 2 3</text>\n",
       "\t<rect height=\"11.4540110650069\" rx=\"0\" ry=\"0\" style=\"fill: rgb(231,0,74); stroke: rgb(0,0,0); stroke-width: 0.848445264074586\" width=\"24.4352236053481\" x=\"123.826648224988\" y=\"-604.287562112597\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"8.48445264074586\" text-anchor=\"middle\" x=\"136.044260027663\" y=\"-595.378886839814\">0 2 4</text>\n",
       "\t<rect height=\"11.4540110650069\" rx=\"0\" ry=\"0\" style=\"fill: rgb(231,0,74); stroke: rgb(0,0,0); stroke-width: 0.848445264074586\" width=\"24.4352236053481\" x=\"241.115721530659\" y=\"-604.287562112597\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"8.48445264074586\" text-anchor=\"middle\" x=\"253.333333333333\" y=\"-595.378886839814\">0 3 5</text>\n",
       "\t<rect height=\"11.4540110650069\" rx=\"0\" ry=\"0\" style=\"fill: rgb(255,255,255); stroke: rgb(0,0,0); stroke-width: 0.848445264074586\" width=\"24.4352236053481\" x=\"94.5043798985708\" y=\"-604.287562112597\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"8.48445264074586\" text-anchor=\"middle\" x=\"106.721991701245\" y=\"-595.378886839814\">1 2 3</text>\n",
       "\t<rect height=\"11.4540110650069\" rx=\"0\" ry=\"0\" style=\"fill: rgb(255,255,255); stroke: rgb(0,0,0); stroke-width: 0.848445264074586\" width=\"24.4352236053481\" x=\"65.1821115721531\" y=\"-604.287562112597\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"8.48445264074586\" text-anchor=\"middle\" x=\"77.3997233748271\" y=\"-595.378886839814\">1 2 5</text>\n",
       "\t<rect height=\"11.4540110650069\" rx=\"0\" ry=\"0\" style=\"fill: rgb(255,255,255); stroke: rgb(0,0,0); stroke-width: 0.848445264074586\" width=\"24.4352236053481\" x=\"211.793453204242\" y=\"-604.287562112597\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"8.48445264074586\" text-anchor=\"middle\" x=\"224.011065006916\" y=\"-595.378886839814\">1 3 4</text>\n",
       "\t<rect height=\"11.4540110650069\" rx=\"0\" ry=\"0\" style=\"fill: rgb(255,255,255); stroke: rgb(0,0,0); stroke-width: 0.848445264074586\" width=\"24.4352236053481\" x=\"35.8598432457354\" y=\"-604.287562112597\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"8.48445264074586\" text-anchor=\"middle\" x=\"48.0774550484094\" y=\"-595.378886839814\">2 4 5</text>\n",
       "\t<rect height=\"11.4540110650069\" rx=\"0\" ry=\"0\" style=\"fill: rgb(255,255,255); stroke: rgb(0,0,0); stroke-width: 0.848445264074586\" width=\"24.4352236053481\" x=\"182.471184877824\" y=\"-604.287562112597\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"8.48445264074586\" text-anchor=\"middle\" x=\"194.688796680498\" y=\"-595.378886839814\">3 4 5</text>\n",
       "\t<rect height=\"11.4540110650069\" rx=\"0\" ry=\"0\" style=\"fill: rgb(231,0,74); stroke: rgb(0,0,0); stroke-width: 0.848445264074586\" width=\"24.4352236053481\" x=\"446.738128169663\" y=\"-604.287562112597\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"8.48445264074586\" text-anchor=\"middle\" x=\"458.955739972338\" y=\"-595.378886839814\">0 1 8</text>\n",
       "\t<rect height=\"11.4540110650069\" rx=\"0\" ry=\"0\" style=\"fill: rgb(231,0,74); stroke: rgb(0,0,0); stroke-width: 0.848445264074586\" width=\"24.4352236053481\" x=\"388.093591516828\" y=\"-604.287562112597\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"8.48445264074586\" text-anchor=\"middle\" x=\"400.311203319502\" y=\"-595.378886839814\">0 6 7</text>\n",
       "\t<rect height=\"11.4540110650069\" rx=\"0\" ry=\"0\" style=\"fill: rgb(231,0,74); stroke: rgb(0,0,0); stroke-width: 0.848445264074586\" width=\"24.4352236053481\" x=\"329.449054863993\" y=\"-604.287562112597\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"8.48445264074586\" text-anchor=\"middle\" x=\"341.666666666667\" y=\"-595.378886839814\">0 4 6</text>\n",
       "\t<rect height=\"11.4540110650069\" rx=\"0\" ry=\"0\" style=\"fill: rgb(231,0,74); stroke: rgb(0,0,0); stroke-width: 0.848445264074586\" width=\"24.4352236053481\" x=\"534.704933148917\" y=\"-604.287562112597\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"8.48445264074586\" text-anchor=\"middle\" x=\"546.922544951591\" y=\"-595.378886839814\">0 7 8</text>\n",
       "\t<rect height=\"11.4540110650069\" rx=\"0\" ry=\"0\" style=\"fill: rgb(255,255,255); stroke: rgb(0,0,0); stroke-width: 0.848445264074586\" width=\"24.4352236053481\" x=\"358.77132319041\" y=\"-604.287562112597\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"8.48445264074586\" text-anchor=\"middle\" x=\"370.988934993084\" y=\"-595.378886839814\">1 6 7</text>\n",
       "\t<rect height=\"11.4540110650069\" rx=\"0\" ry=\"0\" style=\"fill: rgb(255,255,255); stroke: rgb(0,0,0); stroke-width: 0.848445264074586\" width=\"24.4352236053481\" x=\"505.382664822499\" y=\"-604.287562112597\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"8.48445264074586\" text-anchor=\"middle\" x=\"517.600276625173\" y=\"-595.378886839814\">1 6 8</text>\n",
       "\t<rect height=\"11.4540110650069\" rx=\"0\" ry=\"0\" style=\"fill: rgb(255,255,255); stroke: rgb(0,0,0); stroke-width: 0.848445264074586\" width=\"24.4352236053481\" x=\"300.126786537575\" y=\"-604.287562112597\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"8.48445264074586\" text-anchor=\"middle\" x=\"312.344398340249\" y=\"-595.378886839814\">1 4 7</text>\n",
       "\t<rect height=\"11.4540110650069\" rx=\"0\" ry=\"0\" style=\"fill: rgb(255,255,255); stroke: rgb(0,0,0); stroke-width: 0.848445264074586\" width=\"24.4352236053481\" x=\"476.060396496081\" y=\"-604.287562112597\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"8.48445264074586\" text-anchor=\"middle\" x=\"488.278008298755\" y=\"-595.378886839814\">4 6 8</text>\n",
       "\t<rect height=\"11.4540110650069\" rx=\"0\" ry=\"0\" style=\"fill: rgb(255,255,255); stroke: rgb(0,0,0); stroke-width: 0.848445264074586\" width=\"24.4352236053481\" x=\"417.415859843246\" y=\"-604.287562112597\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"8.48445264074586\" text-anchor=\"middle\" x=\"429.63347164592\" y=\"-595.378886839814\">4 7 8</text>\n",
       "\t<rect height=\"11.4540110650069\" rx=\"0\" ry=\"0\" style=\"fill: rgb(255,255,255); stroke: rgb(0,0,0); stroke-width: 0.848445264074586\" width=\"16.358024691358\" x=\"328.58024691358\" y=\"-427.287562112597\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"8.48445264074586\" text-anchor=\"middle\" x=\"336.759259259259\" y=\"-418.378886839814\">0 1</text>\n",
       "\t<rect height=\"11.4540110650069\" rx=\"0\" ry=\"0\" style=\"fill: rgb(255,255,255); stroke: rgb(0,0,0); stroke-width: 0.848445264074586\" width=\"16.358024691358\" x=\"269.691358024691\" y=\"-427.287562112597\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"8.48445264074586\" text-anchor=\"middle\" x=\"277.87037037037\" y=\"-418.378886839814\">0 5</text>\n",
       "\t<rect height=\"11.4540110650069\" rx=\"0\" ry=\"0\" style=\"fill: rgb(255,255,255); stroke: rgb(0,0,0); stroke-width: 0.848445264074586\" width=\"16.358024691358\" x=\"171.543209876543\" y=\"-427.287562112597\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"8.48445264074586\" text-anchor=\"middle\" x=\"179.722222222222\" y=\"-418.378886839814\">1 5</text>\n",
       "\t<rect height=\"11.4540110650069\" rx=\"0\" ry=\"0\" style=\"fill: rgb(231,0,74); stroke: rgb(0,0,0); stroke-width: 0.848445264074586\" width=\"16.358024691358\" x=\"132.283950617284\" y=\"-427.287562112597\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"8.48445264074586\" text-anchor=\"middle\" x=\"140.462962962963\" y=\"-418.378886839814\">0 2</text>\n",
       "\t<rect height=\"11.4540110650069\" rx=\"0\" ry=\"0\" style=\"fill: rgb(231,0,74); stroke: rgb(0,0,0); stroke-width: 0.848445264074586\" width=\"16.358024691358\" x=\"230.432098765432\" y=\"-427.287562112597\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"8.48445264074586\" text-anchor=\"middle\" x=\"238.611111111111\" y=\"-418.378886839814\">0 3</text>\n",
       "\t<rect height=\"11.4540110650069\" rx=\"0\" ry=\"0\" style=\"fill: rgb(255,255,255); stroke: rgb(0,0,0); stroke-width: 0.848445264074586\" width=\"16.358024691358\" x=\"93.0246913580247\" y=\"-427.287562112597\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"8.48445264074586\" text-anchor=\"middle\" x=\"101.203703703704\" y=\"-418.378886839814\">2 3</text>\n",
       "\t<rect height=\"11.4540110650069\" rx=\"0\" ry=\"0\" style=\"fill: rgb(231,0,74); stroke: rgb(0,0,0); stroke-width: 0.848445264074586\" width=\"16.358024691358\" x=\"250.061728395062\" y=\"-427.287562112597\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"8.48445264074586\" text-anchor=\"middle\" x=\"258.240740740741\" y=\"-418.378886839814\">0 4</text>\n",
       "\t<rect height=\"11.4540110650069\" rx=\"0\" ry=\"0\" style=\"fill: rgb(231,0,74); stroke: rgb(0,0,0); stroke-width: 0.848445264074586\" width=\"16.358024691358\" x=\"53.7654320987654\" y=\"-427.287562112597\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"8.48445264074586\" text-anchor=\"middle\" x=\"61.9444444444444\" y=\"-418.378886839814\">2 4</text>\n",
       "\t<rect height=\"11.4540110650069\" rx=\"0\" ry=\"0\" style=\"fill: rgb(255,255,255); stroke: rgb(0,0,0); stroke-width: 0.848445264074586\" width=\"16.358024691358\" x=\"191.172839506173\" y=\"-427.287562112597\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"8.48445264074586\" text-anchor=\"middle\" x=\"199.351851851852\" y=\"-418.378886839814\">3 5</text>\n",
       "\t<rect height=\"11.4540110650069\" rx=\"0\" ry=\"0\" style=\"fill: rgb(255,255,255); stroke: rgb(0,0,0); stroke-width: 0.848445264074586\" width=\"16.358024691358\" x=\"73.3950617283951\" y=\"-427.287562112597\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"8.48445264074586\" text-anchor=\"middle\" x=\"81.5740740740741\" y=\"-418.378886839814\">1 2</text>\n",
       "\t<rect height=\"11.4540110650069\" rx=\"0\" ry=\"0\" style=\"fill: rgb(255,255,255); stroke: rgb(0,0,0); stroke-width: 0.848445264074586\" width=\"16.358024691358\" x=\"151.913580246914\" y=\"-427.287562112597\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"8.48445264074586\" text-anchor=\"middle\" x=\"160.092592592593\" y=\"-418.378886839814\">1 3</text>\n",
       "\t<rect height=\"11.4540110650069\" rx=\"0\" ry=\"0\" style=\"fill: rgb(255,255,255); stroke: rgb(0,0,0); stroke-width: 0.848445264074586\" width=\"16.358024691358\" x=\"34.1358024691358\" y=\"-427.287562112597\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"8.48445264074586\" text-anchor=\"middle\" x=\"42.3148148148148\" y=\"-418.378886839814\">2 5</text>\n",
       "\t<rect height=\"11.4540110650069\" rx=\"0\" ry=\"0\" style=\"fill: rgb(255,255,255); stroke: rgb(0,0,0); stroke-width: 0.848445264074586\" width=\"16.358024691358\" x=\"289.320987654321\" y=\"-427.287562112597\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"8.48445264074586\" text-anchor=\"middle\" x=\"297.5\" y=\"-418.378886839814\">1 4</text>\n",
       "\t<rect height=\"11.4540110650069\" rx=\"0\" ry=\"0\" style=\"fill: rgb(255,255,255); stroke: rgb(0,0,0); stroke-width: 0.848445264074586\" width=\"16.358024691358\" x=\"210.802469135802\" y=\"-427.287562112597\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"8.48445264074586\" text-anchor=\"middle\" x=\"218.981481481481\" y=\"-418.378886839814\">3 4</text>\n",
       "\t<rect height=\"11.4540110650069\" rx=\"0\" ry=\"0\" style=\"fill: rgb(255,255,255); stroke: rgb(0,0,0); stroke-width: 0.848445264074586\" width=\"16.358024691358\" x=\"112.654320987654\" y=\"-427.287562112597\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"8.48445264074586\" text-anchor=\"middle\" x=\"120.833333333333\" y=\"-418.378886839814\">4 5</text>\n",
       "\t<rect height=\"11.4540110650069\" rx=\"0\" ry=\"0\" style=\"fill: rgb(231,0,74); stroke: rgb(0,0,0); stroke-width: 0.848445264074586\" width=\"16.358024691358\" x=\"505.246913580247\" y=\"-427.287562112597\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"8.48445264074586\" text-anchor=\"middle\" x=\"513.425925925926\" y=\"-418.378886839814\">0 8</text>\n",
       "\t<rect height=\"11.4540110650069\" rx=\"0\" ry=\"0\" style=\"fill: rgb(255,255,255); stroke: rgb(0,0,0); stroke-width: 0.848445264074586\" width=\"16.358024691358\" x=\"485.617283950617\" y=\"-427.287562112597\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"8.48445264074586\" text-anchor=\"middle\" x=\"493.796296296296\" y=\"-418.378886839814\">1 8</text>\n",
       "\t<rect height=\"11.4540110650069\" rx=\"0\" ry=\"0\" style=\"fill: rgb(231,0,74); stroke: rgb(0,0,0); stroke-width: 0.848445264074586\" width=\"16.358024691358\" x=\"367.839506172839\" y=\"-427.287562112597\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"8.48445264074586\" text-anchor=\"middle\" x=\"376.018518518518\" y=\"-418.378886839814\">0 6</text>\n",
       "\t<rect height=\"11.4540110650069\" rx=\"0\" ry=\"0\" style=\"fill: rgb(231,0,74); stroke: rgb(0,0,0); stroke-width: 0.848445264074586\" width=\"16.358024691358\" x=\"465.987654320988\" y=\"-427.287562112597\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"8.48445264074586\" text-anchor=\"middle\" x=\"474.166666666667\" y=\"-418.378886839814\">0 7</text>\n",
       "\t<rect height=\"11.4540110650069\" rx=\"0\" ry=\"0\" style=\"fill: rgb(255,255,255); stroke: rgb(0,0,0); stroke-width: 0.848445264074586\" width=\"16.358024691358\" x=\"407.098765432099\" y=\"-427.287562112597\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"8.48445264074586\" text-anchor=\"middle\" x=\"415.277777777778\" y=\"-418.378886839814\">6 7</text>\n",
       "\t<rect height=\"11.4540110650069\" rx=\"0\" ry=\"0\" style=\"fill: rgb(255,255,255); stroke: rgb(0,0,0); stroke-width: 0.848445264074586\" width=\"16.358024691358\" x=\"387.469135802469\" y=\"-427.287562112597\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"8.48445264074586\" text-anchor=\"middle\" x=\"395.648148148148\" y=\"-418.378886839814\">4 6</text>\n",
       "\t<rect height=\"11.4540110650069\" rx=\"0\" ry=\"0\" style=\"fill: rgb(255,255,255); stroke: rgb(0,0,0); stroke-width: 0.848445264074586\" width=\"16.358024691358\" x=\"524.876543209876\" y=\"-427.287562112597\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"8.48445264074586\" text-anchor=\"middle\" x=\"533.055555555555\" y=\"-418.378886839814\">7 8</text>\n",
       "\t<rect height=\"11.4540110650069\" rx=\"0\" ry=\"0\" style=\"fill: rgb(231,0,74); stroke: rgb(0,0,0); stroke-width: 0.848445264074586\" width=\"16.358024691358\" x=\"426.728395061728\" y=\"-427.287562112597\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"8.48445264074586\" text-anchor=\"middle\" x=\"434.907407407407\" y=\"-418.378886839814\">1 6</text>\n",
       "\t<rect height=\"11.4540110650069\" rx=\"0\" ry=\"0\" style=\"fill: rgb(231,0,74); stroke: rgb(0,0,0); stroke-width: 0.848445264074586\" width=\"16.358024691358\" x=\"308.950617283951\" y=\"-427.287562112597\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"8.48445264074586\" text-anchor=\"middle\" x=\"317.12962962963\" y=\"-418.378886839814\">1 7</text>\n",
       "\t<rect height=\"11.4540110650069\" rx=\"0\" ry=\"0\" style=\"fill: rgb(255,255,255); stroke: rgb(0,0,0); stroke-width: 0.848445264074586\" width=\"16.358024691358\" x=\"544.506172839506\" y=\"-427.287562112597\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"8.48445264074586\" text-anchor=\"middle\" x=\"552.685185185185\" y=\"-418.378886839814\">6 8</text>\n",
       "\t<rect height=\"11.4540110650069\" rx=\"0\" ry=\"0\" style=\"fill: rgb(255,255,255); stroke: rgb(0,0,0); stroke-width: 0.848445264074586\" width=\"16.358024691358\" x=\"348.20987654321\" y=\"-427.287562112597\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"8.48445264074586\" text-anchor=\"middle\" x=\"356.388888888889\" y=\"-418.378886839814\">4 7</text>\n",
       "\t<rect height=\"11.4540110650069\" rx=\"0\" ry=\"0\" style=\"fill: rgb(255,255,255); stroke: rgb(0,0,0); stroke-width: 0.848445264074586\" width=\"16.358024691358\" x=\"446.358024691358\" y=\"-427.287562112597\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"8.48445264074586\" text-anchor=\"middle\" x=\"454.537037037037\" y=\"-418.378886839814\">4 8</text>\n",
       "\t<rect height=\"11.4540110650069\" rx=\"0\" ry=\"0\" style=\"fill: rgb(231,0,74); stroke: rgb(0,0,0); stroke-width: 0.848445264074586\" width=\"8.28082577736796\" x=\"322.668342871685\" y=\"-250.287562112597\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"8.48445264074586\" text-anchor=\"middle\" x=\"326.808755760369\" y=\"-241.378886839814\">0</text>\n",
       "\t<rect height=\"11.4540110650069\" rx=\"0\" ry=\"0\" style=\"fill: rgb(255,255,255); stroke: rgb(0,0,0); stroke-width: 0.848445264074586\" width=\"8.28082577736796\" x=\"283.59000185786\" y=\"-250.287562112597\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"8.48445264074586\" text-anchor=\"middle\" x=\"287.730414746544\" y=\"-241.378886839814\">1</text>\n",
       "\t<rect height=\"11.4540110650069\" rx=\"0\" ry=\"0\" style=\"fill: rgb(255,255,255); stroke: rgb(0,0,0); stroke-width: 0.848445264074586\" width=\"8.28082577736796\" x=\"160.859587111316\" y=\"-250.287562112597\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"8.48445264074586\" text-anchor=\"middle\" x=\"165\" y=\"-241.378886839814\">5</text>\n",
       "\t<rect height=\"11.4540110650069\" rx=\"0\" ry=\"0\" style=\"fill: rgb(255,255,255); stroke: rgb(0,0,0); stroke-width: 0.848445264074586\" width=\"8.28082577736796\" x=\"82.9184106407279\" y=\"-250.287562112597\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"8.48445264074586\" text-anchor=\"middle\" x=\"87.0588235294119\" y=\"-241.378886839814\">2</text>\n",
       "\t<rect height=\"11.4540110650069\" rx=\"0\" ry=\"0\" style=\"fill: rgb(255,255,255); stroke: rgb(0,0,0); stroke-width: 0.848445264074586\" width=\"8.28082577736796\" x=\"180.344881228963\" y=\"-250.287562112597\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"8.48445264074586\" text-anchor=\"middle\" x=\"184.485294117647\" y=\"-241.378886839814\">3</text>\n",
       "\t<rect height=\"11.4540110650069\" rx=\"0\" ry=\"0\" style=\"fill: rgb(255,255,255); stroke: rgb(0,0,0); stroke-width: 0.848445264074586\" width=\"8.28082577736796\" x=\"266.493227664311\" y=\"-250.287562112597\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"8.48445264074586\" text-anchor=\"middle\" x=\"270.633640552995\" y=\"-241.378886839814\">4</text>\n",
       "\t<rect height=\"11.4540110650069\" rx=\"0\" ry=\"0\" style=\"fill: rgb(255,255,255); stroke: rgb(0,0,0); stroke-width: 0.848445264074586\" width=\"8.28082577736796\" x=\"503.800763581904\" y=\"-250.287562112597\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"8.48445264074586\" text-anchor=\"middle\" x=\"507.941176470588\" y=\"-241.378886839814\">8</text>\n",
       "\t<rect height=\"11.4540110650069\" rx=\"0\" ry=\"0\" style=\"fill: rgb(255,255,255); stroke: rgb(0,0,0); stroke-width: 0.848445264074586\" width=\"8.28082577736796\" x=\"429.756645934845\" y=\"-250.287562112597\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"8.48445264074586\" text-anchor=\"middle\" x=\"433.897058823529\" y=\"-241.378886839814\">6</text>\n",
       "\t<rect height=\"11.4540110650069\" rx=\"0\" ry=\"0\" style=\"fill: rgb(255,255,255); stroke: rgb(0,0,0); stroke-width: 0.848445264074586\" width=\"8.28082577736796\" x=\"414.168410640728\" y=\"-250.287562112597\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"8.48445264074586\" text-anchor=\"middle\" x=\"418.308823529412\" y=\"-241.378886839814\">7</text>\n",
       "\t<rect height=\"11.4540110650069\" rx=\"0\" ry=\"0\" style=\"fill: rgb(255,255,255); stroke: rgb(0,0,0); stroke-width: 0.848445264074586\" width=\"12.319425234363\" x=\"291.340287382819\" y=\"-73.2875621125967\" />\n",
       "\t<text font-family=\"Times-Roman\" font-size=\"8.48445264074586\" text-anchor=\"middle\" x=\"297.5\" y=\"-64.3788868398135\"> </text>\n",
       "\t<!--\n",
       "\tGenerated using the Perl SVG Module V2.84\n",
       "\tby Ronan Oger\n",
       "\tInfo: http://www.roitsystems.com/\n",
       "\t-->\n",
       "</svg>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<details><summary><pre style=\"display:inline\"><small>Click here for additional output</small></pre></summary>\n",
       "<pre>\n",
       "polymake: used package SVG\n",
       "   Generated using the Perl SVG Module\n",
       "   by Ronan Oger\n",
       "\n",
       "</pre>\n",
       "</details>\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "$k =  klein_bottle();\n",
    "svg($k->VISUAL_FACE_LATTICE->MORSE_MATCHING->FACES($k->MORSE_MATCHING->CRITICAL_FACES));"
   ]
  },
  {
   "attachments": {
    "kb_mm_faces.gif": {
     "image/gif": "[encoded data, 173600 characters]"
    }
   },
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![](attachment:kb_mm_faces.gif)\n",
    "Here the matching of faces is denoted by reversed red arrows and the critical faces are marked red. Check that the graph remains acyclic.\n",
    "\n",
    "For higher dimensional complexes that cannot be visualized in 3D, you can still have a look at the graphs while ignoring any specified coordinates by using `VISUAL_GRAPH`, `VISUAL_DUAL_GRAPH`, or `VISUAL_MIXED_GRAPH`. An easy example:\n",
    "\n",
    "    \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<!--\n",
       "polymake for knusper\n",
       "Thu Aug 27 10:41:00 2020\n",
       "GRAPH of \n",
       "-->\n",
       "\n",
       "\n",
       "<html>\n",
       "   <head>\n",
       "      <meta charset=utf-8>\n",
       "      <title>GRAPH of </title>\n",
       "      <style>\n",
       "/*\n",
       "// COMMON_CODE_BLOCK_BEGIN\n",
       "*/\n",
       "         html {overflow: scroll;}\n",
       "         strong{font-size: 18px;}\n",
       "         canvas { z-index: 8; }\n",
       "         input[type='radio'] {margin-left:0;}\n",
       "         input[type='checkbox'] {margin-right:7px; margin-left: 0px; padding-left:0px;}\n",
       "         .group{padding-bottom: 15px;}\n",
       "         .settings * {z-index: 11; }\n",
       "         .settings{z-index: 10; font-family: Arial, Helvetica, sans-serif; margin-left: 30px; visibility: hidden; width: 14em; height: 96%; border: solid 1px silver; padding: 2px; overflow-y: scroll; box-sizing: border-box; background-color: white; position: absolute;}\n",
       "         .indented{margin-left: 20px; margin-top: 10px; padding-bottom: 0px;} \n",
       "         .shownObjectsList{overflow: auto; max-width: 150px; max-height: 150px;}\n",
       "         .showSettingsButton{visibility: visible; z-index: 12; position: absolute }\n",
       "         .hideSettingsButton{visibility: hidden; z-index: 12; position: absolute; opacity: 0.5}\n",
       "         button{margin-left: 0; margin-top: 10px}\n",
       "         img{cursor: pointer;}\n",
       "         .suboption{padding-top: 15px;}\n",
       "         #model89825377319 { width: 100%; height: 100%; }\n",
       "         .threejs_container { width: 100%; height: 75vh;}\n",
       "         .settings{max-height: 74vh} \n",
       "         input[type=range] {\n",
       "           -webkit-appearance: none;\n",
       "           padding:0; \n",
       "           width:90%; \n",
       "           margin-left: auto;\n",
       "           margin-right: auto;\n",
       "           margin-top: 15px;\n",
       "           margin-bottom: 15px;\n",
       "           display: block;\t\n",
       "         }\n",
       "         input[type=range]:focus {\n",
       "           outline: none;\n",
       "         }\n",
       "         input[type=range]::-webkit-slider-runnable-track {\n",
       "           height: 4px;\n",
       "           cursor: pointer;\n",
       "           animate: 0.2s;\n",
       "           box-shadow: 0px 0px 0px #000000;\n",
       "           background: #E3E3E3;\n",
       "           border-radius: 0px;\n",
       "           border: 0px solid #000000;\n",
       "         }\n",
       "         input[type=range]::-webkit-slider-thumb {\n",
       "           box-shadow: 1px 1px 2px #B8B8B8;\n",
       "           border: 1px solid #ABABAB;\n",
       "           height: 13px;\n",
       "           width: 25px;\n",
       "           border-radius: 20px;\n",
       "           background: #E0E0E0;\n",
       "           cursor: pointer;\n",
       "           -webkit-appearance: none;\n",
       "           margin-top: -5px;\n",
       "         }\n",
       "         input[type=range]:focus::-webkit-slider-runnable-track {\n",
       "           background: #E3E3E3;\n",
       "         }\n",
       "         input[type=range]::-moz-range-track {\n",
       "           height: 4px;\n",
       "           cursor: pointer;\n",
       "           animate: 0.2s;\n",
       "           box-shadow: 0px 0px 0px #000000;\n",
       "           background: #E3E3E3;\n",
       "           border-radius: 0px;\n",
       "           border: 0px solid #000000;\n",
       "         }\n",
       "         input[type=range]::-moz-range-thumb {\n",
       "           box-shadow: 1px 1px 2px #B8B8B8;\n",
       "           border: 1px solid #ABABAB;\n",
       "           height: 13px;\n",
       "           width: 25px;\n",
       "           border-radius: 20px;\n",
       "           background: #E0E0E0;\n",
       "           cursor: pointer;\n",
       "         }\n",
       "         input[type=range]::-ms-track {\n",
       "           height: 4px;\n",
       "           cursor: pointer;\n",
       "           animate: 0.2s;\n",
       "           background: transparent;\n",
       "           border-color: transparent;\n",
       "           color: transparent;\n",
       "         }\n",
       "         input[type=range]::-ms-fill-lower {\n",
       "           background: #E3E3E3;\n",
       "           border: 0px solid #000000;\n",
       "           border-radius: 0px;\n",
       "           box-shadow: 0px 0px 0px #000000;\n",
       "         }\n",
       "         input[type=range]::-ms-fill-upper {\n",
       "           background: #E3E3E3;\n",
       "           border: 0px solid #000000;\n",
       "           border-radius: 0px;\n",
       "           box-shadow: 0px 0px 0px #000000;\n",
       "         }\n",
       "         input[type=range]::-ms-thumb {\n",
       "           box-shadow: 1px 1px 2px #B8B8B8;\n",
       "           border: 1px solid #ABABAB;\n",
       "           height: 13px;\n",
       "           width: 25px;\n",
       "           border-radius: 20px;\n",
       "           background: #E0E0E0;\n",
       "           cursor: pointer;\n",
       "         }\n",
       "         input[type=range]:focus::-ms-fill-lower {\n",
       "           background: #E3E3E3;\n",
       "         }\n",
       "         input[type=range]:focus::-ms-fill-upper {\n",
       "           background: #E3E3E3;\n",
       "         }\n",
       "/*\n",
       "// COMMON_CODE_BLOCK_END\n",
       "*/\n",
       "\t\t</style>\n",
       "   </head>\n",
       "<body>\n",
       "   <div class='threejs_container'>\n",
       "\t\t<div id='settings_3' class='settings'>\n",
       "\t\t\t<div class=group id='explode_3'>\n",
       "\t\t\t\t<strong>Explode</strong>\n",
       "\t\t\t\t<input id='explodeRange_3' type='range' min=0 max=6 step=0.01 value=0>\n",
       "\t\t\t\t<div class=indented><input id='explodeCheckbox_3' type='checkbox'>Automatic explosion</div>\n",
       "\t\t\t\t<div class=suboption>Exploding speed</div>\n",
       "\t\t\t\t<input id='explodingSpeedRange_3' type='range' min=0 max=0.5 step=0.001 value=0.05>\n",
       "\t\t\t</div>\n",
       "\t\n",
       "\t\t\t<div class=group id='transparency_3' class='transparency'>\n",
       "\t\t\t\t<strong>Transparency</strong>\n",
       "\t\t\t\t<input id='transparencyRange_3' type='range' min=0 max=1 step=0.01 value=0>\n",
       "\t\t\t</div>\n",
       "\t\t\t\n",
       "\t\t\t<div class=group id='rotation_3'>\n",
       "\t\t\t\t<strong>Rotation</strong>\n",
       "\t\t\t\t<div class=indented>\n",
       "\t\t\t\t\t<div><input type='checkbox' id='changeRotationX_3'> x-axis</div>\n",
       "\t\t\t\t\t<div><input type='checkbox' id='changeRotationY_3'> y-axis</div>\n",
       "\t\t\t\t\t<div><input type='checkbox' id='changeRotationZ_3'> z-axis</div>\n",
       "\t\t\t\t\t<button id='resetButton_3'>Reset</button>\n",
       "\t\t\t\t</div>\n",
       "\n",
       "\t\t\t\t<div class=suboption>Rotation speed</div>\n",
       "\t\t\t\t<input id='rotationSpeedRange_3' type='range' min=0 max=5 step=0.01 value=2>\n",
       "\t\t\t</div>\n",
       "\n",
       "\n",
       "\t\t\t<div class=group id='display_3'>\n",
       "\t\t\t\t<strong>Display</strong>\n",
       "\t\t\t\t<div class=indented>\n",
       "\t\t\t\t\t<div id='shownObjectTypesList_3' class='shownObjectsList'></div>\n",
       "\t\t\t\t</div>\n",
       "\t\t\t\t<div class=suboption>Objects</div>\n",
       "\t\t\t\t<div class=indented>\n",
       "\t\t\t\t   <div id='shownObjectsList_3' class='shownObjectsList'></div>\n",
       "\t\t\t\t</div>\n",
       "\t\t\t</div>\n",
       "         \n",
       "         <div class=group id='camera_3'>\n",
       "            <strong>Camera</strong>\n",
       "            <div class=indented>\n",
       "               <form>\n",
       "                  <select id=\"cameraType_3\">\n",
       "                     <option value='perspective' selected> Perspective<br></option>\n",
       "                     <option value='orthographic' > Orthographic<br></option>\n",
       "                  </select>\n",
       "               </form>\n",
       "            </div>\n",
       "         </div>\n",
       "\n",
       "\t\t\t<div class=group id='svg_3'>\n",
       "\t\t\t\t<strong>SVG</strong>\n",
       "\t\t\t\t<div class=indented>\n",
       "\t\t\t\t\t<form>\n",
       "\t\t\t\t\t\t<input type=\"radio\" name='screenshotMode' value='download' id='download_3' checked> Download<br>\n",
       "\t\t\t\t\t\t<input type=\"radio\" name='screenshotMode' value='tab' id='tab_3' > New tab<br>\n",
       "\t\t\t\t\t</form>\n",
       "\t\t\t\t\t<button id='takeScreenshot_3'>Screenshot</button>\n",
       "\t\t\t\t</div>\n",
       "\t\t\t</div>\n",
       "\n",
       "\t\t</div>\t<!-- end of settings -->\n",
       "\t\t<img id='hideSettingsButton_3' class='hideSettingsButton' src='/kernelspecs/polymake/close.svg' width=20px\">\n",
       "\t\t<img id='showSettingsButton_3' class='showSettingsButton' src='/kernelspecs/polymake/menu.svg' width=20px\">\n",
       "<div id=\"model89825377319\"></div>\n",
       "</div>\n",
       "   <script>\n",
       "    requirejs.config({\n",
       "      paths: {\n",
       "        three: '/kernelspecs/polymake/three',\n",
       "        TrackballControls: '/kernelspecs/polymake/TrackballControls',\n",
       "        OrbitControls: '/kernelspecs/polymake/OrbitControls',\n",
       "        Projector: '/kernelspecs/polymake/Projector',\n",
       "        SVGRenderer: '/kernelspecs/polymake/SVGRenderer',\n",
       "        WEBGL: '/kernelspecs/polymake/WebGL',\n",
       "      },\n",
       "      shim: {\n",
       "        'three': { exports: 'THREE'},\n",
       "        'SVGRenderer': { deps: [ 'three' ], exports: 'THREE.SVGRenderer' },\n",
       "        'WEBGL': { deps: [ 'three' ], exports: 'THREE.WEBGL' },\n",
       "        'Projector': { deps: [ 'three' ], exports: 'THREE.Projector' },\n",
       "        'TrackballControls': { deps: [ 'three' ], exports: 'THREE.TrackballControls' },\n",
       "        'OrbitControls': { deps: [ 'three' ], exports: 'THREE.OrbitControls' },\n",
       "      }\n",
       "    });\n",
       "    \n",
       "    require(['three'],function(THREE){\n",
       "        window.THREE = THREE;\n",
       "      require(['TrackballControls', 'OrbitControls', 'Projector', 'SVGRenderer', 'WEBGL'],\n",
       "               function(TrackballControls, OrbitControls, Projector, SVGRenderer, WEBGL) {\n",
       "    THREE.TrackballControls = TrackballControls;\n",
       "    THREE.OrbitControls = OrbitControls;\n",
       "    THREE.Projector = Projector;\n",
       "    THREE.SVGRenderer = SVGRenderer;\n",
       "    THREE.WEBGL = WEBGL;\n",
       "\n",
       "// COMMON_CODE_BLOCK_BEGIN\n",
       "\n",
       "const intervalLength = 25; // for automatic animations\n",
       "const explodableModel = true; \n",
       "const modelContains = { points: false, pointlabels: false, lines: false, edgelabels: false, faces: false, arrowheads: false };\n",
       "const foldables = [];\n",
       "\n",
       "var three = document.getElementById(\"model89825377319\");\n",
       "var scene = new THREE.Scene();\n",
       "var renderer = new THREE.WebGLRenderer( { antialias: true } );\n",
       "var svgRenderer = new THREE.SVGRenderer( { antialias: true } );\n",
       "renderer.setPixelRatio( window.devicePixelRatio );\n",
       "renderer.setClearColor(0xFFFFFF, 1);\n",
       "svgRenderer.setClearColor(0xFFFFFF, 1);\n",
       "three.appendChild(renderer.domElement);\n",
       "\n",
       "var frustumSize = 4;\n",
       "var cameras = [new THREE.PerspectiveCamera(75, 1, 0.1, 1000), new THREE.OrthographicCamera()];\n",
       "cameras.forEach(function(cam) {\n",
       "    cam.position.set(0, 0, 5);\n",
       "    cam.lookAt(0, 0, 0);  \n",
       "    cam.up.set(0, 1, 0);         \n",
       "});\n",
       "var controls = [new THREE.TrackballControls(cameras[0], three), new THREE.OrbitControls(cameras[1], three)];\n",
       "var camera, control;\n",
       "\n",
       "controls[0].zoomSpeed = 0.2;\n",
       "controls[0].rotateSpeed = 4;\n",
       "\n",
       "\n",
       "// class to allow move points together with labels and spheres\n",
       "var PMPoint = function (x,y,z) {\n",
       "   this.vector = new THREE.Vector3(x,y,z);\n",
       "   this.sprite = null;\n",
       "   this.sphere = null;\n",
       "}\n",
       "PMPoint.prototype.addLabel = function(labelsprite) {\n",
       "   this.sprite = labelsprite;\n",
       "   this.sprite.position.copy(this.vector);\n",
       "}\n",
       "PMPoint.prototype.addSphere = function(spheremesh) {\n",
       "   this.sphere = spheremesh;\n",
       "   this.sphere.position.copy(this.vector);\n",
       "}\n",
       "PMPoint.prototype.set = function(x,y,z) {\n",
       "   this.vector.set(x,y,z);\n",
       "   if (this.sprite) {\n",
       "      this.sprite.position.copy(this.vector);\n",
       "   }\n",
       "   if (this.sphere) {\n",
       "      this.sphere.position.copy(this.vector);\n",
       "   }\n",
       "}\n",
       "PMPoint.prototype.radius = function() {\n",
       "   if (this.sphere) {\n",
       "      return this.sphere.geometry.parameters.radius;\n",
       "   } else {\n",
       "      return 0;\n",
       "   }\n",
       "};\n",
       "// select the target node\n",
       "var target = document.querySelector('#model89825377319');\n",
       "\n",
       "// create an observer instance\n",
       "var observer = new MutationObserver(function(mutations) {\n",
       "   mutations.forEach(function(mutation) {\n",
       "      if (mutation.removedNodes && mutation.removedNodes.length > 0) {\n",
       "         cancelAnimationFrame(renderId);\n",
       "         observer.disconnect();\n",
       "         console.log(\"cancelled frame \"+renderId);\n",
       "      }\n",
       "   });\n",
       "});\n",
       "\n",
       "// configuration of the observer:\n",
       "var config = { childList: true, characterData: true }\n",
       "\n",
       "// pass in the target node, as well as the observer options\n",
       "while (target) {\n",
       "   if (target.className==\"output\") {\n",
       "      observer.observe(target, config);\n",
       "      break;\n",
       "   }\n",
       "   target = target.parentNode;\n",
       "}\n",
       "\n",
       "// COMMON_CODE_BLOCK_END\n",
       "\n",
       "var obj0 = new THREE.Object3D();\n",
       "obj0.name = \"GRAPH of \";\n",
       "obj0.userData.explodable = 1;\n",
       "obj0.userData.points = [];\n",
       "obj0.userData.points.push(new PMPoint(0.260149, 5.35382, -2.53012));\n",
       "obj0.userData.points.push(new PMPoint(0.370088, 1.79627, -2.09822));\n",
       "obj0.userData.points.push(new PMPoint(-1.57921, 2.92588, -0.0407512));\n",
       "obj0.userData.points.push(new PMPoint(-0.177396, -0.87633, 0.407089));\n",
       "obj0.userData.points.push(new PMPoint(0.472728, 1.40965, -0.205839));\n",
       "obj0.userData.points.push(new PMPoint(0.995523, -2.75996, -0.359188));\n",
       "obj0.userData.points.push(new PMPoint(-0.505, -1.89374, 2.26388));\n",
       "obj0.userData.points.push(new PMPoint(0.193857, -6.21922, 1.97844));\n",
       "\n",
       "obj0.userData.pointradii = 0.02;\n",
       "   <!-- Vertex style -->\n",
       "obj0.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0xFFFF00, side: THREE.DoubleSide, transparent: false } );\n",
       "obj0.userData.pointlabels = [\"0\", \"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\"];\n",
       "obj0.userData.edgeindices = [1, 0, 2, 0, 2, 1, 3, 1, 3, 2, 4, 0, 4, 1, 4, 2, 4, 3, 5, 1, 5, 3, 5, 4, 6, 2, 6, 3, 6, 4, 6, 5, 7, 3, 7, 5, 7, 6];\n",
       "   <!-- Edge style -->\n",
       "obj0.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0xFFFF00, depthTest: true, linewidth: 1.5, transparent: false } );\n",
       "init_object(obj0);\n",
       "scene.add(obj0);\n",
       "\n",
       "var obj1 = new THREE.Object3D();\n",
       "obj1.name = \"DUAL_GRAPH of \";\n",
       "obj1.userData.explodable = 1;\n",
       "obj1.userData.points = [];\n",
       "obj1.userData.points.push(new PMPoint(0.209943, 3.50271, -1.82493));\n",
       "obj1.userData.points.push(new PMPoint(-0.501277, 1.55753, -0.700496));\n",
       "obj1.userData.points.push(new PMPoint(0.631593, -0.314424, -0.973504));\n",
       "obj1.userData.points.push(new PMPoint(-0.645615, 0.254295, 1.48736));\n",
       "obj1.userData.points.push(new PMPoint(0.0781263, -1.54938, 1.25282));\n",
       "obj1.userData.points.push(new PMPoint(0.196489, -3.18711, 1.34346));\n",
       "\n",
       "obj1.userData.pointradii = 0.02;\n",
       "   <!-- Vertex style -->\n",
       "obj1.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0x0000FF, side: THREE.DoubleSide, transparent: false } );\n",
       "obj1.userData.pointlabels = [\"0\", \"1\", \"2\", \"3\", \"4\", \"5\"];\n",
       "obj1.userData.edgeindices = [1, 0, 2, 1, 3, 1, 4, 2, 4, 3, 5, 4];\n",
       "   <!-- Edge style -->\n",
       "obj1.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x0000FF, depthTest: true, linewidth: 1.5, transparent: false } );\n",
       "init_object(obj1);\n",
       "scene.add(obj1);\n",
       "\n",
       "var obj2 = new THREE.Object3D();\n",
       "obj2.name = \"MIXED_GRAPH of \";\n",
       "obj2.userData.explodable = 1;\n",
       "obj2.userData.points = [];\n",
       "obj2.userData.points.push(new PMPoint(0.260149, 5.35382, -2.53012));\n",
       "obj2.userData.points.push(new PMPoint(0.370088, 1.79627, -2.09822));\n",
       "obj2.userData.points.push(new PMPoint(-1.57921, 2.92588, -0.0407512));\n",
       "obj2.userData.points.push(new PMPoint(-0.177396, -0.87633, 0.407089));\n",
       "obj2.userData.points.push(new PMPoint(0.472728, 1.40965, -0.205839));\n",
       "obj2.userData.points.push(new PMPoint(0.995523, -2.75996, -0.359188));\n",
       "obj2.userData.points.push(new PMPoint(-0.505, -1.89374, 2.26388));\n",
       "obj2.userData.points.push(new PMPoint(0.193857, -6.21922, 1.97844));\n",
       "obj2.userData.points.push(new PMPoint(0.209943, 3.50271, -1.82493));\n",
       "obj2.userData.points.push(new PMPoint(-0.501277, 1.55753, -0.700496));\n",
       "obj2.userData.points.push(new PMPoint(0.631593, -0.314424, -0.973504));\n",
       "obj2.userData.points.push(new PMPoint(-0.645615, 0.254295, 1.48736));\n",
       "obj2.userData.points.push(new PMPoint(0.0781263, -1.54938, 1.25282));\n",
       "obj2.userData.points.push(new PMPoint(0.196489, -3.18711, 1.34346));\n",
       "\n",
       "obj2.userData.pointradii = 0.02;\n",
       "   <!-- Vertex style -->\n",
       "obj2.userData.pointmaterial = new THREE.MeshBasicMaterial( { color: 0x000000, side: THREE.DoubleSide, transparent: false } );\n",
       "obj2.userData.pointlabels = [\"0\", \"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\", \"10\", \"11\", \"12\", \"13\"];\n",
       "obj2.userData.edgeindices = [1, 0, 2, 0, 2, 1, 3, 1, 3, 2, 4, 0, 4, 1, 4, 2, 4, 3, 5, 1, 5, 3, 5, 4, 6, 2, 6, 3, 6, 4, 6, 5, 7, 3, 7, 5, 7, 6, 8, 0, 8, 1, 8, 2, 8, 4, 9, 1, 9, 2, 9, 3, 9, 4, 9, 8, 10, 1, 10, 3, 10, 4, 10, 5, 10, 9, 11, 2, 11, 3, 11, 4, 11, 6, 11, 9, 12, 3, 12, 4, 12, 5, 12, 6, 12, 10, 12, 11, 13, 3, 13, 5, 13, 6, 13, 7, 13, 12];\n",
       "   <!-- Edge style -->\n",
       "obj2.userData.edgematerial = new THREE.LineBasicMaterial( { color: 0x000000, depthTest: true, linewidth: 0.1666667, transparent: false } );\n",
       "init_object(obj2);\n",
       "scene.add(obj2);\n",
       "\n",
       "// COMMON_CODE_BLOCK_BEGIN\n",
       "function textSpriteMaterial(message, parameters) {\n",
       "    if ( parameters === undefined ) parameters = {};\n",
       "    var fontface = \"Helvetica\";\n",
       "    var fontsize = parameters.hasOwnProperty(\"fontsize\") ? parameters[\"fontsize\"] : 15;\n",
       "    fontsize = fontsize*10;\n",
       "    var lines = message.split('\\\\n');\n",
       "    var size = 512;\n",
       "    for(var i = 0; i<lines.length; i++){\n",
       "        var tmp = lines[i].length;\n",
       "        while(tmp*fontsize > size){\n",
       "           fontsize--;\n",
       "        }\n",
       "    }\n",
       "    \n",
       "    var canvas = document.createElement('canvas');\n",
       "    canvas.width = size;\n",
       "    canvas.height = size;\n",
       "    var context = canvas.getContext('2d');\n",
       "    context.fillStyle = \"rgba(255, 255, 255, 0)\";\n",
       "    context.fill();\n",
       "    context.font = fontsize + \"px \" + fontface;\n",
       "    \n",
       "    // text color\n",
       "    context.fillStyle = \"rgba(0, 0, 0, 1.0)\";\n",
       "     for(var i = 0; i<lines.length; i++){\n",
       "        context.fillText(lines[i], size/2, size/2+i*fontsize);\n",
       "     }\n",
       "    \n",
       "    // canvas contents will be used for a texture\n",
       "    var texture = new THREE.Texture(canvas);\n",
       "    texture.needsUpdate = true;\n",
       "    \n",
       "    var spriteMaterial = new THREE.SpriteMaterial({map: texture, depthTest: true, depthWrite: false, polygonOffset: true, polygonOffsetFactor: -1, polygonOffsetUnits: 1 });\n",
       "    return spriteMaterial;\n",
       "}\n",
       "\n",
       "\n",
       "// ---------------------- INITIALIZING OBJECTS--------------------------------------\n",
       "// ---------------------------------------------------------------------------------\n",
       "\n",
       "function init_object(obj) {\n",
       "    if (obj.userData.hasOwnProperty(\"pointmaterial\")) {\n",
       "        init_points(obj);\n",
       "        modelContains.points = true;\n",
       "    }\n",
       "    if (obj.userData.hasOwnProperty(\"pointlabels\")) {\n",
       "        init_pointlabels(obj);\n",
       "        modelContains.pointlabels = true;\n",
       "    }\n",
       "    if (obj.userData.hasOwnProperty(\"edgematerial\")) {\n",
       "        init_lines(obj);\n",
       "        modelContains.lines = true;\n",
       "    }\n",
       "    if (obj.userData.hasOwnProperty(\"edgelabels\")) {\n",
       "        init_edgelabels(obj);\n",
       "        modelContains.edgelabels = true;\n",
       "    }\n",
       "    if (obj.userData.hasOwnProperty(\"arrowstyle\")) {\n",
       "        init_arrowheads(obj);\n",
       "        modelContains.arrowheads = true;\n",
       "    }\n",
       "    if (obj.userData.hasOwnProperty(\"facetmaterial\")) {\n",
       "        init_faces(obj);\n",
       "        modelContains.faces = true;\n",
       "    }\n",
       "}\n",
       "\n",
       "function init_points(obj) {\n",
       "    var pointgroup = new THREE.Group();\n",
       "    pointgroup.name = \"points\";\n",
       "    var points = obj.userData.points;\n",
       "    var radii = obj.userData.pointradii;\n",
       "    var materials = obj.userData.pointmaterial;\n",
       "    var geometry,material;\n",
       "    if (!Array.isArray(radii)) {\n",
       "        geometry = new THREE.SphereBufferGeometry(radii);  \n",
       "    }\n",
       "    if (!Array.isArray(materials)) {\n",
       "        material = materials;\n",
       "    }\n",
       "    for (var i=0; i<points.length; i++) {\n",
       "        var point = points[i];\n",
       "        if (Array.isArray(radii)) {\n",
       "            if (radii[i] == 0) {\n",
       "                continue;\n",
       "            }\n",
       "            geometry = new THREE.SphereBufferGeometry(radii[i]);  \n",
       "        } \n",
       "        if (Array.isArray(materials)) {\n",
       "            material = materials[i];     \n",
       "        } \n",
       "        var sphere = new THREE.Mesh(geometry, material);\n",
       "        point.addSphere(sphere);\n",
       "        pointgroup.add(sphere);\n",
       "    }\n",
       "    obj.add(pointgroup);\n",
       "}\n",
       "\n",
       "function init_pointlabels(obj) {\n",
       "    var points = obj.userData.points;\n",
       "    var labels = obj.userData.pointlabels;\n",
       "    var pointlabels = new THREE.Group();\n",
       "    pointlabels.name = \"pointlabels\";\n",
       "    if (Array.isArray(labels)) {\n",
       "        for (var i=0; i<points.length; i++) {\n",
       "            var point = points[i];\n",
       "            var spriteMaterial = textSpriteMaterial( labels[i] );\n",
       "\t        var sprite = new THREE.Sprite(spriteMaterial);\n",
       "            point.addLabel(sprite);\n",
       "            pointlabels.add(sprite);\n",
       "        }\n",
       "    } else {\n",
       "        var spriteMaterial = textSpriteMaterial( labels );\n",
       "        for (var i=0; i<points.length; i++) {\n",
       "            var point = points[i];\n",
       "\t        var sprite = new THREE.Sprite(spriteMaterial);\n",
       "            point.addLabel(sprite);\n",
       "            pointlabels.add(sprite);\n",
       "        }\n",
       "    }\n",
       "    obj.add(pointlabels);\n",
       "}\n",
       "\n",
       "function init_lines(obj) {\n",
       "    var edgeindices = obj.userData.edgeindices;\n",
       "    var points = obj.userData.points;\n",
       "    var materials = obj.userData.edgematerial;\n",
       "    var geometry = new THREE.BufferGeometry();\n",
       "    var bufarr = new Float32Array( obj.userData.edgeindices.length * 3 );\n",
       "    var bufattr = new THREE.Float32BufferAttribute( bufarr, 3 );\n",
       "    var geometry = new THREE.BufferGeometry();\n",
       "    geometry.setAttribute('position', bufattr);\n",
       "    if (Array.isArray(materials)) {     \n",
       "        for (var i=0; i<materials.length; i++) {\n",
       "            geometry.addGroup(2*i,2,i);\n",
       "        }\n",
       "    }\n",
       "    var lines = new THREE.LineSegments(geometry, materials);\n",
       "    lines.name = \"lines\";\n",
       "    obj.add(lines);\n",
       "    updateEdgesPosition(obj);\n",
       "}\n",
       "\n",
       "function init_edgelabels(obj) {\n",
       "    var points = obj.userData.points;\n",
       "    var edgeindices = obj.userData.edgeindices;\n",
       "    var labels = obj.userData.edgelabels;\n",
       "    var edgelabels = new THREE.Group();\n",
       "    edgelabels.name = \"edgelabels\";\n",
       "    if (Array.isArray(labels)) {\n",
       "        for (var i=0; i<edgeindices.length; i=i+2) {\n",
       "            var point = points[i];\n",
       "            var spriteMaterial = textSpriteMaterial( labels[i] );\n",
       "            var sprite = new THREE.Sprite(spriteMaterial);\n",
       "            sprite.position.copy(new THREE.Vector3().addVectors(points[edgeindices[i]].vector,points[edgeindices[i+1]].vector).multiplyScalar(0.5));\n",
       "            edgelabels.add(sprite);\n",
       "        }\n",
       "    } else {\n",
       "        var spriteMaterial = textSpriteMaterial( labels );\n",
       "        for (var i=0; i<points.length; i++) {\n",
       "            var point = points[i];\n",
       "            var sprite = new THREE.Sprite(spriteMaterial);\n",
       "            sprite.position.copy(new THREE.Vector3().addVectors(points[edgeindices[i]].vector,points[edgeindices[i+1]].vector).multiplyScalar(0.5));\n",
       "            pointlabels.add(sprite);\n",
       "        }\n",
       "    }\n",
       "    obj.add(edgelabels);\n",
       "}\n",
       "\n",
       "function init_arrowheads(obj) {\n",
       "    var arrowheads = new THREE.Group();\n",
       "    arrowheads.name = \"arrowheads\";\n",
       "    var arrowstyle = obj.userData.arrowstyle;\n",
       "    var edgeindices = obj.userData.edgeindices;\n",
       "    var edgematerials = obj.userData.edgematerial;\n",
       "    var points = obj.userData.points;\n",
       "    var material;\n",
       "    if (!Array.isArray(edgematerials)) {\n",
       "        material = new THREE.MeshBasicMaterial( {color: edgematerials.color} );\n",
       "    }\n",
       "\n",
       "    for (var i=0; i<edgeindices.length; i=i+2) {\n",
       "        var start = points[edgeindices[i]];\n",
       "        var end = points[edgeindices[i+1]];\n",
       "        var dist = start.vector.distanceTo( end.vector ) - start.radius() - end.radius();\n",
       "        if (dist <= 0) {\n",
       "            continue;\n",
       "        }\n",
       "        var dir = new THREE.Vector3().subVectors(end.vector,start.vector);\n",
       "        dir.normalize();\n",
       "        var axis = new THREE.Vector3().set(dir.z,0,-dir.x);\n",
       "        axis.normalize();\n",
       "        var radians = Math.acos( dir.y );\n",
       "        var radius = dist/25;\n",
       "        var height = dist/5;\n",
       "        var geometry = new THREE.ConeBufferGeometry(radius,height);\n",
       "        var position = new THREE.Vector3().addVectors(start.vector,dir.clone().multiplyScalar(start.radius()+dist-height/2));\n",
       "        if (Array.isArray(edgematerials)) {\n",
       "            material = new THREE.MeshBasicMaterial( {color: edgematerials[i].color} );\n",
       "        }\n",
       "        var cone = new THREE.Mesh( geometry, material );\n",
       "        cone.quaternion.setFromAxisAngle(axis,radians);;\n",
       "        cone.position.copy(position);;\n",
       "        arrowheads.add(cone);\n",
       "    }\n",
       "    obj.add(arrowheads);\n",
       "}\n",
       "\n",
       "function init_faces(obj) {\n",
       "    var points = obj.userData.points;\n",
       "    var facets = obj.userData.facets;\n",
       "    obj.userData.triangleindices = [];\n",
       "    for (var i=0; i<facets.length; i++) {\n",
       "        facet = facets[i];\n",
       "        for (var t=0; t<facet.length-2; t++) {\n",
       "            obj.userData.triangleindices.push(facet[0],facet[t+1],facet[t+2]);  \n",
       "        }\n",
       "    }\n",
       "    var bufarr = new Float32Array( obj.userData.triangleindices.length * 3 );\n",
       "    var bufattr = new THREE.Float32BufferAttribute(bufarr,3);\n",
       "    \n",
       "    var materials = obj.userData.facetmaterial;\n",
       "    var geometry = new THREE.BufferGeometry();\n",
       "    geometry.setAttribute('position',bufattr);\n",
       "    if (Array.isArray(materials)) {\n",
       "        var tricount = 0;\n",
       "        var facet;\n",
       "        for (var i=0; i<facets.length; i++) {\n",
       "            facet = facets[i];\n",
       "            geometry.addGroup(tricount,(facet.length-2)*3,i);\n",
       "            tricount += (facet.length-2)*3;\n",
       "        }\n",
       "    }\n",
       "    var mesh = new THREE.Mesh(geometry, materials);\n",
       "    mesh.name = \"faces\";\n",
       "    obj.add(mesh); \n",
       "    updateFacesPosition(obj);\n",
       "}\n",
       "// //INITIALIZING\n",
       "\n",
       "\n",
       "function updateFacesPosition(obj) {\n",
       "    var points = obj.userData.points;\n",
       "    var indices = obj.userData.triangleindices;\n",
       "    var faces = obj.getObjectByName(\"faces\");\n",
       "    var ba = faces.geometry.getAttribute(\"position\");\n",
       "    for (var i=0; i<indices.length; i++) {\n",
       "        ba.setXYZ(i, points[indices[i]].vector.x, points[indices[i]].vector.y ,points[indices[i]].vector.z); \n",
       "    }\n",
       "    faces.geometry.attributes.position.needsUpdate = true;\n",
       "    \n",
       "}\n",
       "\n",
       "function updateEdgesPosition(obj) {\n",
       "    var points = obj.userData.points;\n",
       "    var indices = obj.userData.edgeindices;\n",
       "    var lines = obj.getObjectByName(\"lines\");\n",
       "    var ba = lines.geometry.getAttribute(\"position\"); \n",
       "    for (var i=0; i<indices.length; i++) {\n",
       "        ba.setXYZ(i, points[indices[i]].vector.x, points[indices[i]].vector.y ,points[indices[i]].vector.z); \n",
       "    }\n",
       "    lines.geometry.attributes.position.needsUpdate = true;\n",
       "}\n",
       "\n",
       "function onWindowResize() {\n",
       "    renderer.setSize( three.clientWidth, three.clientHeight );\n",
       "    svgRenderer.setSize( three.clientWidth, three.clientHeight );\n",
       "    updateCamera();\n",
       "}\n",
       "\n",
       "function updateCamera() {\n",
       "    var width = three.clientWidth;\n",
       "    var height = three.clientHeight;\n",
       "    var aspect = width / height;\n",
       "    if (camera.type == \"OrthographicCamera\") {\n",
       "        camera.left = frustumSize * aspect / - 2;\n",
       "        camera.right = frustumSize * aspect / 2;\n",
       "        camera.top = frustumSize / 2;\n",
       "        camera.bottom = - frustumSize / 2;\n",
       "    } else if (camera.type == \"PerspectiveCamera\") {\n",
       "        camera.aspect = aspect;\n",
       "    }\n",
       "    camera.updateProjectionMatrix();\n",
       "}\n",
       "\n",
       "function changeCamera(event) {\n",
       "    var selindex = event.currentTarget.selectedIndex;\n",
       "    camera = cameras[selindex];\n",
       "    control = controls[selindex];\n",
       "    control.enabled = true; \n",
       "    for (var i=0; i<controls.length; i++) {\n",
       "        if (i!=selindex) {\n",
       "            controls[i].enabled = false;\n",
       "        }\n",
       "    }\n",
       "    updateCamera();\n",
       "}\n",
       "\n",
       "var camtypenode = document.getElementById('cameraType_3');\n",
       "camtypenode.onchange = changeCamera;\n",
       "camtypenode.dispatchEvent(new Event('change'));\n",
       "\n",
       "onWindowResize();\n",
       "window.addEventListener('resize', onWindowResize);\t\n",
       "\n",
       "\n",
       "var xRotationEnabled = false;\n",
       "var yRotationEnabled = false;\n",
       "var zRotationEnabled = false;\n",
       "var rotationSpeedFactor = 1;\n",
       "var settingsShown = false;\n",
       "var labelsShown = true;\n",
       "var intervals = [];\n",
       "var timeouts = [];\n",
       "var explodingSpeed = 0.05;\n",
       "var explodeScale = 0;\n",
       "var XMLS = new XMLSerializer();\n",
       "var svgElement;\n",
       "var renderId;\n",
       "\n",
       "var render = function () {\n",
       "\n",
       "\trenderId = requestAnimationFrame(render);\n",
       "\n",
       "//\tcomment in for automatic explosion\n",
       "//\texplode(updateFactor());\n",
       "\n",
       "    var phi = 0.02 * rotationSpeedFactor;\n",
       "\n",
       "    if (xRotationEnabled) {\n",
       "        scene.rotation.x += phi;\n",
       "    }\n",
       "    if (yRotationEnabled) {\n",
       "        scene.rotation.y += phi;\n",
       "    }\n",
       "    if (zRotationEnabled) {\n",
       "        scene.rotation.z += phi;\n",
       "    }\n",
       "\n",
       "    control.update();\n",
       "    renderer.render(scene, camera);\n",
       "};\n",
       "\n",
       "if ( THREE.WEBGL.isWebGLAvailable() ) {\n",
       "\trender();\n",
       "} else {\n",
       "\tvar warning = WEBGL.getWebGLErrorMessage();\n",
       "\tthree.appendChild( warning );\n",
       "}\n",
       "    \n",
       "function changeTransparency() {\n",
       "    var opacity = 1-Number(event.currentTarget.value);\n",
       "    for (var i=0; i<scene.children.length; i++) {\n",
       "        child = scene.children[i];\n",
       "        if ( child.userData.hasOwnProperty(\"facetmaterial\") ) {\n",
       "            if (Array.isArray(child.userData.facetmaterial)) {\n",
       "                for (var j=0; j<child.userData.facetmaterial.length; j++) {\n",
       "                    child.userData.facetmaterial[j].opacity = opacity;\n",
       "                }\n",
       "            } else {\n",
       "                child.userData.facetmaterial.opacity = opacity;\n",
       "            }    \n",
       "        }\n",
       "    }\n",
       "}\n",
       "\n",
       "function changeRotationX(event){\n",
       "    xRotationEnabled = event.currentTarget.checked;\n",
       "}\t\n",
       "\n",
       "function changeRotationY(event){\n",
       "    yRotationEnabled = event.currentTarget.checked;\n",
       "}\t\n",
       "\n",
       "function changeRotationZ(event){\n",
       "    zRotationEnabled = event.currentTarget.checked;\n",
       "}\t\n",
       "\n",
       "\n",
       "function changeRotationSpeedFactor(event){\n",
       "    rotationSpeedFactor = Number(event.currentTarget.value);\n",
       "}\n",
       "\n",
       "function resetScene(){\n",
       "    scene.rotation.set(0,0,0);\n",
       "    camera.position.set(0,0,5);\n",
       "    camera.up.set(0,1,0);\n",
       "}\n",
       "\n",
       "function showSettings(event){\n",
       "    document.getElementById('settings_3').style.visibility = 'visible';\n",
       "    document.getElementById('showSettingsButton_3').style.visibility = 'hidden';\n",
       "    document.getElementById('hideSettingsButton_3').style.visibility = 'visible';\n",
       "    settingsShown = true;\n",
       "}\n",
       "\n",
       "function hideSettings(event){\n",
       "    document.getElementById('settings_3').style.visibility = 'hidden';\n",
       "    document.getElementById('showSettingsButton_3').style.visibility = 'visible';\n",
       "    document.getElementById('hideSettingsButton_3').style.visibility = 'hidden';\n",
       "    settingsShown = false;\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "var pos = 150* Math.PI;\n",
       "\n",
       "function updateFactor() {\n",
       "    pos++;\n",
       "    return Math.sin(.01*pos)+1;\n",
       "}\n",
       "\n",
       "// ------------------------ FOLDING ------------------------------------------------\n",
       "// ---------------------------------------------------------------------------------\n",
       "// rotate point p around axis defined by points p1 and p2 by given angle\n",
       "function rotate(p, p1, p2, angle ){   \n",
       "    angle = -angle;\n",
       "    var x = p.x, y = p.y, z = p.z, \n",
       "    a = p1.x, b = p1.y, c = p1.z, \n",
       "    u = p2.x-p1.x, v = p2.y-p1.y, w = p2.z-p1.z;\n",
       "    var result = [];\n",
       "    var L = u*u + v*v + w*w;\n",
       "    var sqrt = Math.sqrt;\n",
       "    var cos = Math.cos;\n",
       "    var sin = Math.sin;\n",
       "\n",
       "    result[0] = ((a*(v*v+w*w)-u*(b*v+c*w-u*x-v*y-w*z))*(1-cos(angle))+L*x*cos(angle)+sqrt(L)*(-c*v+b*w-w*y+v*z)*sin(angle))/L;\n",
       "    result[1] = ((b*(u*u+w*w)-v*(a*u+c*w-u*x-v*y-w*z))*(1-cos(angle))+L*y*cos(angle)+sqrt(L)*(c*u-a*w+w*x-u*z)*sin(angle))/L;\n",
       "    result[2] = ((c*(u*u+v*v)-w*(a*u+b*v-u*x-v*y-w*z))*(1-cos(angle))+L*z*cos(angle)+sqrt(L)*(-b*u+a*v-v*x+u*y)*sin(angle))/L;\n",
       "\n",
       "    return result;\n",
       "}\n",
       "\n",
       "var fold = function(event){\n",
       "    var obj = foldables[Number(event.currentTarget.name)];\n",
       "    var foldvalue = Number(event.currentTarget.value);\n",
       "    var scale = foldvalue - obj.userData.oldscale;\n",
       "\n",
       "    for (var j=0; j<obj.userData.axes.length; j++) {\n",
       "        rotateVertices(obj, j, scale);\n",
       "    }\n",
       "    update(obj);\n",
       "    obj.userData.oldscale += scale;\n",
       "    lookAtBarycenter(obj);\n",
       "}\n",
       "\n",
       "function lookAtBarycenter(obj){\n",
       "    control.target = barycenter(obj);\n",
       "}\n",
       "\n",
       "function barycenter(obj) {\n",
       "    var center = new THREE.Vector3(0,0,0);\n",
       "    var points = obj.userData.points;\n",
       "    for (var i=0; i<points.length; i++){\n",
       "        center.add(points[i].vector);\n",
       "    }\n",
       "    center.divideScalar(points.length);\n",
       "    return center;\n",
       "}\n",
       "\n",
       "function rotateVertices(obj, edge, scale) {\n",
       "    var axes = obj.userData.axes;\n",
       "    var subtrees = obj.userData.subtrees;\n",
       "    var points = obj.userData.points;\n",
       "    var angles = obj.userData.angles;\n",
       "    if (edge < axes.length){\n",
       "        for (var j=0; j<subtrees[edge].length; j++){\n",
       "            var rotP = rotate(points[subtrees[edge][j]].vector, points[axes[edge][0]].vector,points[axes[edge][1]].vector, scale * (Math.PI - angles[edge]));\n",
       "            points[subtrees[edge][j]].set(rotP[0],rotP[1],rotP[2]);\n",
       "        }\n",
       "    }\n",
       "}\n",
       "\n",
       "function update(obj) {\n",
       "   updateFacesPosition(obj);\n",
       "   updateEdgesPosition(obj);\n",
       "}\n",
       "\n",
       "if (foldables.length) {\n",
       "    var settings = document.getElementById('settings_3');\n",
       "    var foldDiv = document.createElement('div');\n",
       "    foldDiv.id = 'fold_3';\n",
       "    var title = document.createElement('strong');\n",
       "    title.innerHTML = 'Fold';\n",
       "    foldDiv.appendChild(title);\n",
       "    foldDiv.className = 'group';\n",
       "    for (var i=0; i<foldables.length; i++) {\n",
       "        var range = document.createElement('input');\n",
       "        range.type = 'range';\n",
       "        range.min = 0;\n",
       "        range.max = 1;\n",
       "        range.value = 0;\n",
       "        range.step = 0.001;\n",
       "        range.name = String(i);\n",
       "        range.oninput = fold;\n",
       "        foldDiv.appendChild(range);\n",
       "    }\n",
       "    lookAtBarycenter(foldables[0]);\n",
       "    settings.insertBefore(foldDiv,settings.childNodes[0]);\n",
       "}\n",
       "\n",
       "    \n",
       "// ---------------------- EXPLOSION ------------------------------------------------\n",
       "// ---------------------------------------------------------------------------------\n",
       "\n",
       "if (explodableModel) {\n",
       "    for (var i=0; i<scene.children.length; i++) {\n",
       "        obj = scene.children[i];\n",
       "        if ( obj.userData.explodable ) {\n",
       "            computeCentroid(obj);\n",
       "        }\n",
       "    }\n",
       "    document.getElementById('explodeRange_3').oninput = triggerExplode;\n",
       "    document.getElementById('explodeCheckbox_3').onchange = triggerAutomaticExplode;\n",
       "    document.getElementById('explodingSpeedRange_3').oninput = setExplodingSpeed;\n",
       "}\n",
       "\n",
       "function computeCentroid(obj) {\n",
       "    centroid = new THREE.Vector3();\n",
       "    obj.userData.points.forEach(function(pmpoint) {\n",
       "        centroid.add(pmpoint.vector);\t\t\t\n",
       "    });\n",
       "    centroid.divideScalar(obj.userData.points.length);\n",
       "    obj.userData.centroid = centroid;\n",
       "}\n",
       "\n",
       "function explode(factor) {\n",
       "    for (var i=0; i<scene.children.length; i++) {\n",
       "        var obj = scene.children[i];\n",
       "        if (obj.userData.hasOwnProperty(\"centroid\")) { \n",
       "            var c = obj.userData.centroid;\n",
       "            obj.position.set(c.x*factor, c.y*factor, c.z*factor);\n",
       "        }\n",
       "    }\t\n",
       "}\n",
       "\n",
       "function triggerExplode(event){\n",
       "    explodeScale = Number(event.currentTarget.value);\n",
       "    explode(explodeScale);\n",
       "}\n",
       "\n",
       "function setExplodingSpeed(event){\n",
       "    explodingSpeed = Number(event.currentTarget.value);\n",
       "}\n",
       "\n",
       "function triggerAutomaticExplode(event){\n",
       "    if (event.currentTarget.checked){\n",
       "        startExploding();\n",
       "    } else {\n",
       "        clearIntervals();\n",
       "    }\t\n",
       "}\n",
       "\n",
       "function startExploding(){\n",
       "    intervals.push(setInterval(explodingInterval, 25));\n",
       "}\n",
       "\n",
       "\n",
       "function explodingInterval(){\n",
       "    explodeScale += explodingSpeed;\n",
       "    if (explodeScale <= 6){ \n",
       "        explode(explodeScale);\n",
       "    }\n",
       "    else{\n",
       "        explode(6);\n",
       "        explodeScale = 6;\n",
       "        clearIntervals();\n",
       "        timeouts.push(setTimeout(startUnexploding, 3000));\n",
       "    }\n",
       "    document.getElementById('explodeRange_3').value = explodeScale;\n",
       "}\n",
       "\n",
       "\n",
       "function startUnexploding(){\n",
       "    intervals.push(setInterval(unexplodingInterval, 25));\n",
       "}\n",
       "\n",
       "function unexplodingInterval(){\n",
       "    explodeScale -= explodingSpeed;\n",
       "    if (explodeScale >= 0){\t\n",
       "        explode(explodeScale);\n",
       "    }\n",
       "    else {\n",
       "        explode(0);\n",
       "        explodeScale = 0;\n",
       "        clearIntervals();\n",
       "        timeouts.push(setTimeout(startExploding, 3000));\n",
       "    }\n",
       "    document.getElementById('explodeRange_3').value = explodeScale;\n",
       "}\n",
       "\n",
       "function clearIntervals(){\n",
       "    intervals.forEach(function(interval){\n",
       "        clearInterval(interval);\n",
       "    });\n",
       "    intervals = [];\n",
       "    timeouts.forEach(function(timeout){\n",
       "        clearTimeout(timeout);\n",
       "    });\n",
       "    timeouts = [];\n",
       "}\n",
       "\n",
       "// ---------------------- DISPLAY --------------------------------------------------\n",
       "// ---------------------------------------------------------------------------------\n",
       "\n",
       "const objectTypeInnerHTMLs = { points: \"Points\", pointlabels: \"Point labels\", lines: \"Edges\", edgelabels: \"Edge labels\", faces: \"Faces\", arrowheads: \"Arrow heads\" };\n",
       "const objectTypeVisible = {};\n",
       "Object.assign(objectTypeVisible,modelContains);\n",
       "const sortedObjectTypeKeys = Object.keys(objectTypeInnerHTMLs).sort();\n",
       "const shownObjectTypesList = document.getElementById('shownObjectTypesList_3');\n",
       "\n",
       "function setVisibility(bool,objname) {\n",
       "    for (var i=0; i<scene.children.length; i++){\n",
       "        var obj = scene.children[i].getObjectByName(objname);\n",
       "        if (obj) {\n",
       "            obj.visible = bool;\n",
       "        }\n",
       "    }\n",
       "}\n",
       "\n",
       "function toggleObjectTypeVisibility(event){\n",
       "    var name = event.currentTarget.name;\n",
       "    var checked = event.currentTarget.checked;\n",
       "    objectTypeVisible[name] = checked;\n",
       "    setVisibility(checked,name);\n",
       "}\n",
       "\n",
       "for (var i=0; i<sortedObjectTypeKeys.length; i++){\n",
       "    var key = sortedObjectTypeKeys[i];\n",
       "    if (modelContains[key]) {\n",
       "        var objTypeNode = document.createElement('span');\n",
       "        objTypeNode.innerHTML = objectTypeInnerHTMLs[key] + '<br>';\n",
       "        var checkbox = document.createElement('input');\n",
       "        checkbox.type = 'checkbox';\n",
       "        checkbox.checked = true;\n",
       "        checkbox.name = key;\n",
       "        checkbox.onchange = toggleObjectTypeVisibility;\n",
       "        shownObjectTypesList.appendChild(checkbox);\n",
       "        shownObjectTypesList.appendChild(objTypeNode);\n",
       "    }\n",
       "}\n",
       "\n",
       "// ------------------------------------------------------\n",
       "\n",
       "function toggleObjectVisibility(event){\n",
       "    var nr = Number(event.currentTarget.name);\n",
       "    scene.children[nr].visible = event.currentTarget.checked;\n",
       "}\n",
       "\n",
       "// append checkboxes for displaying or hiding objects\n",
       "var shownObjectsList = document.getElementById('shownObjectsList_3');\n",
       "for (var i=0; i<scene.children.length; i++){\n",
       "    obj = scene.children[i];\n",
       "    var objNode = document.createElement('span');\n",
       "    objNode.innerHTML = obj.name + '<br>';\n",
       "    var checkbox = document.createElement('input');\n",
       "    checkbox.type = 'checkbox';\n",
       "    checkbox.checked = true;\n",
       "    checkbox.name = String(i);\n",
       "    checkbox.onchange = toggleObjectVisibility;\n",
       "    shownObjectsList.appendChild(checkbox);\n",
       "    shownObjectsList.appendChild(objNode);\n",
       "}\n",
       "\n",
       "// ---------------------- SVG ------------------------------------------------------\n",
       "// ---------------------------------------------------------------------------------\n",
       "\n",
       "function takeSvgScreenshot() {\n",
       "    if (objectTypeVisible[\"pointlabels\"]) {\n",
       "        setVisibility(false,\"pointlabels\");\n",
       "    }\n",
       "    if (objectTypeVisible[\"edgelabels\"]) {\n",
       "        setVisibility(false,\"edgelabels\");\n",
       "    }\n",
       "    svgRenderer.render(scene,camera);\n",
       "    svgElement = XMLS.serializeToString(svgRenderer.domElement);\n",
       "    \n",
       "    if (objectTypeVisible[\"pointlabels\"]) {\n",
       "        setVisibility(true,\"pointlabels\");\n",
       "    }\n",
       "    if (objectTypeVisible[\"edgelabels\"]) {\n",
       "        setVisibility(true,\"edgelabels\");\n",
       "    }\n",
       "\n",
       "    if (document.getElementById('tab_3').checked){\n",
       "        //show in new tab\n",
       "        var myWindow = window.open(\"\",\"\");\n",
       "        myWindow.document.body.innerHTML = svgElement;\n",
       "    } else{\n",
       "        // download svg file \n",
       "        download(\"screenshot.svg\", svgElement);\n",
       "    }\n",
       "}\n",
       "\n",
       "function download(filename, text) {\n",
       "    var element = document.createElement('a');\n",
       "    element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));\n",
       "    element.setAttribute('download', filename);\n",
       "\n",
       "    element.style.display = 'none';\n",
       "    document.body.appendChild(element);\n",
       "\n",
       "    element.click();\n",
       "\n",
       "    document.body.removeChild(element);\n",
       "}\n",
       "\n",
       "\n",
       "document.getElementById('transparencyRange_3').oninput = changeTransparency;\n",
       "document.getElementById('changeRotationX_3').onchange = changeRotationX;\n",
       "document.getElementById('changeRotationY_3').onchange = changeRotationY;\n",
       "document.getElementById('changeRotationZ_3').onchange = changeRotationZ;\n",
       "document.getElementById('resetButton_3').onclick = resetScene;\n",
       "document.getElementById('rotationSpeedRange_3').oninput = changeRotationSpeedFactor;\n",
       "document.getElementById('takeScreenshot_3').onclick = takeSvgScreenshot;\n",
       "document.getElementById('showSettingsButton_3').onclick = showSettings;\n",
       "document.getElementById('hideSettingsButton_3').onclick = hideSettings;\n",
       "\n",
       "\n",
       "// ------------------ SHORTCUTS --------------------------------------------\n",
       "// -------------------------------------------------------------------------\n",
       "\n",
       "/**\n",
       " * http://www.openjs.com/scripts/events/keyboard_shortcuts/\n",
       " * Version : 2.01.B\n",
       " * By Binny V A\n",
       " * License : BSD\n",
       " */\n",
       "shortcut = {\n",
       "\t'all_shortcuts':{},//All the shortcuts are stored in this array\n",
       "\t'add': function(shortcut_combination,callback,opt) {\n",
       "\t\t//Provide a set of default options\n",
       "\t\tvar default_options = {\n",
       "\t\t\t'type':'keydown',\n",
       "\t\t\t'propagate':false,\n",
       "\t\t\t'disable_in_input':false,\n",
       "\t\t\t'target':document,\n",
       "\t\t\t'keycode':false\n",
       "\t\t}\n",
       "\t\tif(!opt) opt = default_options;\n",
       "\t\telse {\n",
       "\t\t\tfor(var dfo in default_options) {\n",
       "\t\t\t\tif(typeof opt[dfo] == 'undefined') opt[dfo] = default_options[dfo];\n",
       "\t\t\t}\n",
       "\t\t}\n",
       "\n",
       "\t\tvar ele = opt.target;\n",
       "\t\tif(typeof opt.target == 'string') ele = document.getElementById(opt.target);\n",
       "\t\tvar ths = this;\n",
       "\t\tshortcut_combination = shortcut_combination.toLowerCase();\n",
       "\n",
       "\t\t//The function to be called at keypress\n",
       "\t\tvar func = function(e) {\n",
       "\t\t\te = e || window.event;\n",
       "\t\t\t\n",
       "\t\t\tif(opt['disable_in_input']) { //Don't enable shortcut keys in Input, Textarea fields\n",
       "\t\t\t\tvar element;\n",
       "\t\t\t\tif(e.target) element=e.target;\n",
       "\t\t\t\telse if(e.srcElement) element=e.srcElement;\n",
       "\t\t\t\tif(element.nodeType==3) element=element.parentNode;\n",
       "\n",
       "\t\t\t\tif(element.tagName == 'INPUT' || element.tagName == 'TEXTAREA') return;\n",
       "\t\t\t}\n",
       "\t\n",
       "\t\t\t//Find Which key is pressed\n",
       "\t\t\tif (e.keyCode) code = e.keyCode;\n",
       "\t\t\telse if (e.which) code = e.which;\n",
       "\t\t\tvar character = String.fromCharCode(code).toLowerCase();\n",
       "\t\t\t\n",
       "\t\t\tif(code == 188) character=\",\"; //If the user presses , when the type is onkeydown\n",
       "\t\t\tif(code == 190) character=\".\"; //If the user presses , when the type is onkeydown\n",
       "\n",
       "\t\t\tvar keys = shortcut_combination.split(\"+\");\n",
       "\t\t\t//Key Pressed - counts the number of valid keypresses - if it is same as the number of keys, the shortcut function is invoked\n",
       "\t\t\tvar kp = 0;\n",
       "\t\t\t\n",
       "\t\t\t//Work around for stupid Shift key bug created by using lowercase - as a result the shift+num combination was broken\n",
       "\t\t\tvar shift_nums = {\n",
       "\t\t\t\t\"`\":\"~\",\n",
       "\t\t\t\t\"1\":\"!\",\n",
       "\t\t\t\t\"2\":\"@\",\n",
       "\t\t\t\t\"3\":\"#\",\n",
       "\t\t\t\t\"4\":\"$\",\n",
       "\t\t\t\t\"5\":\"%\",\n",
       "\t\t\t\t\"6\":\"^\",\n",
       "\t\t\t\t\"7\":\"&\",\n",
       "\t\t\t\t\"8\":\"*\",\n",
       "\t\t\t\t\"9\":\"(\",\n",
       "\t\t\t\t\"0\":\")\",\n",
       "\t\t\t\t\"-\":\"_\",\n",
       "\t\t\t\t\"=\":\"+\",\n",
       "\t\t\t\t\";\":\":\",\n",
       "\t\t\t\t\"'\":\"\\\"\",\n",
       "\t\t\t\t\",\":\"<\",\n",
       "\t\t\t\t\".\":\">\",\n",
       "\t\t\t\t\"/\":\"?\",\n",
       "\t\t\t\t\"\\\\\":\"|\"\n",
       "\t\t\t}\n",
       "\t\t\t//Special Keys - and their codes\n",
       "\t\t\tvar special_keys = {\n",
       "\t\t\t\t'esc':27,\n",
       "\t\t\t\t'escape':27,\n",
       "\t\t\t\t'tab':9,\n",
       "\t\t\t\t'space':32,\n",
       "\t\t\t\t'return':13,\n",
       "\t\t\t\t'enter':13,\n",
       "\t\t\t\t'backspace':8,\n",
       "\t\n",
       "\t\t\t\t'scrolllock':145,\n",
       "\t\t\t\t'scroll_lock':145,\n",
       "\t\t\t\t'scroll':145,\n",
       "\t\t\t\t'capslock':20,\n",
       "\t\t\t\t'caps_lock':20,\n",
       "\t\t\t\t'caps':20,\n",
       "\t\t\t\t'numlock':144,\n",
       "\t\t\t\t'num_lock':144,\n",
       "\t\t\t\t'num':144,\n",
       "\t\t\t\t\n",
       "\t\t\t\t'pause':19,\n",
       "\t\t\t\t'break':19,\n",
       "\t\t\t\t\n",
       "\t\t\t\t'insert':45,\n",
       "\t\t\t\t'home':36,\n",
       "\t\t\t\t'delete':46,\n",
       "\t\t\t\t'end':35,\n",
       "\t\t\t\t\n",
       "\t\t\t\t'pageup':33,\n",
       "\t\t\t\t'page_up':33,\n",
       "\t\t\t\t'pu':33,\n",
       "\t\n",
       "\t\t\t\t'pagedown':34,\n",
       "\t\t\t\t'page_down':34,\n",
       "\t\t\t\t'pd':34,\n",
       "\t\n",
       "\t\t\t\t'left':37,\n",
       "\t\t\t\t'up':38,\n",
       "\t\t\t\t'right':39,\n",
       "\t\t\t\t'down':40,\n",
       "\t\n",
       "\t\t\t\t'f1':112,\n",
       "\t\t\t\t'f2':113,\n",
       "\t\t\t\t'f3':114,\n",
       "\t\t\t\t'f4':115,\n",
       "\t\t\t\t'f5':116,\n",
       "\t\t\t\t'f6':117,\n",
       "\t\t\t\t'f7':118,\n",
       "\t\t\t\t'f8':119,\n",
       "\t\t\t\t'f9':120,\n",
       "\t\t\t\t'f10':121,\n",
       "\t\t\t\t'f11':122,\n",
       "\t\t\t\t'f12':123\n",
       "\t\t\t}\n",
       "\t\n",
       "\t\t\tvar modifiers = { \n",
       "\t\t\t\tshift: { wanted:false, pressed:false},\n",
       "\t\t\t\tctrl : { wanted:false, pressed:false},\n",
       "\t\t\t\talt  : { wanted:false, pressed:false},\n",
       "\t\t\t\tmeta : { wanted:false, pressed:false}\t//Meta is Mac specific\n",
       "\t\t\t};\n",
       "                        \n",
       "\t\t\tif(e.ctrlKey)\tmodifiers.ctrl.pressed = true;\n",
       "\t\t\tif(e.shiftKey)\tmodifiers.shift.pressed = true;\n",
       "\t\t\tif(e.altKey)\tmodifiers.alt.pressed = true;\n",
       "\t\t\tif(e.metaKey)   modifiers.meta.pressed = true;\n",
       "                        \n",
       "\t\t\tfor(var i=0; k=keys[i],i<keys.length; i++) {\n",
       "\t\t\t\t//Modifiers\n",
       "\t\t\t\tif(k == 'ctrl' || k == 'control') {\n",
       "\t\t\t\t\tkp++;\n",
       "\t\t\t\t\tmodifiers.ctrl.wanted = true;\n",
       "\n",
       "\t\t\t\t} else if(k == 'shift') {\n",
       "\t\t\t\t\tkp++;\n",
       "\t\t\t\t\tmodifiers.shift.wanted = true;\n",
       "\n",
       "\t\t\t\t} else if(k == 'alt') {\n",
       "\t\t\t\t\tkp++;\n",
       "\t\t\t\t\tmodifiers.alt.wanted = true;\n",
       "\t\t\t\t} else if(k == 'meta') {\n",
       "\t\t\t\t\tkp++;\n",
       "\t\t\t\t\tmodifiers.meta.wanted = true;\n",
       "\t\t\t\t} else if(k.length > 1) { //If it is a special key\n",
       "\t\t\t\t\tif(special_keys[k] == code) kp++;\n",
       "\t\t\t\t\t\n",
       "\t\t\t\t} else if(opt['keycode']) {\n",
       "\t\t\t\t\tif(opt['keycode'] == code) kp++;\n",
       "\n",
       "\t\t\t\t} else { //The special keys did not match\n",
       "\t\t\t\t\tif(character == k) kp++;\n",
       "\t\t\t\t\telse {\n",
       "\t\t\t\t\t\tif(shift_nums[character] && e.shiftKey) { //Stupid Shift key bug created by using lowercase\n",
       "\t\t\t\t\t\t\tcharacter = shift_nums[character]; \n",
       "\t\t\t\t\t\t\tif(character == k) kp++;\n",
       "\t\t\t\t\t\t}\n",
       "\t\t\t\t\t}\n",
       "\t\t\t\t}\n",
       "\t\t\t}\n",
       "\t\t\t\n",
       "\t\t\tif(kp == keys.length && \n",
       "\t\t\t\t\t\tmodifiers.ctrl.pressed == modifiers.ctrl.wanted &&\n",
       "\t\t\t\t\t\tmodifiers.shift.pressed == modifiers.shift.wanted &&\n",
       "\t\t\t\t\t\tmodifiers.alt.pressed == modifiers.alt.wanted &&\n",
       "\t\t\t\t\t\tmodifiers.meta.pressed == modifiers.meta.wanted) {\n",
       "\t\t\t\tcallback(e);\n",
       "\t\n",
       "\t\t\t\tif(!opt['propagate']) { //Stop the event\n",
       "\t\t\t\t\t//e.cancelBubble is supported by IE - this will kill the bubbling process.\n",
       "\t\t\t\t\te.cancelBubble = true;\n",
       "\t\t\t\t\te.returnValue = false;\n",
       "\t\n",
       "\t\t\t\t\t//e.stopPropagation works in Firefox.\n",
       "\t\t\t\t\tif (e.stopPropagation) {\n",
       "\t\t\t\t\t\te.stopPropagation();\n",
       "\t\t\t\t\t\te.preventDefault();\n",
       "\t\t\t\t\t}\n",
       "\t\t\t\t\treturn false;\n",
       "\t\t\t\t}\n",
       "\t\t\t}\n",
       "\t\t}\n",
       "\t\tthis.all_shortcuts[shortcut_combination] = {\n",
       "\t\t\t'callback':func, \n",
       "\t\t\t'target':ele, \n",
       "\t\t\t'event': opt['type']\n",
       "\t\t};\n",
       "\t\t//Attach the function with the event\n",
       "\t\tif(ele.addEventListener) ele.addEventListener(opt['type'], func, false);\n",
       "\t\telse if(ele.attachEvent) ele.attachEvent('on'+opt['type'], func);\n",
       "\t\telse ele['on'+opt['type']] = func;\n",
       "\t},\n",
       "\n",
       "\t//Remove the shortcut - just specify the shortcut and I will remove the binding\n",
       "\t'remove':function(shortcut_combination) {\n",
       "\t\tshortcut_combination = shortcut_combination.toLowerCase();\n",
       "\t\tvar binding = this.all_shortcuts[shortcut_combination];\n",
       "\t\tdelete(this.all_shortcuts[shortcut_combination])\n",
       "\t\tif(!binding) return;\n",
       "\t\tvar type = binding['event'];\n",
       "\t\tvar ele = binding['target'];\n",
       "\t\tvar callback = binding['callback'];\n",
       "\n",
       "\t\tif(ele.detachEvent) ele.detachEvent('on'+type, callback);\n",
       "\t\telse if(ele.removeEventListener) ele.removeEventListener(type, callback, false);\n",
       "\t\telse ele['on'+type] = false;\n",
       "\t}\n",
       "}\n",
       "\n",
       "shortcut.add(\"Alt+Left\",function() {\n",
       "\tvar event = new Event('click');\n",
       "\tif (settingsShown){\n",
       "\t\tdocument.getElementById('hideSettingsButton_3').dispatchEvent(event);\n",
       "\t} else {\n",
       "\t\tdocument.getElementById('showSettingsButton_3').dispatchEvent(event);\n",
       "\t}\n",
       "});\n",
       "\n",
       "\n",
       "// COMMON_CODE_BLOCK_END\n",
       "\n",
       "});});\n",
       "      </script>\n",
       "   </body>\n",
       "</html>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "polytope::cube(3)->TRIANGULATION->VISUAL_MIXED_GRAPH;"
   ]
  },
  {
   "attachments": {
    "cube_graph.png": {
     "image/png": "[encoded data, 82668 characters]"
    }
   },
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "shows the primal and dual graph of the polytope together with an edge between a primal and a dual node iff the primal node represents a vertex of the corresponding facet of the dual node.\n",
    "\n",
    "![](attachment:cube_graph.png)\n",
    "\n",
    "Visualization of the `HASSE_DIAGRAM` is possible via `VISUAL_FACE_LATTICE`. It renders the graph in a .pdf file. You can even pipe the tikz code to whatever location using the `tikz` client:\n",
    "\n",
    "    \n",
    "    tikz($s->VISUAL_FACE_LATTICE, File=>\"/path/to/file.tikz\");\n",
    "\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "polymake",
   "language": "polymake",
   "name": "polymake"
  },
  "language_info": {
   "codemirror_mode": "perl",
   "file_extension": ".pl",
   "mimetype": "text/x-polymake",
   "name": "polymake"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
