diff --git a/.bithoundrc b/.bithoundrc
index ea936acc45e1df47ba47e194019ae9ab94728816..c57938dee8012011acf92089721c8e3e39026ad0 100644
--- a/.bithoundrc
+++ b/.bithoundrc
@@ -4,17 +4,15 @@
     ],
     "unused-ignores": [
       "almond",
-      "chroma-js",
-      "d3",
       "d3-*",
       "leaflet",
-      "leaflet-label",
       "moment",
+      "navigo",
       "node-polyglot",
+      "promise-polyfill",
       "rbush",
       "requirejs",
-      "virtual-dom",
-      "promise-polyfill"
+      "snabbdom"
     ]
   },
   "critics": {
diff --git a/app.js b/app.js
index 1901493f94648a47c9ab43d25d719fa6adcd3543..5d674d37659b6cdb4708face458521f7e814a4c9 100644
--- a/app.js
+++ b/app.js
@@ -77,7 +77,7 @@ require.config({
     'd3-force': '../node_modules/d3-force/build/d3-force',
     'd3-zoom': '../node_modules/d3-zoom/build/d3-zoom',
     'd3-drag': '../node_modules/d3-drag/build/d3-drag',
-    'virtual-dom': '../node_modules/virtual-dom/dist/virtual-dom',
+    'snabbdom': '../node_modules/snabbdom/dist/snabbdom-patch',
     'rbush': '../node_modules/rbush/rbush',
     'helper': 'utils/helper'
   },
diff --git a/lib/infobox/link.js b/lib/infobox/link.js
index 2e4e36eb0f99b964f6e9d25d2982f16cde25591f..017e5dcae568ef6ba89c80219d540da1b78231bd 100644
--- a/lib/infobox/link.js
+++ b/lib/infobox/link.js
@@ -4,25 +4,19 @@ define(['helper'], function (helper) {
   function showStatImg(o, d, time) {
     var subst = {};
     subst['{SOURCE_ID}'] = d.source.node_id;
-    subst['{SOURCE_NAME}'] = d.source.node.nodeinfo.hostname ? d.source.node.nodeinfo.hostname.replace(/[^a-z0-9\-]/ig, '_') : _.t('unknown');
+    subst['{SOURCE_NAME}'] = d.source.node.nodeinfo.hostname.replace(/[^a-z0-9\-]/ig, '_');
     subst['{TARGET_ID}'] = d.target.node_id;
-    subst['{TARGET_NAME}'] = d.target.node.nodeinfo.hostname ? d.target.node.nodeinfo.hostname.replace(/[^a-z0-9\-]/ig, '_') : _.t('unknown');
+    subst['{TARGET_NAME}'] = d.target.node.nodeinfo.hostname.replace(/[^a-z0-9\-]/ig, '_');
     subst['{TIME}'] = time;
     subst['{LOCALE}'] = _.locale();
     return helper.showStat(o, subst);
   }
 
   return function (config, el, router, d) {
-    var unknown = !d.source.node;
     var h2 = document.createElement('h2');
-    var a1;
-    if (!unknown) {
-      a1 = document.createElement('a');
-      a1.href = router.generateLink({ node: d.source.node_id });
-    } else {
-      a1 = document.createElement('span');
-    }
-    a1.textContent = unknown ? d.source.id : d.source.node.nodeinfo.hostname;
+    var a1 = document.createElement('a');
+    a1.href = router.generateLink({ node: d.source.node_id });
+    a1.textContent = d.source.node.nodeinfo.hostname;
     h2.appendChild(a1);
 
     var arrow = document.createElement('span');
@@ -40,9 +34,9 @@ define(['helper'], function (helper) {
 
     helper.attributeEntry(attributes, 'node.tq', helper.showTq(d));
     helper.attributeEntry(attributes, 'node.distance', helper.showDistance(d));
-    var hw1 = unknown ? null : helper.dictGet(d.source.node.nodeinfo, ['hardware', 'model']);
+    var hw1 = helper.dictGet(d.source.node.nodeinfo, ['hardware', 'model']);
     var hw2 = helper.dictGet(d.target.node.nodeinfo, ['hardware', 'model']);
-    helper.attributeEntry(attributes, 'node.hardware', (hw1 !== null ? hw1 : _.t('unknown')) + ' – ' + (hw2 !== null ? hw2 : _.t('unknown')));
+    helper.attributeEntry(attributes, 'node.hardware', hw1 + ' – ' + hw2);
 
     el.appendChild(attributes);
 
diff --git a/lib/infobox/node.js b/lib/infobox/node.js
index aa599c960372d31a16371338d11bc49d0bebfc1e..22ae9f8183e015f0ad3dd54b6e2af9a994b0160e 100644
--- a/lib/infobox/node.js
+++ b/lib/infobox/node.js
@@ -1,6 +1,7 @@
-define(['sorttable', 'virtual-dom', 'd3-interpolate', 'moment', 'helper'],
+define(['sorttable', 'snabbdom', 'd3-interpolate', 'moment', 'helper'],
   function (SortTable, V, d3Interpolate, moment, helper) {
     'use strict';
+    V = V.default;
 
     function showGeoURI(d) {
       if (!helper.hasLocation(d)) {
@@ -170,8 +171,8 @@ define(['sorttable', 'virtual-dom', 'd3-interpolate', 'moment', 'helper'],
 
     function showStatImg(o, d) {
       var subst = {};
-      subst['{NODE_ID}'] = d.nodeinfo.node_id ? d.nodeinfo.node_id : _.t('unknown');
-      subst['{NODE_NAME}'] = d.nodeinfo.hostname ? d.nodeinfo.hostname.replace(/[^a-z0-9\-]/ig, '_') : _.t('unknown');
+      subst['{NODE_ID}'] = d.nodeinfo.node_id;
+      subst['{NODE_NAME}'] = d.nodeinfo.hostname.replace(/[^a-z0-9\-]/ig, '_');
       subst['{TIME}'] = d.lastseen.format('DDMMYYYYHmmss');
       subst['{LOCALE}'] = _.locale();
       return helper.showStat(o, subst);
@@ -182,24 +183,21 @@ define(['sorttable', 'virtual-dom', 'd3-interpolate', 'moment', 'helper'],
 
       function renderNeighbourRow(n) {
         var icons = [];
-        var name = [];
-        var unknown = !(n.node);
-
-        icons.push(V.h('span', { className: n.incoming ? 'ion-arrow-left-c' : 'ion-arrow-right-c' }));
-        if (!unknown && helper.hasLocation(n.node)) {
-          icons.push(V.h('span', { className: 'ion-location' }));
+        icons.push(V.h('span', { props: { className: n.incoming ? 'ion-arrow-left-c' : 'ion-arrow-right-c' } }));
+        if (helper.hasLocation(n.node)) {
+          icons.push(V.h('span', { props: { className: 'ion-location' } }));
         }
 
-        if (!unknown) {
-          name.push(V.h('a', {
-            href: router.generateLink({ node: n.node.nodeinfo.node_id }),
-            onclick: function (e) {
+        var name = V.h('a', {
+          props: {
+            className: 'online',
+            href: router.generateLink({ node: n.node.nodeinfo.node_id })
+          }, on: {
+            click: function (e) {
               router.fullUrl({ node: n.node.nodeinfo.node_id }, e);
-            }, className: 'online'
-          }, n.node.nodeinfo.hostname));
-        } else {
-          name.push(n.link.id);
-        }
+            }
+          }
+        }, n.node.nodeinfo.hostname);
 
         var td1 = V.h('td', icons);
         var td2 = V.h('td', name);
@@ -282,10 +280,9 @@ define(['sorttable', 'virtual-dom', 'd3-interpolate', 'moment', 'helper'],
         }];
 
         var table = new SortTable(headings, 1, renderNeighbourRow);
-        table.el.classList.add('node-links');
         table.setData(d.neighbours);
-
-        el.appendChild(table.el);
+        table.el.elm.classList.add('node-links');
+        el.appendChild(table.el.elm);
       }
 
       if (config.nodeInfos) {
diff --git a/lib/linklist.js b/lib/linklist.js
index 5391a452a5ce255b103611f0973abfa11fc0fe21..bb8eb75b1040ba6f395f2ba04f21864d838de318 100644
--- a/lib/linklist.js
+++ b/lib/linklist.js
@@ -1,4 +1,4 @@
-define(['sorttable', 'virtual-dom', 'helper'], function (SortTable, V, helper) {
+define(['sorttable', 'snabbdom', 'helper'], function (SortTable, V, helper) {
   'use strict';
 
   function linkName(d) {
@@ -30,18 +30,21 @@ define(['sorttable', 'virtual-dom', 'helper'], function (SortTable, V, helper) {
 
   return function (linkScale, router) {
     var table = new SortTable(headings, 2, renderRow);
-    table.el.classList.add('link-list');
+    V = V.default;
 
     function renderRow(d) {
       var td1Content = [V.h('a', {
-        href: router.generateLink({ link: d.id }),
-        onclick: function (e) {
-          router.fullUrl({ link: d.id }, e);
+        props: {
+          href: router.generateLink({ link: d.id })
+        }, on: {
+          click: function (e) {
+            router.fullUrl({ link: d.id }, e);
+          }
         }
       }, linkName(d))];
 
       var td1 = V.h('td', td1Content);
-      var td2 = V.h('td', { style: { color: linkScale(1 / d.tq) } }, helper.showTq(d));
+      var td2 = V.h('td', {  style: { color: linkScale(1 / d.tq) } }, helper.showTq(d));
       var td3 = V.h('td', helper.showDistance(d));
 
       return V.h('tr', [td1, td2, td3]);
@@ -51,8 +54,8 @@ define(['sorttable', 'virtual-dom', 'helper'], function (SortTable, V, helper) {
       var h2 = document.createElement('h2');
       h2.textContent = _.t('node.links');
       d.appendChild(h2);
-
-      d.appendChild(table.el);
+      table.el.elm.classList.add('link-list');
+      d.appendChild(table.el.elm);
     };
 
     this.setData = function setData(d) {
diff --git a/lib/main.js b/lib/main.js
index 4b863bc0b1dcb0f1f5a1a1ace982cb35d7c884cf..0eb99fb96318fa92523e68006b633e6927085fa8 100644
--- a/lib/main.js
+++ b/lib/main.js
@@ -89,19 +89,13 @@ define(['moment', 'utils/router', 'leaflet', 'gui', 'helper', 'utils/language'],
         });
 
         links.forEach(function (d) {
-          var unknown = (d.source.node === undefined);
           var ids;
 
-          if (unknown) {
-            d.target.node.neighbours.push({ id: d.source.id, link: d, incoming: true });
-            ids = [d.source.id.replace(/:/g, ''), d.target.node.nodeinfo.node_id];
-          } else {
-            ids = [d.source.node.nodeinfo.node_id, d.target.node.nodeinfo.node_id];
-            d.source.node.neighbours.push({ node: d.target.node, link: d, incoming: false });
-            d.target.node.neighbours.push({ node: d.source.node, link: d, incoming: true });
-            if (d.vpn) {
-              d.source.node.meshlinks = d.source.node.meshlinks ? d.source.node.meshlinks + 1 : 1;
-            }
+          ids = [d.source.node.nodeinfo.node_id, d.target.node.nodeinfo.node_id];
+          d.source.node.neighbours.push({ node: d.target.node, link: d, incoming: false });
+          d.target.node.neighbours.push({ node: d.source.node, link: d, incoming: true });
+          if (d.vpn) {
+            d.source.node.meshlinks = d.source.node.meshlinks ? d.source.node.meshlinks + 1 : 1;
           }
 
           d.id = ids.join('-');
diff --git a/lib/nodelist.js b/lib/nodelist.js
index 7432b95a78fb1a61b725fdd59a48c4dc855e6fc4..8cec0f472a946da6f7e236ba6b70cd0a243e0d94 100644
--- a/lib/nodelist.js
+++ b/lib/nodelist.js
@@ -1,5 +1,6 @@
-define(['sorttable', 'virtual-dom', 'helper'], function (SortTable, V, helper) {
+define(['sorttable', 'snabbdom', 'helper'], function (SortTable, V, helper) {
   'use strict';
+  V = V.default;
 
   function getUptime(now, d) {
     if (d.flags.online && 'uptime' in d.statistics) {
@@ -64,14 +65,18 @@ define(['sorttable', 'virtual-dom', 'helper'], function (SortTable, V, helper) {
       var aClass = ['hostname', d.flags.online ? 'online' : 'offline'];
 
       td1Content.push(V.h('a', {
-        className: aClass.join(' '),
-        href: router.generateLink({ node: d.nodeinfo.node_id }),
-        onclick: function (e) {
-          router.fullUrl({ node: d.nodeinfo.node_id }, e);
+        props: {
+          className: aClass.join(' '),
+          href: router.generateLink({ node: d.nodeinfo.node_id })
+        }, on: {
+          click: function (e) {
+            router.fullUrl({ node: d.nodeinfo.node_id }, e);
+          }
         }
       }, d.nodeinfo.hostname));
+
       if (helper.hasLocation(d)) {
-        td0Content.push(V.h('span', { className: 'icon ion-location' }));
+        td0Content.push(V.h('span', { props: { className: 'icon ion-location' } }));
       }
 
       var td0 = V.h('td', td0Content);
@@ -84,14 +89,13 @@ define(['sorttable', 'virtual-dom', 'helper'], function (SortTable, V, helper) {
     }
 
     var table = new SortTable(headings, 1, renderRow);
-    table.el.classList.add('node-list');
 
     this.render = function render(d) {
       var h2 = document.createElement('h2');
       h2.textContent = _.t('node.all');
       d.appendChild(h2);
-
-      d.appendChild(table.el);
+      table.el.elm.classList.add('node-list');
+      d.appendChild(table.el.elm);
     };
 
     this.setData = function setData(d) {
diff --git a/lib/proportions.js b/lib/proportions.js
index d5a80ea935691e5a203ddb2af35a13839c127aef..84d8cd9047b611aa5d64c8affd91729702408507 100644
--- a/lib/proportions.js
+++ b/lib/proportions.js
@@ -1,18 +1,18 @@
-define(['d3-interpolate', 'virtual-dom', 'filters/genericnode', 'helper'],
+define(['d3-interpolate', 'snabbdom', 'filters/genericnode', 'helper'],
   function (d3Interpolate, V, Filter, helper) {
     'use strict';
 
     return function (config, filterManager) {
       var self = this;
       var scale = d3Interpolate.interpolate('#770038', '#dc0067');
+      V = V.default;
 
-      var statusTable = document.createElement('table');
-      statusTable.classList.add('proportion');
-      var fwTable = statusTable.cloneNode(false);
-      var hwTable = statusTable.cloneNode(false);
-      var geoTable = statusTable.cloneNode(false);
-      var autoTable = statusTable.cloneNode(false);
-      var siteTable = statusTable.cloneNode(false);
+      var statusTable;
+      var fwTable;
+      var hwTable;
+      var geoTable;
+      var autoTable;
+      var siteTable;
 
       function showStatGlobal(o) {
         return helper.showStat(o);
@@ -48,8 +48,8 @@ define(['d3-interpolate', 'virtual-dom', 'filters/genericnode', 'helper'],
       }
 
       function fillTable(name, table, data) {
-        if (!table.last) {
-          table.last = V.h('table');
+        if (!table) {
+          table = document.createElement('table');
         }
 
         var max = Math.max.apply(Math, data.map(function (o) {
@@ -61,7 +61,7 @@ define(['d3-interpolate', 'virtual-dom', 'filters/genericnode', 'helper'],
 
           var filter = new Filter(_.t(name), d[2], d[0], d[3]);
 
-          var a = V.h('a', { href: '#', onclick: addFilter(filter) }, d[0]);
+          var a = V.h('a', { props: { href: '#' }, on: { click: addFilter(filter) } }, d[0]);
 
           var th = V.h('th', a);
           var td = V.h('td', V.h('span', {
@@ -74,10 +74,8 @@ define(['d3-interpolate', 'virtual-dom', 'filters/genericnode', 'helper'],
 
           return V.h('tr', [th, td]);
         });
-
-        var tableNew = V.h('table', items);
-        table = V.patch(table, V.diff(table.last, tableNew));
-        table.last = tableNew;
+        var tableNew = V.h('table', { props: { className: 'proportion' } }, items);
+        return V.patch(table, tableNew);
       }
 
       self.setData = function setData(data) {
@@ -119,10 +117,10 @@ define(['d3-interpolate', 'virtual-dom', 'filters/genericnode', 'helper'],
           return rt;
         });
 
-        fillTable('node.status', statusTable, statusDict.sort(function (a, b) {
+        statusTable = fillTable('node.status', statusTable, statusDict.sort(function (a, b) {
           return b[1] - a[1];
         }));
-        fillTable('node.firmware', fwTable, fwDict.sort(function (a, b) {
+        fwTable = fillTable('node.firmware', fwTable, fwDict.sort(function (a, b) {
           if (b[0] < a[0]) {
             return -1;
           }
@@ -131,16 +129,16 @@ define(['d3-interpolate', 'virtual-dom', 'filters/genericnode', 'helper'],
           }
           return 0;
         }));
-        fillTable('node.hardware', hwTable, hwDict.sort(function (a, b) {
+        hwTable = fillTable('node.hardware', hwTable, hwDict.sort(function (a, b) {
           return b[1] - a[1];
         }));
-        fillTable('node.visible', geoTable, geoDict.sort(function (a, b) {
+        geoTable = fillTable('node.visible', geoTable, geoDict.sort(function (a, b) {
           return b[1] - a[1];
         }));
-        fillTable('node.update', autoTable, autoDict.sort(function (a, b) {
+        autoTable = fillTable('node.update', autoTable, autoDict.sort(function (a, b) {
           return b[1] - a[1];
         }));
-        fillTable('node.site', siteTable, siteDict.sort(function (a, b) {
+        siteTable = fillTable('node.site', siteTable, siteDict.sort(function (a, b) {
           return b[1] - a[1];
         }));
       };
@@ -172,7 +170,7 @@ define(['d3-interpolate', 'virtual-dom', 'filters/genericnode', 'helper'],
           table.classList.toggle('hide');
         };
         el.appendChild(h2);
-        el.appendChild(table);
+        el.appendChild(table.elm);
       };
       return self;
     };
diff --git a/lib/simplenodelist.js b/lib/simplenodelist.js
index a4e9e3f179582a67b1acf92acbff7a59e11a07bf..ea2c6cfeb10b1158ea1e1a9def9a9b3b828aa840 100644
--- a/lib/simplenodelist.js
+++ b/lib/simplenodelist.js
@@ -1,5 +1,6 @@
-define(['moment', 'virtual-dom', 'helper'], function (moment, V, helper) {
+define(['moment', 'snabbdom', 'helper'], function (moment, V, helper) {
   'use strict';
+  V = V.default;
 
   return function (nodes, field, router, title) {
     var self = this;
@@ -40,15 +41,18 @@ define(['moment', 'virtual-dom', 'helper'], function (moment, V, helper) {
         var aClass = ['hostname', d.flags.online ? 'online' : 'offline'];
 
         td1Content.push(V.h('a', {
-          className: aClass.join(' '),
-          href: router.generateLink({ node: d.nodeinfo.node_id }),
-          onclick: function (e) {
-            router.fullUrl({ node: d.nodeinfo.node_id }, e);
+          props: {
+            className: aClass.join(' '),
+            href: router.generateLink({ node: d.nodeinfo.node_id })
+          }, on: {
+            click: function (e) {
+              router.fullUrl({ node: d.nodeinfo.node_id }, e);
+            }
           }
         }, d.nodeinfo.hostname));
 
         if (helper.hasLocation(d)) {
-          td0Content.push(V.h('span', { className: 'icon ion-location' }));
+          td0Content.push(V.h('span', { props: { className: 'icon ion-location' } }));
         }
 
         var td0 = V.h('td', td0Content);
@@ -59,8 +63,7 @@ define(['moment', 'virtual-dom', 'helper'], function (moment, V, helper) {
       });
 
       var tbodyNew = V.h('tbody', items);
-      tbody = V.patch(tbody, V.diff(tbody.last, tbodyNew));
-      tbody.last = tbodyNew;
+      tbody = V.patch(tbody, tbodyNew);
     };
 
     return self;
diff --git a/lib/sorttable.js b/lib/sorttable.js
index 61ab8a015d21177e676b12efe99d619e9dbf0455..235b66c8ffd4719c1e1f51dfcd23cd07da8ebd62 100644
--- a/lib/sorttable.js
+++ b/lib/sorttable.js
@@ -1,11 +1,12 @@
-define(['virtual-dom'], function (V) {
+define(['snabbdom'], function (V) {
   'use strict';
+  V = V.default;
 
   return function (headings, sortIndex, renderRow) {
+    var self = this;
     var data;
     var sortReverse = false;
-    var el = document.createElement('table');
-    var elLast = V.h('table');
+    self.el = document.createElement('table');
 
     function sortTable(i) {
       sortReverse = i === sortIndex ? !sortReverse : false;
@@ -41,7 +42,7 @@ define(['virtual-dom'], function (V) {
             properties.className += sortReverse ? ' sort-up' : ' sort-down';
           }
 
-          return V.h('th', properties, name);
+          return V.h('th', { props: properties }, name);
         });
 
         var links = data.slice(0).sort(headings[sortIndex].sort);
@@ -55,17 +56,14 @@ define(['virtual-dom'], function (V) {
       }
 
       var elNew = V.h('table', children);
-      el = V.patch(el, V.diff(elLast, elNew));
-      elLast = elNew;
+      self.el = V.patch(self.el, elNew);
     }
 
-    this.setData = function setData(d) {
+    self.setData = function setData(d) {
       data = d;
       updateView();
     };
 
-    this.el = el;
-
-    return this;
+    return self;
   };
 });
diff --git a/package.json b/package.json
index 701f3c94e8f2c41f69b6743fb5a07377e203647b..b9c93bae65f9250dc466afdcd4a8cb7e9ad8befd 100644
--- a/package.json
+++ b/package.json
@@ -53,6 +53,6 @@
     "promise-polyfill": "^6.0.2",
     "rbush": "^2.0.1",
     "requirejs": "^2.3.2",
-    "virtual-dom": "^2.1.1"
+    "snabbdom": "^0.6.4"
   }
 }
diff --git a/yarn.lock b/yarn.lock
index 1250b6141ee81550d062af45fdd1c4b214e47a67..0c6da3c5e73ba9fd7cca49e62ceb044925faa3a5 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -440,10 +440,6 @@ braces@^1.8.2:
     preserve "^0.2.0"
     repeat-element "^1.1.2"
 
-browser-split@0.0.1:
-  version "0.0.1"
-  resolved "https://registry.yarnpkg.com/browser-split/-/browser-split-0.0.1.tgz#7b097574f8e3ead606fb4664e64adfdda2981a93"
-
 browser-sync-client@2.4.5:
   version "2.4.5"
   resolved "https://registry.yarnpkg.com/browser-sync-client/-/browser-sync-client-2.4.5.tgz#976afab1a54f255baa38fe22ae3c0d3753ad337b"
@@ -588,10 +584,6 @@ camelcase@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a"
 
-camelize@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/camelize/-/camelize-1.0.0.tgz#164a5483e630fa4321e5af07020e531831b2609b"
-
 caniuse-db@^1.0.30000634, caniuse-db@^1.0.30000639:
   version "1.0.30000655"
   resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000655.tgz#e40b6287adc938848d6708ef83d65b5f54ac1874"
@@ -1083,10 +1075,6 @@ dom-serializer@0, dom-serializer@~0.1.0:
     domelementtype "~1.1.1"
     entities "~1.1.1"
 
-dom-walk@^0.1.0:
-  version "0.1.1"
-  resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.1.tgz#672226dc74c8f799ad35307df936aba11acd6018"
-
 domelementtype@1, domelementtype@^1.3.0:
   version "1.3.0"
   resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.0.tgz#b17aed82e8ab59e52dd9c19b1756e0fc187204c2"
@@ -1232,14 +1220,6 @@ error-ex@^1.2.0:
   dependencies:
     is-arrayish "^0.2.1"
 
-error@^4.3.0:
-  version "4.4.0"
-  resolved "https://registry.yarnpkg.com/error/-/error-4.4.0.tgz#bf69ff251fb4a279c19adccdaa6b61e90d9bf12a"
-  dependencies:
-    camelize "^1.0.0"
-    string-template "~0.2.0"
-    xtend "~4.0.0"
-
 es-abstract@^1.5.0, es-abstract@^1.7.0:
   version "1.7.0"
   resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.7.0.tgz#dfade774e01bfcd97f96180298c449c8623fb94c"
@@ -1472,12 +1452,6 @@ etag@~1.7.0:
   version "1.7.0"
   resolved "https://registry.yarnpkg.com/etag/-/etag-1.7.0.tgz#03d30b5f67dd6e632d2945d30d6652731a34d5d8"
 
-ev-store@^7.0.0:
-  version "7.0.0"
-  resolved "https://registry.yarnpkg.com/ev-store/-/ev-store-7.0.0.tgz#1ab0c7f82136505dd74b31d17701cb2be6d26558"
-  dependencies:
-    individual "^3.0.0"
-
 event-emitter@~0.3.5:
   version "0.3.5"
   resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39"
@@ -1898,13 +1872,6 @@ global-prefix@^0.1.4:
     is-windows "^0.2.0"
     which "^1.2.12"
 
-global@^4.3.0:
-  version "4.3.1"
-  resolved "https://registry.yarnpkg.com/global/-/global-4.3.1.tgz#5f757908c7cbabce54f386ae440e11e26b7916df"
-  dependencies:
-    min-document "^2.19.0"
-    process "~0.5.1"
-
 globals@^9.0.0, globals@^9.14.0, globals@^9.2.0:
   version "9.17.0"
   resolved "https://registry.yarnpkg.com/globals/-/globals-9.17.0.tgz#0c0ca696d9b9bb694d2e5470bd37777caad50286"
@@ -2399,10 +2366,6 @@ indexof@0.0.1:
   version "0.0.1"
   resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d"
 
-individual@^3.0.0:
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/individual/-/individual-3.0.0.tgz#e7ca4f85f8957b018734f285750dc22ec2f9862d"
-
 inflight@^1.0.4:
   version "1.0.6"
   resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
@@ -2580,10 +2543,6 @@ is-number@^2.0.2, is-number@^2.1.0:
   dependencies:
     kind-of "^3.0.2"
 
-is-object@^1.0.1:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.1.tgz#8952688c5ec2ffd6b03ecc85e769e02903083470"
-
 is-path-cwd@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d"
@@ -3187,12 +3146,6 @@ mime@1.3.4, "mime@>= 0.0.1":
   version "1.3.4"
   resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53"
 
-min-document@^2.19.0:
-  version "2.19.0"
-  resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685"
-  dependencies:
-    dom-walk "^0.1.0"
-
 "minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@~3.0.2:
   version "3.0.3"
   resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774"
@@ -3273,10 +3226,6 @@ negotiator@0.6.1:
   version "0.6.1"
   resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9"
 
-next-tick@^0.2.2:
-  version "0.2.2"
-  resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-0.2.2.tgz#75da4a927ee5887e39065880065b7336413b310d"
-
 next-tick@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c"
@@ -3720,10 +3669,6 @@ process-nextick-args@~1.0.6:
   version "1.0.7"
   resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3"
 
-process@~0.5.1:
-  version "0.5.2"
-  resolved "https://registry.yarnpkg.com/process/-/process-0.5.2.tgz#1638d8a8e34c2f440a91db95ab9aeb677fc185cf"
-
 progress@^1.1.8:
   version "1.1.8"
   resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be"
@@ -4219,6 +4164,10 @@ slice-ansi@0.0.4:
   dependencies:
     readable-stream "~1.0.31"
 
+snabbdom@^0.6.4:
+  version "0.6.7"
+  resolved "https://registry.yarnpkg.com/snabbdom/-/snabbdom-0.6.7.tgz#045d9fc292574fe3597578bde2d9c403f79a1352"
+
 sntp@1.x.x:
   version "1.0.9"
   resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198"
@@ -4382,10 +4331,6 @@ stream-to-array@^2.3.0:
   dependencies:
     any-promise "^1.1.0"
 
-string-template@~0.2.0:
-  version "0.2.1"
-  resolved "https://registry.yarnpkg.com/string-template/-/string-template-0.2.1.tgz#42932e598a352d01fc22ec3367d9d84eec6c9add"
-
 string-width@^1.0.1, string-width@^1.0.2:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"
@@ -4846,19 +4791,6 @@ vinyl@^0.5.0:
     clone-stats "^0.0.1"
     replace-ext "0.0.1"
 
-virtual-dom@^2.1.1:
-  version "2.1.1"
-  resolved "https://registry.yarnpkg.com/virtual-dom/-/virtual-dom-2.1.1.tgz#80eda2d481b9ede0c049118cefcb4a05f21d1375"
-  dependencies:
-    browser-split "0.0.1"
-    error "^4.3.0"
-    ev-store "^7.0.0"
-    global "^4.3.0"
-    is-object "^1.0.1"
-    next-tick "^0.2.2"
-    x-is-array "0.1.0"
-    x-is-string "0.1.0"
-
 vlq@^0.2.1:
   version "0.2.2"
   resolved "https://registry.yarnpkg.com/vlq/-/vlq-0.2.2.tgz#e316d5257b40b86bb43cb8d5fea5d7f54d6b0ca1"
@@ -4952,14 +4884,6 @@ wtf-8@1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/wtf-8/-/wtf-8-1.0.0.tgz#392d8ba2d0f1c34d1ee2d630f15d0efb68e1048a"
 
-x-is-array@0.1.0:
-  version "0.1.0"
-  resolved "https://registry.yarnpkg.com/x-is-array/-/x-is-array-0.1.0.tgz#de520171d47b3f416f5587d629b89d26b12dc29d"
-
-x-is-string@0.1.0:
-  version "0.1.0"
-  resolved "https://registry.yarnpkg.com/x-is-string/-/x-is-string-0.1.0.tgz#474b50865af3a49a9c4657f05acd145458f77d82"
-
 xml-char-classes@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/xml-char-classes/-/xml-char-classes-1.0.0.tgz#64657848a20ffc5df583a42ad8a277b4512bbc4d"