diff --git a/config.json b/config.json
index eff648254ff5add725f321e8a4de6df25ae08b30..26d204de9de6a0fc0cba95d3d71e121fc85bef12 100644
--- a/config.json
+++ b/config.json
@@ -4,7 +4,7 @@
       "serverAddress": "ressims.iota.cafe:188"
     },
     "server": {
-      "port": 0
+      "port": 9191
     },
     "httpServer": {
       "bindAddress": "0.0.0.0:80"
diff --git a/go.sum b/go.sum
index fb6165532b14b8d48a8ce3e14a3522ba2e2f08d5..769edd98ff040c8c9302717d4486feb75fea7d1f 100644
--- a/go.sum
+++ b/go.sum
@@ -75,7 +75,6 @@ github.com/gobuffalo/logger v1.0.3 h1:YaXOTHNPCvkqqA7w05A4v0k2tCdpr+sgFlgINbQ6gq
 github.com/gobuffalo/logger v1.0.3/go.mod h1:SoeejUwldiS7ZsyCBphOGURmWdwUFXs0J7TCjEhjKxM=
 github.com/gobuffalo/packd v0.3.0 h1:eMwymTkA1uXsqxS0Tpoop3Lc0u3kTfiMBE6nKtQU4g4=
 github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b36chA3Q=
-github.com/gobuffalo/packr v1.30.1 h1:hu1fuVR3fXEZR7rXNW3h8rqSML8EVAf6KNm0NKO/wKg=
 github.com/gobuffalo/packr/v2 v2.7.1 h1:n3CIW5T17T8v4GGK5sWXLVWJhCz7b5aNLSxW6gYim4o=
 github.com/gobuffalo/packr/v2 v2.7.1/go.mod h1:qYEvAazPaVxy7Y7KR0W8qYEE+RymX74kETFqjFoFlOc=
 github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
@@ -336,8 +335,6 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U
 golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20191122220453-ac88ee75c92c/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876 h1:sKJQZMuxjOAR/Uo2LBfU90onWEf1dF4C+0hPJCc9Mpc=
-golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d h1:9FCpayM9Egr1baVnV1SX0H87m+XB0B8S0hAMi99X/3U=
 golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@@ -391,8 +388,6 @@ golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191018095205-727590c5006e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8 h1:JA8d3MPx/IToSyXZG/RhwYEtfrKO1Fxrqe8KrkiLXKM=
-golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9 h1:1/DFK4b7JH8DmkqhUk48onnSfrPzImPoVxuomtbT2nk=
 golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
diff --git a/plugins/analysis/webinterface/httpserver/httpserver-packr.go b/plugins/analysis/webinterface/httpserver/httpserver-packr.go
new file mode 100644
index 0000000000000000000000000000000000000000..38f8e3fb83c1cc95108d36b76797055b16716b30
--- /dev/null
+++ b/plugins/analysis/webinterface/httpserver/httpserver-packr.go
@@ -0,0 +1,8 @@
+// +build !skippackr
+// Code generated by github.com/gobuffalo/packr/v2. DO NOT EDIT.
+
+// You can use the "packr clean" command to clean up this,
+// and any other packr generated files.
+package httpserver
+
+import _ "github.com/iotaledger/goshimmer/plugins/analysis/webinterface/httpserver/packrd"
diff --git a/plugins/analysis/webinterface/httpserver/index.go b/plugins/analysis/webinterface/httpserver/index.go
deleted file mode 100644
index c9a07ecfae146e9fde06bcabb8b486a6c9cade85..0000000000000000000000000000000000000000
--- a/plugins/analysis/webinterface/httpserver/index.go
+++ /dev/null
@@ -1,321 +0,0 @@
-package httpserver
-
-import (
-	"fmt"
-	"net/http"
-)
-
-func index(w http.ResponseWriter, r *http.Request) {
-	fmt.Fprintf(w, `<head>
-  <style> 
-  html {
-    font-family: monospace, monospace;
-    line-height: 1.15;
-    -webkit-text-size-adjust: 100%%;
-  }
-  body {
-    text-align: center;
-    margin: 0;
-    overflow: hidden;
-  }
-
-  #nfo{
-    position:absolute;
-    right: 0;
-    padding:10px;	
-  }
-
-  #knownPeers{
-    position:relative;
-    margin:0;
-    font-size:14px;
-    font-weight: bold;
-    text-align:right;
-    color:#aaa;
-  }
-
-  #avgNeighbors{
-    position:relative;
-    margin:0;
-    font-size:13px;
-    text-align:right;
-    color:grey;
-  }
-
-  #graphc {
-    position: absolute;
-    top: 0px;
-    right: 0px;
-    margin:0;
-    right: 0px;
-  }
-
-  #nodeId{
-    position:relative;
-    margin:0;
-    padding:5px 0;
-    font-size:13px;
-    font-weight: bold;
-    text-align:right;
-    color:#aaa; 
-  }
-  
-  #nodestat{
-    position:relative;
-    margin:0;
-    font-size:12px;
-    text-align:right;
-    color:grey; 
-  }
-  
-  #in, #out{
-    margin:0;
-    padding: 3px 0;
-  }
-
-  </style>
-
-  <script src="https://unpkg.com/3d-force-graph"></script>
-  <!--<script src="../../dist/3d-force-graph.js"></script>-->
-</head>
-
-<body>
-  <div id="graphc"></div>
-  <div id="nfo">
-    <p id="knownPeers"></p>
-    <p id="avgNeighbors"></p>
-    <div id="nodeId"></div>
-    <div id="nodestat">
-      <p id="in"></p>
-      <p id="out"></p>
-    </div>
-  </div>
-  <script>
-	var socket = new WebSocket(((window.location.protocol === "https:") ? "wss://" : "ws://") + window.location.host + "/datastream");
-
-	socket.onopen = function () {
-        setInterval(function() {
-          socket.send("_");
-        }, 1000);
-	};
-
-	socket.onmessage = function (e) {
-        document.getElementById("knownPeers").innerHTML = "Known peers: " + data.nodes.length;
-        document.getElementById("avgNeighbors").innerHTML = "Average neighbors: " + parseFloat(((data.links.length * 2) / data.nodes.length).toFixed(2));
-        switch (e.data[0]) {
-          case "_":
-            // do nothing - its just a ping
-          break;
-
-          case "A":
-             addNode(e.data.substr(1));
-             console.log("Add node:",e.data.substr(1));
-          break;
-
-          case "a":
-             removeNode(e.data.substr(1));
-             console.log("Remove node:", e.data.substr(1));
-          break;
-
-          case "C":
-             connectNodes(e.data.substr(1, 64), e.data.substr(65, 64));
-             console.log("Connect nodes:",e.data.substr(1, 64), " - ", e.data.substr(65, 64));
-          break;
-
-          case "c":
-             disconnectNodes(e.data.substr(1, 64), e.data.substr(65, 64));
-             console.log("Disconnect nodes:",e.data.substr(1, 64), " - ", e.data.substr(65, 64));
-          break;
-
-          case "O":
-             setNodeOnline(e.data.substr(1));
-             console.log("setNodeOnline:",e.data.substr(1));
-          break;
-
-          case "o":
-             setNodeOffline(e.data.substr(1));
-             console.log("setNodeOffline:",e.data.substr(1));
-          break;
-        }
-	};
-
-    var nodesById = {};
-
-    const data = {
-      nodes: [],
-      links: []
-    };
-
-    var existingLinks = {};
-
-    let highlightNodes = [];
-    let highlightInbound = [];
-    let highlightOutbound = [];
-    let highlightLinks = [];
-    let highlightLink = null;
-
-    const elem = document.getElementById("graphc");
-
-      //.onNodeHover(node => elem.style.cursor = node ? 'pointer' : null)
-
-    const Graph = ForceGraph3D()(elem)
-        .graphData(data)
-        .enableNodeDrag(false)
-        .onNodeClick(showNodeStat)
-        .nodeColor(node =>  {
-          if (highlightNodes.indexOf(node) != -1) {
-            return 'rgb(255,0,0,1)'
-          }
-          if (highlightInbound.indexOf(node) != -1) {
-            return 'rgba(0,255,100,0.6)'
-          }
-          if (highlightOutbound.indexOf(node) != -1)  {
-            return 'rgba(0,100,255,0.6)'
-          }
-          else {
-            return 'rgba(0,255,255,0.6)'
-          }
-        })
-        .linkWidth(link => highlightLinks.indexOf(link) === -1 ? 1 : 3)
-        .linkDirectionalParticles(link => highlightLinks.indexOf(link) === -1 ? 0 : 3)
-        .linkDirectionalParticleWidth(3)
-        .onNodeHover(node => {
-          // no state change
-          if ((!node && !highlightNodes.length) || (highlightNodes.length === 1 && highlightNodes[0] === node)) return;
-
-          highlightNodes = node ? [node] : [];
-
-          highlightLinks = [];
-          highlightInbound = [];
-          highlightOutbound = [];
-          clearNodeStat();
-          if (node != null) {
-            highlightLinks = data.links.filter(l => (l.target.id == node.id) || (l.source.id == node.id));
-
-            highlightLinks.forEach(function(link){
-              if (link.target.id == node.id) {
-                highlightInbound.push(link.source)
-              }
-              else {
-                highlightOutbound.push(link.target)
-              }
-            });
-
-            showNodeStat(node);
-          }
-          updateHighlight();
-        })
-        .onLinkHover(link => {
-          // no state change
-          if ((!link && !highlightLinks.length) || (highlightLinks.length === 1 && highlightLinks[0] === link)) return;
-
-          highlightLinks = [link];
-          highlightNodes = link ? [link.source, link.target] : [];
-
-          updateHighlight();
-        });
-
-    var updateRequired = true;
-
-    setInterval(function() {
-      if (updateRequired) {
-        Graph.graphData(data);
-
-        updateRequired = false;
-      }
-    }, 500)
-
-    function updateHighlight() {
-      // trigger update of highlighted objects in scene
-      Graph
-        .nodeColor(Graph.nodeColor())
-        .linkWidth(Graph.linkWidth())
-        .linkDirectionalParticles(Graph.linkDirectionalParticles());
-    }
-
-    updateGraph = function() {
-      updateRequired = true;
-    };
-
-    function addNode(nodeId, displayImmediately) {
-      node = {id : nodeId, online: false};
-
-      if (!(node.id in nodesById)) {
-        data.nodes = [...data.nodes, node];
-
-        nodesById[node.id] = node;
-        nodesById[nodeId].online = true;
-
-        updateGraph();
-      }
-    }
-
-    function removeNode(nodeId) {
-      data.links = data.links.filter(l => l.source.id !== nodeId && l.target.id !== nodeId);
-      data.nodes = data.nodes.filter(currentNode => currentNode.id != nodeId)
-
-      delete nodesById[nodeId];
-
-      updateGraph();
-    }
-
-    function setNodeOnline(nodeId) {
-      if (nodeId in nodesById) {
-        nodesById[nodeId].online = true;
-      }
-
-      updateGraph();
-    }
-
-    function setNodeOffline(nodeId) {
-      if (nodeId in nodesById) {
-        nodesById[nodeId].online = false;
-
-        updateGraph();
-      }
-    }
-
-    function connectNodes(sourceNodeId, targetNodeId) {
-      if(existingLinks[sourceNodeId + targetNodeId] == undefined) {
-        if ((sourceNodeId in nodesById) && (targetNodeId in nodesById)) {
-          //nodesById[sourceNodeId].online = true;
-          //nodesById[targetNodeId].online = true;
-          existingLinks[sourceNodeId + targetNodeId] = true
-          data.links = [...data.links, { source: sourceNodeId, target: targetNodeId }];
-        }
-
-        updateGraph();
-      }
-    }
-
-    function disconnectNodes(sourceNodeId, targetNodeId) {
-      data.links = data.links.filter(l => !(l.source.id == sourceNodeId && l.target.id == targetNodeId));
-      delete existingLinks[sourceNodeId + targetNodeId];
-
-      updateGraph();
-    }
-
-    function clearNodeStat() {
-      document.getElementById("nodeId").innerHTML = ""
-      document.getElementById("in").innerHTML = ""
-      document.getElementById("out").innerHTML = ""
-    }
-
-    function showNodeStat(node) {
-      document.getElementById("nodeId").innerHTML = "ID: " + node.id.substr(0, 16);
-
-      var incoming = data.links.filter(l => (l.target.id == node.id));
-      document.getElementById("in").innerHTML = "INBOUND (accepted): " + incoming.length + "<br>";
-      incoming.forEach(function(link){
-        document.getElementById("in").innerHTML += link.source.id.substr(0, 16) + " &rarr; NODE <br>";
-      });
-
-      var outgoing = data.links.filter(l => (l.source.id == node.id));
-      document.getElementById("out").innerHTML = "OUTBOUND (chosen): " + outgoing.length + "<br>";
-      outgoing.forEach(function(link){
-        document.getElementById("out").innerHTML += "NODE &rarr; " + link.target.id.substr(0, 16) + "<br>";
-      });
-    }
-  </script>
-</body>`)
-}
diff --git a/plugins/analysis/webinterface/httpserver/packrd/packed-packr.go b/plugins/analysis/webinterface/httpserver/packrd/packed-packr.go
new file mode 100644
index 0000000000000000000000000000000000000000..4241a1363e26fa3ef3ccb451ccf0b00e14fb98f8
--- /dev/null
+++ b/plugins/analysis/webinterface/httpserver/packrd/packed-packr.go
@@ -0,0 +1,38 @@
+// +build !skippackr
+// Code generated by github.com/gobuffalo/packr/v2. DO NOT EDIT.
+
+// You can use the "packr2 clean" command to clean up this,
+// and any other packr generated files.
+package packrd
+
+import (
+	"github.com/gobuffalo/packr/v2"
+	"github.com/gobuffalo/packr/v2/file/resolver"
+)
+
+var _ = func() error {
+	const gk = "4c80c379ef2b80415266c114d9f8d6a8"
+	g := packr.New(gk, "")
+	hgr, err := resolver.NewHexGzip(map[string]string{
+		"166310f2d73113b478111b0a976a0eea": "1f8b08000000000000ff9c57793494fbff7f701b528454f6a6414d0bb330c34c46b319141a63494a356661304b331343ca9232527675254b961a85b2e5226d52e426a25c1165c992352d971a7ec7fdd5fdfeceefdc73fff87ece79ce799ecf79bd5eefcffbf5bc9ef7394f1cd5c55e4d554f150000354707320d0000e6f2a5020200403090ee0e0080aed8ce4becc6678b43e842164060f27d5960472edd8f4563d199a1479b593600a0c4e6b87b89bd9c9db00c3ed79cbe8c31977005c0f2b2d92511d019812c31d897e5c7e1e120d375f720600e1307d98772863b0b482c7f8e439890e516e6e2ce080b646098905db6601b0956c2157059623a58c20de289b0121ce42f5d2c4f845dde8641c07f41c48138c8ff1ecacb990a26f1852c30cadcc28c014720c068b439c2128546237680917004120647c2e0683384251685c622adc03f16c4166c2364b2b13432e5472d21938d83f88bc5022c0c161212621e6261ce17fac110180c66590389341332d966a2509e982e31e3898c7f2a9059228690231073f83cf0f233dd977f4c8c83407eb6c015383bff2dcc13fd308ac1e7c22474010c610e8771b9b09f689198c662ff3b5ae41e2a60c1682c11ff9890c1a2b1d8c6ffa7d4bf539781026767ec5e21c78fc3a30791f98c635c164fec48c641245c813993c3c492e0d61696240286802212ed3008040665412158a348186b22dc9a6205ffa9f14f5c0ba2350a498193ec50966404c20e43b023910948b21d91444121d094bfb98e3c9198ce63b07e7239ffe112ff958b25095974315fe8cee707fd4c00d59f2fe68bfcf90230c90d0d86eee3f098fc10d1d6e5d7f3e3a42c212798c5a408f95cf05ffe6239ff509f648724a0911824c5924859eedbdadace92842120890822c20e4db484fce032ff1bcf60b6601bd8ff0bcbcf2d1a99b27cfb77f46dc1fff978583c260e2284ecb2456c7c1a0100aad71cc90477c9eb091f1f2783ae757d1972852f1b2fbcf94c73d3d5dbd2d4b6704d637f00637f952fd3f4d9814ec87ed4f5dac71f1999328f02879262cfaa8517b15f1acf2b30b679941ffeded95975c3ab64d89aaad963b6127de445658bf98e6f4b4b56f256f6556f2a42837d41579828c6357c6eed3d3e15f2bc6624fbf894615642f275697e0408045aece8eb9b82673ebb1a6e7b737bfaee4bb23b6095dadd857983d6a5bd9d9deec80ca733be653298b6eacbf09219aaf9c563eab1f96fe7e6074043f506f18dde5cf401739dd52e8f078faa3b71cee88ab3779348a7ba0667c56834baf5667171cc8b31cb9bebf0b2ecb7044047f9b28b9f85822f79f39a4b7afafac7dd185ae6e08cbadada430a16bb769b684d1fbc77527e1b84f268895bbbe5a4aa6d8206d820ec02909efe48fec8b3dfd2dafa37c6c1a400c38d1bf9163aab2903efde3e3815353535158707e7769c4d4b4c4878519818135d701a682760ad470f2fceddd1783ed90b3479c4e28df6b9dcecfa905b2b79f144676fc152c70baf56d20a9187c6fd18a3b0ae5c5643cce3b566fafb6411eb941463623d3e5a1ba83f47e48b4680a8b36a1448f25645135b14eab33c08fd6d73e045c3fc4f0db16b22d4a82e49976a37a89ede761176d8bc22b81b71c96573ea4646244c0b6cf7ca68a70b0b31761b97d4404c7d23cc53f0d62b48372a2eb229dc818cdb1097f86ca69c8b87375c4c5750fc7562f6a0f935e30d525a2455d7fd42bbbf89687f7282697d6aaf6b5a9349bf34c74c41f8fe775d25d53181b5812de09a96baf23a74b344f1bd8665c9af898dbe7b1c149d67864076e27d495e1278e2383943f1e9fba16db17d24eea9e6eb9ad33e4e85b4bd7442ba8a06c6342633236336d4263be7ca7d05787a5ef3af079da8ac76b71515dd0715ffe0e73fe853300e3565f7fed2f4e8510cb7ffee897e5243fde98f9fa039c64569f11b03f493d6599efd66456d7dcaceee51053fdeb2373b5c572dadf117b656d388abf4960fc804b7eab3fb2daf1d86b27065fcd1c1a75b0b7b62636343af758c9130874f55ee6c3f5ea4bcebf4183fa5a5e37cad9b6e74cfe4a24a0aad77e278b5a2038bc532958a1dcb5598b79113caea0692c691b9faf657af3c15496713defb838d1d37466ec8d583f9d4054f5ef8dd2e491a936c8b89580ce754f48d9400448de771631126b12257b1d6c995290f3b70f3e2f12301aa26a793b4de5c21c52ebe7cf912b5f59a1badbccfe19823c3dea77807e6727c4a40b46ae79ebb45619ac53bd41917930d5276634cabf35e856685490fafa2e21cb82e8e879e48151e4a151e02f44740f73a930fe525cce3a91bed2f4575c4f85764bb9450cd72aafa401849fa0a8d222dcb95014141c5afe75272b6673ef3ec601b047a839bf73819f90ea4ffa92df7bc2191dfc96d5254f1002c7a37bb4fd839691fbecfdcee57d12d39b894ec60b299f3a54e1fd8046f3aaf1e37ba028c7b5b455cf9953db378ff08dc29aaeb61b004d5b4c9b0a1a161a1afaf6fe4cb44f7dcfa6de1e55428d5cbef21af3a316db7a990eca9db8e75251dae0f7b193adeb97517b6e703bba21b7448ad92a75432b3b3b23171b6225aefb1c6e0c444d09ecda9f3403debc13bc104e9f45eb49555ddcad5351b2282b534a8fa05773b2683ad9415a30e5ca1fab7fa9669df39345d07402b7c9c6f71f1642bfbadebe39fe5e62d51606521c1c1775ff7f52da67846dfae1e6573f0f9736dc07e07f91fcf32adfaed959d6a0e96162e2e2e965bde9a96c5fc295fd4daa669d26ea8af2f72f32336fef686b9bfe4d2f6993bf83d5d381c4e4176ab3b2a4a212a32c9f8fe81f53e908cc8826c9971fbc0b9d2d6433d6199f59543abaa8aef09de45833f9ac587de8c11f657e16d48ac8a0cac280bee1b09c777b20e21f19d96d4dd9efaf37169de2f0a919d680e4ae68c241fb03daf1bd13e26f6243816d2ca63d25fb5ae15d618d48408037ab885b53e6efeb27064467833affa498967a081d6c711df329d8bc605eee268ac4b8eed09e4faf8132b724394d26c86e3dfd9af4e42dd0e5fa1969e919525bfdd321cb64e8b68d4cc07e392480b140ae59c7da2d1e4e7b0fafca473a0c8078d83b3d052c5d3c9d7e9dbab2e019a79eda34a0e8f8605d64179d6fd0909096bdef0be469fabafe68485d59a66b92c81c0969074c192f6f052fa78ee1953450f00a25e9cdcd8d8d8e3301dd75d5817326d9eb333a4146a3cda4d861cfdda9e6fffd5d4ec8cb6a19eded3cea9e1235ad18f67bec97565e79cb846a6b3a3abf7ebad6269cf66e327eb64169d81a2a4aba0635bd53d9b439b2b82f714b1a61ad8e341be4dcbe176bd78881d19aee050d47a55966eb7a5def14062f396aa8c26dbe6775b30f282b55d43e74ea6eda82db9e05a51262bcfb69379e3c9a0add2e2daf964452564c6395e7d56695e4f5ead0bb7ccebface0ac0b7900a756faa81da1fbcd8b9890a4a444aceda6a575f4e47303640c767748fe5f7bf40500db2d741035ce39a0b6891eed53af690645bf84cc3d5ab57b5819a158fd94bfda1d24f56c31be21b471e0c554f04d73d0b427f18c30c2d29ccb7f47cfe72f689c278db561bc97448f20ecf1b55e7cab5a0733087c4ae1bfa18f4ec84e8cf672d72b9fc5bfb832fa9e24d39fd2e7fc80622a510e777bb0ac910cdcb3939fd394e9b238605d690ca28a3f98a0f9f7bcbca102db3834f0ef7d4854cc3e25cc74b9af6becdd8e9d0221cfddedeeedaf1ae21f65e02f26402b2f81720ec7823bb62be7d70e3cd6ab470f8e9ba9632c6930425e9e1dc7ceb077ee67ae74f9e5dda56bcc52340b14011ce265e699b6694fd7a8c4ebf3231376f4b31762add5067821c528d6de09694940c1716161eff2de753587d84bd71382456e45a7c60b0b7f7f28af1e9eaa483abfa22548edc91524a836e69b03333329a2536d97ba8856a49a536f7bfabcc2fa56d37dae3884f696969f99a34fa9df23477a6b1a9ad8dca53cadaf380ad38293d4dae5f155773eece2dadd6c6b1b1b13582bdb16bbf038c275645bd6ad9f1574ed5c77eb27ae3a7ccdf6d333c6c64cf547e34fd75c4f5815d514aca92bf85ba0db6360af4bab5d5656aa0317e486e96b23ba9e5779311885e44f2ea187d2b9e25f1fc6bf4f81bc8de1aef6b439e92d7b3841375ea361c5cbde7e926ee544262e29c4e9b73e6093e2e2be57aa6ceaba3d5e9dbdea85c3f8fa597aea5acd6a0acd600a91883549462349562fe1eb1f4ca339db777916146330fbb9a9b9bda073664ed837ca54df080980b24681b5e4a8618707fdf273c1e29fe8db039f5cac76dc29bdf397a1a47cd0e78797b2fb40d0bb32abc4b4282d00708cd3ecec05d9dd5a0e9cacacaefcdbceafeab70d3dbbb982870cb6851c49d88a593aa69631f3edc80ca88bf44ca3950ed5acdf39441434343ccd572cf1b6b381996508582211de19789fd0b52fc25dae4751325a61ab46a95dbe7c5f204ef81a4aa85c9871efae1a3ab9407089c75b534f74dc97fbe5bff2c5ce6951ae9f04a036573a23b125bddccdc2655e6bf870614d6d4d42ce89ff58a7b3278f624766cd51a15b5bbfefe58c19ce262f84981809a78af4e5873d9d6407de997f9fea84f6d5dea46830bc1d8ac562db013513b2f3959f3446060e0f36463fb85f63f606d21e1636bfba2f060657ced79cae0beb14c1adc0f073cc9adeaa056e9f411b246a129f99ea92547951a93fbba4eaca7374935f37d48063dca3273dfa9907f723e7279862e8f511d043e5849be2f5201703603e3e232da84cbbf828e762ee452e291e8ff090000ffff241161e8770e0000",
+		"2f53e054245e3cec681be9135541dbcb": "1f8b08000000000000ff9c544f8f9b3e14bce753bc9f7fe7e06c0e55d5029736daaeaadd54bbabae7a74cc039cf89fec076dfae92b2024e44f2f3d016fc6e399b145fadfe7f5a7d71fdf565093d1f92c1d1f288a7c0600901a2401b216212265aca172fe9e013f80a448637eef5e6a650c0698c313d24f1776f05dc54668f51b43ca07d6b0422bbb83803a6391f61a638d480c68ef316384bf88cb1819d401cb8cf1488294ec46dcba607abda4231cc4a20ccad374f556b462983288419e34b691b7aa155510be9e2f92bb65b2488cb2c936b23ce5c3927f5235e24a25e5437fb374e38a3df44133b611725705d7d8e203fcbf5c2cef96ef3e8e410ad5822a32a65de50eb37eeefb69df1fcbefd72f5f1e1e1f57cfe926e44fabd7b7f5f3d794fb095d990aa416311e94cecd2a53f1cac5c4db8a81d094b1e3c18d3e78a1da7c76eea9af4c76f96e80ca96370c771b367d25fe0616509833c68932ca461441d66f41787f34774a697d4313daf4fa30f05a48ac9d2e308c04285d00eb0a4c92848168c84967bc46c28cb9b2bcad3f686e1a226759bf9bd428028356e806c7af1c4ee6877eaeb2741bc7b5d5cae231d02d706c78daf3b510098a9786fd117e282e4a9fe0cafe1d730d5d9ed629cde135e5dd6dee6e35efff127f020000ffffe59390183c040000",
+		"853579e9f8c28c5a0ea8a5ed642bbad0": "1f8b08000000000000ffecbded7adb38b230f87faf82d6798f06b04ab424dbe90e15c4eb244e4fce3a4e3671cf4c3f1a1d0f2d42123b14a006415b6a4917b03ff70af616f712f6c1074990a2ec74bfe73dbfb63b8f450085ef42a15055281c4d333691316788e24d3c452d7eff2b9dc8162172bda47cead1d5920b99b6dbad8c45741a331ab58ef2c4058fb28462f3e35b5042111ed224a59e2a2f2fbf2cd194d26e9b5f3f5c44d87ca2d118a8c9ba790885c7864d753ec62ce28f178c988fa0096696f0fb30b960c47c34c2a43499b6db8811f58181f97f8b1f42d5f6dd0e1583823782ca4c302f8ff128622041e04d11c35108991ebc23390ac7e68be92fd58b94348c81a0bf65b1a0edb6fd18aa3c59bb9d625b5f8a4238ea61151fe771b18d53a54e09a38fde95105ca0d6db90312ebd69cc223b25de5f5a9db0d3fa4b0b0fe55cf0476fea4f784449ebe3a7773f5f5fdddd7cbabd7bffe9e79b772d98ee547913a2da4e36760e83cd6e37547d18f5c6fe244c1234c9a7175c8c515925d180fdf1888e87b6a91cc90b1950bc830994392998b1db592855659eb89b72815471f1f78c1784a4370c5f093fa16c26e7c3b0d3c11c0935e845137668d30f46656b55e5a6c58250d46233112ee7be0859c4172d0c9c6c92f0f7f5d54a521605fb185066595031a32dec87cb65b246721ea7108a59b6a04ca67807a6c40f928a5072d15092f0ab20b620d150ca13b91b73d107f511946d35112dbc1b72ff271543360f54a431670ac83fb101ffd7b48541677132ebbf2d0c29157198c4bfd386de6c121e46ef055ffcc7d74f374edea9e08b5f53ce5476c905bde53500c94df26e0713caa4089358ae4da32e931917b19c2fd29332c934912fd598c59ca57ba06592ed0d6d1abf4dcc2415299d4855c0ac08b53014df5f6caa7ff2b38c93f4a492a00bdfede091decf1203f5777affd3f5898e3055ebcf0f6c99c9ab62422a604e5ade5876105f9c09c9a154134017126c1426a9af8f210b675498ba74cc492da9deb8861c7b89a6bba00722d844229cb148f065a5963cd294afc8d05542154a7ee6692c0b5c3383d9906cf2c97891b7c540ea887c78e4bb7841595a2bcc8db723499d113740f7e1e4db6328a2b77cb10c657c9f5067e477701daeb91ac7291713fa2e16742269e462b28a4f34500bc384b35486cce287c97b9247da12ff16d3c760734b573213d49d7b69a29c79b89449b88f1e3ad69dad4538a3373ca29f059f8970b18f4f350027ef75ccbe1dcae6a439399eaae8601db4a970b7a75f7fcb42b10f65a2eb7d6deea003a569593cb143a706fca4126f40ef749cc28260b30c454adff2840bb7f032d6ce5dfa306b28db8935250bca222a727cd53079940198a469518eb3a4cd6eececdd0e9c17a75e4497824e424923dffb9cd030a55e96528f2711159e25d61e9f7a0ff143a8d1d343afbc9eff03f6e2a9b7e699c7288dbc58daaea8e97a1f4e2417eb275b5105fdaf6ec8842f161953e4fdc991c8a19ea8beac4d5756ab0b3c2ebc7fcda55ca6c1c9c92c96f3ecde9ff0c549c81ec26fe1895dd069b20cff6519254dcaebf45ee4645e0da14a48e3c532a1e9c3ac85e18de08f29151fd89457884c196d3189150c31dfc1e6a96d2d387d014fed65c1e90ff0144d0f4e7f84666a1c9cbe84a7697b70d6836642169cf5e1bb686870368043e3109c9dc273a43f383b87c3143d387b018777e2e0ec07d89bb7e0ec25ecef22c1b9eee9de5a0dce0770609d07e7a77090bc04e76770808e04e7e7d044f483f317b0cf2f04e73fc001fa1f9cff0807086170feb229a946a08317bd3a5495f5085ef4a1996e072f06fb29df2a659fc293bb43f0e20c0e51fbe0851e2287ff0c5ebc80921f0b4ea1c6c3062fa1694b0efa7dd8633a837e99dd619a82fe195499dba0ff02aa7c7dd0ff016a8783e0b40735b63538ed43411582d3c16e0c83fdc346714614283ffb14074a32dd6e51c4279a77f7c328d273721da752b5f76213465110835804e12ed0814c05d21d86a9822e0adc3907d1ffd24ac4a2a18eb8ac83ee9587ead0a10b2de8823fd0a733646586788a04dedf24cc51374be9db70a996951733b5297db86ae121f54329c3c95cd7815a9cb53a6a1acae253b73d116d82154ded241cc45e6f897048bcc84fe55992ec60b31bc3e9f7a0037088418b0fb4a800a63081081258c203cc61060b58c30a1ee19e6c56410fd6416f979f6f5322ba0c2684762524441eb32e3d163023e931ef4c8ee34e020b921e879dc971d649a07744c8acdd563f8b767bf69af40859bc266717aac1019a92ac1b434478378425098fe32e3fcee0814c8f69273a669d25ccc9f45876a263d159eac21e4c61f376fb4117367f4d7ab6b035498fa3eef478023d42c8dac6aec8fa55efa2bb3e1904eb9301ac480f1ec9e478d98d8e13b8f757043dbeea5d3c7657c16367854fd6f048a6c749373d5ec2bdbfde4bbdc718ef9cf137837eb63fe8058c1fd199a094e84d3b15931313361b7d09754fe523a58cd1342d419dc83afc24e129ad42175175583ad11b7f3c89e5ba0477632defb069ae37d03473af8ae005ec7529f8010e141ffcb81bc3f973d8e98425a278331fd1f10919ec5c281debc7d198f42a54086f52a2e2214329861855e80756072d44150dbf0a2773b565a0100f27b928c7a46bf91f99f84bbe44182441fdcec3888df1c972c4c62048a47e38e90d792904ea74b859473111233e1e3e8ce271872c47f1f858eed8112169bb8de62336ee105dd6ae42a8f0e661bf3319aa0d0cdec44841e15a874d7b55ca50358d8cc690a8df6e1f548bdd3263059f8ce89810d2edb7db487f27a370dce9c3d45f66e91c518cc1829884761b2d475477271c4334a263031862bcdb1f4fae72cb31e9c152fd14c54a3c9c96e3acda1c92a99fcee3a9446a0a6c915094a6767c1a993902010cef769650a91e4ed49f887cd222637f2268282952ab1d43d218bb6c8c7d688c9d37c5e6c4afda5de1b438ef3fdb6e6dfe6f749da239ce0190c430dfa71c2ffee88298ee638bc68fd0a07eacc691a30a9e9821a7c46d588afd45b844ae503527f0233ade617f1a27928a26007aa410688741219e995590446db45136a1c8ed4e99a7c37678285ff72ea6a3704c10ebf6f1890c74a082a37b78ef60786a30fbf012d00016bbf577aa96621f328361ac11690586d4206d56606b56c5d6986405b636e1680cbcc0d11032859e6923724dbf1fb9641db90486e93efefcf087f087e5a273eacfa8543d4811536465988d98462b8124e818dd190159638be3296204b1edb675cfe5bc857dc9aff923156fc394220c269610a22062a6d86515c08284a5862666792437ba17ad06ca64eb48c5ee716057aba5969079e519d633db8ef72d669117a7811733f07826d571dcb46b2848bc3b34bc598d85cdc7a6a7b52234577fc861be3108d21b8a5739ce0f4587f4b1ec103a12635ff20f91eace453fe8e5132a6bfcebff5405ea8cf16415a1bb442ff24282de3ecefcf8df48737ac31ad5c9c961d1826258d48a1dd257b2dd469448ac0e038a3cd0ff9f3cfc79f2f0f2e9a9ce87e770b51bce4ae9993e39187d6da12b2b149b8da7a624b90f27dfbc38f568be7e25f7eea91716aacd96d12cc6848d64a1c88bb75b6462c8688c213643bfc90b0c044ce42ae03b0c74077c3aadb4d1f48a1347fd5a68f4a45a7b3c5f7a8d3d07ad165575e7d3dbd45ba3228d684225f574d33565cb9772a81b0f19e90db35761c92a66381c6546b7a93a420811ed76e8a7cb249e509441bfd052d21d4c63419d9ee55a445d9b222122ef07d543c887854ece56f85aa13a279742846b7f29b8e4aaf9b636a3602db2401fe361a90ded0d6397c58d73be4d8ce2f1302c3a60d581a13f912be04ee377b5756848de3e595747db78baf6ca13b6370d9374ed198b002f4c3d2388f1d2ccd80894ad6464a44ed0d05203d582169f4e5b63500456be6265db258ea788faf330fdf4c83e0bbea442aecd04ef37e8aba9256fcf3d35d5c7d39846e0a5319b502f965e98081a466b6f1ea6ded216e9fda5d551a56a05b8b3165d1e4a8dc5d0b45dadbf7271734698cf19509f4fa7ea733a552b3c169430fd037467d674bff7fc113f4795d6c80ea34681b1da712dc697d820f95729623633f820f5ee2e701513a48b0956e0338ac7b886f45ecc3c6ad3c37d1191c682bd8990b846528ac5aaa7c88cd050d382a2dba5ace981c791d73b22445c20aa60d47121505fbbdd3e3dec37a8e69db16b2090eef675d3bc7d5174a38e850cef6a32a87c1ad4889a761242241624377729c809bda081dea30a2b144e981a28b58de892f482cf09d75010eec751bedabe8dc4b822cc2a46e74631f38e1c0a6f1492a1d6641eb2198d5a30719a3c5519ef34b2a1562ac3fb84b6803a0013cd0cd8c936cb8cbacb2cb77250f4a915468aec12e19bba6ed74b7a8184cf7844dbedc47e294e13849fc4ec5bbbfd80cc17c641cb48c3ea05b4db45094bfb55669f17d9779f09530caeda18d3b73c63d2654e2284379f490f5865ff74176962cedaf0b943f439c7ddd3d1835354521aa3a891d6735492e9bc096a9d1b72bd476d6216cb373c5a23ec3d86a9a756208dbcc758cebd8c7d63fc9179aa935e1cd96d9213e12fad12c3a284dda46648e0212757aad637349537f451959c6b3c508c77925cf96114a9e84ba94eabd28f234241b59d4858208a618d046eb791f4e3f473cc188dc851cf15592cab4c15a89eb3f150716dea434b22c16e8b7a595c59c9a6eea6c4cee83da8a2168adfd2bc2d560dd08c744e216f4679da58d76352c7204c3fbe2e15d9d2c2dc1c0df1f057444160f86659565156372f27cba6aa016c9aaea241bc126b9a26daed05121a3fb8fae4fad3f6d8165c74da3651ba23382b47706450866abc2d8cb0d8b05c631f4339f717314316263f700f3098d3821c763a05c7638146620c31e1b61b4744cfd4c5cd288f1907ea5b8fe5306eb7638551ed36334c565c6ce2ac6cf3a26c738ee8cc5f84694aae15d2dc648b7b2afc38bd096f6c42c3d6aa86d153695e3ae75912193e90e9bc2d072fd6ee49469d060a5cdc6ea91f85326cb7cd6f91e0e45ed59a9a7766bb456ab98289c6e0f4eed1b1292b0fc6e5ee2c2ffa9d7c073c390dfa3b6d6ab7df41ada6f35229b289d611943c44c9891adcbe774cc196f3751a4f523f8d1759124a2e5a18aec8bd62f1afc9a35a590d5ba3d4c4ef6398a6ed36ba2665d0947fd3c8d87e239b1d28d2f72bb9f2532a65cc66a99f6a1cbd15214ba75c2cb65b3e8c10861499a22ec9511feec8269574e92ad2e32952dbd9678bb547bda139f15df90a12e1e19d9f84a9fcc81f28a1506e2b74d9cad7373df90c92b057c4eff5f3b1be3c224411934b2241ad4e0c7207760d16763d0d522935ed0a8f77903e016cea55b043a646a0d0071b3696c11eab7c8053862b3f660f611247a1a46fdef015c2ba995a5779b8e66ff9e2b1a3b6510b32607a5daad683e401f325d73dd1056a9cd29602fb165a86d6dbcaed1ea5c86c20601933350841551a67707c65b6b7a14be38fd80ee2548f9b8e3930c42a5f916b07519c2e794adda669ceb5c26014736fa1a396192addd24c7d192a1984502c81e0ca5a0532c891c8d141c5e80ec35d55dce0f27a8eeaa328f1e905678fa00d068cb0a9eb83fb03385c52d07fa9d8cc06a56c813ea3b3f1e8a5b670b5969c1553ca4d942d035dc67768f272fe9211b6dd729044aa1f415aa9e6e81d73ea8bfff8fae9c6d7e60288e2c01c1843c8488c70853d353c54badd3a318ab6a4fbe4cedaff263c8c3c631da318179e494f17e1852cd2dc4b6a8f6cb9f1ac8e2bf9c63037586696a54bb53dada2b169fdacd0528cd021c2ab392545c242e9c5a967d767e0dd180e4ac52de2345503838799e220f4c69e2a3626d5fb8911001546bece865bb6734aa46534cb764ef7da6936da16de6e1b12d5ce7bb81baae8fd6ef8de1b2ee79e29570fad2ac50b05cdad94a3bc579a4d9ddabd1ea67aa387a9eda05d4259ed785e9cdbebba65775158c35c674d14d60c0a611bb4a0eed9aa2e55d49ccf764b5ff5f647e283e9b4650e3c7516b488a4491808c290412a7b0ce9f6f5094414fd97203b7d0c6504ed48a09d5aa48e2af67907b8db87c131ed2ae09ad0f3cf379b11e93015aca8ac07baa23282e675b326218aaabbbf5ff7a5f4121aa6d2938fdc54ab91a390bb4db9f0267cb1d47caa9dc97c3415a35b1d4f3d9a2a2c88ecf48742c7082c8fb4c08a3b03281cd3f78abc5b16ed3d927abcb65bd9346806eba3c2fa4a37bbc0fa9bea506a094338997bcb50c8d89c6a0b6672a6991de1c979c8bc9eed9e367628ba6745ecba332acc091df257b423b51a372efa258017fd8a6b42f6ff1ac4150501ea6190a45f8cba839ddd3e38d859b557b1d294577d35ac0df870a0256a0067228e2a28508e513c457d42086db7fb46566187c06d6c7c60247b43fe4a96eaf090880e3fa643f1baa7ce1879a74210ddbe4ac0c0f7523a8877fbf89816742aae5ad1e4263a79b7b75bf127fa7e5ae9bcb58569eabef929c4ac993b0a99bba7e9eda11c05aa474185adf8ac94a0a6243ca6c712a68477e263da49877a141cc20dbcdb374918e2bdb40e8af508a9d4703f55e543a18638964dd47e6a31f88f60af1ab7fb3009d984469e149456d119b839a62ef9231a0035e8dd33c35862793fc7725eca8a6222212483e31832f557119aa23731842ea58e212bba236a22a943dda9d38e9252bc26057d68d84cca6568752d0d4b30324b704f7156958ee99278595287e1611348a90174a9ad43663b0c4487e19dc1fdef99b94912ff96512dfd52f36783b198246afae229fa4eaa61327e8d7fa70dc5e4edd6fb071864a71ad90592101f4b8bc2654fe2631ddfed97db86b311f2bad84eed82dc15b859eb3563a8f79ac806b674ce794abd7411260915debfbefdcbf73eb802fd2414b37c97a863fabfd8bf2c5e849041da7063cb7ea078bb3d1b609816c863488134a4a098f2b01ca4895926d3842bf2793250ac4844fac3e8d564d8e944b85e484650d409f1bf4b637a696964660a7c2a633c45a9cfe84abee3d97d42117e65497242c26151aaeee592184824313c90252124d96ea785e43981a5391eb4dbd352329260cb152b1ad9ede30967326619d50d1b3e0cf1f794aa6a9f133752f5cccacd74cc1c3b1d5779f2f53fdde597c0c228a22290903336012f3edfc48645a0410c39f17a13b35b416930856528e7410893584cb22414d7a620016a7b508752b54b042930ae7b1c4ce0319432fd2a059f85f2f720017721049151eef27d5e79e8f0d3da3ea838994ecda507ad99386c1c9c9b02f7cf1587fd8cf95c2e656859991a71d50b1db544de8592160c287df43862759332398f533fa534aa6adead425f553a8cb8c7c8e05843ba68a6d89503f194b063d691c772f8388f138ae86bd2df6ef5265172c4c77a7da4bf0989ba031348f80c517c422b9a95dcb8a0686aa14623b433e80f7e78d91f0cfa671d445fbdea0f70fb6cf0f2ece58b1f062fcf819232d046a7a767e7bd1f063ff47aff49ff93be7efdbaff12832ae4f487b31f5ef44f5f9eea32ce9f2882764ecfcf7b2f4ecffbfd17ff495fbdb2059c0dcefb2f5f9efef0f2075dc2e9538de89d0dce5f9e9dbf789937e205066716000d5efc78767a7e767edea6f8240fbc68d6f83824666f1e8e69dd28b97226b3e8a3982cbd924bfbae6e7fc85ef786dd2ec392c46669337d92d2ca1ed08a373a62ea8b8d8928e6c3c5ad5cfea408b8dd6d9df2a52e5f629197af4f6a5c1bbf80fae3d4c481218e8779ee769b213aea8d8dcd524cd8762b0c2fd7a0b837a537d82a64a9e48b2f7ab97911a7a9a7768b452827f3f20c75f9f943e0e9d6e1f26a7645ac908bf58c302ee090ceb3e934a181dc1d90509915de1095dfd32529704722a9aa27d95e94996312561232164fb958d462676196a671c8486c95a2cf18213a21869c002d2591bff9f77416b39f97512829794fbec16f3e65910dff443ec31b22e11311f09bd674432e71fdcd157e19eaa520861acc411f69b0f58b35044962f62da0506a0603e62a5f45155a6ded4f404f0cb42b056bb054283823234db23601a28587efada45c92a8a2344052cb5c08834f48422bd383d1c23840525fa3374661f0b5d331006114b530860f461bf713c2202bfc6631da1f2a5adda424fc51ae6acce5cb477da775cc48adacd6cb86b4c2ae6681e668fb055e203912e362efb58a2ed504f8daedc227c420d7d662dde8a35e455b68f0296f85d06ddc6e15df0e9c4488e90053cce3cf16381fc1db5c210521121063a04784b0763b448a01843728b663a6ab8d2b8a45d708c2503a77dbcb1aae98cc9b3201276febe23ba187986fb76b0d82377cbb456f1585eae572e4d6ffdeea789d8e8a1ceaa23a31b08ea3593bd086596d2a73f00b3b5981bee751d5cab9b684477d2b68e288c2adb1d37cd5abe002dce6c6460cfa0ede163a4f3d43b9aed3a2b27658a1ca94565309ec35e9b5db36e896884114d0a20a2d9aa0df20fa04feac1dbd85699955a56fb747a2a635cdf1d89cabf6c4b7325792e6c25b6344c54bcb4aaace29b921272e845a4ef9ae9651e3347c6c321cd8e98e34e81715f3d46cea42b1d9717b20c96dde68a6f9798629bad517078a02efabb89a0f8b28c6b8516758f4495e5ce7226c50e31b5c5582653d57c57690d3077bf981365c7ea0233e8690c4aea96aacc733c8e3742389441f46e118625ca80e1dedf8f51fad521be23975b6dbb68ad85a0bc4b8b1a21b843765e81bc29b771de2588f7e56315dd2d7b789deb5db5f729bba5ebb8d7eb32aad42cdf505430e407ace08fe5aee918e25d1c565e0a8af2e73273887d0a262a4a92d913ee043666ee8c3888de478ecf4b9a8e8eea98aacef1b8d86eaa4ffa128ce2d6b4709dd6e373b68654c1d80d4f1e843d48a8da67ec259ca13ea3f8682554f4281f755aae3189b6915467195bbe7f7cfbc7fb965fdab760ffb9fece7947aff5a64898c7551fff2f8d2305e2c95348cfec95ad0d27f6eb8a48127e75450554898a4dc3333a43a14d1699825d2bba7f3f021e622f0deab9630fee8f1472b55d615fc93c5a9a7ba1247541416ab8a1d0cbdb219defdba2812e9cc349ae97a4d6fb0dfc240fd3203d1fc58d14f0c25b7e140697b0727d39125d21f9afcd35494fc170d2aff60b3835b321ac35bb2d9c157d28377a4071fc9af08c3cf957a2fe6c1037c51a06fc80d7c2237f09edcc04fe4067e231b2bcc0826608fe3c112ca837ab0b0010d93e4dafa20828a30a74181fdb5d0991f04c989610919ccc031dc0a3ec29ec57570efc6058fe030a7c17b2818d3e02798243414c10aac142258abafb2f526ae503c4fd16f1818c2f0dbdedd0197ebeaf68d814ccc22bafa342d76a83c22b701d5a2c77c013b5bd75076481f5b2364cd8d165705f20af6ae16e8c39eb6e6d25f256f67c28611ad5d91c51b6b3074915b175943f8c086c9888d1b6fc9ea322dcdb535ea8d9339b549c8db24f64e9d85d96b6e7c8a70a7f5fffe3ffff7ffe5b53acc89dc53474ebf4f47af15e8df713746cf829a2cbadd224a363b0c4c935c2d33657a0e9aec557373abbd24885de35508c911df6e731a3b92e32342e26178a18fb10a22283d9f9158ad7d6dc2aa7fc05828ef9a54b3f6e0f61d3739f41c2c794a8cb84733b5264ed087cf0df1fa92bb8935110f34e1fae6a813a74dbffa7b8b80b6dbb9ecc9316d358288558358ca5f5d507f15f44ca1eb2688f505f5d7414f1d9a0e9572419f28815db0a0b77f93bc3630f6c678c3d05453cac1091b06276c1e9cbc88ff85c363207e6f82f8fd82fabfffcf0ee0c1f2e58554c35ba2e6c61a20fd8d4e24178328e0a0624ea320b671a75110ee40b84656a52116a91a2cb9d3e1af483e67fe2aa73a79daba4c5b13b6abc83b044da924ced66207c2f6b8b783f83b1a53e2cc1f6e4e35edf732ed772277107e7f53ed2cf4f29b004f5fef6992ee516064996f39da104d51bbb91fb3940af98647314dd1120f59b73bc494e86bcfaefda5b91d35b12d4518e6be916ba8497eaf52b411b18d44d4de2961e4a138d4a892173980b9115d78c7f34f92f8fec458246ae7780eb55f2d79aace88ae458af5890761c3b6306424460c36a6b46b731deeb40726fc96d3e934f89176cf6026c28758ae836edf1f809c531906fe8f1089d002f9bd81f612f655d26530e8edcce69d116659adff330ba35b41e9765b36e2b72c8ca4a0f45e3bb22b40dff08c45a906345dbdd7112dad47b230ef4438d323e98045795c0bc3a48034767375d8b48c6d618888623b249d6959a20346b3848a0f454a0b43e234335a3ba065640bc352f1880feacf9c6488619891142dd5f6b1205a90b3260aad60458e7af0487a704f36f71aaf8225fc66872a98db69488307c82d51030675235369c5469444aa0e3f9f86423431cb1149df04b3c6ed15e3c503178f149c62d61de3295be432bf0bef947829bfbbccdc3abf56b839c3258e546799735bc07650dac8d72b2a24424b977d542dd0b21d5c94e68855f499755988c767c56a552738284ce7832af128f4aada66a7c1bed91afc8551a4a5219e9942753ed234c1730d2af7363ad96e2349baf63813ea0d33774812bf26bd8b38e8f61dab9b87c22d40a879ff5b2ec3e4237fd07e9c1a0e0a8ff920eef5ad3a8c0fee30e69cf9eb6eff023d5486f0a8870373423386b80d772a9a8c6467cefd8be2ee05b516af6ff8aaa1e5ab761b3978bc52673e98f9f77cb583aa91b19b59adaf5d41bb1a5a52dc8ca21788f916905098fbe6fc9ca24d9e9bee0c7f838302706729e1b3056bb06ab126a75ba88ed9ed4a3fad0cee3184e81ec37d8dafad12c660a01d49d5a85030e8c31e650c06033840db82c12954f7966070060df432189c3fe1ffc96e4141bff784f32687f2078317bb310c1aeeeb355c0eacefdeb9929339bbb51e74d7c8c45ebcf878f98fbbbf5d5eff7c05623f8a17511f6e6c54b81735a46a5bded88d6d44c7c3acd8f52f5066b99cac647e20b3dc4d19b7c601722088cd050e848d5b639b7df5ca90051b2aa25f737d71b516bd7e25b474af56c8fa75d86ea3b088dec5feaa4f24c4fe6a4038c4feba4f84fa1990705f515fb7eb381b281663b3ea073d58ab3fab81fa1a94f6e79b7bbe0a62300b3610a0896be56a84aa5f57db338dd075f75c32f2c41d811804e9694fc3fab6a4bdd8544cbab9524cdd2bc5a243e8281bdbe10e9dd07a284e4a2f1d61f9bdd317370541cc5ff53bcc5f0df0c90042155eabf05a8587c6604dfa2e0b950fc22a101d6e54b529eea627035807613566a7fe2b0fe7a55b33b52abec349726e5ebf14f12296f183b6a36cbe57eb285684afaf9a51ecd6dd5054d0ff51b5a3c154bf6975169e33f6784fd1c0a40e19918af7ac3091bbfc0adfc6a28edb819caf5e7509f38b6cc7b43861fa2bc861d60761d6258d1588018751ab806b8d3170774c9e22676a649ebd80502a667ac015ae1bbc85ac40b3a1bd2594e56c4acf917365a5562635dafd296127e6fc3c4c9d8e77c8f438cdc7079c94b59bb21e1a232b3727446e700d09294d4c26c7934e741ce161a2afc9bbd9c8e424a9d443a29344cd343bae941e5723d6608f831d22ece7ba4362e01d536d789f2281d5022d82854e10f163de098f437c92ed0b7a064f9bd6175edd1cc15c2996cbcf9f563b61c5721385124498c0238d6773b97fbae7173ce83734a7c10ee9cfaf992602dc74f0cbd7947b7e1ba8f35be580f7637e3e8b1b97996d901e22558b2fb93a50dac179d5bb6015621794b4937033b75d996f6b36666d63d6903ad8151e879dec38c34385fea9de9f90a85a45f9e7f8e45cad9603094dc5e56ef8d36e0c13828ea899c8edd67e383d302364e3f1f1f4243da676a687325f4d1d32390e210fae5530035ed22295ca4bb23339ceaa5c5c0ca396535d0b5aeef02992137f2fc969707fa970ed3b3c64e5b445ab1ca9e6c07a41df09f58381131a04a74ee8b4a6542f7c15548a23b25a2091d5228934856af58d2e96c8461f108d4219321b2d8a9baaf402e5956af97d5ea31318b881d33c70cfa375fead6590e6e71ff6f717d2d3f7a4a7da59975ef00afd9744e594922f480f07c84837a7a05a4428864e6701b4e645ae3013d3d7069696e6f7604afa30213d6dd4aa8ddf47bd31590fa796b17c20f16832861979d04d1d4ebb0abe438cd1c282cc14773b9cb5db8b0b24c9cc2e376a979bb0316b1bb3cecdcef5fa90c7b2238e8539f972cd53d66c60f355250e253415878191e478a6c7efd80ce389a2d4c75c9371762c21533f02070b5de98319f213f3eb34de44fc524df86fea037a30f3dd7dd0d38f4ff8abf905523d7bf89e9ea107838eed368a47d198d8204c3ba40f5187f43198a87e15a2bf0f31a8420cf6214eab10a70e04c63b5ad2adb064873a24abfb54d418fae461a8888abfe77c0469c9d31881666a2499f64e201db19cff9e9481f5706a8f2c530cd3d7b1ea9bfa9cbc32e79b0986893dbc4c8c14342271574042c2aeb1918c5e271721e19d288889d0ce557bb0261261589ba52c606d17730c6bbd9c39acf3051d022369b76fed6fd0da9008d53c2be1cd90b6da5ce39a31a93e6c1452232b8a5903c5c3a3073f4eaf164bb9467858ca548cc3cc98307d831342c2cc1ad7c619ea2b3f5bc6b578eb30c21c3121547f713ea8a7c3886f72a6ce457748088a2d4ec706a78f27b024ba4cd5f36eac86021f4f86f9d1d5807592e2dcaa213a4b505468678c92a7af7bed76ad2939073bdd4b31e47a67072786ac18a81842bc2b3cb9cc4968316366bfd6c3d81068f3d309f50fc4965cdb5f1b7d3cb709bfd8845ff28499a59b3dc8bb078fc5b87456ea40776fba0957e5d074eed5c96efefab1dd460bb5b656e4111e89cd8661f6facaa4a8dc577045f28c86f5b82602c5b0c0c3eb0bdbdb6b087180ae35525e1ba45cc1b546c57bb8b6c8f908d739525ee9cf684d42e0aa28b8c678b7dbe93bcc9b1d94a2aa7d55549e74517c050abbad0caa015e275cd8dfc0ffd19e680f339ffd973f9e61981a5d8442652d70d721a322f92ac3c9372d573791e9d77051f81ab04274dbb65c54ae36d409cc896d06cc5474b19087c50331a50626086146e517ce9b049deb1dd4542e410c56f6d624aea317a8412d68dbd86ea38414210c0d90bad1ed369a13fb9d8bf50af161626585f3fcc05f1dac60a09d02d7862a18681ff37a8c83c1cb03dcdfd33afcfcb682aa460daa55ac2d3f44ab9a6fe04299a8eacbcf4686fe54ecb21db524d95842d73007da915359d90ed44a6874b6503670e464180fb57970de18db121c1c807695f49d4eb5625ef7cae124bfee15962365c1ddae5bf46e5f7c551d45ab6b1c34d81a348962ca9e17675c759060fe4a9dfa9cb87597f9ebd2c4f4559f767f6cb785fecdeb6cd06f36d4695b5cee263ae870d045b85f0b0f6ae15327ac0974affcfe871bf8250f6872d7cb8fdacbfc3367a84dc890c05c6b7bfa8cffb6efbbc503153571e1cf9055eebfb0bdfb2fecd0fd17f69fccde7f518538f75f58fdfe4bb508e6de7f61fafe8b2ac0bdffc2eaf75fd8a1fb2fb6112fb07be785b9775e726aa9b8812662e75e7f31175ea0641c1a16b244b8e6aab044e027ef91c8ffd67b2475998a3e79d96bd8ce251aa12fd108cc89691e129dbe56988ff818d41fe73a4d0c0cc54d97688a2b2bce68597eda5edc69bc1824f23ad9fec59dfc62101f3afe211d9b11fbea9ca83f62c7f325f3b4dbbec64594593f239a474911c5f58b6e996bf336ad0294c75cb28923ed9aaf107b94ea2feb8b0a3163f066c215af0da1538e31970b724b7bd096d1c6d2fe8f946dd8687da7250d466330170346e31da40a63639812b9dd86cfbb2cd7d72a3906ed19c6388c89a76b9435bc6f70faec2323f99ae156395dd8b6b22637c7ae2933cbef0d1ff2360a997ee971d8523d6d1142c20b73ef006538907e28a5d0d76277fb3e9179edf292a3c3dc6ed10389d1122bae5d9746312c6b178e543f6d8670ffd9912558d3b06583f4a8c8d6f4fe48534e47452d2a5602e1724959f4761e27913116a85f5cb2900335343507b017da0cf8881076b1f4532a2fa514f17d26e9cd57642445c070b0b48ddc4fc5b054c9b3a69cb8f972d27e13f66a4ea1b5d237b8e6824e5b876aa942d5bd2e36e8a297bea42bf99633499924d414ea44edcc8567edde77df43125edaa75dfde2e11aa371b64f47dd7c4559fe4eaca73573c5433c5537bc0fe5d41510e4a8074b8daa6402f99492292c35ea91084c4349024b9f3322d5cf744a382cf5baffca336d7708cb1ab33ae18b659cd0d274ca46141ead0a905bba5826a1dc07bd93362537a30aa3a8ab75dfddc4e26b0b43465a732997c1c9c9e3e3a3ff78ea73313b19f47abd93f461d682b429b9fff2e5cb133d85ad52af9f3730382d54f27b0d094ecfa0a919c140d1a267d4527823c5ba38fb688204218a8defabf7822fac6d3185961af293d52269e162ceed64e3dd44edd888150fc635f8332ed6eb5f568b84a5819ae7a746c9d3604f82fc45bfa4a0b90574f29faffef9d839c1152f9572d41b17fee1730a9f66f7a914a80702775a5eabc3f4df225ee0dd21531e3d285ecc9699f4d46804b9e31dd5d68b96755a1e1ba489f842c3dba70635b2f8fe49f592bb9e69ffa4159c6a6b8c4a9ee0f45c4de033caace79d92e74721730dd4e5021df2cdf0461bde54f79a7d07beb474ab4dc743e1bcd7b13bcc1a52cd5cdcae971404d1ae62b6db53f5639c271b59d730f776ac69b7be088170a1eff42745acde198d5e3f75f5fa1ca5a34c3b168ea7e8d438a43186fba0df9c32a4322d64904e9c53e4d42d32465355a4bee6b56bb08aae4e046bdc3342a0a3d45a6d7242fd8730c9a8f1ab6eef65718bc2997d49daeee6d44ff8244c6ec2058594c4a3fe18a6242decb15a7e0bbf328f234cf719eb82967a934c08ca64b22ef9eb345b2afcf3184d157f7d1fb32866b3dcedd284c8513a1e4e2eec53330207268a8cc478b7dbbb1551c52233d77f539d246c148f736bd532da99744e44a5efe590a8de8604c5b5eec2ffc6b423edf022ccdf1708425d0fd9f3616ded4e4f361be4772ef06e7762d9b3a7fd42e49b65933ffc779f3e7ed6ebf36253239001df05fab0994354fd2deecd4f01a70e32ce9ca8e9586bf983a7a8fb948b45f1b6265f5275ee4933eae94b5b87dfd0749ec2744704613b024f6b098b57989d87adde96af3f73302f893851719dde1b9a94b9ef74395c5a58f1a35179ed23b30f80552e218748e2da29c161535d06928ee4b84b2bf7703456da0e7da3eb80815e818186daeddf364414fb29172a9b7ef447627b8828c5a0e5a32afbd47c1f24385343fe9c68ceb630a22cad5a2842f5191ad7ddcfd095af5ddc843701bb28dfaab14027481e23d9ed631c0c8e9f486d72007ffa071f3fc9cd926267170e4bafd03f7fb0be5463c25188a1d1532f67faee63bb1de79fa8883c98e59d08672687fa4279d41355f0655e035fa23c0a83b09eb063ad914031b111b8dd46b12fa85e89a8f0609da75a2ab7298dde6216a916dcbc137c597367312c8ceafcdab3dc86f1ab3f0eab26e2fb9e26d15ae60cec1385a40709e9c1921cf5e181f4604ef6cde77afa666ce91066bbb56cbd662681facb7046ffb1dd9a8f5f2eb43443c769de4b47e200517f92c494490d693e7fc1fa667b91d2a99f17ee79b4f6d389e049724da7722fbdc6643aa0ba6a5bcb53c5def2e577967aabe67ec4408e7730ab5e64117823db6d85dc9b55c0ba11ac03d14d76faae00246aa52c48d5342d957cf959f06538d3af035fecc5201c507f12b2094dde64f7f709d5c6c9eb5a314ba1e7e09db935db6ed76314355f3599f569cff447fd1d3c564bdc9b5dc5d617f303e5c4ede09ed40dc2f7322f71b53aeb1c413b04f4ef3329396bb7ed79dacd68fd185910c7ff4754e20a24e504c384505f866246a542ae544cecd401d35238352d6a52d49470fd5cc38267a97191008f95b86cd9822b6c3cf7a77be757ce529ad0894c15a5816943ba5a9826f5c9bc640513179aace0a85f98c7c3d533b3c28d4fe8bd5e1491b61b4fb721adb5610a1323ae17edb6d026f6d715339be68bee19de684d63a5816c0f35eb310803f3cdcc1a4e30470f1044dfe1e044ede2da723810a3deb8cb47bdb15a59a3befaee8f77434998ff38a734794713ad952c0327a72f7a01d36fc3c6c949f72564fa598318ef767053e9d551d66eb38bd623bdff169b5ba3be7dfbfaa2e1655c33bcba9e165ceb496b827af7e9e34705f855938e1c326bb78f58bb8d0e54d624d86aacaf11b0b14a0c19613bf856d327590bc962317559fe858f1b633b45ec2f45ec2f0eac1bbb83cf75d26056bce4d9645e38aad62f55148eebf3c4516f3c5434a7a81a9c827349d1a0b138435cbe21b72c2803fdb179e141be7ab810a4db0fe4eb076d49d2c790210a425109376fd1827553f42f3b0c0fe51b1fda38fad74abff5a66a17a5ce6e56ea675c89a42c6ac1afd53843f775747d455eba3329cd18eaea2122d2a18df2cfd0c6e5768b96e4a86709e25ea3d97e9bd95e93f10eee9ab69c261cb8b8d4db4b39b88604364e70bb8dcace3e3c39cf18ef4a59ce81251cf147d6827b7df0df83d06569a2d8823b0c1bcb5b36e9c798d57defc0f0934d30d281513c64138c7061f4126e82ba519d376096d174954a4f9110a7bf8d40b52e7fef0ef33f8bdf37460ed5702ce7561a665eff2f78b2e2c17b7b6fb580b074f4039bf2aa38cd244f631659cc2fdea828f8e903650467a7f0541382b33378b686e0ec7c3786b367df182b153e4c1bc6ab651f93cd0ec2fd37c3a5afe7e01d7f64f5e7610985d05f91927e86feba08fd0236a77d741d89fc06456c1ff0c9e581ed362f8f59c5276210ea3b8fd814f373f5c15b999f7e3e56ebb0ddb1b4be56952243c5712bff426e2d1ff943fd15dc523e24493c126e798a132f8e7bf917629a352f76b6d05fc1ba08ffd20dfdf50e3f397047bddd0e43edd0566b943d183260dbad3dfdd9b827f0fbeff4fea7eb93477a3f4b3eb065e662b8c5cdc310c18bbec2ad6795b9f5970272d773233ade318571b05984ab7f04fddee00c16e1ea17f395521a05ad775452b188599cca78e2198532a369ea2dc2887a0bea455c4ba35abbdc235d8c9876b5a9b90fedf261cf46f46044611f5a8f50fcf86607d386bd4571885655eeab7e60c5263a11bfa8cd7952e381a8bf7ac5fc555fab84577d42fd95228eabd7cc5f0d4ce4208f5cbf62feda40ae15e45a47be66feda40ae073a7207d19f762a9454fa1559549a2a7a3f41360819dec1d23553319aed9acca7dd4699ead1de1867aaf50db1abc1be796ea63ab5175b557e276ab37fa8343cb50da7bb9a2ca174bbd51b32f7b65d29bbd2cf9ed9d7e850fedc9d749fbb4bac89170eecf28a46327ff66e8cad33bd43991f90492f32a7231361c433bb66057f5257f03fa888ca937f730c1b91556f1e5af330ba5447f0fa25fc5c9d69a8dc738f12658dcf0251f75920d586679f1b525535bf62b4ff1e94fc8ea797d2f23130f3ea925a6db9d343c975507b3ddc3df58454c5ed9e2e51bf49b8220c84bf2652617c124e68add985087e7fb9d10b342514d4e81ab3caa9e6ce9b0970ed1a557cd892b5c64f08b588f718883c36387bf9bdf771ce9e3105a9398b2ddc5156df3da97073e6e153b68ba78503b984cf50eb761ea7de82ca398f6a3ee172fd419652ef6ff14368ef6a239cfb846b61281fd8a65690e318d770963f706482d369253c8d052de5381bba9294450db84e15fb1ba8e220558cb22e6917e4195853eade05e4d25f49a3dcdd756975f6b4eedbc83c1ab43c46d8b1dd1e59a947fd4122163ec433e3b8217f98ccf29641ab05d6575fd0eab576d61b872da7c8e76729159733ca64ed2978464e90111fe091f7cf93311afdf3d11f77f00948728254fd214617817f6c2bc1173530414ed0228d29f6ca38aee2f8ef7192d8cc179e7808f2747c71a22f22d0159d685fb3b2fc14e5272d157113be588632be4f680bbfd2af151450a38266e403128ffae3edd6199678345011bdd6ae493375f6b4b6bb66c8428a29cbd9f78b30d8701670fdca75bcaf8f2e84657bc7c2aa2bcfb806de74aad239acaa56dbbf6749e2f077c37af7f64082b31f5597bfd34dbd91d46b25399f4e532a3f8782328923eeb10ec9238d78bc0cdff2a5f5216f45b188925a0139ad31e2ef3d1dd0d9b3feae1dff2e9b054dd3704683dc646246a5fb58119f968f3b7a13ce6418332aec422995057f8f233977a4fc7f35f7302d6e25742a831e2822d18347051a30986b909aa6c5f6e059d7765a6fa2dfb581b4c031639c469d94ed56fbe9ad40ab38a9e3582d8e69b3b53cae2464b398492a52f33877b5b1655270aa1afeb4faade0900b8ce78674f2dde1d7fe8a95f68c46a9e2bb5071d0db6deef5ac4f5811580d882c5306446cb7bdfd19386f3820a30396287513c4ca06c949e80bfa5b465379c9e285d6a6bc17e182aa7335458a7cb9ae845569a1d5b4d4e03906eede7a50c3c9b75b86ec4c151b30c2b0d1a32a41502d4309c46e573d7219ec45b9b539564cfb6dbc50243d7f94365ca11ef45f7411eb66581d9a433f35403c93c8e5fd10eb28c6a8f4ec9d11d691206a2af6d0d7de38f312a8f5e7af1f67ea414a46ad45da82d682ffde825c260d2dde1adbe7579c9defa8baf35d989fa009825ed06053363c10e0b622103b6b9e5a0af68e0ecc5869b83a25a97926bf118e84a369a7f5a529a93586e6d93579de36a4b4c6dbad9378a0d89d638fda00b0dda2438d95f84093749ec6b6f28a95aaa8ae5785ced8be353f8f53689a9359c2efc3e4c2fc34ce5a4a93e985fad3985a9df5cdce5288f3a7250f4fd9c9d8129fd98c2d5bf47d5bb105fe5fb8119f7f87d97693a465cf38f6b78bdf1caf59af492f68dd739ed0d0b910f1db76fb5b75d27f223f157ab68a321b3e914fdbad1a864dcd7703d49d3bec30bc27efb7db500117db6bf0937e96bdcec60aca222ab431480b6fb788f94e0c39ea61a3e83391c4f956f4fe6782defbda12f263c8c2998a4c31a2f0be62798c37efcd53175f7446ab162c2a69b7dfbb4184210f5bf33f78ef5316e599dd87128a5dfa1fe4933d8ab7db477f83441dbbff517b35fdcb768bbe38079a8ba94b70154bd5257da0af7a39253f2a1e5866bbf23cbf838feabcb9848fb8f21202defc7dbb45ff20477df8e2db3d02e1ca4305e6acb17fe3b21853ab433581d7bdc2913925bd217de5a40d6987f471de67f77583dc3bc227df9539e853c504fda4762244fdd5a043fd551f9f0c40a8f05a85d72a3cfcab650bff4198afb9aa934117c9e3bffae9244c685762c8217e21cc37fc96021105885013a6cf616fa96264de1a210a2a4a2e4bc0f00b39ead75e31b796ac7e4d60618d86de17af845509847ec2fc7d2e9d36008dcf0998925dc1875bb27d4b94551f0e704a3600557fffe60a216a99bbaf0efafcec5784c96a3deee999f04635c915ec208ae1936fe53888825a847f23473d982becabeba01ce1caa131fbe4a70df120fc5547faab133b7120fc7547faeb3c6c2b4d4ca555a516deb80d641ab4bfdbe1eaa30478b33f0046175440dd68ea10b3582ae4accae5d67b84a22aa67bc4d5b7088a39423f61f74d82f2729a16240e73d121734587487ba2be527f7e69b71708e3207f62630ff45a41add41f63c4b22f9cfd45514e1ce4efd7d44a68b79d228a7a2b2f20386e7792987dd3d72f6cb3a95312ae0dd02392e56d0ba7fd4fe5b9afe4295b5cc9a3cf752de302de53842bb758d536a66a97a291efdd7e7af729f03ee451de821eb56a6f36580b357b27ae2228668aa61921311899efc567247190cb7c7f550d9dbbe4ee0ee1cd0261a8d0c00f086fdeb4dbe88d63a8f786d4f0eeb62e5f8d5a70e9a4bf753dd4dba950f473c8c86615c89c34c23a900511dc59fbbfe261cfbe7f06f4a2eb0f027f50f0f1767591f7e61709b57cd486f51ff973ff2aba05c52ab41f65dbbe22bcc9b47c5ad034fe9d6a6dee0775ca40da73594b61e01b12a915f526d78e55c5c1ef7d29429626a1a45f688298bf02e6afabedd045294a8875c9c644ce94bddddaf24d0546998dea6cd35bc45ef540ea02aa2bfb0ac32dda13b2bbe3ff0ee1cdef6a2f5570aa6f99992ca7c7ffa163307cd18675a82ec4770f967b184ff1aede26175ed12e5819a84fbe15cd230cdfecb9f02339ed0dadf3052db4f819bec01bf844989f846b9e49786f5c1a2ce7f124859fd4eacff930f88d9417fdb49b61114e64fc40b7db4a1074f7152101cd54280a0b7f577ffe4a3676270d7a6077d2a0071a4b82fe0efe8370b4d915f761eb7a0b8b87bf6fb748f1623384e1066150ebe82bc2aada1e8607d70aa176d7fdbd7172f255a3afc99823757f07cb30abaa31feaeba904f922e2e5bd4012a3c938231f3d5203e4e50deaedf395f7cca9ad4296fd1510f1b800fac39bd6fbccbdeaa5530e562d100f5d71d28f279cb83fada798ab9e9d29c112ad99c2e3b2e56b3de4e73d62c9ea40d15bf37ef7668446a48fed4a82c7a67b6e9a0c90accfb0fdf46e4f627d3e941c0e9d4817c5aa5924be12b3a15ed5fc8ac82c242e3247d98e51d36961b5945d3620e3caee1476ad3b536fc245213599e320cc8b452848c1779c2a49230a3f25d217a340051b5f07de3eb27ea0d4e7f84037983d397f044bdc1d90b68686f70de83c323119c6bafbdb5f10bce4f9f70b9ebce40d0efab43ed733a9022408b0304472d7d75a43803a998590b9bcbc3adfb6c3aa582465db352d5d1175ad19a858b78a21ff1a95dc1a53bc7365d8ba672df679b1d44644f3d5e885f5b42cb486db57adf6d41bf974798cdd78d99c649d282d6bff57ae180fed8aaead3ad5d80815cb580f9abee799e73adc2ebeef99ecabb6c4c12335a342695827fa3aaae972f5faa8ae67baf1f1455f5755d454d3ab8ce83ab410ba493aa836b5cb542d7fe4ef5ce2ca8262691aa72519a0ec1daf95e39df8fa47ad065f91cb716a114f10ab53ad34e0bbc9efa67be5b9d4cff4d3b2ddc1a32db309993cb1650bcdb0d25a1d6d9fc3dd914d73b9a769bc9888e8be7889a41b4a90ab0ba12f8d0db5bf97e5018d5ed5d6c7c26e74391f329edb3b7ac825dd76bb160f302cc1175b8047a078510a31abdbf9bd468734628a484c1a322f1aeb42508c165e3dc6cc5d5badc0ce5ebdf7efacc63753cd18abe19956f6f3f2245a0f7217c8316c5e6a82fe03d50a178203ce4fae90eeeaf89006eae2d1e0406058cb8bfea86fe0a1fc77ea83322eeafbba1bf563111c43eed10eeaf20f6a7ea636defec95d819fba1839fb11f69dc54f9cceff41096667867f9a2ef1b1bdd39e1af4cf7b4afc1fd0e96a3e70e8bb9b2e814f9d1b41e97acb61a085532b6ac3f75d3ba2ab1ab52217426c83c37b64cd628c6c32909fd103212fa0a23427f6aaf6a96231556462ab42315da910aed48956605f5019b288650db54c0d4b27e5fabe3873753eb7db2a41f7d5ba3673f9eac8296559805a34eff35bfceeee621b1c2fca63b5cda645ae2064359aaafebd0763b3785cd8bda15afb139085108501ef24721731a21fcfc690a22edd39c84426eba2580991bc9d626549fff5ff72e58fe340c9d72a14f788a70a752370207acd23d8141143dd8a32ee6e4692b1cea47456b3d82c24eca5e4283fce5b9a61e26cff4d07ad79a383d3cd8d83d8a698fc9dfd1d849d15847d25bc1b15cf2e9c5cc9be0788a2675d1352d246d6a73192eb46567de197f050b6ddc5944ac6189182cc00881f02eafdabc8f77a8ea48551d1dae5adb33adab554f055ff82b5857ebd7b16b585561a55af5ab2aa4e4fe1ae688c11ad4b15c1bb4ed2a8786aa97bb272da5da6d242f28923810441de974395f1f66071ce5c9d2482ede7b69a23c0038578b2bcc7f7122089fe5dfbf8bd1dee3718b8a83d381626c9ff58b40c90451d85016de27f44d42f525f7e0a8074b45dcc4037d27c2c798cdde687e3638ea1b55e65b9ef05a48df610a3622e8c32ce8c37dd08730e8efac49ace16c234860090f308719e9597f85a33ef4ecff8d5f635891d1181ed59f7bc5085fa93fd72456077312225cb9db53da0ca2bd6b38362545a7bdfed98f2f7f7cf1e30fb87265056faeed9b29e56eb6c670d31059b9878237dfd18dcaa510bc61edb6a20011b1c2b25203ceecb9d8d877f4b1becb62f8f87d2063f4a1a0f44bbd0f317d54d888549d112418aedbedbc535fe3df298a4e06909c0c30dcb4db374d0978071f9e63ab87f269c736a83509d943983b4bb8d5dcef61d6f62ae77e0f33c8f77f8afbfdf6a7b9dfcfffa5dc6fc94b57f853fe0799e1c5eb9e9a4d91eb09672a7c53847770af359f31fb76cbdf0bcee4becdaa5a86e45ab14f1ac0bc1b8bf0f0dad7796d3e443188d76a0fb2d793e30824791c8931a83fe471c4cc977e8a13549048fda32218fe0eae7d3dea0fc664704c4fa26e1fd6a3fee998f4bb83637692c0afa899112944cd8b4e0704f9ec98800a55b1daa1f5f38b706df1518b3a058647fd06265c15fbb668e4038a0a66ba826f072a30fc002bf9811b5b5dee106d65aabb77ab3b7414c9c7a24306c7eb516fac46e464ad6f7aaa41e9eae8f3b11a9813f56146678f6b2f9a3e3866fe4a0faa3003eaaf4f92c2f2b44b746520f4c7a9ae44d52d8f51bf4bb1a9b3434411ec8d8f0905dd024255ddf0c172a72aed100f6cabbb44e6edf63b8455d69ca32da94e7057636f0be7269b9d31e36bdc87b49f81c614a392271c5495975a975e63960591faf4c099a42b895a74b5a42256542b4cbafa8a490b620c4722f7ccd07acbb32432da1c16cb384ce2dfa9a7afa4f8de574a17a997c4dfa827e7d4b3169dda8b0cfb4be94426967e6b68fc9be4061d0915d23c45a6fb59dd81b505f8bd0abccfd80409ffeb97b77797d79fff7a09c2ff747375f7f1c3cdcf5fef8a580cc2968084ffe6faeae69d562a94bb73ee2bdb8d338e66841383325f40e6cf20f3ef21f3ad5b5ed73aa1e221d4e444c27ffbe9fad397bb373fbf7f7ff5e5eecd875bbcdb5dfb090f35477c60fb29d21b77218d690d047ade6ecffff099264ebfe68e63ea1e28e9f76e64c0882ebb449d6aa811914ae9e0e1238c26ea68d125fdfc2ab0a552437b18b041b8f6cbf7b111b3cf3d13e6c7fa0d7cf96aa137b51e2164b1dd2e0821d26e66f64ed2e368311e5a4268a8d9eef059456f2d68e6b4eabeda2a1b841bbf7ca8bba955b3a255b3ed76b6dfaad568361eaedc56e922f5766a0f14314d1103519e490e1f871ca99ed19ecedcfb35ab111b0fa9bf22d23d08517fed46ac61d96e2f915407f19b225a870f1f8ae2293ad24b852f62e33ae64b2ef7c5cd8d2bbfcdcb458bf2e5223555720c9ce8cd469f8c86cc5f691910f3d7a4cbb5e4c5a44a0ed4a6d13ceda1dd7e50c76ad585ebb20b26e6bfe0a834b747a5dc6c42f09908177bcf598a769be21b424bff86564f7e53578c5b3be8f4315c7ae93c8ca8f038d304759aac7ddff77ea1d26fe90ab565ca53155eff575658c865de6a13eb5baec7ed2de7228a592869b377747fa5181bbb0bab5951fb3055fbb09e2bedbd5aefbbd86cf40a44bbafd6bb2f36dbbc82a4feea5891447dd98e507f7d8cba9a3a52a769ba49b7dcb4f03b9aa61a5629f4242fd4d6a8dad4316c425ead6a51c7300c790f3a7d7caca8b56e7cbf4bfd353e4e54b8e0e42fa569d3679ed6ef8936fa3f2efcbaeaabb2c6fff573e3af38b4f2ed42b590667a21c553c490222baabdaa8dc5aba62ad218ba38b5ed9cf7f86f31dc1ebcab6acee3e54dd48aca2ddebfd0eaa06bf54eb603e3aca1aaf6cf81f9fa5b160a5a55fe55aba18edaaf2e6e98ec5ff4aac8171afb139c19cd5b4335c18b414392dbd1e0c5691da2d6cde0c5591da2ec64f0e2a94733dd27e5cebff36648bf77d63f3b3d3d6ff6d4aa08473c4567daaea7f0b64009cdb722748246fff96f637c3283d6ffe8ff8f7e0b6378e9406346b4b3bb0feaf0947bc9ec63e8bf30c6430ae57f3872e03561fa8be6ba4a27de31f3e674e529840fa5f718cbb9b7147442154be8b5feade57b57feccf7feadd79b4e7b3ddffb894bcf386af3fed2a1c3c36d78f5eac7ede0fc5cfb0fd977026f0e790eb3b27f37e1d9fb2de60538cd2c7d374b65f248fb16b989aeb0548328878ad377b1906b72d40717d8884edc182b28a10d7d78e686cbbebfbcdc2ba3d559e87d02496c0e2666db306e748d9512cd1de35a4881e148b38826fc3914e1824a9500d47ffbe9e3e70fd757775f6f2f6f7ffe8a739d8b03ff814df9359f21819b4e0e1c03cfcd6e857bd342960a9cbce576d519dd96e264fcbf5d7db9bdfac7ddd7bf5ebebbfaa2352aba51efbf5cfef4f1eae6364f303d0da50c2773db29ae0e477b71a18a4b4a12a09a67fa6e23cace2b7ee5fac3cdff51ed79d6d473ded8f30c4396f79cbbe6e1764ee329d20ee38fe56b5a718d23f455fcf7090fe5e9e05288705dbc857a2c8f07ce513fa54604b22b2e6516d584f655ddc2f1f866079cf486fc952c6f7417a75839e2630849b76f2c14b5bfa3516fdc6eb7eecc777fac1b1c9aee1bbfa8d77c623ca03135d62121a4dbdf775e6a07b6386acec3075abc0eee156e5b03afd589f1508c623fd52f510ff09884bb9c26b5b2d69169d376dbba33dffd71c33bddea0cacaa99c6b34c508f67d25bf34c78b1f683ed7b9749e2652c56a42bf5d2b93e326b832543c6fe92ddfd45d1b269bc022f644e03530b10defda5a511ce8ec5cfa6b0ea60a8bd9a1012fed1e1b02d3b3018e53ab236619565134830976f35ca0402267cb9d6df9f4321030e8a8b2cc3b156e3db56a741081343cd025abfdc61ee8ee59864904868eca123d6d12f2bc80e1fefb9d43d94cbe29cc93cac9401e687c40d37ffce9ff15fd970fd9a6a9eebcaa5cac606ffb15c03143f8ee8d80169bc0eb61ed1f1d09891da3bfa7aa9d843a64a057534868536073432ef1cb237cc0d4f8b141064821678b8440264eed9653dba1f2dc6a567170b5c9407f7a3fc734c14a8b92051bbf766733fd67cacda68d5d2ca836796cd5d37e8c61852d0962fb0e7655a10b90f8b70464190c5503fa5a5764f9ea69f443c8b1969858cb3f58267690ba4cf59c2c3c815c9a8864f91be68897720fd544c888b7769f906387df462343f9ee1e1a3f112ec5aed4fab6e09268a1af2dcae32a0bba1d0cee533418d838cd7e4b1609b52946bfb1f4735b0f13056fbbd1f89f051f7539debfd094f8e67207cc11f8f6730831986fb111d13a69a0feb91fe1deb67b70b6cea81da02dd770b4a33f613faea550f0461ff4ed531f964ae823111ff5e3c345d69542041f0c780c38427951b5811c29b2bb7ca15e9c103a9beed99a8116db7919dbdca75c3070c2b3587260f86d5eb7eef22423878c85924e776630467bd5ee5fa8e23d47d1cd1da485a7e0704791cb1bd34b902aead6ad5c8c68499b11d0a67e4a5e657543a2d471e38c466061a6a7446a2a1ce32559bb23dc0dc7938926eb7fddee00cab999891392c481fd66aeb54436a557b234308b85a22e6d87e1b2734f5965478b6ae7c63b9a7de923faa43fbd4938fdc6f6984bb221bdb88423369420c8c8cca38f5b83565a58100cd6b9607e610d47a0ab2e2307855bb4eeab81246b44dbb7dec3ab3b78ddcbb4f676ed339a9c1f90b45779fbd5c5cdc5dbeb399831edcd935d88334fe9d068d2f3a9d0e201593803510fb17cfbe14e5107b6b0dc842193f50e3b5a7dd5ef88638db6144d5f45c00b8b0ac670e85870bdf186ee7318b51ebf6ea1fb73f7fb96a75d818c342df8529527d9b7837780752a54abad2883b78574decc1c2fff2d39bcbf2e7e79baf1f7ebab97a77f7e697db2ba076a5d8320a4634ae1653063e5efe74f7fec3f5edd51758284ef5eaf2cbf7e7fd7053cf7bf7f1c3e78f979fefd4f7d5d75b55d48c322a42493fc6cb45b8ac94a5922db3d28fd1e3a895868b6542851a2373c670479bc8ea35ee788ae6f942b4841e2499fb0ed623232f31dbb574b7eb23e9ecd7edb60eb9956db70ca948a07838f7cbe585dc6b4d42d1e10561b022196218e6d6fd15c53023abda79e457f8acfb9b16318af09095ef72506806a35678f740859a019eb6a015de9927b18a6704546476974e04a5ecabbe00d1caee1c9b2a9568c6b1e706fa6e60e0064e4d098afe7ca6c28e5d6beccece143dfa3500a00ac0e861fea6db6b5a68ce1a8f7ed187a7c1ea9dc3b02ed693d172b9f779d2aaf7f3383afe36bc1b49b57daebad4575402ee46b2d31f932ed34f1d17518331393ba6be25293aea54e7eb384067fbf9ce2bf93a7d1df962afc61f4c4eb7b01fab39073af2e57e5b7bfb59fbfda6bcfdc15e83fba7fb2dee9f3535b97fbe9ff94543cd3f54339fd65e58ba232bdf3921a03bb8846f182ef367a899598115a9a56269f0905d14a516dc6880cab81ecc8d9a4cc34341b83559ae67dce10a3f44f1e6522b712ebba4af08471cbdba6cb74d9c2eafdd9e5be58d6d0facfccad906dd814128b83cfe06df70f579268575ac6845d19edaa34a378a5db826748fb1b92714ae080305e05e45c69b3a45303b83c5fc857ff9e5cbe52f56d9086b9dac93de8532ac27dfc1c27ff7cbcde5c70f6fefde7db9fcbb367b4137eac052ac6463887a367d500b3aa71970d4876b67b90fd4722f090cdcc31556c90fcefad546b254b80b1d06b0f0df5f7fbabc55059e1ebbc2075f6d4f5fef3e5f7db9bbbabefa7875730bbdc345d68902f4ff50c93f62904895ae18400d94aa7de7cb87cb9b9faeafbe420f5e1c5f1a6e660e335868e3ba47d54db8861bf846fa3fc267c211865fb5e595f6c8ad5d245e921edced4b565e9c1537ac34532520d743052994d612c1144afd6130813dcd5f1041cdfa2a485c0382a555c9050f357f2ed65f4f6b29e8244ef5ed6f1ac5d962e94d553b872d683d84621db399f7402767de84275cd4624fbd074bdaf5e255a9161fbc7cd778e7957bcb33e9fd67d207cfa49fead6f138f21661ccf47b78d8dbb4a0e5795e3cf550a5adfeef1e215ecf2f203c6f96dcbd17e1ccc89c49ce530fdea1b20750edb0bf5ae3a1c9bef3ac52adb19efe1faba7ff67eb19fcb17a067fb69ed33f56cfe9b3f56ceaa5289c438549781f0fbd5d0b5abbd6d8ff95c70cb5fec95a15ff1e254217923355c6c0735823556599aad1dcdbe7955c2cd325b89c939bb808e599e7f0516e9a297c8f457a7efd1cc0df597297dfbef7885ba9776c86cae9e689dbe07cf85ad0326d9a70c1a81ae1058fd07eefc13bf31d68d5fe0f2ca22b9bc1bcf3ba9fcd3b51f960bfc7b5b254ca17fee8114f9f7b9f03573df0d4f23971325741def2245b30dbbca2b9e0d6562bd4d46f5faccd339cd4e1b56b4433548a4ef4f2a9a823b2c1d5012a86b958394efefef3f9fb4fe51f7c57fd3d37ffb3b5596885732e90774c8aa11fd613fd95d721eeb01f3f01bbce61d5803f05f87b311d4fa3d74933bad48882e3c4476b4d2f651256ae8d9ae8036288222d38d74fa8578b08ce7fdc8de1c533ee946b12e1554d24a6c5bb2b97e513cf59967cce459070597b31f7a95cdf9a7285cfe5ba69ca953d97ebba2957fa5caeaba65cd3e772dd37e59a3c97ebb12957e468c5b4fd9a3ad5949acd9c27034e4c52a9035b75f92bd66eb357c25f7578bb2dfc7597bf92edb67c25fc7527573ebacc7b52be22e6156e3f1c2b10c420aa4a38fffc4b40ce89c131c7b68ffa148973e7700c424b3e8c9548e1554376481fc75324081dc9b11f2e97c9da3e350c0ce3fd4ece9cf7971d1b2ef34805e9434cca07d5c38a21fd1cddc048021d6360dad4a67ce0635d3ee5b383cc95e8ef3f4310ee3f43a0eff155ef23e8f17fc3336d4e6a66c0783ada0d0fb9142bbc47a41852d4fc2e84d38ebaf5d50a6f44a7f3ef3f1042d41153952072f3410e3139ea0f2bddeeaef553f7d5de77d7bee44be024d12fe0b4dbf288107e8164bb3d47f73092630c92a8e2e2ed768e1e750c0eac5e30876fb7910528b218097cdc6e2fb52fe4277a67de89a85bce0bd38314d526efa95e0832d2dda06310a3def802c5648eae4034bcc114eebdc19461583cf3fcd2d38f1b3d802442bf2862b133effc137d5715eff79c9728fddd533834db94ee7f4642fd90a920a370bb95f978945a93033d5800efc6afce7abd763bbb98a3cf20703047dfd400c684c31c5d83c0a65378878d1d75fd9180c263f35e8a6ea13ee89ae129d41070a5fe5cab3f37eacf37f5e7b3faf3ab5956aef124c2c319fad560f925d9e851bc5267f660023a704dc30775cc2ddeab0852b04f47041914cf3b04214c9278f22d8821ba4fdeea4f01ee5315dab7e6dee3120173dcb6d7bb482ee172f75d4f8934bcb7fbc49b1f8a4778d66977ae4bd757c5b85e75ce9b7eda52491f860e302a5580e0fc5c55fa9ca30623f2aeb8aab5cffcbd80840c8ed1e0194149e7e7981d4ec5b0247f46a270f0cce39e080bf02abf070fe4fbcf7cbadef0ae28ea4f9ff3fe6847fef4e1cd57e70abf971f972776306c1ffcf07ed6342673d28399163ae999b2b2c1fe8be34451cd3d61d40cc35ac73ab3ab225735cf0f68dee9e3e3e4f5ccbf5f4b7aedd80ed1bdca06c71528600dd6457ae3a9554bf1506a03a3b56e2aac898419a18505aa119715ed0af186911084790c941251d3a13cc052ed488ec4543f1927aa3a14daa4435103fcb4e244732a871415b1abcf780a4c57a487a2aec4286582f5559d33a871049c88e368b818712dac87c58877faea730deb11ef0cc6849a1a74cae998480b74a63e0dd07901b483f26258c5407a8530cc3ba40fa1ae7507e5658b0adc5ccbcfe7a54c7ddefeffa83b831d3761200cdffb14cd1e10a65304c9de56ee6d0f95508ad4dea21c28260b6263455936218df2ee950788c70636d9b4aad4cb6ac1662e197d1eff33633bf86e6b69e787463b17907b4285bd3d19935a4df9248015cf8cde28b366ba3be622c57b30fb0740d93e20a96a2e4d59bcc261ad9a5bc34f202dd53c751c37e59350799aad9a17a66abe627ad274e51654357f8517a6868724eec250cde5fb54f331938d63dc83b492c293e02ac95c52b95c6242f73b0430f5720609cf3f876dcbe550bb65d2f64f6e7da33ecc5d777e91a05f40820e952887c2ca79d29739d051979c8c55f4da9dbe5a3b2fdd1a707ec85a18c60a86fb2f3cba8a86d19fd1b06430e7124a5e61b6e844cb10d851f00c7678e707a47c6721f0117e3210d4fd53061f367c673230bd998162146e1bcac0b7a6b50c7ce66234915bd989dc87f9a2f2ea867af86f97c36d9f107d98a52cf179a62967466258b2b3a6824c7b5e74ce33b58cc2c1d851a38212a35bc69a73b1e3e0bb9dc5b9b2f1e71a62af869a5149851d339741fc898766051a9542d8d1fee504059730c9f48cc31a5cd67004c202d7c1715cac4f147d706d4c70ad999e345db91b0aae1c9e981a1ea20cf1019881d0e0aaaf00d798c90e5ca20fae8b66c3a9b24bc825fcf8dbd7f90f85aeb8d10f537a144393ede3f7b0e797a0f87678ac764fff3a3a7eb4a3e3d9ff1c1dfbf5612cbbd1592a64d5660de877bf3e7ad4f422582e82e5fb62ea68289ede23966d94470cca1eca2306f1f99af4268a953ac0ab7af1cf96c63a054d03273441fc3a90137e39c73f37af8617da8648f1dd789d5d1840b7bb957f63773bd064a33fbc0bfc30f0c33bace3537f60112e991bb2137bf81d0000ffffce0c5d9bfc000100",
+		"f256e6f5a46e10e60db6a2444386dc4e": "1f8b08000000000000ffdc7d6b73db38b2e877ff8a8eb237a21c85923d4976d61e65af9f19573976ca76923b3737d7059190843545f000a06dedacfffb293c48822028c94eb2a7ced187a9986c34fadd0da0c18968ca05ec9ded9dfe717972797d7974f1f9e8e2fad3c5298ca0b3b5f536dc1e6e87afff166efdf5d70ebc84ce20460271c1309a777637f4e8b3f3c3a3eb93c3ebd3a3b3f757bfc308debededdd8180c604219703ac7c00543e91403c388d314229a5026dfce91e00a0ac753cc01a531a434c61c528c631014c6186232996086531186214488e1499e3c33331f1dbe3fba3e383f3dbfb83e3c3adefb747a25c97efe5afd4afa2ca8f34f57efcf4fcede2bb05f7e791b8fdff8c04ece0ece3f14605bd1aff15f2725d8e7a38baba3ffd39c7578ff56fdfc807b0757279f8f349c336f0deee0fcecece8e0eae85083fae7be3cf9bf12d59614739420cee198d154e034863f3700001434cb23415980b2ac671ecb9f98111ea22c8311a02cdb759e4782dce2331a631841b7ebbce518b1687685d9dc791bd3289f4b0da1383ebac5a938255ce014b3a01b2524bae9f621c03d18bdb3e8903f32816086f8816421c0a1406c8a451fba69b7d77340e52fc10266629e18fa8a01bb5e40694727318cca11214953cc7ebffa70babbd11841261521c5803e74b53cfcd4d8c20c19e658ec95d20b7a4da2e48f6191b3b4f9eea149d1600057e787e73b80e218341da0752dbd84e139bdc59051cec938c140c50c330e418a23cc39620bed7b4a6130c148e40cf79a9394f4d7a9d7b2eb83603976387928ff7ae8c304255c02d4cd84a4445caa990b3118f6ec1796404beb9962719460f9cffdc5491c7434f99d9ec7ac6ef022cfdacc4aaaff1625b96d24a17a100a46e6412f14f494de617680b85295639481193c1a41a7e353bd6253a9bccee72a553b6a6e3a959ab83ea6c119c33c4f048711a4f80e2eb170679f5016280f003aa9341cf35085d6f3342129f6714526411a728198e05f88986929b49abe2143ea26483dfc3fb4984d832732090a5c9cfc538a1db67c930e06901021120c3314ddc8e4802269ec80b5cdf8a3008c4a4a153f3ce88529be17412ff4081b96f8448b3b34351a139e2568715649bb60d01afc609b5dab07440946cce7001d15573b2d0eb0cc3e1fea3e59837a9453161ed6e9ac9b2656454b43129fd13b4dd131c149bc16595d3de91786b20cb36e2fe46291e030e2fc0adf0b49a5d1cace38a1d1cd6ea73621169702899c7f90b1738a83399fae270b35aad3ab520b8c60cea7bb0decb25e7aea1c72ec7a33cde89d94e729496fb80ae27d483199cec694f1b526d381df99463e94a51f907447d68025ca90a4da65e54b9a0be72dcd857a6d197a91c1a542481ad13949a7baf6db01cb8c060328de96cf6a51cd26a1077fd6038a9ae0e5085245d70b8618db0555bcca42f5b7317b674d55052619fe1a9c8d4630941314383b29853ae1cf3a168e56c192d411aa446809a6100acdc594b60aa578bb4a283417ad525142e8b8a251b25a4f34855abdb2a9d3bf9e6c682ebcc2a9fb90a73cc9b31809fc3be2b391ae441a65ae5dceea51bb3653150237e1cc0817942d4286b3044558ba2e0ed23c49faa0ffdb7dde7da931dab1b56ee9a5cc6054cfc3c5f3af1ac337378036fc58725b79723380dbb1d4e2643080286772ed942c8a1a5279f31d491248282f4b4a49ecbdac2d260cf3d99a8b82d542826e6f5752a18884844648109ac20cb97328808a670f8bd6cb2747323b55adefaa6b8d6a1a7131cc30e1a90a5aeab1c140c904e4739893e94cc86530820c33b5644e230c372449307b568eb150c108f618438b70c2e8bc3647c82913b57ad78ac75f2d2bac8795f6aa51c60519061c33f1556f729630cbf92ce8fec633946ac31b755263979d77dd320c0d24c0bb8e5b6a014e387e0cea35707a82dd52933282f0c4abf01f94a441a7539aee43b1363fd43b2679241761dfb940d7bb23ded2bf7a5fdac172a8c9641db043c2239aa63812385e026b60084d979267454409f301658eaf4f8b5aec4a15e975b740b7d322945af3a96cb4b90d03085c19bcdaeac10ebcda92468a53c1163afc0528b9430b2e7db2e4ad574ea4576ea0f50d5421da5159d2455f563f41fdad2db312a6a793ee2b3839e42ebaaa8c7a5566fe02c0e5d480a1dba9060a1e210ff5ead5564fae808fc93d8e83edbaf8511cab2c42e23d5bf664123cb3a89d21ae205c47b740e4b25082ec7a16486671e5ab8a3b288e717c45251119a589665123f2e2d1295c2309fca9b8dc4911789e51a63647c8bdda2099a03c110b40294a169c70e098dd6216424c21a542961d663f926a6709dd958e4a4b269c575496796b4e4d567e9a3c6594a0090e316394059d0a1f8c73a12824a92130215cec74fa1e51b91b119664c82468315a8ba236bb8e718285e1ba5e2bd65ddd83ab7ce5e0f013664c77b5d119401ba9df68a60c653303f7193381ef9f64ab963e64ae35a1a2cd6c2b11b5b0694c6c0d3e0de46a46d7a65c636c27dd4ff23a81e0c711992e89091ee12e0d11d5bac271e0ef76d21aca1fe4a7b28e9fe1e806c8a486cd4cc2b16821fab1ae53456dafa6b4dfa0386e771a492ac34860936f25a965d29fa3cc337fb91a22f1deb732bf2b2467c5bbf3f13f70d4d8e96c894c4fcd3d35d555565669c457813e0e2bf01b926538f661f7ebbbd4b529d71c65ffb0f8f114df8c8f199d9ffb62878fab751cb245ed162ba63a731622e94e5573f66baf682ebcef1e7c7140b3e206829f524014eefe83c28db18efff975c1b3efb1f8efac4ad736f57ac08e31106eedc4e83ae1bf65b1a33dde53e73cd9e1b5dda86d9120a2a9b254f99ffdef4fc536eea59ed1972357bac75262f67f1431fbeb11d3b01e7b0128499248bcd6b34cc93522dd54a5169eefcc5ffb76f1e5cb8b72b91ec72af256a449d35f48a718533133ac23865d8f80155e012f5e343da1d0837c29a97d3672ada8c535501c1fc553ec585fcbc1a02d66194db4ae1ab08381d99d86b8b6fba37306aff68621a1f426cffc93d54b23b5f3ae23582b79f688fd6f2149db429e21d2f411a8fadade0d5106d918f033f2c2bab8f7d7c2bd5fcf170d8daf63f8ab0dbe81b66d170296ed5b160122a1d336cfc344cc30d32944c60bed279d563375f733abbde79f19671df4ffe5a1f611f4fcf4686b031a2b6d4ee8cdd5de98e486d8a70799b60063bbd2f2013abeb42f22dc22880317244960866e71b5287483bed6f70c71a9bb7221b02ab89451ce892ccb102e8d28659cf5b6782c0b258ef5ad174d56ef67faa2482d82b856ffa420520b1b5e25582478cf38eb26b5ebaedb02cf21bbaf69a007ef60d833d4944729efa57f7ce711ca8c4c670999ce048ecf569ca658a0eae8b10e5a8755ae0b23f84c6e51a8e8d48f1a48d55312f13aec6782efc23b3c9e26efcdfbe6110b4aa23c4182b2fad008a782a184884593aa042d682eeaf0a7ea5938a12cc28784297b0f2ad2fa8e91f18c91747a8ad3a998edc02fc3bee7ed01c593c90e0cc3e170b855078819b25e6fd75f4e19ba2562b103afb6c2edca08fdc225110f1392de0481fcafa7edc9989857aaa7725ddf6c176eebc8aacf6a16d91f199d32340fc63949e203c2a244ed4e5ece508c59d06b1f2f5d2f5047b1ed544bc3fa82c7ef4f35e2c06af5ed7b7b8e9792ce701a638699c7c88a574b54aead66c736a186de14673b7546fb6e741288a498edb4b76da99151d7d9b3d1242a97db515d774b38252911aa37ce5d59ea482a15f4891cd08432d311a59acffbc0d12d1ea98e3e37a2c9112745382b7538d536f0e944ebd1ee2381c08c7936823c8df184a43876ab010d12ead6f791a6a2adc490b479ab093776e9eecb3a3d0f4d21484916422882fe6a414434ad49418a40620a7cf50899c85a454a20cd93c4255ea2934eeb97ab22ef448e0f49ec2446295d33729974d5240aac94708618c79a67f56879e7668bd47d925776592cfe9a14b7d4e00d4dec2fe41f27b1626fb536568a4f05c5ba59ae21b8f585f67813ad04e5d056df7bad753b719ca884e4f6911485772325bf8321fceb5f2deea1ca8b77aa4dad519a2618a5906745638ebf1c5bd2d7ef6e74691f19e329493f295d373a6d56f783d9dc7fdbaded2796bc151b892aa2d44968863c1b61df7723a5d7364bd9e568ad604ac865cd984d417a2271bfe5d68baf2c6ec6b0b40f75c63c57775a7b012a16692e1ecfa3eeadfc373059e730edfbae31ad34479cc69531d6de176540c8b0fea7e7b2469157ddd21aabe7f5da42555927699617a3ea9581455423856b74e19ce61c1fa502b3d65ac95e7c390da132102f2913ec394e31bac541e0bd90f423a30cac1169e011b7881e6afc81d320f991e15b4273aeacc7a3b4e5f1a97969c465f389566faad5eab290c7608bc913dfe44a014b26f7a6d4bee76ae052127e88cff87792fd8a40715c2ba6ec8da862dbae6d1fc8531aacacd43c24e8cd5f056825e88a17ebb4a89587b2bbc943f9caf14e839463d35ac0eec84a07791a349b2df7b22c21a6cdb8b94f90b3a4813067098c20678923a34971a5522ffa8b1b962a40b8f28c8bad815aafa717b4d82790d02a7216505e36e5ecca6a551b35e120661890c5234a1846f1020af8bf3b4c2494c667f80e463074f993afce9358bfaa55644febb6d73af535afbb322844db72edd06acb5fbbd5bd66559e68d842c08a9b482b2e0615e9a210be374ad9cc36b1edba4be67243affbbfa21af80e74e125ccf9b40f5d559befc865f8a2db5a57af75efe8092cf871ae60a431e8b1ecd437465dcd37646bdc3274fa899b37cdf4e9a13e17b1d1722c4e642d728b92a25468dc5b748553dc7b0b13b55bd65613f8af86b64bdd7375a060afd69c5f09ae0fbf0c878ef3c870e9240e59e311941ccb487045e6981de7690423f09746a69db80c29ef9c38f212b6865e7e2b0d79b6cbc3300486234c6e715c353d9793bc848e3412b7711f3c51ac3670dd33b8042356eab9dc50aa09a56d6a7555f642f90d49a74b8a35cf8e556d0218d5accdab953ebc29355ac3f4058f398d6eaaddebc2b61deaeafd4c3724baa19389491bf6953237fb089663efc666582f81a0d17bf9e3346e557bcd93119b2de32960b7eeabfbf2c54d788293b82d17b9d74e3db7b26ac1a26de5ac0e5a32c4398e81a4b2b2a8ef02141f26b823694cefc2e2565438437c16f27ccc85d2d8566d33a7c8a4bef0eccba26d61d43199461c55cf4d79f2058f2f355c6dce207029cf181534a289be323f1322e33b9d1efc1d3a779cef0c061dd891ff94ffea15fab6c56288f59112d29466386d094afed8df2909073916c7219c5214cb85beb43d379678227d8bc36b8ab8ac023bd78dbb447d19ff6c1f7d58ca963aac967cb52e749731a647d3b16a388c43f89860c431309c5014872e6dce01791b9a4e1fea17dc977330d764b5f1208d5d2c32fd15861809f475f86db701215f9410c6fc6bb65f0092780f4660430dfbcea767bca3f6eb0fdd1cfecc2d7feae1e8e5cbc60930bf23229a412079f3a5bb482aa273ddd969bc01152a746fe84c9ae32b2082c33f722e0041668761fb376618dd389aa84fb6d73259ed80d8acd6406d85f87b422b226142128119d05c009e67620124e65e5832918bb7a2e4198d5c9db47c3f02aab593671de9fe9afd4296605a8482d6118a75c9600db914047b17ae2dd441bbda0e5a2824f1be63ea7599aeb07b2fa3b5de009bd5beba4ed669eb7ab3d9ae35119178efa5dab758d232b79e18a27fa318dc2e89274ac2eda8fa71c2385fc76aeb770a1e61b86d37d61e4f277d0c9da63bfd09845a1df92b292d7ecd13b8878d8d0d990d543788a95e682a53a55358e8a61159fc581b4981e7f368861ab56b2b57566a8a8d8d499e46c51577f359ab04cffbfa4af2199a9709c39cfacbb7a17a794ab808cd91390f2af85d89b944db389f33e86e11d3efe203739237bc1f0eff86f1af938909906a01b7c8309d98efafc962adab8bcd2ebc78013584c508f5b00aee23782d53e46000cfd974ecd418d6c976f14d8060107cfdffcfbff5067299ff97adbf6c990f02c4b9962e068ca299ccd432d9e0fb08670226847101cfc38da642bd24fdad24894da7e3314235baea62517f9da4c26029eb8d3e6cbd6db65b79a7fbab998eb262c670c984c1d219e1b7dfe0d71efc0b86f75251cef46e4dc8e81d7435627c9fe9465d92c20cdf9b8fe9c11d1133c8e4ea4a95bb9de79d108ec26908cf87c3c964380ce13d351fc7d21b308d3e0487fba6c5a4f97c8c59d736943ac716ca72e34e19bb05a6ac7a63b0b9b9019bbaed05b8c82713d880cd8165ef76470c27ff2cda378ac9753daa3e4602fa533350355ed6a879d8180ce00cdf0b88e81ceb7dd41962b1244ac83a6c9ee9be14bdad4a27b0f7f1447552463917740e5c75f9482c996e03ea432e5778e305a8a3af620796ed54d4b7340a19e2070338969a940e90313227eafb1c77587ffcf03520211819e702f31db8efc3c2f0aed7b3e49fe62e91f4fcbdabab8b93fd4f574797d71f8f2eae3f5e9c7c38319f1b7c5d75d6a845f1f1258ce06bcdaebad25e089704cf714cf27906938422b1dbad77e5746f115b48abbac5d16b23d706082531cc114903f9af1efce902181f0ea6c9f5474a527140298bc37b7805c3f04d0f36a1edcd4bf7cda2754cf9e6371886db6ffc54004c93eb63d59c661b8a07b270c6759048d104c39e178dfbeca1fb4d7f34a2fbff52bb034ae9e9b3474fa541c869b6015ddfaa03968f94bbf30d06f01145378ec100490595630565211cab282b13502ad4fd24d38082239ac6f0ca32310beb2549230c4474b9b611690e9994bcb4db08990b1e39c7b0fd1ac64480a0909594f0306c6014b39c034ab219826886d21427929898d12cc3715fd14e2480fa6003e23c9f975f06dd0a57c847bbee5ee9470db5e429918153c3e7d73c6218a7973290b441ce91780df9b56028e5f2c1cf721265d19ca83032b227844d6d6496f60736e57d18f661cb6b8185975cea80d994cfd7ad6fb0694ff675f84d2eda3db894f621f2a3f10fd1f96f0c2398d33888fab0fde66d38eced2a2c72bdcd8268609eb50e9f7edf70b6d670e33783116cbf79130edbd12118c19607a0eedabb5589665247093d4daa7f8ff3c904b3eaef627bcd6aabcc0549b813298af349a9905fb6d5a77f82b7afdd787240f354c8b2b07a1ea1f416f12f2416b3bef9e3774ca633d187d2002a68c20f14c8216162b16ba7756b6359e6f3e2b7090728497c1952baafaabd6512d6795587a669a29a46f1bdb03c7b73604904c53b50a6d7609a1c68707793619ac008cab7f5d581a2e59314a4a781c542591f653407236bbcb9a45eb4059bb8dd2f12ad83619a84392f810d3e77c7aa50797d9e2916a7c59ba02c3fbe76ad18d0ed43b7e989f2a91d1cf4dfa576bbdf9a34e2148d137374af1169932a490bcb399f32d8a5d0c1a17d4029cf48775f3da935def59f6270e6a68cde9c2f222b49950d9a5991a4d5c267a3fedf1992ea378dbeaff4b6e59cc6385145a2c4521e9ae86f0c59a5ab9e47e658c471cf8336a31c5ec19fb2ca7b804816312445425d1b57a8558393d7250a566cb7d044f6e53bd731641022f1bdf91cdea79390c4750528dbfd2a41365bcbca6f721d457978fff8a1f012b6e4f05772fce249e3b7bf55d43bab974760f9c5c252ad1c969bd705fe8f1c73a16f4b362d0c45224749b28098a13ba039334b1a15dac40cdba8ac480757d2324c6b474419964a57a35564f4ab5dcf6b2bbd190257879b69128e491a1b179b26e1dec5c5de1fd7fb9f8e8f8f2efac62d3c63d4f3432450738c127f5f421dfe71b6f7e1e4e0faf062ef8ba7a9bb964fbc9f23b601ca36980698e453d7661f9060e4fef5e4d60a375522d3e3add4e6d94faa706d4f2c247671d59a345b8f7f0de25b2b28aa2a0c335f4cedc3b692def1e9f9de554974ab216fd6f27eb8ff470172747af4e1e8ecaa0fc3a6fe9693e246e81f4ed1366cc2eb2655d26bd4182eadeae3f9c9d9d5a52a66abfae5fb92c0dd0ca77269c2804728c17c90a1d4789dd2a3de3cd1374dbd4ea753c8556140b5908befcae78d33dab27457955a09e7f88463eefadcfd87b0cbb08c704f60559abcc3e5816dffe5dfc605dceb8915ac66dd1abceb81d4586c50fde4270b4aa8f3383291eb5610332474cac577e65ba9889bcfd2c445bda0fa1fbc7233dfafa1317613b2ef3e9053e6e17b81d358574c268e56b6dfee723d4f02d4e5fecb116cfd0cd1146231df04d10971b960aa13b3558229ee53191e740f95cdd52bc955e39e2f145de0f09b0dfce205349035e2fe600077b8f8660fc33a89ab165640e9421fd5963ceaec17fa909ca45c60144b64fc0e6506475c7c7357cc14824e82b8e898efc2a4f5caa0c255d4a4690c319666c531cc11bbc1ac280a2d3c21bc27b798434a220ce7c156cf87d1fa7e6c5fdd899fa31b5971c418b8ea5c49166a4b54ea7d86522002229a27318c71f3a8c75e05d16ca18cf62362c2365ca98cf622cc36eea5606bdafdc31a86ae4aad391633aa7695a2a5b153f23f43e91473b549ac8a7122b88d4f2b8987f0459a4fda156aeb8b0898616684acf6ca528c633dd1dec7130838c6a6da9bd7ffcf059b4584b10e987b86e05e8b5fa973968f8c66980982b9ed5ee665718504df995b5585841e76371e36fe330000ffff85c9196802680000",
+		"f3aa7c7c063ea75f55c6f07e3b99f877": "1f8b08000000000000ffcc595b8fdbb8f57fd7a738ff0cf2327fcb97997a67a1c13eb4db6c11a08b14cd027d580430251d59ec50a44052633bd97cf7821749d4cd49da9da26320b128f2dc2fbf436f6eff0fb8901561f423ae33a5e0f9fbf576bd83dfe0e7b7bfc05f69865c21fc0647aacb265d67a2da70cc04236a333c77bb89a2cd2dfc59644d855c4700f0c3eff6e7a9df46700bbb35fc28a4c44c832e1118e50825d263a98172208c412ac549a1546bb3fd6e0d7f93f88c5c03c9ffd9286da453200a2804d7a0e84704526894202445ae89a6824356127e446528d277ef0da14d1495ba62f029027b322e4845d925814a70a16a92e1aafffa089b5bd8994360058c9d8009ecd6bb7df8323e61fa4475acf1ac63234bec844c60b7ddbeb63befcccecfd6b8ef3133d2a99733eedfb112cf680d5b117934ea4f6dba89a254e4176b0ab72b81ed6304209e51164c9c1228699e237f74727bca3c4769291f2a42f90190a1f10564822baa3472cd2e86dddb379e89d96699e454d58c5c124899c89e42aa612404fee4792bbee07028771d330527aa4bcae1a09c2d0f66b3a1742052d38ce1c1c863dc619dff632945852bf8894a2cc4796549bf270591b40d8a5d1f1286790277583d8696597ff78095319073e25fa4686aca8f8ecf0b67ca1ff3dcda26f3764ac5d998c8b0a7bcd5aacd93f7a538d9ddad1fcd9e37f9d119b4734b29adc6a938c78e54d2aa12a7e21c46771bf5db70b10f9267aa68ca7014e573494e7989926ac233278bca08333a0cb27821fb433a22cfe180d5a13be50d3113e1b5c46fcff5200a76588dd3f71793e40c9f9181c28a704db3ff4e2a1f25b9404ab2a7a3140dcf4d52904cd3675b3d9f944b3ad86dbdeac4f9b7db1f67820999809684ab9a48e4fa71e8ab80572ab41615a4429a74ef5208f60fb177c838264db2418e9990aef6066967826f056fdface05d8d92cca41f4953f9aba69ae1071f95866feca448800b3e7090adb33daf041a53954c89ee9d756d17e4426bcce74276ac960db153d798862a4df4485791d252f0631f74279f3da96039cac7ffa9ecc8448eabe829cd57912255fd3b67cab23d9754d94491aacce2a8167fbf7d1d1aae450207d5a4b6f29b6f75d01d0a292a2045619a033fce000c43658e79631cd8d463fe0ffbd78f630c605b652d1475b1259111938b66f5194d13222c268c1e790229516883d3e8a09ad487b88bed78bbbedb9b5e63df39d65ad4f645bbbeb98537558a798ef9cbf79b4115b0e96fb2b9220e48299a2fd41b5a1dc3dc55fac2d0a7aed7e12721ab172c95269f2ce00b708411422d65cd2c4cf2dd7426b71bad055f4594d78d5e45a2d6a6aed6ab4821c34caf22536f8844f29fa5510b18bf0677f6b06d26f36671806bffc6548b30614e5df874b5f50f006267d3b0a089c23508db7c0a21ab96db0894f5f27d0ba1000105923bbf0c44b72da13b3a88ce0910a59ca494517d012d5c2041c668f6445286a02f7537572c87caaf66db0fafdce3ab0fdd8244853a78564d5a51fdcaf5be769820758d441aa513701416edcc51b6b96a64a9499e4fb161275792c495f81817226b546c0f4f24bdb2c5cb7e6547abcd74cb627d8056e6a443d85e4ba5856c133a6b549bd10d57a821bdd837b5c4672a1a05b261c3f00d2490941fa77a2ebc6f955c78dd69387c6fd5138d36399bc0ae3e7b9c017fb2ec0c705c0ab645971514596e74fd3430d2fa7e6fa691f583fbefbbbbbe55cc610b9b322749eada3319cd03630c61a1e220ef6c4b3db4d204bdb62f2af783a46d355202720396458d520191085c68c848633ab168349c4ae4e6c4053ea21466c9100358e236d3b7191e91e79379a643918371c6c360af5c0818bb01559376a0e90aed393ed15c97d3021d04ae59bd77aba7926a8c6da14ffcd54c7f68191db5c8012c72b073f5d2f86aa17437e588a344a5ac05aea28f69f5c8b1200d0b58ab4c0ac65222bb06ffff9ecda0c1f55d80345a8c62effac0daa18651130e922004163ee9b212b3a7549cc33a4a722a5e7df84ac78f3c356a9783f06fa412d2177d5100e59974b71cc6f239b64fae8c04570c43897953a5286d21f435dd56c158d594c7a31e31dd2b1a3ddc6bd56ca1c08cd1c74340df4082016ed8ab26b3832b5e5e73ca876dadad7e4864565ee956264e6cee0e2e0c1ce9581485429d407c579fe7fc30696c41544c7430d0b4225977b73792b037a65b09a6c145e1c7906032a5fd7ba8c05adaa1538b4c6b690aa2a6a80ca183af468789cd7b150aca306e6a26481e06c415b83042983335cfe1f2b75ca37457092f82cee72a9dafb53d0c7495c6d5b6610bcc5113cad4f21de217e8cf0e7a5545e465489251a563aafb99eb67aab2971b57ae483caaba55cd88c6a1b0e330fd12b53641dc95ee87456271ff274e3c788acdf11b268ec29e0d665f922ac11a6d611c00c3a29d8ebb0165b7adcf6ea19b64b6dd52df57cdcae7285a074cc6feee89c68e91ab83c1b20ceb63407fefef106eec359327efb1c051e2c56db603826f9c199abc70ebe184f68756f2f07e27152c1fe8dc9ac097afee2e6befb5bca1bcf882296570d3d0b72f67cc9154bbbb56a840037bde31539ae8468dd98597169de0dbb1c6f30a43afb1b3e20d21c43d7f8c29cff16c7cda729748aa6f9001eeea336ccd27e4e0dc6409da72fe0f0368fd543189e62f333186842ddc9b7f9704b77cc60c28b79d2c08c9fe967574bf6a5f5a3432ce89b15bdb671fae77dbdecd57a33474b2953671839293b99b467aa3786ace5de658c6904c8cf8a23a3a7c95402da84bb1a99a9d60d7d4e93795068e0e93ba8fc7c945b0554d975234c7d252896eb8c851bdb34afbb01ac5290c63a82d64df7775ac05c4f125f1187a2ead3a53ec5dd8cd3b78128881785ff6d4e676e0ac9491ece9d1b7fb012555137ea5d00e64ddb77a8eeee6ed984b548939dc3c64e6b3e0e339e66bff03c6d071f7f7dfe5e97efe445250a9749c9594e5fe9817c85e9ace49d392799b87bf756ec35b877d5b03662bdc959f1ba241f5835e644df45796ba87c55207be4face0c60cca9fae8593af62e6c05192baccc6cc61d85bc26976dc995fcf056e1f928fd1e77f050000ffff222970aa71200000",
+	})
+	if err != nil {
+		panic(err)
+	}
+	g.DefaultResolver = hgr
+
+	func() {
+		b := packr.New("Assets", "./static")
+		b.SetResolver("css/normalize.css", packr.Pointer{ForwardBox: gk, ForwardPath: "f3aa7c7c063ea75f55c6f07e3b99f877"})
+		b.SetResolver("img/gos.png", packr.Pointer{ForwardBox: gk, ForwardPath: "166310f2d73113b478111b0a976a0eea"})
+		b.SetResolver("index.html", packr.Pointer{ForwardBox: gk, ForwardPath: "2f53e054245e3cec681be9135541dbcb"})
+		b.SetResolver("js/main.js", packr.Pointer{ForwardBox: gk, ForwardPath: "f256e6f5a46e10e60db6a2444386dc4e"})
+		b.SetResolver("js/vivagraph-0.12.0.min.js", packr.Pointer{ForwardBox: gk, ForwardPath: "853579e9f8c28c5a0ea8a5ed642bbad0"})
+		}()
+
+	return nil
+}()
diff --git a/plugins/analysis/webinterface/httpserver/parameters.go b/plugins/analysis/webinterface/httpserver/parameters.go
index a32ab36fd895ad1d470a4a63afd32f8ca7db311e..0bee3d52e7250dbac3afcdb00715f4965b1e7c51 100644
--- a/plugins/analysis/webinterface/httpserver/parameters.go
+++ b/plugins/analysis/webinterface/httpserver/parameters.go
@@ -6,8 +6,10 @@ import (
 
 const (
 	CFG_BIND_ADDRESS = "analysis.httpServer.bindAddress"
+	CFG_DEV          = "analysis.httpServer.dev"
 )
 
 func init() {
 	flag.String(CFG_BIND_ADDRESS, "0.0.0.0:80", "the bind address for the web API")
+	flag.Bool(CFG_DEV, false, "whether the analysis server visualizer is running dev mode")
 }
diff --git a/plugins/analysis/webinterface/httpserver/plugin.go b/plugins/analysis/webinterface/httpserver/plugin.go
index c84fabe599f9c30f316ce63f88f142c2e3bc18d5..dfc752a3ec08edaf39f619e49972fa294c6a8f1e 100644
--- a/plugins/analysis/webinterface/httpserver/plugin.go
+++ b/plugins/analysis/webinterface/httpserver/plugin.go
@@ -5,34 +5,41 @@ import (
 	"net/http"
 	"time"
 
+	"github.com/gobuffalo/packr/v2"
 	"github.com/iotaledger/goshimmer/packages/parameter"
 	"github.com/iotaledger/goshimmer/packages/shutdown"
 	"github.com/iotaledger/hive.go/daemon"
 	"github.com/iotaledger/hive.go/logger"
+	"github.com/labstack/echo"
 	"golang.org/x/net/context"
 	"golang.org/x/net/websocket"
 )
 
 var (
-	log        *logger.Logger
-	httpServer *http.Server
-	router     *http.ServeMux
+	log    *logger.Logger
+	engine *echo.Echo
 )
 
 const name = "Analysis HTTP Server"
 
+var assetsBox = packr.New("Assets", "./static")
+
 func Configure() {
 	log = logger.NewLogger(name)
 
-	router = http.NewServeMux()
+	engine = echo.New()
+	engine.HideBanner = true
 
-	httpServer = &http.Server{
-		Addr:    parameter.NodeConfig.GetString(CFG_BIND_ADDRESS),
-		Handler: router,
+	// we only need this special flag, because we always keep a packed box in the same directory
+	if parameter.NodeConfig.GetBool(CFG_DEV) {
+		engine.Static("/static", "./plugins/analysis/webinterface/httpserver/static")
+		engine.File("/", "./plugins/analysis/webinterface/httpserver/static/index.html")
+	} else {
+		engine.GET("/static/*", echo.WrapHandler(http.StripPrefix("/static", http.FileServer(assetsBox))))
+		engine.GET("/", index)
 	}
 
-	router.Handle("/datastream", websocket.Handler(dataStream))
-	router.HandleFunc("/", index)
+	engine.GET("/datastream", echo.WrapHandler(websocket.Handler(dataStream)))
 }
 
 func Run() {
@@ -44,9 +51,10 @@ func Run() {
 
 func start(shutdownSignal <-chan struct{}) {
 	stopped := make(chan struct{})
+	bindAddr := parameter.NodeConfig.GetString(CFG_BIND_ADDRESS)
 	go func() {
-		log.Infof("Started %s: http://%s", name, httpServer.Addr)
-		if err := httpServer.ListenAndServe(); err != nil {
+		log.Infof("Started %s: http://%s", name, bindAddr)
+		if err := engine.Start(bindAddr); err != nil {
 			if !errors.Is(err, http.ErrServerClosed) {
 				log.Errorf("Error serving: %s", err)
 			}
@@ -63,8 +71,16 @@ func start(shutdownSignal <-chan struct{}) {
 	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
 	defer cancel()
 
-	if err := httpServer.Shutdown(ctx); err != nil {
+	if err := engine.Shutdown(ctx); err != nil {
 		log.Errorf("Error stopping: %s", err)
 	}
 	log.Info("Stopping %s ... done", name)
 }
+
+func index(e echo.Context) error {
+	indexHTML, err := assetsBox.Find("index.html")
+	if err != nil {
+		return err
+	}
+	return e.HTMLBlob(http.StatusOK, indexHTML)
+}
diff --git a/plugins/analysis/webinterface/httpserver/static/css/normalize.css b/plugins/analysis/webinterface/httpserver/static/css/normalize.css
new file mode 100644
index 0000000000000000000000000000000000000000..a0feda7664c4890b3ba635708e0e925d05319945
--- /dev/null
+++ b/plugins/analysis/webinterface/httpserver/static/css/normalize.css
@@ -0,0 +1,504 @@
+/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */
+
+/* Document
+   ========================================================================== */
+
+/**
+ * 1. Correct the line height in all browsers.
+ * 2. Prevent adjustments of font size after orientation changes in iOS.
+ */
+
+html {
+  font-family: monospace, monospace; /* 1 */
+  line-height: 1.15; /* 1 */
+  -webkit-text-size-adjust: 100%; /* 2 */
+}
+
+/* Sections
+   ========================================================================== */
+
+/**
+ * Remove the margin in all browsers.
+ */
+
+body {
+  margin: 0;
+  overflow: hidden;
+}
+
+/**
+ * Render the `main` element consistently in IE.
+ */
+
+main {
+  display: block;
+}
+
+/**
+ * Correct the font size and margin on `h1` elements within `section` and
+ * `article` contexts in Chrome, Firefox, and Safari.
+ */
+
+h1 {
+  font-size: 2em;
+  margin: 0.67em 0;
+}
+
+/* Grouping content
+   ========================================================================== */
+
+/**
+ * 1. Add the correct box sizing in Firefox.
+ * 2. Show the overflow in Edge and IE.
+ */
+
+hr {
+  box-sizing: content-box; /* 1 */
+  height: 0; /* 1 */
+  overflow: visible; /* 2 */
+}
+
+/**
+ * 1. Correct the inheritance and scaling of font size in all browsers.
+ * 2. Correct the odd `em` font sizing in all browsers.
+ */
+
+pre {
+  font-family: monospace, monospace; /* 1 */
+  font-size: 1em; /* 2 */
+}
+
+/* Text-level semantics
+   ========================================================================== */
+
+/**
+ * Remove the gray background on active links in IE 10.
+ */
+
+a {
+  background-color: transparent;
+}
+
+/**
+ * 1. Remove the bottom border in Chrome 57-
+ * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
+ */
+
+abbr[title] {
+  border-bottom: none; /* 1 */
+  text-decoration: underline; /* 2 */
+  text-decoration: underline dotted; /* 2 */
+}
+
+/**
+ * Add the correct font weight in Chrome, Edge, and Safari.
+ */
+
+b,
+strong {
+  font-weight: bolder;
+}
+
+/**
+ * 1. Correct the inheritance and scaling of font size in all browsers.
+ * 2. Correct the odd `em` font sizing in all browsers.
+ */
+
+code,
+kbd,
+samp {
+  font-family: monospace, monospace; /* 1 */
+  font-size: 1em; /* 2 */
+}
+
+/**
+ * Add the correct font size in all browsers.
+ */
+
+small {
+  font-size: 80%;
+}
+
+/**
+ * Prevent `sub` and `sup` elements from affecting the line height in
+ * all browsers.
+ */
+
+sub,
+sup {
+  font-size: 75%;
+  line-height: 0;
+  position: relative;
+  vertical-align: baseline;
+}
+
+sub {
+  bottom: -0.25em;
+}
+
+sup {
+  top: -0.5em;
+}
+
+/* Embedded content
+   ========================================================================== */
+
+/**
+ * Remove the border on images inside links in IE 10.
+ */
+
+img {
+  border-style: none;
+}
+
+/* Forms
+   ========================================================================== */
+
+/**
+ * 1. Change the font styles in all browsers.
+ * 2. Remove the margin in Firefox and Safari.
+ */
+
+button,
+input,
+optgroup,
+select,
+textarea {
+  font-family: monospace, monospace; /* 1 */
+  font-size: 100%; /* 1 */
+  line-height: 1.15; /* 1 */
+  margin: 0; /* 2 */
+}
+
+/**
+ * Show the overflow in IE.
+ * 1. Show the overflow in Edge.
+ */
+
+button,
+input { /* 1 */
+  overflow: visible;
+}
+
+/**
+ * Remove the inheritance of text transform in Edge, Firefox, and IE.
+ * 1. Remove the inheritance of text transform in Firefox.
+ */
+
+button,
+select { /* 1 */
+  text-transform: none;
+}
+
+/**
+ * Correct the inability to style clickable types in iOS and Safari.
+ */
+
+button,
+[type="button"],
+[type="reset"],
+[type="submit"] {
+  -webkit-appearance: button;
+}
+
+/**
+ * Remove the inner border and padding in Firefox.
+ */
+
+button::-moz-focus-inner,
+[type="button"]::-moz-focus-inner,
+[type="reset"]::-moz-focus-inner,
+[type="submit"]::-moz-focus-inner {
+  border-style: none;
+  padding: 0;
+}
+
+/**
+ * Restore the focus styles unset by the previous rule.
+ */
+
+button:-moz-focusring,
+[type="button"]:-moz-focusring,
+[type="reset"]:-moz-focusring,
+[type="submit"]:-moz-focusring {
+  outline: 1px dotted ButtonText;
+}
+
+/**
+ * Correct the padding in Firefox.
+ */
+
+fieldset {
+  padding: 0.35em 0.75em 0.625em;
+}
+
+/**
+ * 1. Correct the text wrapping in Edge and IE.
+ * 2. Correct the color inheritance from `fieldset` elements in IE.
+ * 3. Remove the padding so developers are not caught out when they zero out
+ *    `fieldset` elements in all browsers.
+ */
+
+legend {
+  box-sizing: border-box; /* 1 */
+  color: inherit; /* 2 */
+  display: table; /* 1 */
+  max-width: 100%; /* 1 */
+  padding: 0; /* 3 */
+  white-space: normal; /* 1 */
+}
+
+/**
+ * Add the correct vertical alignment in Chrome, Firefox, and Opera.
+ */
+
+progress {
+  vertical-align: baseline;
+}
+
+/**
+ * Remove the default vertical scrollbar in IE 10+.
+ */
+
+textarea {
+  overflow: auto;
+}
+
+/**
+ * 1. Add the correct box sizing in IE 10.
+ * 2. Remove the padding in IE 10.
+ */
+
+[type="checkbox"],
+[type="radio"] {
+  box-sizing: border-box; /* 1 */
+  padding: 0; /* 2 */
+}
+
+/**
+ * Correct the cursor style of increment and decrement buttons in Chrome.
+ */
+
+[type="number"]::-webkit-inner-spin-button,
+[type="number"]::-webkit-outer-spin-button {
+  height: auto;
+}
+
+/**
+ * 1. Correct the odd appearance in Chrome and Safari.
+ * 2. Correct the outline style in Safari.
+ */
+
+[type="search"] {
+  -webkit-appearance: textfield; /* 1 */
+  outline-offset: -2px; /* 2 */
+}
+
+/**
+ * Remove the inner padding in Chrome and Safari on macOS.
+ */
+
+[type="search"]::-webkit-search-decoration {
+  -webkit-appearance: none;
+}
+
+/**
+ * 1. Correct the inability to style clickable types in iOS and Safari.
+ * 2. Change font properties to `inherit` in Safari.
+ */
+
+::-webkit-file-upload-button {
+  -webkit-appearance: button; /* 1 */
+  font: inherit; /* 2 */
+}
+
+/* Interactive
+   ========================================================================== */
+
+/*
+ * Add the correct display in Edge, IE 10+, and Firefox.
+ */
+
+details {
+  display: block;
+}
+
+/*
+ * Add the correct display in all browsers.
+ */
+
+summary {
+  display: list-item;
+}
+
+/* Misc
+   ========================================================================== */
+
+/**
+ * Add the correct display in IE 10+.
+ */
+
+template {
+  display: none;
+}
+
+/**
+ * Add the correct display in IE 10.
+ */
+
+[hidden] {
+  display: none;
+}
+
+/*-----------own------------*/
+
+#logo {
+    position:absolute;
+    left: 0;
+    margin:10px;
+    height: 100px;
+    width: 100px;
+}
+
+.logo {
+    display: block;
+    margin-left: auto;
+    margin-right: auto;
+    width: 50%;
+}
+
+#title {
+    color: grey;
+    text-align: center;
+    font-size: 14px;
+    font-weight:bold;
+    margin: 0;
+    padding-bottom: 5px;
+}
+
+#info {
+    position:absolute;
+    right: 0;
+    padding:10px;
+
+    font-size:12px;
+    text-align:right;
+}
+
+#status {
+    position:relative;
+    margin:0;
+    font-size:14px;
+    font-weight: bold;
+    color:#aaa;
+    z-index: 10;
+}
+
+#streamstatus {
+    position:relative;
+    margin: 2px 0 0 0;
+    color:grey;
+}
+
+#searchWrapper {
+    display: none;
+    position:relative;
+    margin:10px 0 3px 0;
+    z-index: 10;
+}
+
+#search {
+    display: inline-block;
+    background: transparent;
+    border: 0;
+    margin: 0;
+    padding: 0;
+    width: 200px;
+
+    color: grey;
+    text-align: right;
+}
+
+#search:focus {
+    outline: none;
+    color: #aaa;
+}
+
+#clear {
+    display: inline-block;
+    background: transparent;
+    border: 0;
+    margin: 0;
+    padding: 0;
+    cursor: pointer;
+
+    color: grey;
+}
+
+#clear:focus {
+    outline: none;
+}
+
+#clear:hover {
+    color: #aaa;
+    text-decoration: line-through;
+}
+
+
+#nodesOnlineWrapper{
+    position: relative;
+    height: 80px;
+    overflow-y: scroll;
+    margin:0;
+    padding: 5px 0;
+
+    color: grey;
+    z-index: 10;
+}
+
+#nodesOnline {
+    display: inline-block;
+    /* background: black; */
+}
+
+#nodesOnline span {
+    display: block;
+    padding: 5px 5px;
+    border-bottom: 1px dashed #7c7c7c;
+    cursor: pointer;
+}
+
+#nodesOnline span.active {
+    color: #336db5;
+}
+
+#nodesOnline span:first-child {
+    border-top: 1px dashed #7c7c7c;
+}
+
+#nodeId {
+  margin:0;
+  padding:5px 0;
+  font-weight: bold;
+  text-decoration: underline;
+  color:#aaa; 
+}
+
+#nodestats {
+    position:relative;
+    margin: 7px 0 0 0;
+    color:grey; 
+}
+
+#in, #out {
+    margin:0;
+    padding: 3px 0;
+}
+
+#graphc {
+    position: absolute;
+    width: 100%;
+    height: 100%;
+    margin:0;
+    z-index: 1;
+}
\ No newline at end of file
diff --git a/plugins/analysis/webinterface/httpserver/static/img/gos.png b/plugins/analysis/webinterface/httpserver/static/img/gos.png
new file mode 100644
index 0000000000000000000000000000000000000000..e47b66f9e93837d8e58bb764015047a14bdf8451
Binary files /dev/null and b/plugins/analysis/webinterface/httpserver/static/img/gos.png differ
diff --git a/plugins/analysis/webinterface/httpserver/static/index.html b/plugins/analysis/webinterface/httpserver/static/index.html
new file mode 100644
index 0000000000000000000000000000000000000000..211feba0c7f4799871401ab96dfc4cf51b9583e4
--- /dev/null
+++ b/plugins/analysis/webinterface/httpserver/static/index.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <meta charset="utf-8" />
+    <title>GoShimmer - Network Visualizer</title>
+    <link rel="stylesheet" type="text/css" href="/static/css/normalize.css">
+    <script type="text/javascript" src="/static/js/vivagraph-0.12.0.min.js"></script>
+    <script type="text/javascript" src="/static/js/main.js"></script>
+</head>
+
+<body style="background: #202126;">
+    <div id="logo">
+        <p id="title">GOSHIMMER<br>NETWORK</p>
+        <img class="logo" src="/static/img/gos.png" alt="GoShimmer">
+    </div>
+
+    <div id="graphc"></div>
+
+    <div id="info">
+        <p id="status"></p>
+        <p id="streamstatus"></p>
+
+        <div id="searchWrapper">
+            <input id="search" type="text" placeholder="search for node..." autocomplete="off">
+            <input type="button" id="clear" value="clear"> 
+        </div>
+        <div id="nodesOnlineWrapper"><div id="nodesOnline"></div></div>
+
+        <div id="nodestats">
+            <p id="nodeId"></p>
+            <p id="in"></p>
+            <p id="out"></p>
+        </div>
+    </div>
+</body>
+
+</html>
\ No newline at end of file
diff --git a/plugins/analysis/webinterface/httpserver/static/js/main.js b/plugins/analysis/webinterface/httpserver/static/js/main.js
new file mode 100644
index 0000000000000000000000000000000000000000..8ede0c5a13038ee5b9ceade73e9c47e9e01be8d4
--- /dev/null
+++ b/plugins/analysis/webinterface/httpserver/static/js/main.js
@@ -0,0 +1,819 @@
+const ANALYSIS_SERVER_URL = "116.202.49.178" + "/datastream";
+const NODE_ID_LENGTH = 64;
+
+// for some strange reason color formats for edges and nodes need to be different... careful!
+const EDGE_COLOR_DEFAULT = "#444444";
+const EDGE_COLOR_OUTGOING = "#336db5";
+const EDGE_COLOR_INCOMING = "#1c8d7f";
+const VERTEX_COLOR_DEFAULT = "0x666666";
+const VERTEX_COLOR_ACTIVE = "0x336db5";
+const VERTEX_COLOR_CONNECTED = "0x1c8d7f";
+const VERTEX_SIZE = 14;
+
+class Frontend {
+    constructor(app) {
+        this.app = app;
+        this.activeNode = '';
+        this.searchTerm = '';
+        document.addEventListener('click', (e) => {
+            if (hasClass(e.target, 'n')) {
+                let htmlNode = e.target;
+                let nodeId = htmlNode.innerHTML;
+
+                if(hasClass(htmlNode, 'active')) {
+                    this.app.resetActiveNode();
+                    return;
+                }
+
+                // TODO: add active class and remove possible others (necessary for search feature)
+
+                this.app.setActiveNode(nodeId, true);
+            }
+        }, false);
+
+        this.initSearch();
+    }
+
+    initSearch() {
+        document.getElementById("search").addEventListener('keyup', (e) => {
+            let value = e.target.value.trim().toLowerCase();
+
+            if(value === "") {
+                this.resetSearch();
+                return;
+            }
+
+            this.searchTerm = value;
+            
+            let results = new Set();
+            for(let n of this.app.ds.nodesOnline) {
+                if(n.startsWith(value)) {
+                    results.add(n);
+                }
+            }
+            
+            if(results.size == 1) {
+                // little hack to access element
+                let n = results.values().next().value;
+                this.app.setActiveNode(n, true);
+            }
+
+            this.displayNodesOnline(results);
+        });
+
+        document.getElementById("clear").addEventListener("click", (e) => {
+            this.resetSearch();
+        });
+    }
+
+    resetSearch() {
+        document.getElementById("search").value = "";
+        this.searchTerm = '';
+        this.app.resetActiveNode();
+    }
+
+    showSearchField() {
+        document.getElementById('searchWrapper').style.cssText = "display:block;"
+    }
+
+    setStatusMessage(msg) {
+        document.getElementById("status").innerHTML = msg;
+    }
+
+    setStreamStatusMessage(msg) {
+        document.getElementById("streamstatus").innerHTML = msg;
+    }
+
+    showNodeLinks(node, neighbors) {
+        document.getElementById("nodeId").innerHTML = node + " in:" + neighbors.in.size + " out:" + neighbors.out.size;
+
+        let html = "incoming edges: ";
+        // incoming
+        for(let n of neighbors.in) { 
+            html += n + " &rarr; " + "NODE<br>";
+        }
+        if(neighbors.in.size == 0) { html += "no incoming edges!" }
+        document.getElementById("in").innerHTML = html;
+
+        html = "outgoing edges: ";
+        // outgoing
+        for(let n of neighbors.out) { 
+            html += "NODE" + " &rarr; " + n + "<br>";
+        }
+        if(neighbors.out.size == 0) { html += "no outgoing edges!" }
+        document.getElementById("out").innerHTML = html;
+    }
+
+    setActiveNode(nodeId, updateHash=false) {
+        this.activeNode = nodeId;
+        if(updateHash) {
+            history.replaceState(null, null, '#'+nodeId);
+        }
+
+        let neighbors = this.app.ds.neighbors[nodeId];
+        this.showNodeLinks(nodeId, neighbors);
+    }
+
+    resetActiveNode() {
+        // currently active node will lose class at next refresh
+        this.activeNode = '';
+        history.replaceState(null, null, ' '); // reset location hash
+        this.resetNodeLinks();
+    }
+
+    resetNodeLinks() {
+        document.getElementById("nodeId").innerHTML = "";
+        document.getElementById("in").innerHTML = "";
+        document.getElementById("out").innerHTML = "";
+    }
+
+    displayNodesOnline(nodesOnline) {
+        // this line might be a performance killer!
+        nodesOnline = Array.from(nodesOnline).sort();
+
+        let html = [];
+        for(let n of nodesOnline) {
+            if(n == this.activeNode) {
+                html.push('<span class="n active">' + n + "</span>");
+            } else {
+                html.push('<span class="n">' + n + "</span>");
+            }
+        }
+        document.getElementById("nodesOnline").innerHTML = html.join("");
+    }
+}
+
+class Datastructure {
+    constructor(app) {
+        this.app = app;
+        this.nodes = new Set();
+        this.nodesOnline = new Set();
+        this.nodesOffline = new Set();
+        this.nodesDisconnected = new Set();
+        this.connections = new Set();
+        this.neighbors = new Map();
+    }
+
+    getStatusText() {
+        // avg = this.connections.size*2 / (this.nodesOnline-1) : -1 == entry node (always disconnected)
+        return "nodes online: " + this.nodesOnline.size + "(" + this.nodesDisconnected.size + ")" + " - IDs: " + this.nodes.size + " - edges: " + this.connections.size + " - avg: " + (this.connections.size*2 / (this.nodesOnline.size-1)).toFixed(2);
+    }
+
+    addNode(idA) {
+        if(!this.nodes.has(idA)) {
+            this.nodes.add(idA);
+
+            this.app.setStreamStatusMessage("addedToNodepool: " + idA);
+            this.app.updateStatus();
+        }
+
+        // TODO: temporary fix for faulty analysis server. do not set nodes offline.
+        this.setNodeOnline(idA);
+    }
+
+    removeNode(idA) {
+        if(!this.nodes.has(idA)) {
+            console.error("removeNode but not in nodes list:", idA);
+            return;
+        }
+
+        if(this.nodesDisconnected.has(idA)) { this.nodesDisconnected.delete(idA); }
+        if(this.neighbors.has(idA)) { this.neighbors.delete(idA); }
+
+        if(this.nodesOnline.has(idA)) {
+            this.nodesOnline.delete(idA);
+            this.app.graph.deleteVertex(idA);
+
+            this.app.setStreamStatusMessage("removeNode from onlinepool: " + idA);
+        }
+        
+        if(this.nodesOffline.has(idA)) {
+            this.nodesOffline.delete(idA);
+            this.app.setStreamStatusMessage("removeNode from offlinepool: " + idA);
+        }
+
+        if(this.nodes.has(idA)) {
+            this.nodes.delete(idA);
+            this.app.setStreamStatusMessage("removeNode from nodepool: " + idA);
+        }
+        
+        this.app.updateStatus();
+    }
+
+    setNodeOnline(idA) {
+        if(!this.nodes.has(idA)) {
+            console.error("setNodeOnline but not in nodes list:", idA);
+            return;
+        }
+
+        // check if not in nodesOnline set
+        if(!this.nodesOnline.has(idA)) {
+            this.nodesOnline.add(idA);
+            this.app.graph.addVertex(idA);
+
+            // create entry in neighbors map
+            this.neighbors[idA] = this.createNeighborsObject();
+            this.nodesDisconnected.add(idA);
+
+            this.app.setStreamStatusMessage("setNodeOnline: " + idA)
+        } else {
+            this.app.setStreamStatusMessage("setNodeOnline skipped: " + idA)
+        }
+
+        // check if in nodesOffline set
+        if(this.nodesOffline.has(idA)) {
+            this.nodesOffline.delete(idA);
+
+            this.app.setStreamStatusMessage("removedFromOfflinepool: " + idA)
+        }
+
+        this.app.updateStatus();
+    }
+
+    createNeighborsObject() {
+        return {
+            in: new Set(),
+            out: new Set(),
+        }
+    }
+
+    setNodeOffline(idA) {
+        // TODO: temporary fix for faulty analysis server. do not set nodes offline.
+        return;
+
+        if(!this.nodes.has(idA)) {
+            console.error("setNodeOffline but not in nodes list:", idA);
+            return;
+        }
+
+        if(this.nodesDisconnected.has(idA)) { this.nodesDisconnected.delete(idA); }
+        if(this.neighbors.has(idA)) { this.neighbors.delete(idA); }
+
+        if(!this.nodesOffline.has(idA)) {
+            this.nodesOffline.add(idA);
+
+            this.app.setStreamStatusMessage("addedToOfflinepool: " + idA)
+        }
+
+        // check if node is currently online
+        if(this.nodesOnline.has(idA)) {
+            this.nodesOnline.delete(idA);
+            this.app.graph.deleteVertex(idA);
+
+            this.app.setStreamStatusMessage("removedFromOnlinepool: " + idA)
+        }
+
+        this.app.updateStatus();
+    }
+
+    connectNodes(con, idA, idB) {
+        if(!this.nodes.has(idA)) {
+            console.error("connectNodes but not in nodes list:", idA, con);
+            return;
+        }
+        if(!this.nodes.has(idB)) {
+            console.error("connectNodes but not in nodes list:", idB, con);
+            return;
+        }
+
+        if(this.connections.has(con)) {
+            this.app.setStreamStatusMessage("connectNodes skipped: " + idA + " > " + idB);
+        } else {
+            // add new connection only if both nodes are online
+            if(this.nodesOnline.has(idA) && this.nodesOnline.has(idB) && idA != idB) {
+                this.app.graph.addEdge(con, idA, idB);
+                this.connections.add(con);
+
+                // update datastructure for fast neighbor lookup
+                this.neighbors[idA].out.add(idB);
+                this.neighbors[idB].in.add(idA);
+
+                // remove from disconnected list
+                if(this.nodesDisconnected.has(idA)) { this.nodesDisconnected.delete(idA); }
+                if(this.nodesDisconnected.has(idB)) { this.nodesDisconnected.delete(idB); }
+
+                this.app.setStreamStatusMessage("connectNodes: " + idA + " > " + idB);
+                this.app.updateStatus();
+            } else {
+                console.log("connectNodes skipped: either node not online", idA, idB);
+            }
+        }
+    }
+
+    disconnectNodes(con, idA, idB) {
+        if(!this.nodes.has(idA)) {
+            console.error("disconnectNodes but not in nodes list:", idA, con);
+            return;
+        }
+        if(!this.nodes.has(idB)) {
+            console.error("disconnectNodes but not in nodes list:", idB, con);
+            return;
+        }
+
+        if(this.connections.has(con)) {
+            this.connections.delete(con);
+            this.app.graph.deleteEdge(con, idA, idB);
+
+            // update datastructure for fast neighbor lookup
+            this.neighbors[idA].out.delete(idB);
+            this.neighbors[idB].in.delete(idA);
+
+            // check if nodes still have neighbors
+            if(!this.hasNodeNeighbors(idA)) { this.nodesDisconnected.add(idA); }
+            if(!this.hasNodeNeighbors(idB)) { this.nodesDisconnected.add(idB); }
+
+            this.app.setStreamStatusMessage("disconnectNodes: " + idA + " > " + idB);
+            this.app.updateStatus();
+        } else {
+            console.log("disconnectNodes skipped: either node not online", idA, idB);
+        }
+    }
+
+    hasNodeNeighbors(idA) {
+        let neighbors = this.neighbors[idA];
+        return ((neighbors.in.size + neighbors.out.size) > 0)
+    }
+}
+
+class Graph {
+    constructor(app) {
+        this.app = app;
+        this.highlightedNodes = new Set();
+        this.highlightedLinks = new Set();
+
+        this.graph = Viva.Graph.graph();
+        this.graphics = Viva.Graph.View.webglGraphics();
+        this.calculator = Viva.Graph.centrality();
+
+        this.layout = Viva.Graph.Layout.forceDirected(this.graph, {
+            springLength: 30,
+            springCoeff: 0.0001,
+            dragCoeff: 0.02,
+            gravity: -1.2
+        });
+
+        this.graphics.link((link) => {
+            return Viva.Graph.View.webglLine(EDGE_COLOR_DEFAULT);
+        });
+
+        this.graphics.setNodeProgram(buildCircleNodeShader());
+
+        this.graphics.node((node) => {
+            return new WebGLCircle(VERTEX_SIZE, VERTEX_COLOR_DEFAULT);
+        });
+
+        this.renderer = Viva.Graph.View.renderer(this.graph, {
+            layout: this.layout,
+            graphics: this.graphics,
+            container: document.getElementById('graphc'),
+            renderLinks: true
+        });
+
+        this.initEvents();
+    }
+
+    updateNodeUiColor(node, color, save=true) {
+        let nodeUI = this.graphics.getNodeUI(node);
+        if (nodeUI != undefined) {
+            nodeUI.color = color;
+        }
+
+        if(save) {
+            this.highlightedNodes.add(node);
+        }
+    }
+
+    updateLinkUiColor(idA, idB, color, save=true) {
+        let con = this.graph.getLink(idA, idB);
+
+        if(con != null) {
+            let linkUI = this.graphics.getLinkUI(con.id);
+            if (linkUI != undefined) {
+                linkUI.color = parseColor(color);
+            }
+
+            if(save) {
+                this.highlightedLinks.add(con.id);
+            }
+        }
+    }
+
+    updateLinkUiColorByLinkId(link, color, save=true) {
+        let linkUI = this.graphics.getLinkUI(link);
+        if (linkUI != undefined) {
+            linkUI.color = parseColor(color);
+        }
+
+        if(save) {
+            this.highlightedLinks.add(link);
+        }
+    }
+
+    showNodeLinks(selectedNode) {
+        if(this.highlightedLinks > 0 || this.highlightedNodes.size > 0) {
+            // clean up display
+            this.app.resetActiveNode();
+        }
+
+        this.graph.beginUpdate();
+
+        let neighbors = this.app.ds.neighbors[selectedNode];
+
+        // highlight current node
+        this.updateNodeUiColor(selectedNode, VERTEX_COLOR_ACTIVE);
+
+        // highlight incoming connections
+        for(let n of neighbors.in) {
+            this.updateNodeUiColor(n, VERTEX_COLOR_CONNECTED);
+            this.updateLinkUiColor(n, selectedNode, EDGE_COLOR_INCOMING);
+        }
+
+        // highlight outcoming connections
+        for(let n of neighbors.out) {
+            this.updateNodeUiColor(n, VERTEX_COLOR_CONNECTED);
+            this.updateLinkUiColor(selectedNode, n, EDGE_COLOR_OUTGOING);
+        }
+
+        this.graph.endUpdate();
+        this.renderer.rerender();
+    }
+
+    initEvents() {
+        this.events = Viva.Graph.webglInputEvents(this.graphics, this.graph);
+
+        this.events.mouseEnter((node) => {
+            this.app.setActiveNode(node.id)
+        });
+
+        this.events.mouseLeave(() => {
+            if(this.highlightedLinks > 0 || this.highlightedNodes.size > 0) {
+                // clean up display
+                this.app.resetActiveNode();
+            }
+        });
+    }
+
+    resetPreviousColors() {
+        this.graph.beginUpdate();
+
+        for(let n of this.highlightedNodes) {
+            this.updateNodeUiColor(n, VERTEX_COLOR_DEFAULT, false);
+        }
+
+        for(let l of this.highlightedLinks) {
+            this.updateLinkUiColorByLinkId(l, EDGE_COLOR_DEFAULT, false);
+        }
+
+        this.graph.endUpdate();
+        this.renderer.rerender();
+    }
+
+    addEdge(con, idA, idB) {
+        this.graph.addLink(idA, idB, con);
+    }
+
+    deleteEdge(con, idA, idB) {
+        let link = this.graph.getLink(idA, idB);
+        this.graph.removeLink(link);
+    }
+
+    addVertex(idA) {
+        this.graph.addNode(idA);
+    }
+
+    deleteVertex(idA) {
+        this.graph.removeNode(idA);
+    }
+
+    render() {
+        this.renderer.run();
+    }
+}
+
+class Application {
+    constructor(url) {
+        this.url = url;
+        this.frontend = new Frontend(this);
+        this.ds = new Datastructure(this);
+        this.graph = new Graph(this);
+
+        this.rendered = false; // is the application already rendered?
+        this.floodNew = 0;
+        this.floodOld = 0;
+
+    }
+
+    setActiveNode(nodeId, updateHash=false) {
+        this.graph.showNodeLinks(nodeId);
+        this.frontend.setActiveNode(nodeId, updateHash);
+    }
+
+    resetActiveNode() {
+        this.graph.resetPreviousColors()
+        this.frontend.resetActiveNode();
+    }
+
+    setStatusMessage(msg) {
+        if(this.rendered) {
+            this.frontend.setStatusMessage(msg);
+            console.log('%cStatusMessage: ' + msg, 'color: gray');
+        }
+    }
+
+    setStreamStatusMessage(msg) {
+        if(this.rendered) {
+            this.frontend.setStreamStatusMessage(msg);
+            console.log('%cStreamStatusMessage: ' + msg, 'color: gray');
+        }
+    }
+
+    updateStatus() {
+        this.setStatusMessage(this.ds.getStatusText());
+    }
+
+    showOnlineNodes() {
+        setInterval(() => { 
+            if(this.frontend.searchTerm.length > 0) {
+                return;
+            }
+            this.frontend.displayNodesOnline(this.ds.nodesOnline) 
+        }, 300);
+    }
+
+    run() {
+        let initialFloodTimerFunc = () => {
+            if (this.floodNew > this.floodOld + 100) {
+                this.setStreamStatusMessage("... received " + this.floodNew + " msg");
+                this.floodOld = this.floodNew;
+            } else {
+                clearInterval(this.initialFloodTimer);
+                this.startRendering();
+            }
+        }
+
+        this.initialFloodTimer = setInterval(initialFloodTimerFunc, 500);
+        this.initWebsocket();
+    }
+
+    startRendering() {
+        // kickoff rendering
+        this.rendered = true;
+
+        this.graph.render();
+        
+        this.setStreamStatusMessage("... received " + this.floodNew + " msg");
+        this.updateStatus();
+        
+        // display nodes online and search field
+        this.frontend.showSearchField();
+        this.showOnlineNodes();
+
+        // highlight node passed in url
+        let nodeId = window.location.hash.substring(1);
+        if(nodeId) {
+            this.setActiveNode(nodeId);
+        }
+    }
+
+    initWebsocket() {
+        this.socket = new WebSocket(
+            ((window.location.protocol === "https:") ? "wss://" : "ws://") + this.url
+        );
+    
+        this.socket.onopen = () => {
+            this.setStatusMessage("WebSocket opened. Loading ... ");
+            setInterval(() => {
+                this.socket.send("_");
+            }, 1000);
+        };
+    
+        this.socket.onerror = (e) => {
+            this.setStatusMessage("WebSocket error observed. Please reload.");
+            console.error("WebSocket error observed", e);
+          };
+    
+        this.socket.onmessage = (e) => {
+            let type = e.data[0];
+            let data = e.data.substr(1);
+            let idA = data.substr(0, NODE_ID_LENGTH);
+            let idB;
+            
+            if(!this.rendered) { this.floodNew++; }
+
+            switch (type) {
+                case "_":
+                    //do nothing - its just a ping
+                    break;
+    
+                case "A":
+                    console.log("addNode event:", idA);
+                    // filter out empty ids
+                    if(idA.length == NODE_ID_LENGTH) {
+                        this.ds.addNode(idA);
+                    }
+                    break;
+
+                case "a":
+                    console.log("removeNode event:", idA);
+                    this.ds.removeNode(idA);
+                    break;
+    
+                case "C":
+                    idB = data.substr(NODE_ID_LENGTH, NODE_ID_LENGTH);
+                    console.log("connectNodes event:", idA, " - ", idB);
+                    this.ds.connectNodes(idA+idB, idA, idB);
+                    break;
+    
+                case "c":
+                    idB = data.substr(NODE_ID_LENGTH, NODE_ID_LENGTH);
+                    console.log("disconnectNodes event:", idA, " - ", idB);
+                    this.ds.disconnectNodes(idA+idB, idA, idB);
+                    break;
+    
+                case "O":
+                    console.log("setNodeOnline event:", idA);
+                    this.ds.setNodeOnline(idA);
+                    break;
+    
+                case "o":
+                    console.log("setNodeOffline event:", idA);
+                    this.ds.setNodeOffline(idA);
+                    break;
+            }
+        }
+    }
+}
+
+
+let app;
+window.onload = () => {
+    app = new Application(ANALYSIS_SERVER_URL);
+    app.run()
+}
+
+
+
+
+function hasClass(elem, className) {
+    return elem.classList.contains(className);
+}
+
+function parseColor(color) {
+    var parsedColor = 0x009ee8ff;
+
+    if (typeof color === 'string' && color) {
+        if (color.length === 4) { // #rgb
+            color = color.replace(/([^#])/g, '$1$1'); // duplicate each letter except first #.
+        }
+        if (color.length === 9) { // #rrggbbaa
+            parsedColor = parseInt(color.substr(1), 16);
+        } else if (color.length === 7) { // or #rrggbb.
+            parsedColor = (parseInt(color.substr(1), 16) << 8) | 0xff;
+        } else {
+            throw 'Color expected in hex format with preceding "#". E.g. #00ff00. Got value: ' + color;
+        }
+    } else if (typeof color === 'number') {
+        parsedColor = color;
+    }
+
+    return parsedColor;
+}
+
+
+/**
+ * WebGL stuff 
+ */
+
+function WebGLCircle(size, color) {
+    this.size = size;
+    this.color = color;
+}
+// Next comes the hard part - implementation of API for custom shader
+// program, used by webgl renderer:
+function buildCircleNodeShader() {
+    // For each primitive we need 4 attributes: x, y, color and size.
+    var ATTRIBUTES_PER_PRIMITIVE = 4,
+        nodesFS = [
+            'precision mediump float;',
+            'varying vec4 color;',
+            'void main(void) {',
+            '   if ((gl_PointCoord.x - 0.5) * (gl_PointCoord.x - 0.5) + (gl_PointCoord.y - 0.5) * (gl_PointCoord.y - 0.5) < 0.25) {',
+            '     gl_FragColor = color;',
+            '   } else {',
+            '     gl_FragColor = vec4(0);',
+            '   }',
+            '}'].join('\n'),
+        nodesVS = [
+            'attribute vec2 a_vertexPos;',
+            // Pack color and size into vector. First elemnt is color, second - size.
+            // Since it's floating point we can only use 24 bit to pack colors...
+            // thus alpha channel is dropped, and is always assumed to be 1.
+            'attribute vec2 a_customAttributes;',
+            'uniform vec2 u_screenSize;',
+            'uniform mat4 u_transform;',
+            'varying vec4 color;',
+            'void main(void) {',
+            '   gl_Position = u_transform * vec4(a_vertexPos/u_screenSize, 0, 1);',
+            '   gl_PointSize = a_customAttributes[1] * u_transform[0][0];',
+            '   float c = a_customAttributes[0];',
+            '   color.b = mod(c, 256.0); c = floor(c/256.0);',
+            '   color.g = mod(c, 256.0); c = floor(c/256.0);',
+            '   color.r = mod(c, 256.0); c = floor(c/256.0); color /= 255.0;',
+            '   color.a = 1.0;',
+            '}'].join('\n');
+    var program,
+        gl,
+        buffer,
+        locations,
+        utils,
+        nodes = new Float32Array(64),
+        nodesCount = 0,
+        canvasWidth, canvasHeight, transform,
+        isCanvasDirty;
+    return {
+        /**
+         * Called by webgl renderer to load the shader into gl context.
+         */
+        load: function (glContext) {
+            gl = glContext;
+            webglUtils = Viva.Graph.webgl(glContext);
+            program = webglUtils.createProgram(nodesVS, nodesFS);
+            gl.useProgram(program);
+            locations = webglUtils.getLocations(program, ['a_vertexPos', 'a_customAttributes', 'u_screenSize', 'u_transform']);
+            gl.enableVertexAttribArray(locations.vertexPos);
+            gl.enableVertexAttribArray(locations.customAttributes);
+            buffer = gl.createBuffer();
+        },
+        /**
+         * Called by webgl renderer to update node position in the buffer array
+         *
+         * @param nodeUI - data model for the rendered node (WebGLCircle in this case)
+         * @param pos - {x, y} coordinates of the node.
+         */
+        position: function (nodeUI, pos) {
+            var idx = nodeUI.id;
+            nodes[idx * ATTRIBUTES_PER_PRIMITIVE] = pos.x;
+            nodes[idx * ATTRIBUTES_PER_PRIMITIVE + 1] = -pos.y;
+            nodes[idx * ATTRIBUTES_PER_PRIMITIVE + 2] = nodeUI.color;
+            nodes[idx * ATTRIBUTES_PER_PRIMITIVE + 3] = nodeUI.size;
+        },
+        /**
+         * Request from webgl renderer to actually draw our stuff into the
+         * gl context. This is the core of our shader.
+         */
+        render: function () {
+            gl.useProgram(program);
+            gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
+            gl.bufferData(gl.ARRAY_BUFFER, nodes, gl.DYNAMIC_DRAW);
+            if (isCanvasDirty) {
+                isCanvasDirty = false;
+                gl.uniformMatrix4fv(locations.transform, false, transform);
+                gl.uniform2f(locations.screenSize, canvasWidth, canvasHeight);
+            }
+            gl.vertexAttribPointer(locations.vertexPos, 2, gl.FLOAT, false, ATTRIBUTES_PER_PRIMITIVE * Float32Array.BYTES_PER_ELEMENT, 0);
+            gl.vertexAttribPointer(locations.customAttributes, 2, gl.FLOAT, false, ATTRIBUTES_PER_PRIMITIVE * Float32Array.BYTES_PER_ELEMENT, 2 * 4);
+            gl.drawArrays(gl.POINTS, 0, nodesCount);
+        },
+        /**
+         * Called by webgl renderer when user scales/pans the canvas with nodes.
+         */
+        updateTransform: function (newTransform) {
+            transform = newTransform;
+            isCanvasDirty = true;
+        },
+        /**
+         * Called by webgl renderer when user resizes the canvas with nodes.
+         */
+        updateSize: function (newCanvasWidth, newCanvasHeight) {
+            canvasWidth = newCanvasWidth;
+            canvasHeight = newCanvasHeight;
+            isCanvasDirty = true;
+        },
+        /**
+         * Called by webgl renderer to notify us that the new node was created in the graph
+         */
+        createNode: function (node) {
+            nodes = webglUtils.extendArray(nodes, nodesCount, ATTRIBUTES_PER_PRIMITIVE);
+            nodesCount += 1;
+        },
+        /**
+         * Called by webgl renderer to notify us that the node was removed from the graph
+         */
+        removeNode: function (node) {
+            if (nodesCount > 0) { nodesCount -= 1; }
+            if (node.id < nodesCount && nodesCount > 0) {
+                // we do not really delete anything from the buffer.
+                // Instead we swap deleted node with the "last" node in the
+                // buffer and decrease marker of the "last" node. Gives nice O(1)
+                // performance, but make code slightly harder than it could be:
+                webglUtils.copyArrayPart(nodes, node.id * ATTRIBUTES_PER_PRIMITIVE, nodesCount * ATTRIBUTES_PER_PRIMITIVE, ATTRIBUTES_PER_PRIMITIVE);
+            }
+        },
+        /**
+         * This method is called by webgl renderer when it changes parts of its
+         * buffers. We don't use it here, but it's needed by API (see the comment
+         * in the removeNode() method)
+         */
+        replaceProperties: function (replacedNode, newNode) { },
+    };
+}
diff --git a/plugins/analysis/webinterface/httpserver/static/js/vivagraph-0.12.0.min.js b/plugins/analysis/webinterface/httpserver/static/js/vivagraph-0.12.0.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..6872dddec6b8486d728ef75708eb2d6b768d2abf
--- /dev/null
+++ b/plugins/analysis/webinterface/httpserver/static/js/vivagraph-0.12.0.min.js
@@ -0,0 +1,3 @@
+!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var n;"undefined"!=typeof window?n=window:"undefined"!=typeof global?n=global:"undefined"!=typeof self&&(n=self),n.Viva=e()}}(function(){return function e(n,t,r){function o(a,u){if(!t[a]){if(!n[a]){var s="function"==typeof require&&require;if(!u&&s)return s(a,!0);if(i)return i(a,!0);var f=new Error("Cannot find module '"+a+"'");throw f.code="MODULE_NOT_FOUND",f}var c=t[a]={exports:{}};n[a][0].call(c.exports,function(e){var t=n[a][1][e];return o(t?t:e)},c,c.exports,e,n,t,r)}return t[a].exports}for(var i="function"==typeof require&&require,a=0;a<r.length;a++)o(r[a]);return o}({1:[function(e,n,t){var r=e("ngraph.random"),o={lazyExtend:function(){return e("ngraph.merge").apply(this,arguments)},randomIterator:function(){return r.randomIterator.apply(r,arguments)},random:function(){return r.random.apply(r,arguments)},events:e("ngraph.events")};o.Graph={version:e("./version.js"),graph:e("ngraph.graph"),serializer:function(){return{loadFromJSON:e("ngraph.fromjson"),storeToJSON:e("ngraph.tojson")}},centrality:e("./Algorithms/centrality.js"),operations:e("./Algorithms/operations.js"),geom:function(){return{intersect:e("gintersect"),intersectRect:e("./Utils/intersectRect.js")}},webgl:e("./WebGL/webgl.js"),webglInputEvents:e("./WebGL/webglInputEvents.js"),generator:function(){return e("ngraph.generators")},Input:{domInputManager:e("./Input/domInputManager.js"),webglInputManager:e("./Input/webglInputManager.js")},Utils:{dragndrop:e("./Input/dragndrop.js"),findElementPosition:e("./Utils/findElementPosition.js"),timer:e("./Utils/timer.js"),getDimension:e("./Utils/getDimensions.js"),events:e("./Utils/backwardCompatibleEvents.js")},Layout:{forceDirected:e("ngraph.forcelayout"),constant:e("./Layout/constant.js")},View:{Texture:e("./WebGL/texture.js"),webglAtlas:e("./WebGL/webglAtlas.js"),webglImageNodeProgram:e("./WebGL/webglImageNodeProgram.js"),webglLinkProgram:e("./WebGL/webglLinkProgram.js"),webglNodeProgram:e("./WebGL/webglNodeProgram.js"),webglLine:e("./WebGL/webglLine.js"),webglSquare:e("./WebGL/webglSquare.js"),webglImage:e("./WebGL/webglImage.js"),webglGraphics:e("./View/webglGraphics.js"),_webglUtil:{parseColor:e("./WebGL/parseColor.js")},svgGraphics:e("./View/svgGraphics.js"),renderer:e("./View/renderer.js"),cssGraphics:function(){throw new Error("cssGraphics is deprecated. Please use older version of vivagraph (< 0.7) if you need it")},svgNodeFactory:function(){throw new Error("svgNodeFactory is deprecated. Please use older version of vivagraph (< 0.7) if you need it")},community:function(){throw new Error("community is deprecated. Please use vivagraph < 0.7 if you need it, or `https://github.com/anvaka/ngraph.slpa` module")}},Rect:e("./Utils/rect.js"),svg:e("simplesvg"),BrowserInfo:e("./Utils/browserInfo.js")},n.exports=o},{"./Algorithms/centrality.js":36,"./Algorithms/operations.js":37,"./Input/domInputManager.js":38,"./Input/dragndrop.js":39,"./Input/webglInputManager.js":40,"./Layout/constant.js":41,"./Utils/backwardCompatibleEvents.js":42,"./Utils/browserInfo.js":43,"./Utils/findElementPosition.js":45,"./Utils/getDimensions.js":46,"./Utils/intersectRect.js":47,"./Utils/rect.js":49,"./Utils/timer.js":50,"./View/renderer.js":52,"./View/svgGraphics.js":53,"./View/webglGraphics.js":54,"./WebGL/parseColor.js":55,"./WebGL/texture.js":56,"./WebGL/webgl.js":57,"./WebGL/webglAtlas.js":58,"./WebGL/webglImage.js":59,"./WebGL/webglImageNodeProgram.js":60,"./WebGL/webglInputEvents.js":61,"./WebGL/webglLine.js":62,"./WebGL/webglLinkProgram.js":63,"./WebGL/webglNodeProgram.js":64,"./WebGL/webglSquare.js":65,"./version.js":66,gintersect:3,"ngraph.events":9,"ngraph.forcelayout":11,"ngraph.fromjson":13,"ngraph.generators":14,"ngraph.graph":16,"ngraph.merge":17,"ngraph.random":30,"ngraph.tojson":31,simplesvg:32}],2:[function(e,n,t){function r(e,n,t,r){return f=f||(document.addEventListener?{add:i,rm:a}:{add:u,rm:s}),f.add(e,n,t,r)}function o(e,n,t,r){return f=f||(document.addEventListener?{add:i,rm:a}:{add:u,rm:s}),f.rm(e,n,t,r)}function i(e,n,t,r){e.addEventListener(n,t,r)}function a(e,n,t,r){e.removeEventListener(n,t,r)}function u(e,n,t,r){if(r)throw new Error("cannot useCapture in oldIE");e.attachEvent("on"+n,t)}function s(e,n,t,r){e.detachEvent("on"+n,t)}r.removeEventListener=o,r.addEventListener=r,n.exports=r;var f=null},{}],3:[function(e,n,t){function r(e,n,t,r,o,i,a,u){var s,f,c,d,l,p,v,h,g,m,y,x,w,b={x:0,y:0};return s=r-n,c=e-t,l=t*n-e*r,g=s*o+c*i+l,m=s*a+c*u+l,0!==g&&0!==m&&g>=0==m>=4?null:(f=u-i,d=o-a,p=a*i-o*u,v=f*e+d*n+p,h=f*t+d*r+p,0!==v&&0!==h&&v>=0==h>=0?null:(y=s*d-f*c,0===y?null:(x=y<0?-y/2:y/2,x=0,w=c*p-d*l,b.x=(w<0?w-x:w+x)/y,w=f*l-s*p,b.y=(w<0?w-x:w+x)/y,b)))}n.exports=r},{}],4:[function(e,n,t){n.exports.degree=e("./src/degree.js"),n.exports.betweenness=e("./src/betweenness.js"),n.exports.closeness=e("./src/closeness.js"),n.exports.eccentricity=e("./src/eccentricity.js")},{"./src/betweenness.js":5,"./src/closeness.js":6,"./src/degree.js":7,"./src/eccentricity.js":8}],5:[function(e,n,t){function r(e,n){function t(e){h[e]/=2}function r(e){h[e.id]=0}function o(e){s=e.id,u(s),i()}function i(){for(e.forEachNode(a);c.length;){for(var n=c.pop(),t=(1+v[n])/p[n],r=d[n],o=0;o<r.length;++o){var i=r[o];v[i]+=p[i]*t}n!==s&&(h[n]+=v[n])}}function a(e){v[e.id]=0}function u(t){function r(e){i(e.id)}function o(e){var n=e.id;d[n]=[],l[n]=-1,p[n]=0}function i(e){l[e]===-1&&(l[e]=l[a]+1,f.push(e)),l[e]===l[a]+1&&(p[e]+=p[a],d[e].push(a))}for(e.forEachNode(o),l[t]=0,p[t]=1,f.push(t);f.length;){var a=f.shift();c.push(a),e.forEachLinkedNode(a,r,n)}}var s,f=[],c=[],d=Object.create(null),l=Object.create(null),p=Object.create(null),v=Object.create(null),h=Object.create(null);return e.forEachNode(r),e.forEachNode(o),n||Object.keys(h).forEach(t),h}n.exports=r},{}],6:[function(e,n,t){function r(e,n){function t(e){f[e.id]=0}function r(e){a=e.id,i(a),o()}function o(){var e=Object.keys(s).map(function(e){return s[e]}).filter(function(e){return e!==-1}),n=e.length,t=e.reduce(function(e,n){return e+n});t>0?f[a]=(n-1)/t:f[a]=0}function i(t){function r(e){var n=e.id;s[n]=-1}function o(e){var n=e.id;s[n]===-1&&(s[n]=s[i]+1,u.push(n))}for(e.forEachNode(r),s[t]=0,u.push(t);u.length;){var i=u.shift();e.forEachLinkedNode(i,o,n)}}var a,u=[],s=Object.create(null),f=Object.create(null);return e.forEachNode(t),e.forEachNode(r),f}n.exports=r},{}],7:[function(e,n,t){function r(e,n){function t(n){var t=e.getLinks(n.id);u[n.id]=r(t,n.id)}var r,u=Object.create(null);if(n=(n||"both").toLowerCase(),"both"===n||"inout"===n)r=a;else if("in"===n)r=o;else{if("out"!==n)throw new Error("Expected centrality degree kind is: in, out or both");r=i}return e.forEachNode(t),u}function o(e,n){var t=0;if(!e)return t;for(var r=0;r<e.length;r+=1)t+=e[r].toId===n?1:0;return t}function i(e,n){var t=0;if(!e)return t;for(var r=0;r<e.length;r+=1)t+=e[r].fromId===n?1:0;return t}function a(e){return e?e.length:0}n.exports=r},{}],8:[function(e,n,t){function r(e,n){function t(e){f[e.id]=0}function r(e){a=e.id,i(a),o()}function o(){var e=0;Object.keys(s).forEach(function(n){var t=s[n];e<t&&(e=t)}),f[a]=e}function i(t){function r(e){var n=e.id;s[n]=-1}function o(e){var n=e.id;s[n]===-1&&(s[n]=s[i]+1,u.push(n))}for(e.forEachNode(r),s[t]=0,u.push(t);u.length;){var i=u.shift();e.forEachLinkedNode(i,o,n)}}var a,u=[],s=Object.create(null),f=Object.create(null);return e.forEachNode(t),e.forEachNode(r),f}n.exports=r},{}],9:[function(e,n,t){function r(e){var n=Object.create(null);return{on:function(t,r,o){if("function"!=typeof r)throw new Error("callback is expected to be a function");var i=n[t];return i||(i=n[t]=[]),i.push({callback:r,ctx:o}),e},off:function(t,r){var o="undefined"==typeof t;if(o)return n=Object.create(null),e;if(n[t]){var i="function"!=typeof r;if(i)delete n[t];else for(var a=n[t],u=0;u<a.length;++u)a[u].callback===r&&a.splice(u,1)}return e},fire:function(t){var r=n[t];if(!r)return e;var o;arguments.length>1&&(o=Array.prototype.splice.call(arguments,1));for(var i=0;i<r.length;++i){var a=r[i];a.callback.apply(a.ctx,o)}return e}}}function o(e){if(!e)throw new Error("Eventify cannot use falsy object as events subject");for(var n=["on","fire","off"],t=0;t<n.length;++t)if(e.hasOwnProperty(n[t]))throw new Error("Subject cannot be eventified, since it already has property '"+n[t]+"'")}n.exports=function(e){o(e);var n=r(e);return e.on=n.on,e.off=n.off,e.fire=n.fire,e}},{}],10:[function(e,n,t){function r(e,n,t){var r="[object Array]"===Object.prototype.toString.call(t);if(r)for(var i=0;i<t.length;++i)o(e,n,t[i]);else for(var a in e)o(e,n,a)}function o(e,n,t){if(e.hasOwnProperty(t)){if("function"==typeof n[t])return;n[t]=function(r){return void 0!==r?(e[t]=r,n):e[t]}}}n.exports=r},{}],11:[function(e,n,t){function r(n,t){function r(e){Object.keys(N).forEach(function(n){e(N[n],n)})}function a(e,t){var r;if(void 0===t)r="object"!=typeof e?e:e.id;else{var o=n.hasLink(e,t);if(!o)return;r=o.id}return k[r]}function u(e){return N[e]}function s(){n.on("changed",c)}function f(e){_.fire("stable",e)}function c(e){for(var t=0;t<e.length;++t){var r=e[t];"add"===r.changeType?(r.node&&l(r.node.id),r.link&&v(r.link)):"remove"===r.changeType&&(r.node&&p(r.node),r.link&&h(r.link))}P=n.getNodesCount()}function d(){P=0,n.forEachNode(function(e){l(e.id),P+=1}),n.forEachLink(v)}function l(e){var t=N[e];if(!t){var r=n.getNode(e);if(!r)throw new Error("initBody() was called with unknown node id");var o=r.position;if(!o){var i=g(r);o=E.getBestNewBodyPosition(i)}t=E.addBodyAt(o),t.id=e,N[e]=t,m(e),y(r)&&(t.isPinned=!0)}}function p(e){var n=e.id,t=N[n];t&&(N[n]=null,delete N[n],E.removeBody(t))}function v(e){m(e.fromId),m(e.toId);var n=N[e.fromId],t=N[e.toId],r=E.addSpring(n,t,e.length);j(e,r),k[e.id]=r}function h(e){var t=k[e.id];if(t){var r=n.getNode(e.fromId),o=n.getNode(e.toId);r&&m(r.id),o&&m(o.id),delete k[e.id],E.removeSpring(t)}}function g(e){var n=[];if(!e.links)return n;for(var t=Math.min(e.links.length,2),r=0;r<t;++r){var o=e.links[r],i=o.fromId!==e.id?N[o.fromId]:N[o.toId];i&&i.pos&&n.push(i)}return n}function m(e){var n=N[e];if(n.mass=L(e),Number.isNaN(n.mass))throw new Error("Node mass should be a number")}function y(e){return e&&(e.isPinned||e.data&&e.data.isPinned)}function x(e){var n=N[e];return n||(l(e),n=N[e]),n}function w(e){var t=n.getLinks(e);return t?1+t.length/3:1}if(!n)throw new Error("Graph structure cannot be undefined");var b=e("ngraph.physics.simulator"),E=b(t),L=w;t&&"function"==typeof t.nodeMass&&(L=t.nodeMass);var N=Object.create(null),k={},P=0,j=E.settings.springTransform||o;d(),s();var A=!1,_={step:function(){if(0===P)return!0;var e=E.step();_.lastMove=e,_.fire("step");var n=e/P,t=n<=.01;return A!==t&&(A=t,f(t)),t},getNodePosition:function(e){return x(e).pos},setNodePosition:function(e){var n=x(e);n.setPosition.apply(n,Array.prototype.slice.call(arguments,1)),E.invalidateBBox()},getLinkPosition:function(e){var n=k[e];if(n)return{from:n.from.pos,to:n.to.pos}},getGraphRect:function(){return E.getBBox()},forEachBody:r,pinNode:function(e,n){var t=x(e.id);t.isPinned=!!n},isNodePinned:function(e){return x(e.id).isPinned},dispose:function(){n.off("changed",c),_.fire("disposed")},getBody:u,getSpring:a,simulator:E,graph:n,lastMove:0};return i(_),_}function o(){}n.exports=r,n.exports.simulator=e("ngraph.physics.simulator");var i=e("ngraph.events")},{"ngraph.events":12,"ngraph.physics.simulator":19}],12:[function(e,n,t){arguments[4][9][0].apply(t,arguments)},{dup:9}],13:[function(e,n,t){function r(e,n,t){var r;n=n||o,t=t||o,r="string"==typeof e?JSON.parse(e):e;var a,u=i();if(void 0===r.links||void 0===r.nodes)throw new Error("Cannot load graph without links and nodes");for(a=0;a<r.nodes.length;++a){var s=n(r.nodes[a]);if(!s.hasOwnProperty("id"))throw new Error("Graph node format is invalid: Node id is missing");u.addNode(s.id,s.data)}for(a=0;a<r.links.length;++a){var f=t(r.links[a]);if(!f.hasOwnProperty("fromId")||!f.hasOwnProperty("toId"))throw new Error("Graph link format is invalid. Both fromId and toId are required");u.addLink(f.fromId,f.toId,f.data)}return u}function o(e){return e}n.exports=r;var i=e("ngraph.graph")},{"ngraph.graph":16}],14:[function(e,n,t){function r(n){function t(e){if(!e||e<0)throw new Error("Invalid number of nodes");var t,r=n();for(t=0;t<e-1;++t)r.addLink(t,t+1),r.addLink(e+t,e+t+1),r.addLink(t,e+t);return r.addLink(e-1,2*e-1),r}function r(e){if(!e||e<0)throw new Error("Invalid number of nodes");var n=t(e);return n.addLink(0,e-1),n.addLink(e,2*e-1),n}function o(e){if(!e||e<1)throw new Error("At least two nodes are expected for complete graph");var t,r,o=n();for(t=0;t<e;++t)for(r=t+1;r<e;++r)t!==r&&o.addLink(t,r);return o}function i(e,t){if(!e||!t||e<0||t<0)throw new Error("Graph dimensions are invalid. Number of nodes in each partition should be greater than 0");var r,o,i=n();for(r=0;r<e;++r)for(o=e;o<e+t;++o)i.addLink(r,o);return i}function a(e){if(!e||e<0)throw new Error("Invalid number of nodes");var t,r=n();for(r.addNode(0),t=1;t<e;++t)r.addLink(t-1,t);return r}function u(e,t){if(e<1||t<1)throw new Error("Invalid number of nodes in grid graph");var r,o,i=n();if(1===e&&1===t)return i.addNode(0),i;for(r=0;r<e;++r)for(o=0;o<t;++o){var a=r+o*e;r>0&&i.addLink(a,r-1+o*e),o>0&&i.addLink(a,r+(o-1)*e)}return i}function s(e,t,r){if(e<1||t<1||r<1)throw new Error("Invalid number of nodes in grid3 graph");var o,i,a,u=n();if(1===e&&1===t&&1===r)return u.addNode(0),u;for(a=0;a<r;++a)for(o=0;o<e;++o)for(i=0;i<t;++i){var s=a*e*t,f=o+i*e+s;o>0&&u.addLink(f,o-1+i*e+s),i>0&&u.addLink(f,o+(i-1)*e+s),a>0&&u.addLink(f,o+i*e+(a-1)*e*t)}return u}function f(e){if(e<0)throw new Error("Invalid number of nodes in balanced tree");var t,r=n(),o=Math.pow(2,e);for(0===e&&r.addNode(1),t=1;t<o;++t){var i=t,a=2*i,u=2*i+1;r.addLink(i,a),r.addLink(i,u)}return r}function c(e){if(e<0)throw new Error("Number of nodes should be >= 0");var t,r=n();for(t=0;t<e;++t)r.addNode(t);return r}function d(e,t){function r(e,n){for(var t=0;t<e;++t)o.addNode(t+n);for(var t=0;t<e;++t)for(var r=t+1;r<e;++r)o.addLink(t+n,r+n)}if(e<1)throw new Error("Invalid number of cliqueCount in cliqueCircle");if(t<1)throw new Error("Invalid number of cliqueSize in cliqueCircle");for(var o=n(),i=0;i<e;++i)r(t,i*t),i>0&&o.addLink(i*t,i*t-1);return o.addLink(0,o.getNodesCount()-1),o}function l(t,r,o,i){if(r>=t)throw new Error("Choose smaller `k`. It cannot be larger than number of nodes `n`");var a,u,s=e("ngraph.random").random(i||42),f=n();for(a=0;a<t;++a)f.addNode(a);for(var c=Math.floor(r/2+1),d=1;d<c;++d)for(a=0;a<t;++a)u=(d+a)%t,f.addLink(a,u);for(d=1;d<c;++d)for(a=0;a<t;++a)if(s.nextDouble()<o){var l=a;u=(d+a)%t;var p=s.next(t),v=p===l||f.hasLink(l,p);if(v&&f.getLinks(l).length===t-1)continue;for(;v;)p=s.next(t),v=p===l||f.hasLink(l,p);var h=f.hasLink(l,u);f.removeLink(h),f.addLink(l,p)}return f}return{ladder:t,complete:o,completeBipartite:i,balancedBinTree:f,path:a,circularLadder:r,grid:u,grid3:s,noLinks:c,wattsStrogatz:l,cliqueCircle:d}}var o=e("ngraph.graph");n.exports=r(o),n.exports.factory=r},{"ngraph.graph":16,"ngraph.random":15}],15:[function(e,n,t){function r(e){var n="number"==typeof e?e:+new Date;return new o(n)}function o(e){this.seed=e}function i(){var e,n,t;do n=2*this.nextDouble()-1,t=2*this.nextDouble()-1,e=n*n+t*t;while(e>=1||0===e);return n*Math.sqrt(-2*Math.log(e)/e)}function a(){var e=this.seed;return e=e+2127912214+(e<<12)&4294967295,e=4294967295&(3345072700^e^e>>>19),e=e+374761393+(e<<5)&4294967295,e=4294967295&(e+3550635116^e<<9),e=e+4251993797+(e<<3)&4294967295,e=4294967295&(3042594569^e^e>>>16),this.seed=e,(268435455&e)/268435456}function u(e){return Math.floor(this.nextDouble()*e)}function s(e,n){function t(){var n,t,r;for(n=e.length-1;n>0;--n)t=i.next(n+1),r=e[t],e[t]=e[n],e[n]=r;return e}function o(n){var t,r,o;for(t=e.length-1;t>0;--t)r=i.next(t+1),o=e[r],e[r]=e[t],e[t]=o,n(o);e.length&&n(e[0])}var i=n||r();if("function"!=typeof i.next)throw new Error("customRandom does not match expected API: next() function is missing");return{forEach:o,shuffle:t}}n.exports=r,n.exports.random=r,n.exports.randomIterator=s,o.prototype.next=u,o.prototype.nextDouble=a,o.prototype.uniform=a,o.prototype.gaussian=i},{}],16:[function(e,n,t){function r(e){function n(){function e(){return q.beginUpdate=F=k,q.endUpdate=G=P,B=t,O=r,q.on=n,n.apply(q,arguments)}var n=q.on;q.on=e}function t(e,n){R.push({link:e,changeType:n})}function r(e,n){R.push({node:e,changeType:n})}function c(e,n){if(void 0===e)throw new Error("Invalid node identifier");F();var t=d(e);return t?(t.data=n,O(t,"update")):(t=new i(e,n),S++,O(t,"add")),I[e]=t,G(),t}function d(e){return I[e]}function l(e){var n=d(e);if(!n)return!1;F();var t=n.links;if(t){n.links=null;for(var r=0;r<t.length;++r)m(t[r])}return delete I[e],S--,O(n,"remove"),G(),!0}function p(e,n,t){F();var r=d(e)||c(e),o=d(n)||c(n),i=U(e,n,t);return T.push(i),a(r,i),e!==n&&a(o,i),B(i,"add"),G(),i}function v(e,n,t){var r=s(e,n);return new u(e,n,t,r)}function h(e,n,t){var r=s(e,n),o=C.hasOwnProperty(r);if(o||y(e,n)){o||(C[r]=0);var i="@"+ ++C[r];r=s(e+i,n+i)}return new u(e,n,t,r)}function g(e){var n=d(e);return n?n.links:null}function m(e){if(!e)return!1;var n=o(e,T);if(n<0)return!1;F(),T.splice(n,1);var t=d(e.fromId),r=d(e.toId);return t&&(n=o(e,t.links),n>=0&&t.links.splice(n,1)),r&&(n=o(e,r.links),n>=0&&r.links.splice(n,1)),B(e,"remove"),G(),!0}function y(e,n){var t,r=d(e);if(!r||!r.links)return null;for(t=0;t<r.links.length;++t){var o=r.links[t];if(o.fromId===e&&o.toId===n)return o}return null}function x(){F(),M(function(e){l(e.id)}),G()}function w(e){var n,t;if("function"==typeof e)for(n=0,t=T.length;n<t;++n)e(T[n])}function b(e,n,t){var r=d(e);if(r&&r.links&&"function"==typeof n)return t?L(r.links,e,n):E(r.links,e,n)}function E(e,n,t){for(var r,o=0;o<e.length;++o){var i=e[o],a=i.fromId===n?i.toId:i.fromId;if(r=t(I[a],i))return!0}}function L(e,n,t){for(var r,o=0;o<e.length;++o){var i=e[o];if(i.fromId===n&&(r=t(I[i.toId],i)))return!0}}function N(){}function k(){D+=1}function P(){D-=1,0===D&&R.length>0&&(q.fire("changed",R),R.length=0)}function j(){return Object.keys?A:_}function A(e){if("function"==typeof e)for(var n=Object.keys(I),t=0;t<n.length;++t)if(e(I[n[t]]))return!0}function _(e){if("function"==typeof e){var n;for(n in I)if(e(I[n]))return!0}}e=e||{},"uniqueLinkId"in e&&(console.warn("ngraph.graph: Starting from version 0.14 `uniqueLinkId` is deprecated.\nUse `multigraph` option instead\n","\n","Note: there is also change in default behavior: From now own each graph\nis considered to be not a multigraph by default (each edge is unique)."),e.multigraph=e.uniqueLinkId),void 0===e.multigraph&&(e.multigraph=!1);var I="function"==typeof Object.create?Object.create(null):{},T=[],C={},S=0,D=0,M=j(),U=e.multigraph?h:v,R=[],B=N,O=N,F=N,G=N,q={addNode:c,addLink:p,removeLink:m,removeNode:l,getNode:d,getNodesCount:function(){return S},getLinksCount:function(){return T.length},getLinks:g,forEachNode:M,forEachLinkedNode:b,forEachLink:w,beginUpdate:F,endUpdate:G,clear:x,hasLink:y,hasNode:d,getLink:y};return f(q),n(),q}function o(e,n){if(!n)return-1;if(n.indexOf)return n.indexOf(e);var t,r=n.length;for(t=0;t<r;t+=1)if(n[t]===e)return t;return-1}function i(e,n){this.id=e,this.links=null,this.data=n}function a(e,n){e.links?e.links.push(n):e.links=[n]}function u(e,n,t,r){this.fromId=e,this.toId=n,this.data=t,this.id=r}function s(e,n){return e.toString()+"👉 "+n.toString()}n.exports=r;var f=e("ngraph.events")},{"ngraph.events":9}],17:[function(e,n,t){function r(e,n){var t;if(e||(e={}),n)for(t in n)if(n.hasOwnProperty(t)){var o=e.hasOwnProperty(t),i=typeof n[t],a=!o||typeof e[t]!==i;a?e[t]=n[t]:"object"===i&&(e[t]=r(e[t],n[t]))}return e}n.exports=r},{}],18:[function(e,n,t){function r(e,n){this.pos=new o(e,n),this.prevPos=new o(e,n),this.force=new o,this.velocity=new o,this.mass=1}function o(e,n){e&&"number"!=typeof e?(this.x="number"==typeof e.x?e.x:0,this.y="number"==typeof e.y?e.y:0):(this.x="number"==typeof e?e:0,this.y="number"==typeof n?n:0)}function i(e,n,t){this.pos=new a(e,n,t),this.prevPos=new a(e,n,t),this.force=new a,this.velocity=new a,this.mass=1}function a(e,n,t){e&&"number"!=typeof e?(this.x="number"==typeof e.x?e.x:0,this.y="number"==typeof e.y?e.y:0,this.z="number"==typeof e.z?e.z:0):(this.x="number"==typeof e?e:0,this.y="number"==typeof n?n:0,this.z="number"==typeof t?t:0)}n.exports={Body:r,Vector2d:o,Body3d:i,Vector3d:a},r.prototype.setPosition=function(e,n){this.prevPos.x=this.pos.x=e,this.prevPos.y=this.pos.y=n},o.prototype.reset=function(){this.x=this.y=0},i.prototype.setPosition=function(e,n,t){this.prevPos.x=this.pos.x=e,this.prevPos.y=this.pos.y=n,this.prevPos.z=this.pos.z=t},a.prototype.reset=function(){this.x=this.y=this.z=0}},{}],19:[function(e,n,t){function r(n){function t(){var e,n=p.length;if(n)for(h.insertBodies(p);n--;)e=p[n],e.isPinned||(e.force.reset(),h.updateBodyForce(e),y.update(e));for(n=v.length;n--;)m.update(v[n])}var r=e("./lib/spring"),o=e("ngraph.expose"),i=e("ngraph.merge"),a=e("ngraph.events");n=i(n,{springLength:30,springCoeff:8e-4,gravity:-1.2,theta:.8,dragCoeff:.02,timeStep:20});var u=n.createQuadTree||e("ngraph.quadtreebh"),s=n.createBounds||e("./lib/bounds"),f=n.createDragForce||e("./lib/dragForce"),c=n.createSpringForce||e("./lib/springForce"),d=n.integrator||e("./lib/eulerIntegrator"),l=n.createBody||e("./lib/createBody"),p=[],v=[],h=u(n),g=s(p,n),m=c(n),y=f(n),x=!0,w=0,b={bodies:p,quadTree:h,springs:v,settings:n,step:function(){t();var e=d(p,n.timeStep);return g.update(),e},addBody:function(e){if(!e)throw new Error("Body is required");return p.push(e),e},addBodyAt:function(e){if(!e)throw new Error("Body position is required");var n=l(e);return p.push(n),n},removeBody:function(e){if(e){var n=p.indexOf(e);if(!(n<0))return p.splice(n,1),0===p.length&&g.reset(),!0}},addSpring:function(e,n,t,o,i){if(!e||!n)throw new Error("Cannot add null spring to force simulator");"number"!=typeof t&&(t=-1);var a=new r(e,n,t,i>=0?i:-1,o);return v.push(a),a},getTotalMovement:function(){return w},removeSpring:function(e){if(e){var n=v.indexOf(e);return n>-1?(v.splice(n,1),!0):void 0}},getBestNewBodyPosition:function(e){return g.getBestNewPosition(e)},getBBox:function(){return x&&(g.update(),x=!1),g.box},invalidateBBox:function(){x=!0},gravity:function(e){return void 0!==e?(n.gravity=e,h.options({gravity:e}),this):n.gravity},theta:function(e){return void 0!==e?(n.theta=e,h.options({theta:e}),this):n.theta}};return o(n,b),a(b),b}n.exports=r},{"./lib/bounds":20,"./lib/createBody":21,"./lib/dragForce":22,"./lib/eulerIntegrator":23,"./lib/spring":24,"./lib/springForce":25,"ngraph.events":9,"ngraph.expose":10,"ngraph.merge":17,"ngraph.quadtreebh":26}],20:[function(e,n,t){n.exports=function(n,t){function r(){var e=n.length;if(0!==e){for(var t=Number.MAX_VALUE,r=Number.MAX_VALUE,o=Number.MIN_VALUE,a=Number.MIN_VALUE;e--;){var u=n[e];u.isPinned?(u.pos.x=u.prevPos.x,u.pos.y=u.prevPos.y):(u.prevPos.x=u.pos.x,u.prevPos.y=u.pos.y),u.pos.x<t&&(t=u.pos.x),u.pos.x>o&&(o=u.pos.x),u.pos.y<r&&(r=u.pos.y),u.pos.y>a&&(a=u.pos.y)}i.x1=t,i.x2=o,i.y1=r,i.y2=a}}var o=e("ngraph.random").random(42),i={x1:0,y1:0,x2:0,y2:0};return{box:i,update:r,reset:function(){i.x1=i.y1=0,i.x2=i.y2=0},getBestNewPosition:function(e){var n=i,r=0,a=0;if(e.length){for(var u=0;u<e.length;++u)r+=e[u].pos.x,a+=e[u].pos.y;r/=e.length,a/=e.length}else r=(n.x1+n.x2)/2,a=(n.y1+n.y2)/2;var s=t.springLength;return{x:r+o.next(s)-s/2,y:a+o.next(s)-s/2}}}}},{"ngraph.random":30}],21:[function(e,n,t){var r=e("ngraph.physics.primitives");n.exports=function(e){return new r.Body(e)}},{"ngraph.physics.primitives":18}],22:[function(e,n,t){n.exports=function(n){var t=e("ngraph.merge"),r=e("ngraph.expose");n=t(n,{dragCoeff:.02});var o={update:function(e){e.force.x-=n.dragCoeff*e.velocity.x,e.force.y-=n.dragCoeff*e.velocity.y}};return r(n,o,["dragCoeff"]),o}},{"ngraph.expose":10,"ngraph.merge":17}],23:[function(e,n,t){function r(e,n){var t,r=0,o=0,i=0,a=0,u=e.length;if(0===u)return 0;for(t=0;t<u;++t){var s=e[t],f=n/s.mass;s.velocity.x+=f*s.force.x,s.velocity.y+=f*s.force.y;var c=s.velocity.x,d=s.velocity.y,l=Math.sqrt(c*c+d*d);l>1&&(s.velocity.x=c/l,s.velocity.y=d/l),r=n*s.velocity.x,i=n*s.velocity.y,s.pos.x+=r,s.pos.y+=i,o+=Math.abs(r),a+=Math.abs(i)}return(o*o+a*a)/u}n.exports=r},{}],24:[function(e,n,t){function r(e,n,t,r,o){this.from=e,this.to=n,this.length=t,this.coeff=r,this.weight="number"==typeof o?o:1}n.exports=r},{}],25:[function(e,n,t){n.exports=function(n){var t=e("ngraph.merge"),r=e("ngraph.random").random(42),o=e("ngraph.expose");n=t(n,{springCoeff:2e-4,springLength:80});var i={update:function(e){var t=e.from,o=e.to,i=e.length<0?n.springLength:e.length,a=o.pos.x-t.pos.x,u=o.pos.y-t.pos.y,s=Math.sqrt(a*a+u*u);0===s&&(a=(r.nextDouble()-.5)/50,u=(r.nextDouble()-.5)/50,s=Math.sqrt(a*a+u*u));var f=s-i,c=(!e.coeff||e.coeff<0?n.springCoeff:e.coeff)*f/s*e.weight;t.force.x+=c*a,t.force.y+=c*u,o.force.x-=c*a,o.force.y-=c*u}};return o(n,i,["springCoeff","springLength"]),i}},{"ngraph.expose":10,"ngraph.merge":17,"ngraph.random":30}],26:[function(e,n,t){function r(e,n){return 0===n?e.quad0:1===n?e.quad1:2===n?e.quad2:3===n?e.quad3:null}function o(e,n,t){0===n?e.quad0=t:1===n?e.quad1=t:2===n?e.quad2=t:3===n&&(e.quad3=t)}n.exports=function(n){function t(){var e=g[m];return e?(e.quad0=null,e.quad1=null,e.quad2=null,e.quad3=null,e.body=null,e.mass=e.massX=e.massY=0,e.left=e.right=e.top=e.bottom=0):(e=new f,g[m]=e),++m,e}function i(e){var n,t,r,o,i=p,a=0,u=0,f=1,c=0,d=1;for(i[0]=y;f;){var v=i[c],g=v.body;f-=1,c+=1;var m=g!==e;g&&m?(t=g.pos.x-e.pos.x,r=g.pos.y-e.pos.y,o=Math.sqrt(t*t+r*r),0===o&&(t=(s.nextDouble()-.5)/50,r=(s.nextDouble()-.5)/50,o=Math.sqrt(t*t+r*r)),n=l*g.mass*e.mass/(o*o*o),a+=n*t,u+=n*r):m&&(t=v.massX/v.mass-e.pos.x,r=v.massY/v.mass-e.pos.y,o=Math.sqrt(t*t+r*r),0===o&&(t=(s.nextDouble()-.5)/50,r=(s.nextDouble()-.5)/50,o=Math.sqrt(t*t+r*r)),(v.right-v.left)/o<h?(n=l*v.mass*e.mass/(o*o*o),a+=n*t,u+=n*r):(v.quad0&&(i[d]=v.quad0,f+=1,d+=1),v.quad1&&(i[d]=v.quad1,f+=1,d+=1),v.quad2&&(i[d]=v.quad2,f+=1,d+=1),v.quad3&&(i[d]=v.quad3,f+=1,d+=1)))}e.force.x+=a,e.force.y+=u}function a(e){var n,r=Number.MAX_VALUE,o=Number.MAX_VALUE,i=Number.MIN_VALUE,a=Number.MIN_VALUE,s=e.length;for(n=s;n--;){var f=e[n].pos.x,c=e[n].pos.y;f<r&&(r=f),f>i&&(i=f),c<o&&(o=c),c>a&&(a=c)}var d=i-r,l=a-o;for(d>l?a=o+d:i=r+l,m=0,y=t(),y.left=r,y.right=i,y.top=o,y.bottom=a,n=s-1,n>=0&&(y.body=e[n]);n--;)u(e[n],y)}function u(e){for(v.reset(),v.push(y,e);!v.isEmpty();){var n=v.pop(),i=n.node,a=n.body;if(i.body){var u=i.body;if(i.body=null,d(u.pos,a.pos)){var f=3;do{var c=s.nextDouble(),l=(i.right-i.left)*c,p=(i.bottom-i.top)*c;u.pos.x=i.left+l,u.pos.y=i.top+p,f-=1}while(f>0&&d(u.pos,a.pos));if(0===f&&d(u.pos,a.pos))return}v.push(i,u),v.push(i,a)}else{var h=a.pos.x,g=a.pos.y;i.mass=i.mass+a.mass,i.massX=i.massX+a.mass*h,i.massY=i.massY+a.mass*g;var m=0,x=i.left,w=(i.right+x)/2,b=i.top,E=(i.bottom+b)/2;h>w&&(m+=1,x=w,w=i.right),g>E&&(m+=2,b=E,E=i.bottom);var L=r(i,m);L?v.push(L,a):(L=t(),L.left=x,L.top=b,L.right=w,L.bottom=E,L.body=a,o(i,m,L))}}}n=n||{},n.gravity="number"==typeof n.gravity?n.gravity:-1,n.theta="number"==typeof n.theta?n.theta:.8;var s=e("ngraph.random").random(1984),f=e("./node"),c=e("./insertStack"),d=e("./isSamePosition"),l=n.gravity,p=[],v=new c,h=n.theta,g=[],m=0,y=t();return{insertBodies:a,getRoot:function(){return y},updateBodyForce:i,options:function(e){return e?("number"==typeof e.gravity&&(l=e.gravity),"number"==typeof e.theta&&(h=e.theta),this):{gravity:l,theta:h}}}}},{"./insertStack":27,"./isSamePosition":28,"./node":29,"ngraph.random":30}],27:[function(e,n,t){function r(){this.stack=[],this.popIdx=0}function o(e,n){this.node=e,this.body=n}n.exports=r,r.prototype={isEmpty:function(){return 0===this.popIdx},push:function(e,n){var t=this.stack[this.popIdx];t?(t.node=e,t.body=n):this.stack[this.popIdx]=new o(e,n),++this.popIdx},pop:function(){if(this.popIdx>0)return this.stack[--this.popIdx]},reset:function(){this.popIdx=0}}},{}],28:[function(e,n,t){n.exports=function(e,n){var t=Math.abs(e.x-n.x),r=Math.abs(e.y-n.y);return t<1e-8&&r<1e-8}},{}],29:[function(e,n,t){n.exports=function(){this.body=null,this.quad0=null,this.quad1=null,this.quad2=null,this.quad3=null,this.mass=0,this.massX=0,this.massY=0,this.left=0,this.top=0,this.bottom=0,this.right=0}},{}],30:[function(e,n,t){function r(e){var n="number"==typeof e?e:+new Date,t=function(){return n=n+2127912214+(n<<12)&4294967295,n=4294967295&(3345072700^n^n>>>19),n=n+374761393+(n<<5)&4294967295,n=4294967295&(n+3550635116^n<<9),n=n+4251993797+(n<<3)&4294967295,n=4294967295&(3042594569^n^n>>>16),(268435455&n)/268435456};return{next:function(e){return Math.floor(t()*e)},nextDouble:function(){return t()}}}function o(e,n){var t=n||r();if("function"!=typeof t.next)throw new Error("customRandom does not match expected API: next() function is missing");return{forEach:function(n){var r,o,i;for(r=e.length-1;r>0;--r)o=t.next(r+1),i=e[o],e[o]=e[r],e[r]=i,n(i);e.length&&n(e[0])},shuffle:function(){var n,r,o;for(n=e.length-1;n>0;--n)r=t.next(n+1),o=e[r],e[r]=e[n],e[n]=o;return e}}}n.exports={random:r,randomIterator:o}},{}],31:[function(e,n,t){function r(e,n,t){function r(e){u.nodes.push(s(e))}function o(e){u.links.push(f(e))}function i(e){var n={id:e.id};return void 0!==e.data&&(n.data=e.data),n}function a(e){var n={fromId:e.fromId,toId:e.toId};return void 0!==e.data&&(n.data=e.data),n}var u={nodes:[],links:[]},s=n||i,f=t||a;return e.forEachNode(r),e.forEachLink(o),JSON.stringify(u)}n.exports=r},{}],32:[function(e,n,t){function r(e,n){var t=o(e);if(void 0===n)return t;for(var r=Object.keys(n),i=0;i<r.length;++i){var a=r[i],u=n[a];"link"===a?t.link(u):t.attr(a,u)}return t}function o(e){function n(e){return v||(v=i(p)),v.link(e),p}function t(e,n,t){return a.addEventListener(p,e,n,t),p}function o(e,n,t){return a.removeEventListener(p,e,n,t),p}function f(e){var n=r(e);return p.appendChild(n),n}function c(e,n){return 2===arguments.length?(null!==n?p.setAttributeNS(null,e,n):p.removeAttributeNS(null,e),p):p.getAttributeNS(null,e)}function d(e){return arguments.length?(p.setAttributeNS(s,"xlink:href",e),p):p.getAttributeNS(s,"xlink:href")}function l(e){return void 0!==e?(p.textContent=e,p):p.textContent}var p=e;if("string"==typeof e)p=window.document.createElementNS(u,e);else if(e.simplesvg)return e;var v;return p.simplesvg=!0,p.attr=c,p.append=f,p.link=d,p.text=l,p.on=t,p.off=o,p.dataSource=n,p}n.exports=r,r.compile=e("./lib/compile");var i=r.compileTemplate=e("./lib/compile_template"),a=e("add-event-listener"),u="http://www.w3.org/2000/svg",s="http://www.w3.org/1999/xlink"},{"./lib/compile":33,"./lib/compile_template":34,"add-event-listener":2}],33:[function(e,n,t){function r(e){try{return e=o(e),a(i.parseFromString(e,"text/xml").documentElement)}catch(n){throw n}}function o(e){if(e){var n='xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"',t=e.match(/^<\w+/);if(t){var r=t[0].length;return e.substr(0,r)+" "+n+" "+e.substr(r)}throw new Error("Cannot parse input text: invalid xml?")}}var i=e("./domparser.js"),a=e("../");n.exports=r},{"../":32,"./domparser.js":35}],34:[function(e,n,t){function r(e){var n=Object.create(null);return o(e,n),{link:function(e){function t(n){n(e)}Object.keys(n).forEach(function(e){var r=n[e];r.forEach(t)})}}}function o(e,n){var t=e.nodeType,r=1===t||3===t;if(r){var u;if(e.hasChildNodes()){var s=e.childNodes;for(u=0;u<s.length;++u)o(s[u],n)}if(3===t&&a(e,n),e.attributes){var f=e.attributes;for(u=0;u<f.length;++u)i(f[u],e,n)}}}function i(e,n,t){function r(e){n.setAttributeNS(null,a,e[s])}var o=e.value;if(o){var i=o.match(u);if(i){var a=e.localName,s=i[1],f=s.indexOf(".")<0;if(!f)throw new Error("simplesvg currently does not support nested bindings");var c=t[s];c?c.push(r):c=t[s]=[r]}}}function a(e,n){function t(n){e.nodeValue=n[i]}var r=e.nodeValue;if(r){var o=r.match(u);if(o){var i=o[1],a=(i.indexOf(".")<0,
+n[i]);a?a.push(t):a=n[i]=[t]}}}n.exports=r;var u=/{{(.+?)}}/},{}],35:[function(e,n,t){function r(){return"undefined"==typeof DOMParser?{parseFromString:o}:new DOMParser}function o(){throw new Error("DOMParser is not supported by this platform. Please open issue here https://github.com/anvaka/simplesvg")}n.exports=r()},{}],36:[function(e,n,t){function r(){return{betweennessCentrality:o,degreeCentrality:i}}function o(e){var n=u.betweenness(e);return a(n)}function i(e,n){var t=u.degree(e,n);return a(t)}function a(e){function n(n,t){return e[t]-e[n]}function t(n){return{key:n,value:e[n]}}return Object.keys(e).sort(n).map(t)}var u=e("ngraph.centrality");n.exports=r},{"ngraph.centrality":4}],37:[function(e,n,t){function r(){return{density:function(e,n){var t=e.getNodesCount();return 0===t?NaN:n?e.getLinksCount()/(t*(t-1)):2*e.getLinksCount()/(t*(t-1))}}}n.exports=r},{}],38:[function(e,n,t){function r(e,n){function t(e,t){var i;if(t){var a=n.getNodeUI(e.id);i=o(a),"function"==typeof t.onStart&&i.onStart(t.onStart),"function"==typeof t.onDrag&&i.onDrag(t.onDrag),"function"==typeof t.onStop&&i.onStop(t.onStop),r[e.id]=i}else(i=r[e.id])&&(i.release(),delete r[e.id])}var r={};return{bindDragNDrop:t}}n.exports=r;var o=e("./dragndrop.js")},{"./dragndrop.js":39}],39:[function(e,n,t){function r(e){var n,t,r,u,s,f,c,d=0,l=0,p=!1,v=0,h=function(e){var n=0,t=0;return e=e||window.event,e.pageX||e.pageY?(n=e.pageX,t=e.pageY):(e.clientX||e.clientY)&&(n=e.clientX+window.document.body.scrollLeft+window.document.documentElement.scrollLeft,t=e.clientY+window.document.body.scrollTop+window.document.documentElement.scrollTop),[n,t]},g=function(e,n,r){t&&t(e,{x:n-d,y:r-l}),d=n,l=r},m=function(e){e.stopPropagation?e.stopPropagation():e.cancelBubble=!0},y=function(e){e.preventDefault&&e.preventDefault()},x=function(e){return m(e),!1},w=function(e){e=e||window.event,g(e,e.clientX,e.clientY)},b=function(e){if(e=e||window.event,p)return m(e),!1;var t=1===e.button&&null!==window.event||0===e.button;return t?(d=e.clientX,l=e.clientY,c=e.target||e.srcElement,n&&n(e,{x:d,y:l}),o.on("mousemove",w),o.on("mouseup",E),m(e),s=window.document.onselectstart,f=window.document.ondragstart,window.document.onselectstart=x,c.ondragstart=x,!1):void 0},E=function(e){e=e||window.event,o.off("mousemove",w),o.off("mouseup",E),window.document.onselectstart=s,c.ondragstart=f,c=null,r&&r(e)},L=function(n){if("function"==typeof u){n=n||window.event,n.preventDefault&&n.preventDefault(),n.returnValue=!1;var t,r=h(n),o=a(e),i={x:r[0]-o[0],y:r[1]-o[1]};t=n.wheelDelta?n.wheelDelta/360:n.detail/-9,u(n,t,i)}},N=function(n){!u&&n?"webkit"===i.browser?e.addEventListener("mousewheel",L,!1):e.addEventListener("DOMMouseScroll",L,!1):u&&!n&&("webkit"===i.browser?e.removeEventListener("mousewheel",L,!1):e.removeEventListener("DOMMouseScroll",L,!1)),u=n},k=function(e,n){return(e.clientX-n.clientX)*(e.clientX-n.clientX)+(e.clientY-n.clientY)*(e.clientY-n.clientY)},P=function(e){if(1===e.touches.length){m(e);var n=e.touches[0];g(e,n.clientX,n.clientY)}else if(2===e.touches.length){var t=k(e.touches[0],e.touches[1]),r=0;t<v?r=-1:t>v&&(r=1),u(e,r,{x:e.touches[0].clientX,y:e.touches[0].clientY}),v=t,m(e),y(e)}},j=function(e){p=!1,o.off("touchmove",P),o.off("touchend",j),o.off("touchcancel",j),c=null,r&&r(e)},A=function(e,t){m(e),y(e),d=t.clientX,l=t.clientY,c=e.target||e.srcElement,n&&n(e,{x:d,y:l}),p||(p=!0,o.on("touchmove",P),o.on("touchend",j),o.on("touchcancel",j))},_=function(e){return 1===e.touches.length?A(e,e.touches[0]):void(2===e.touches.length&&(m(e),y(e),v=k(e.touches[0],e.touches[1])))};return e.addEventListener("mousedown",b),e.addEventListener("touchstart",_),{onStart:function(e){return n=e,this},onDrag:function(e){return t=e,this},onStop:function(e){return r=e,this},onScroll:function(e){return N(e),this},release:function(){e.removeEventListener("mousedown",b),e.removeEventListener("touchstart",_),o.off("mousemove",w),o.off("mouseup",E),o.off("touchmove",P),o.off("touchend",j),o.off("touchcancel",j),N(null)}}}n.exports=r;var o=e("../Utils/documentEvents.js"),i=e("../Utils/browserInfo.js"),a=e("../Utils/findElementPosition.js")},{"../Utils/browserInfo.js":43,"../Utils/documentEvents.js":44,"../Utils/findElementPosition.js":45}],40:[function(e,n,t){function r(e,n){var t=o(n),r=null,i={},a={x:0,y:0};return t.mouseDown(function(e,n){r=e,a.x=n.clientX,a.y=n.clientY,t.mouseCapture(r);var o=i[e.id];return o&&o.onStart&&o.onStart(n,a),!0}).mouseUp(function(e){t.releaseMouseCapture(r),r=null;var n=i[e.id];return n&&n.onStop&&n.onStop(),!0}).mouseMove(function(e,n){if(r){var t=i[r.id];return t&&t.onDrag&&t.onDrag(n,{x:n.clientX-a.x,y:n.clientY-a.y}),a.x=n.clientX,a.y=n.clientY,!0}}),{bindDragNDrop:function(e,n){i[e.id]=n,n||delete i[e.id]}}}n.exports=r;var o=e("../WebGL/webglInputEvents.js")},{"../WebGL/webglInputEvents.js":61}],41:[function(e,n,t){function r(e,n){function t(e){return d[e]}n=o(n,{maxX:1024,maxY:1024,seed:"Deterministic randomness made me do this"});var r=i(n.seed),u=new a(Number.MAX_VALUE,Number.MAX_VALUE,Number.MIN_VALUE,Number.MIN_VALUE),s={},f=function(e){return{x:r.next(n.maxX),y:r.next(n.maxY)}},c=function(e,n){e.x<n.x1&&(n.x1=e.x),e.x>n.x2&&(n.x2=e.x),e.y<n.y1&&(n.y1=e.y),e.y>n.y2&&(n.y2=e.y)},d="function"==typeof Object.create?Object.create(null):{},l=function(e){d[e.id]=f(e),c(d[e.id],u)},p=function(){0!==e.getNodesCount()&&(u.x1=Number.MAX_VALUE,u.y1=Number.MAX_VALUE,u.x2=Number.MIN_VALUE,u.y2=Number.MIN_VALUE,e.forEachNode(l))},v=function(e){s[e.id]=e},h=function(e){for(var n=0;n<e.length;++n){var t=e[n];t.node&&("add"===t.changeType?l(t.node):delete d[t.node.id]),t.link&&("add"===t.changeType?v(t.link):delete s[t.link.id])}};return e.forEachNode(l),e.forEachLink(v),e.on("changed",h),{run:function(e){this.step()},step:function(){return p(),!0},getGraphRect:function(){return u},dispose:function(){e.off("change",h)},isNodePinned:function(e){return!0},pinNode:function(e,n){},getNodePosition:t,getLinkPosition:function(e){var n=s[e];return{from:t(n.fromId),to:t(n.toId)}},setNodePosition:function(e,n,t){var r=d[e];r&&(r.x=n,r.y=t)},placeNode:function(e){return"function"==typeof e?(f=e,p(),this):f(e)}}}n.exports=r;var o=e("ngraph.merge"),i=e("ngraph.random").random,a=e("../Utils/rect.js")},{"../Utils/rect.js":49,"ngraph.merge":17,"ngraph.random":30}],42:[function(e,n,t){function r(e){function n(){var n=o(e);return n.addEventListener=n.on,n}if(console.log("This method is deprecated. Please use Viva.events() instead"),!e)return e;var t=void 0!==e.on||void 0!==e.off||void 0!==e.fire;return t?{extend:function(){return e},on:e.on,stop:e.off}:{extend:n,on:e.on,stop:e.off}}var o=e("ngraph.events");n.exports=r},{"ngraph.events":9}],43:[function(e,n,t){function r(){if("undefined"==typeof window||!window.hasOwnProperty("navigator"))return{browser:"",version:"0"};var e=window.navigator.userAgent.toLowerCase(),n=/(webkit)[ \/]([\w.]+)/,t=/(opera)(?:.*version)?[ \/]([\w.]+)/,r=/(msie) ([\w.]+)/,o=/(mozilla)(?:.*? rv:([\w.]+))?/,i=n.exec(e)||t.exec(e)||r.exec(e)||e.indexOf("compatible")<0&&o.exec(e)||[];return{browser:i[1]||"",version:i[2]||"0"}}n.exports=r()},{}],44:[function(e,n,t){function r(){return void 0===typeof document?a:{on:o,off:i}}function o(e,n){document.addEventListener(e,n)}function i(e,n){document.removeEventListener(e,n)}var a=e("./nullEvents.js");n.exports=r()},{"./nullEvents.js":48}],45:[function(e,n,t){function r(e){var n=0,t=0;if(e.offsetParent)do n+=e.offsetLeft,t+=e.offsetTop;while(null!==(e=e.offsetParent));return[n,t]}n.exports=r},{}],46:[function(e,n,t){function r(e){if(!e)throw{message:"Cannot get dimensions of undefined container"};var n=e.clientWidth,t=e.clientHeight;return{left:0,top:0,width:n,height:t}}n.exports=r},{}],47:[function(e,n,t){function r(e,n,t,r,i,a,u,s){return o(e,n,e,r,i,a,u,s)||o(e,r,t,r,i,a,u,s)||o(t,r,t,n,i,a,u,s)||o(t,n,e,n,i,a,u,s)}var o=e("gintersect");n.exports=r},{gintersect:3}],48:[function(e,n,t){function r(){return{on:o,off:o,stop:o}}function o(){}n.exports=r()},{}],49:[function(e,n,t){function r(e,n,t,r){this.x1=e||0,this.y1=n||0,this.x2=t||0,this.y2=r||0}n.exports=r},{}],50:[function(e,n,t){(function(e){function t(){function n(e){function n(){o=a.requestAnimationFrame(n),e()||t()}function t(){a.cancelAnimationFrame(o),o=0}function r(){o||n()}var o;return n(),{stop:t,restart:r}}function t(e){var n=(new Date).getTime(),t=Math.max(0,16-(n-u)),r=a.setTimeout(function(){e(n+t)},t);return u=n+t,r}function o(e){a.clearTimeout(e)}var i,a,u=0,s=["ms","moz","webkit","o"];for(a="undefined"!=typeof window?window:"undefined"!=typeof e?e:{setTimeout:r,clearTimeout:r},i=0;i<s.length&&!a.requestAnimationFrame;++i){var f=s[i];a.requestAnimationFrame=a[f+"RequestAnimationFrame"],a.cancelAnimationFrame=a[f+"CancelAnimationFrame"]||a[f+"CancelRequestAnimationFrame"]}return a.requestAnimationFrame||(a.requestAnimationFrame=t),a.cancelAnimationFrame||(a.cancelAnimationFrame=o),n}function r(){}n.exports=t()}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}],51:[function(e,n,t){function r(){return"undefined"==typeof window?a:{on:o,off:i}}function o(e,n){window.addEventListener(e,n)}function i(e,n){window.removeEventListener(e,n)}var a=e("./nullEvents.js");n.exports=r()},{"./nullEvents.js":48}],52:[function(e,n,t){function r(e,n){function t(e){return"string"==typeof q?q.indexOf(e)>=0:"boolean"!=typeof q||q}function r(){G=G||window.document.body,O=O||i(e,{springLength:80,springCoeff:2e-4}),F=F||a(e,{container:G}),n.hasOwnProperty("renderLinks")||(n.renderLinks=!0),n.prerender=n.prerender||0,U=(F.inputManager||s)(e,F)}function l(){F.beginRender(),n.renderLinks&&F.renderLinks(),F.renderNodes(),F.endRender()}function p(){return X=O.step()&&!V,l(),!X}function v(e){R||(R=void 0!==e?f(function(){if(e-=1,e<0){var n=!1;return n}return p()},M):f(p,M))}function h(){W||(X=!1,R.restart())}function g(){if("number"==typeof n.prerender&&n.prerender>0)for(var e=0;e<n.prerender;e+=1)O.step()}function m(){var e=O.getGraphRect(),n=c(G),t=(e.x2+e.x1)/2,r=(e.y2+e.y1)/2;H.offsetX=n.width/2-(t*H.scale-t),H.offsetY=n.height/2-(r*H.scale-r),F.graphCenterChanged(H.offsetX,H.offsetY),Y=!1}function y(e){var n=O.getNodePosition(e.id);F.addNode(e,n)}function x(e){F.releaseNode(e)}function w(e){var n=O.getLinkPosition(e.id);F.addLink(e,n)}function b(e){F.releaseLink(e)}function E(e){if(t("node")){var n=!1;U.bindDragNDrop(e,{onStart:function(){n=O.isNodePinned(e),O.pinNode(e,!0),V=!0,h()},onDrag:function(n,t){var r=O.getNodePosition(e.id);O.setNodePosition(e.id,r.x+t.x/H.scale,r.y+t.y/H.scale),V=!0,l()},onStop:function(){O.pinNode(e,n),V=!1}})}}function L(e){U.bindDragNDrop(e,null)}function N(){F.init(G),e.forEachNode(y),n.renderLinks&&e.forEachLink(w)}function k(){F.release(G)}function P(n){var t=n.node;"add"===n.changeType?(y(t),E(t),Y&&m()):"remove"===n.changeType?(L(t),x(t),0===e.getNodesCount()&&(Y=!0)):"update"===n.changeType&&(L(t),x(t),y(t),E(t))}function j(e){var t=e.link;if("add"===e.changeType)n.renderLinks&&w(t);else if("remove"===e.changeType)n.renderLinks&&b(t);else if("update"===e.changeType)throw"Update type is not implemented. TODO: Implement me!"}function A(e){var n,t;for(n=0;n<e.length;n+=1)t=e[n],t.node?P(t):t.link&&j(t);h()}function _(){m(),p()}function I(){B&&(B.release(),B=null)}function T(){e.off("changed",A)}function C(e,n){if(!n){var t=c(G);n={x:t.width/2,y:t.height/2}}var r=Math.pow(1.4,e?-.2:.2);return H.scale=F.scale(r,n),l(),J.fire("scale",H.scale),H.scale}function S(){u.on("resize",_),I(),t("drag")&&(B=d(G),B.onDrag(function(e,n){F.translateRel(n.x,n.y),l(),J.fire("drag",n)})),t("scroll")&&(B||(B=d(G)),B.onScroll(function(e,n,t){C(n<0,t)})),e.forEachNode(E),T(),e.on("changed",A)}function D(){z=!1,T(),I(),u.off("resize",_),J.off(),R.stop(),e.forEachLink(function(e){n.renderLinks&&b(e)}),e.forEachNode(function(e){L(e),x(e)}),O.dispose(),k()}var M=30;n=n||{};var U,R,B,O=n.layout,F=n.graphics,G=n.container,q=void 0===n.interactive||n.interactive,z=!1,Y=!0,X=!1,V=!1,W=!1,H={offsetX:0,offsetY:0,scale:1},J=o({});return{run:function(e){return z||(r(),g(),N(),m(),S(),z=!0),v(e),this},reset:function(){F.resetScale(),m(),H.scale=1},pause:function(){W=!0,R.stop()},resume:function(){W=!1,R.restart()},rerender:function(){return l(),this},zoomOut:function(){return C(!0)},zoomIn:function(){return C(!1)},getTransform:function(){return H},moveTo:function(e,n){F.graphCenterChanged(H.offsetX-e*H.scale,H.offsetY-n*H.scale),l()},getGraphics:function(){return F},getLayout:function(){return O},dispose:function(){D()},on:function(e,n){return J.on(e,n),this},off:function(e,n){return J.off(e,n),this}}}n.exports=r;var o=e("ngraph.events"),i=e("ngraph.forcelayout"),a=e("./svgGraphics.js"),u=e("../Utils/windowEvents.js"),s=e("../Input/domInputManager.js"),f=e("../Utils/timer.js"),c=e("../Utils/getDimensions.js"),d=e("../Input/dragndrop.js")},{"../Input/domInputManager.js":38,"../Input/dragndrop.js":39,"../Utils/getDimensions.js":46,"../Utils/timer.js":50,"../Utils/windowEvents.js":51,"./svgGraphics.js":53,"ngraph.events":9,"ngraph.forcelayout":11}],53:[function(e,n,t){function r(){function e(){var e=o("svg");return n=o("g").attr("buffered-rendering","dynamic"),e.appendChild(n),e}var n,t,r,u=0,s=0,f=1,c={},d={},l=function(e){return o("rect").attr("width",10).attr("height",10).attr("fill","#00a2e8")},p=function(e,n){e.attr("x",n.x-5).attr("y",n.y-5)},v=function(e){return o("line").attr("stroke","#999")},h=function(e,n,t){e.attr("x1",n.x).attr("y1",n.y).attr("x2",t.x).attr("y2",t.y)},g=function(e){e.fire("rescaled")},m={x:0,y:0},y={x:0,y:0},x={x:0,y:0},w=function(){if(n){var e="matrix("+f+", 0, 0,"+f+","+u+","+s+")";n.attr("transform",e)}};t=e();var b={getNodeUI:function(e){return c[e]},getLinkUI:function(e){return d[e]},node:function(e){if("function"==typeof e)return l=e,this},link:function(e){if("function"==typeof e)return v=e,this},placeNode:function(e){return p=e,this},placeLink:function(e){return h=e,this},beginRender:function(){},endRender:function(){},graphCenterChanged:function(e,n){u=e,s=n,w()},inputManager:a,translateRel:function(e,r){var o=t.createSVGPoint(),i=n.getCTM(),a=t.createSVGPoint().matrixTransform(i.inverse());o.x=e,o.y=r,o=o.matrixTransform(i.inverse()),o.x=(o.x-a.x)*i.a,o.y=(o.y-a.y)*i.d,i.e+=o.x,i.f+=o.y;var u="matrix("+i.a+", 0, 0,"+i.d+","+i.e+","+i.f+")";n.attr("transform",u)},scale:function(e,r){var o=t.createSVGPoint();o.x=r.x,o.y=r.y,o=o.matrixTransform(n.getCTM().inverse());var i=t.createSVGMatrix().translate(o.x,o.y).scale(e).translate(-o.x,-o.y),a=n.getCTM().multiply(i);f=a.a,u=a.e,s=a.f;var c="matrix("+a.a+", 0, 0,"+a.d+","+a.e+","+a.f+")";return n.attr("transform",c),g(this),f},resetScale:function(){f=1;var e="matrix(1, 0, 0, 1, 0, 0)";return n.attr("transform",e),g(this),this},init:function(e){e.appendChild(t),w(),"function"==typeof r&&r(t)},release:function(e){t&&e&&e.removeChild(t)},addLink:function(e,t){var r=v(e);if(r)return r.position=t,r.link=e,d[e.id]=r,n.childElementCount>0?n.insertBefore(r,n.firstChild):n.appendChild(r),r},releaseLink:function(e){var t=d[e.id];t&&(n.removeChild(t),delete d[e.id])},addNode:function(e,t){var r=l(e);if(r)return r.position=t,r.node=e,c[e.id]=r,n.appendChild(r),r},releaseNode:function(e){var t=c[e.id];t&&(n.removeChild(t),delete c[e.id])},renderNodes:function(){for(var e in c)if(c.hasOwnProperty(e)){var n=c[e];m.x=n.position.x,m.y=n.position.y,p(n,m,n.node)}},renderLinks:function(){for(var e in d)if(d.hasOwnProperty(e)){var n=d[e];y.x=n.position.from.x,y.y=n.position.from.y,x.x=n.position.to.x,x.y=n.position.to.y,h(n,y,x,n.link)}},getGraphicsRoot:function(e){return"function"==typeof e&&(t?e(t):r=e),t},getSvgRoot:function(){return t}};return i(b),b}n.exports=r;var o=e("simplesvg"),i=e("ngraph.events"),a=e("../Input/domInputManager.js")},{"../Input/domInputManager.js":38,"ngraph.events":9,simplesvg:32}],54:[function(e,n,t){function r(e){e=c(e,{enableBlending:!0,preserveDrawingBuffer:!1,clearColor:!1,clearColorValue:{r:1,g:1,b:1,a:1}});var n,t,r,d,l,p,v,h,g=0,m=0,y=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],x=[],w=[],b={},E={},L=i(),N=a(),k=function(e){return u()},P=function(e){return s(3014898687)},j=function(){L.updateTransform(y),N.updateTransform(y)},A=function(){y=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]},_=function(){n&&t&&(d=t.width=Math.max(n.offsetWidth,1),l=t.height=Math.max(n.offsetHeight,1),r&&r.viewport(0,0,d,l),L&&L.updateSize(d/2,l/2),N&&N.updateSize(d/2,l/2))},I=function(e){e.fire("rescaled")};t=window.document.createElement("canvas");var T={getLinkUI:function(e){return E[e]},getNodeUI:function(e){return b[e]},node:function(e){if("function"==typeof e)return k=e,this},link:function(e){if("function"==typeof e)return P=e,this},placeNode:function(e){return p=e,this},placeLink:function(e){return v=e,this},inputManager:o,beginRender:function(){},endRender:function(){m>0&&L.render(),g>0&&N.render()},bringLinkToFront:function(e){var n,t,r=L.getFrontLinkId();L.bringToFront(e),r>e.id&&(n=e.id,t=w[r],w[r]=w[n],w[r].id=r,w[n]=t,w[n].id=n)},graphCenterChanged:function(e,n){y[12]=2*e/d-1,y[13]=1-2*n/l,j()},addLink:function(e,n){var t=m++,r=P(e);return r.id=t,r.pos=n,L.createLink(r),w[t]=r,E[e.id]=r,r},addNode:function(e,n){var t=g++,r=k(e);return r.id=t,r.position=n,r.node=e,N.createNode(r),x[t]=r,b[e.id]=r,r},translateRel:function(e,n){y[12]+=2*y[0]*e/d/y[0],y[13]-=2*y[5]*n/l/y[5],j()},scale:function(e,n){var t=2*n.x/d-1,r=1-2*n.y/l;return t-=y[12],r-=y[13],y[12]+=t*(1-e),y[13]+=r*(1-e),y[0]*=e,y[5]*=e,j(),I(this),y[0]},resetScale:function(){return A(),r&&(_(),j()),this},updateSize:_,init:function(o){var i={};if(e.preserveDrawingBuffer&&(i.preserveDrawingBuffer=!0),n=o,_(),A(),n.appendChild(t),r=t.getContext("experimental-webgl",i),!r){var a="Could not initialize WebGL. Seems like the browser doesn't support it.";throw window.alert(a),a}if(e.enableBlending&&(r.blendFunc(r.SRC_ALPHA,r.ONE_MINUS_SRC_ALPHA),r.enable(r.BLEND)),e.clearColor){var u=e.clearColorValue;r.clearColor(u.r,u.g,u.b,u.a),this.beginRender=function(){r.clear(r.COLOR_BUFFER_BIT)}}L.load(r),L.updateSize(d/2,l/2),N.load(r),N.updateSize(d/2,l/2),j(),"function"==typeof h&&h(t)},release:function(e){t&&e&&e.removeChild(t)},isSupported:function(){var e=window.document.createElement("canvas"),n=e&&e.getContext&&e.getContext("experimental-webgl");return n},releaseLink:function(e){m>0&&(m-=1);var n=E[e.id];delete E[e.id],L.removeLink(n);var t=n.id;if(t<m){if(0===m||m===t)return;var r=w[m];w[t]=r,r.id=t}},releaseNode:function(e){g>0&&(g-=1);var n=b[e.id];delete b[e.id],N.removeNode(n);var t=n.id;if(t<g){if(0===g||g===t)return;var r=x[g];x[t]=r,r.id=t,N.replaceProperties(n,r)}},renderNodes:function(){for(var e={x:0,y:0},n=0;n<g;++n){var t=x[n];e.x=t.position.x,e.y=t.position.y,p&&p(t,e),N.position(t,e)}},renderLinks:function(){if(!this.omitLinksRendering)for(var e={x:0,y:0},n={x:0,y:0},t=0;t<m;++t){var r=w[t],o=r.pos.from;n.x=o.x,n.y=-o.y,o=r.pos.to,e.x=o.x,e.y=-o.y,v&&v(r,n,e),L.position(r,n,e)}},getGraphicsRoot:function(e){return"function"==typeof e&&(t?e(t):h=e),t},setNodeProgram:function(e){if(!r&&e)N=e;else if(e)throw"Not implemented. Cannot swap shader on the fly... Yet."},setLinkProgram:function(e){if(!r&&e)L=e;else if(e)throw"Not implemented. Cannot swap shader on the fly... Yet."},transformClientToGraphCoordinates:function(e){return e.x=2*e.x/d-1,e.y=1-2*e.y/l,e.x=(e.x-y[12])/y[0],e.y=(e.y-y[13])/y[5],e.x=e.x*(d/2),e.y=e.y*(-l/2),e},transformGraphToClientCoordinates:function(e){return e.x=e.x/(d/2),e.y=e.y/(-l/2),e.x=e.x*y[0]+y[12],e.y=e.y*y[5]+y[13],e.x=(e.x+1)*d/2,e.y=(1-e.y)*l/2,e},getNodeAtClientPos:function(e,n){if("function"!=typeof n)return null;this.transformClientToGraphCoordinates(e);for(var t=0;t<g;++t)if(n(x[t],e.x,e.y))return x[t].node;return null}};return f(T),T}n.exports=r;var o=e("../Input/webglInputManager.js"),i=e("../WebGL/webglLinkProgram.js"),a=e("../WebGL/webglNodeProgram.js"),u=e("../WebGL/webglSquare.js"),s=e("../WebGL/webglLine.js"),f=e("ngraph.events"),c=e("ngraph.merge")},{"../Input/webglInputManager.js":40,"../WebGL/webglLine.js":62,"../WebGL/webglLinkProgram.js":63,"../WebGL/webglNodeProgram.js":64,"../WebGL/webglSquare.js":65,"ngraph.events":9,"ngraph.merge":17}],55:[function(e,n,t){function r(e){var n=10414335;if("string"==typeof e&&e)if(4===e.length&&(e=e.replace(/([^#])/g,"$1$1")),9===e.length)n=parseInt(e.substr(1),16);else{if(7!==e.length)throw'Color expected in hex format with preceding "#". E.g. #00ff00. Got value: '+e;n=parseInt(e.substr(1),16)<<8|255}else"number"==typeof e&&(n=e);return n}n.exports=r},{}],56:[function(e,n,t){function r(e){this.canvas=window.document.createElement("canvas"),this.ctx=this.canvas.getContext("2d"),this.isDirty=!1,this.canvas.width=this.canvas.height=e}n.exports=r},{}],57:[function(e,n,t){function r(e){function n(n,t){var r=e.createShader(t);if(e.shaderSource(r,n),e.compileShader(r),!e.getShaderParameter(r,e.COMPILE_STATUS)){var o=e.getShaderInfoLog(r);throw window.alert(o),o}return r}function t(t,r){var o=e.createProgram(),i=n(t,e.VERTEX_SHADER),a=n(r,e.FRAGMENT_SHADER);if(e.attachShader(o,i),e.attachShader(o,a),e.linkProgram(o),!e.getProgramParameter(o,e.LINK_STATUS)){var u=e.getShaderInfoLog(o);throw window.alert(u),u}return o}function r(e,n,t){if((n+1)*t>e.length){var r=new Float32Array(e.length*t*2);return r.set(e),r}return e}function a(n,t){for(var r={},o=0;o<t.length;++o){var i=t[o],a=-1;if("a"===i[0]&&"_"===i[1]){if(a=e.getAttribLocation(n,i),a===-1)throw new Error("Program doesn't have required attribute: "+i);r[i.slice(2)]=a}else{if("u"!==i[0]||"_"!==i[1])throw new Error("Couldn't figure out your intent. All uniforms should start with 'u_' prefix, and attributes with 'a_'");if(a=e.getUniformLocation(n,i),null===a)throw new Error("Program doesn't have required uniform: "+i);r[i.slice(2)]=a}}return r}return{createProgram:t,extendArray:r,copyArrayPart:o,swapArrayPart:i,getLocations:a,context:e}}function o(e,n,t,r){for(var o=0;o<r;++o)e[n+o]=e[t+o]}function i(e,n,t,r){for(var o=0;o<r;++o){var i=e[n+o];e[n+o]=e[t+o],e[t+o]=i}}n.exports=r},{}],58:[function(e,n,t){function r(e){function n(){var e;for(E.isDirty=!1,e=0;e<w.length;++e)w[e].isDirty=!1}function t(e){var n=y[e];if(!n)return!1;if(delete y[e],m-=1,m===n.offset)return!0;var t=c(n.offset),r=c(m);p(r,t);var o=y[b[m]];return o.offset=n.offset,b[n.offset]=b[m],l(),!0}function r(){return w}function a(e){return y[e]}function u(e,n){if(y.hasOwnProperty(e))n(y[e]);else{var t=new window.Image,r=m;m+=1,t.crossOrigin="anonymous",t.onload=function(){l(),f(r,t,n)},t.src=e}}function s(){var e=new i(h*g);w.push(e)}function f(e,n,t){var r=c(e),o={offset:e};r.textureNumber>=w.length&&s();var i=w[r.textureNumber];i.ctx.drawImage(n,r.col*g,r.row*g,g,g),b[e]=n.src,y[n.src]=o,i.isDirty=!0,t(o)}function c(n){var t=n/e<<0,r=n%e,o=r/h<<0,i=r%h;return{textureNumber:t,row:o,col:i}}function d(){E.isDirty=!0,x=0,v=null}function l(){v&&(window.clearTimeout(v),x+=1,v=null),x>10?d():v=window.setTimeout(d,400)}function p(e,n){var t=w[e.textureNumber].canvas,r=w[n.textureNumber].ctx,o=n.col*g,i=n.row*g;r.drawImage(t,e.col*g,e.row*g,g,g,o,i,g,g),w[e.textureNumber].isDirty=!0,w[n.textureNumber].isDirty=!0}var v,h=Math.sqrt(e||1024)<<0,g=h,m=1,y={},x=0,w=[],b=[];if(!o(e))throw"Tiles per texture should be power of two.";var E={isDirty:!1,clearDirty:n,remove:t,getTextures:r,getCoordinates:a,load:u};return E}function o(e){return 0===(e&e-1)}var i=e("./texture.js");n.exports=r},{"./texture.js":56}],59:[function(e,n,t){function r(e,n){return{_texture:0,_offset:0,size:"number"==typeof e?e:32,src:n}}n.exports=r},{}],60:[function(e,n,t){function r(e){function n(e,n){e.nativeObject&&m.deleteTexture(e.nativeObject);var t=m.createTexture();m.activeTexture(m["TEXTURE"+n]),m.bindTexture(m.TEXTURE_2D,t),m.texImage2D(m.TEXTURE_2D,0,m.RGBA,m.RGBA,m.UNSIGNED_BYTE,e.canvas),m.texParameteri(m.TEXTURE_2D,m.TEXTURE_MAG_FILTER,m.LINEAR),m.texParameteri(m.TEXTURE_2D,m.TEXTURE_MIN_FILTER,m.LINEAR_MIPMAP_NEAREST),m.generateMipmap(m.TEXTURE_2D),m.uniform1i(w["sampler"+n],n),e.nativeObject=t}function t(){if(h.isDirty){var e,t=h.getTextures();for(e=0;e<t.length;++e)!t[e].isDirty&&t[e].nativeObject||n(t[e],e);h.clearDirty()}}function r(n){m=n,x=u(n),h=new a(e),g=x.createProgram(j,P),m.useProgram(g),w=x.getLocations(g,["a_vertexPos","a_customAttributes","u_screenSize","u_transform","u_sampler0","u_sampler1","u_sampler2","u_sampler3","u_tilesPerTexture"]),m.uniform1f(w.tilesPerTexture,e),m.enableVertexAttribArray(w.vertexPos),m.enableVertexAttribArray(w.customAttributes),y=m.createBuffer()}function s(e,n){var t=e.id*k;_[t]=n.x-e.size,_[t+1]=-n.y-e.size,_[t+2]=4*e._offset,_[t+3]=n.x+e.size,_[t+4]=-n.y-e.size,_[t+5]=4*e._offset+1,_[t+6]=n.x-e.size,_[t+7]=-n.y+e.size,_[t+8]=4*e._offset+2,_[t+9]=n.x-e.size,_[t+10]=-n.y+e.size,_[t+11]=4*e._offset+2,_[t+12]=n.x+e.size,_[t+13]=-n.y-e.size,_[t+14]=4*e._offset+1,_[t+15]=n.x+e.size,_[t+16]=-n.y+e.size,_[t+17]=4*e._offset+3}function f(e){_=x.extendArray(_,A,k),A+=1;var n=h.getCoordinates(e.src);n?e._offset=n.offset:(e._offset=0,h.load(e.src,function(n){e._offset=n.offset}))}function c(e){A>0&&(A-=1),e.id<A&&A>0&&(e.src&&h.remove(e.src),x.copyArrayPart(_,e.id*k,A*k,k))}function d(e,n){n._offset=e._offset}function l(e){N=!0,L=e}function p(e,n){b=e,E=n,N=!0}function v(){m.useProgram(g),m.bindBuffer(m.ARRAY_BUFFER,y),m.bufferData(m.ARRAY_BUFFER,_,m.DYNAMIC_DRAW),N&&(N=!1,m.uniformMatrix4fv(w.transform,!1,L),m.uniform2f(w.screenSize,b,E)),m.vertexAttribPointer(w.vertexPos,2,m.FLOAT,!1,3*Float32Array.BYTES_PER_ELEMENT,0),m.vertexAttribPointer(w.customAttributes,1,m.FLOAT,!1,3*Float32Array.BYTES_PER_ELEMENT,8),t(),m.drawArrays(m.TRIANGLES,0,6*A)}var h,g,m,y,x,w,b,E,L,N,k=18,P=o(),j=i(),e=e||1024,A=0,_=new Float32Array(64);return{load:r,position:s,createNode:f,removeNode:c,replaceProperties:d,updateTransform:l,updateSize:p,render:v}}function o(){return["precision mediump float;","varying vec4 color;","varying vec3 vTextureCoord;","uniform sampler2D u_sampler0;","uniform sampler2D u_sampler1;","uniform sampler2D u_sampler2;","uniform sampler2D u_sampler3;","void main(void) {","   if (vTextureCoord.z == 0.) {","     gl_FragColor = texture2D(u_sampler0, vTextureCoord.xy);","   } else if (vTextureCoord.z == 1.) {","     gl_FragColor = texture2D(u_sampler1, vTextureCoord.xy);","   } else if (vTextureCoord.z == 2.) {","     gl_FragColor = texture2D(u_sampler2, vTextureCoord.xy);","   } else if (vTextureCoord.z == 3.) {","     gl_FragColor = texture2D(u_sampler3, vTextureCoord.xy);","   } else { gl_FragColor = vec4(0, 1, 0, 1); }","}"].join("\n")}function i(){return["attribute vec2 a_vertexPos;","attribute float a_customAttributes;","uniform vec2 u_screenSize;","uniform mat4 u_transform;","uniform float u_tilesPerTexture;","varying vec3 vTextureCoord;","void main(void) {","   gl_Position = u_transform * vec4(a_vertexPos/u_screenSize, 0, 1);","float corner = mod(a_customAttributes, 4.);","float tileIndex = mod(floor(a_customAttributes / 4.), u_tilesPerTexture);","float tilesPerRow = sqrt(u_tilesPerTexture);","float tileSize = 1./tilesPerRow;","float tileColumn = mod(tileIndex, tilesPerRow);","float tileRow = floor(tileIndex/tilesPerRow);","if(corner == 0.0) {","  vTextureCoord.xy = vec2(0, 1);","} else if(corner == 1.0) {","  vTextureCoord.xy = vec2(1, 1);","} else if(corner == 2.0) {","  vTextureCoord.xy = vec2(0, 0);","} else {","  vTextureCoord.xy = vec2(1, 0);","}","vTextureCoord *= tileSize;","vTextureCoord.x += tileColumn * tileSize;","vTextureCoord.y += tileRow * tileSize;","vTextureCoord.z = floor(floor(a_customAttributes / 4.)/u_tilesPerTexture);","}"].join("\n")}var a=e("./webglAtlas.js"),u=e("./webgl.js");n.exports=r},{"./webgl.js":57,"./webglAtlas.js":58}],61:[function(e,n,t){function r(e){function n(){x=null}function t(e){x=e}function r(e){return"function"==typeof e&&P.push(e),A}function i(e){return"function"==typeof e&&k.push(e),A}function a(e){return"function"==typeof e&&N.push(e),A}function u(e){return"function"==typeof e&&L.push(e),A}function s(e){return"function"==typeof e&&E.push(e),A}function f(e){return"function"==typeof e&&b.push(e),A}function c(e){return"function"==typeof e&&w.push(e),A}function d(e,n,t){if(e&&e.size){var r=e.position,o=e.size;return r.x-o<n&&n<r.x+o&&r.y-o<t&&t<r.y+o}return!0}function l(n){return e.getNodeAtClientPos(n,d)}function p(e){e.stopPropagation?e.stopPropagation():e.cancelBubble=!0}function v(e){return p(e),!1}function h(e,n){var t,r;for(t=0;t<e.length;t+=1)if(r=e[t].apply(void 0,n))return!0}function g(e){var n={x:0,y:0},t=null,r=1,i=+new Date,a=function(e){h(N,[t,e]),n.x=e.clientX,n.y=e.clientY},u=function(){o.off("mousemove",a),o.off("mouseup",u)},s=function(){y=e.getBoundingClientRect()};window.addEventListener("resize",s),s(),e.addEventListener("mousemove",function(e){if(!x){r++%7===0&&(s(),r=1);var o,i=!1;n.x=e.clientX-y.left,n.y=e.clientY-y.top,o=l(n),o&&t!==o?(t&&h(b,[t]),t=o,i=i||h(w,[t])):null===o&&t!==o&&(i=i||h(b,[t]),t=null),i&&p(e)}}),e.addEventListener("mousedown",function(e){var r,i=!1;s(),n.x=e.clientX-y.left,n.y=e.clientY-y.top,r=[l(n),e],r[0]?(i=h(E,r),o.on("mousemove",a),o.on("mouseup",u),m=window.document.onselectstart,window.document.onselectstart=v,t=r[0]):t=null,i&&p(e)}),e.addEventListener("mouseup",function(e){var r,o=+new Date;n.x=e.clientX-y.left,n.y=e.clientY-y.top;var a=l(n),u=a===t;r=[a||t,e],r[0]&&(window.document.onselectstart=m,o-i<400&&u?h(P,r):h(k,r),i=o,h(L,r)&&p(e))})}if(e.webglInputEvents)return e.webglInputEvents;var m,y,x=null,w=[],b=[],E=[],L=[],N=[],k=[],P=[],j=e.getGraphicsRoot();g(j);var A={mouseEnter:c,mouseLeave:f,mouseDown:s,mouseUp:u,mouseMove:a,click:i,dblClick:r,mouseCapture:t,releaseMouseCapture:n};return e.webglInputEvents=A,A}var o=e("../Utils/documentEvents.js");n.exports=r},{"../Utils/documentEvents.js":44}],62:[function(e,n,t){function r(e){return{color:o(e)}}var o=e("./parseColor.js");n.exports=r},{"./parseColor.js":55}],63:[function(e,n,t){function r(){var e,n,t,r,i,a,u,s,f,c,d=6,l=2*(2*Float32Array.BYTES_PER_ELEMENT+Uint32Array.BYTES_PER_ELEMENT),p=["precision mediump float;","varying vec4 color;","void main(void) {","   gl_FragColor = color;","}"].join("\n"),v=["attribute vec2 a_vertexPos;","attribute vec4 a_color;","uniform vec2 u_screenSize;","uniform mat4 u_transform;","varying vec4 color;","void main(void) {","   gl_Position = u_transform * vec4(a_vertexPos/u_screenSize, 0.0, 1.0);","   color = a_color.abgr;","}"].join("\n"),h=0,g=new ArrayBuffer(16*l),m=new Float32Array(g),y=new Uint32Array(g),x=function(){if((h+1)*l>g.byteLength){var e=new ArrayBuffer(2*g.byteLength),n=new Float32Array(e),t=new Uint32Array(e);t.set(y),m=n,y=t,g=e}};return{load:function(a){n=a,r=o(a),e=r.createProgram(v,p),n.useProgram(e),i=r.getLocations(e,["a_vertexPos","a_color","u_screenSize","u_transform"]),n.enableVertexAttribArray(i.vertexPos),n.enableVertexAttribArray(i.color),t=n.createBuffer()},position:function(e,n,t){var r=e.id,o=r*d;m[o]=n.x,m[o+1]=n.y,y[o+2]=e.color,m[o+3]=t.x,m[o+4]=t.y,y[o+5]=e.color},createLink:function(e){x(),h+=1,a=e.id},removeLink:function(e){h>0&&(h-=1),e.id<h&&h>0&&r.copyArrayPart(y,e.id*d,h*d,d)},updateTransform:function(e){c=!0,f=e},updateSize:function(e,n){u=e,s=n,c=!0},render:function(){n.useProgram(e),n.bindBuffer(n.ARRAY_BUFFER,t),n.bufferData(n.ARRAY_BUFFER,g,n.DYNAMIC_DRAW),c&&(c=!1,n.uniformMatrix4fv(i.transform,!1,f),n.uniform2f(i.screenSize,u,s)),n.vertexAttribPointer(i.vertexPos,2,n.FLOAT,!1,3*Float32Array.BYTES_PER_ELEMENT,0),n.vertexAttribPointer(i.color,4,n.UNSIGNED_BYTE,!0,3*Float32Array.BYTES_PER_ELEMENT,8),n.drawArrays(n.LINES,0,2*h),a=h-1},bringToFront:function(e){a>e.id&&r.swapArrayPart(m,e.id*d,a*d,d),a>0&&(a-=1)},getFrontLinkId:function(){return a}}}var o=e("./webgl.js");n.exports=r},{"./webgl.js":57}],64:[function(e,n,t){function r(){function e(){if((P+1)*w>=L.byteLength){var e=new ArrayBuffer(2*L.byteLength),n=new Float32Array(e),t=new Uint32Array(e);t.set(k),N=n,k=t,L=e}}function n(e){d=e,v=o(e),c=v.createProgram(E,b),d.useProgram(c),
+p=v.getLocations(c,["a_vertexPos","a_color","u_screenSize","u_transform"]),d.enableVertexAttribArray(p.vertexPos),d.enableVertexAttribArray(p.color),l=d.createBuffer()}function t(e,n){var t=e.id;N[t*x]=n.x,N[t*x+1]=-n.y,N[t*x+2]=e.size,k[t*x+3]=e.color}function r(e){y=!0,m=e}function i(e,n){h=e,g=n,y=!0}function a(e){P>0&&(P-=1),e.id<P&&P>0&&v.copyArrayPart(k,e.id*x,P*x,x)}function u(){e(),P+=1}function s(){}function f(){d.useProgram(c),d.bindBuffer(d.ARRAY_BUFFER,l),d.bufferData(d.ARRAY_BUFFER,L,d.DYNAMIC_DRAW),y&&(y=!1,d.uniformMatrix4fv(p.transform,!1,m),d.uniform2f(p.screenSize,h,g)),d.vertexAttribPointer(p.vertexPos,3,d.FLOAT,!1,x*Float32Array.BYTES_PER_ELEMENT,0),d.vertexAttribPointer(p.color,4,d.UNSIGNED_BYTE,!0,x*Float32Array.BYTES_PER_ELEMENT,12),d.drawArrays(d.POINTS,0,P)}var c,d,l,p,v,h,g,m,y,x=4,w=3*Float32Array.BYTES_PER_ELEMENT+Uint32Array.BYTES_PER_ELEMENT,b=["precision mediump float;","varying vec4 color;","void main(void) {","   gl_FragColor = color;","}"].join("\n"),E=["attribute vec3 a_vertexPos;","attribute vec4 a_color;","uniform vec2 u_screenSize;","uniform mat4 u_transform;","varying vec4 color;","void main(void) {","   gl_Position = u_transform * vec4(a_vertexPos.xy/u_screenSize, 0, 1);","   gl_PointSize = a_vertexPos.z * u_transform[0][0];","   color = a_color.abgr;","}"].join("\n"),L=new ArrayBuffer(16*w),N=new Float32Array(L),k=new Uint32Array(L),P=0;return{load:n,position:t,updateTransform:r,updateSize:i,removeNode:a,createNode:u,replaceProperties:s,render:f}}var o=e("./webgl.js");n.exports=r},{"./webgl.js":57}],65:[function(e,n,t){function r(e,n){return{size:"number"==typeof e?e:10,color:o(n)}}var o=e("./parseColor.js");n.exports=r},{"./parseColor.js":55}],66:[function(e,n,t){n.exports="0.10.1"},{}]},{},[1])(1)});
\ No newline at end of file
diff --git a/plugins/analysis/webinterface/recordedevents/recorded_events.go b/plugins/analysis/webinterface/recordedevents/recorded_events.go
index 723eef77409319bbc187a6e142fb788b090cd740..31dba5c72fe285221e16302f30274ff9d090ab74 100644
--- a/plugins/analysis/webinterface/recordedevents/recorded_events.go
+++ b/plugins/analysis/webinterface/recordedevents/recorded_events.go
@@ -30,8 +30,8 @@ func Configure(plugin *node.Plugin) {
 		lock.Lock()
 		defer lock.Unlock()
 
-		//delete(nodes, nodeId)
-		nodes[nodeId] = false
+		delete(nodes, nodeId)
+		//nodes[nodeId] = false
 	}))
 
 	server.Events.NodeOnline.Attach(events.NewClosure(func(nodeId string) {