diff --git a/.bithoundrc b/.bithoundrc
index c57938dee8012011acf92089721c8e3e39026ad0..4d216bb619b68a30c483a8208d7194861b649650 100644
--- a/.bithoundrc
+++ b/.bithoundrc
@@ -19,5 +19,8 @@
     "wc": {
       "limit": 5000
     }
-  }
+  },
+  "ignore": [
+    "polyfill.js"
+  ]
 }
diff --git a/app.js b/app.js
index 5d674d37659b6cdb4708face458521f7e814a4c9..5390671cae40fa61a8e2c319641a6ab78e408a12 100644
--- a/app.js
+++ b/app.js
@@ -1,57 +1,4 @@
 'use strict';
-// Node search polyfill for mobile browsers and IE
-if (!String.prototype.includes) {
-  String.prototype.includes = function () {
-    return String.prototype.indexOf.apply(this, arguments) !== -1;
-  };
-}
-
-if (!String.prototype.startsWith) {
-  String.prototype.startsWith = function (searchString, position) {
-    position = position || 0;
-    return this.substr(position, searchString.length) === searchString;
-  };
-}
-if (!String.prototype.repeat) {
-  String.prototype.repeat = function (count) {
-    'use strict';
-    if (this === null) {
-      throw new TypeError('can\'t convert ' + this + ' to object');
-    }
-    var str = '' + this;
-    count = +count;
-    if (count < 0) {
-      throw new RangeError('repeat count must be non-negative');
-    }
-    if (count === Infinity) {
-      throw new RangeError('repeat count must be less than infinity');
-    }
-    count = Math.floor(count);
-    if (str.length === 0 || count === 0) {
-      return '';
-    }
-    // Ensuring count is a 31-bit integer allows us to heavily optimize the
-    // main part. But anyway, most current (August 2014) browsers can't handle
-    // strings 1 << 28 chars or longer, so:
-    if (str.length * count >= 1 << 28) {
-      throw new RangeError('repeat count must not overflow maximum string size');
-    }
-    var rpt = '';
-    for (; ;) {
-      if ((count & 1) === 1) {
-        rpt += str;
-      }
-      count >>>= 1;
-      if (count === 0) {
-        break;
-      }
-      str += str;
-    }
-    // Could we try:
-    // return Array(count + 1).join(this);
-    return rpt;
-  };
-}
 
 require.config({
   baseUrl: 'lib',
diff --git a/gulp/tasks/copy.js b/gulp/tasks/copy.js
index b01325a12fab54ad263a4254e2999e84525d2fcd..17be9dbed3facd4cd47450a4621f3e83b7f4053e 100644
--- a/gulp/tasks/copy.js
+++ b/gulp/tasks/copy.js
@@ -4,7 +4,7 @@ module.exports = function (gulp, plugins, config) {
       .pipe(gulp.dest(config.build));
     gulp.src(['assets/logo.svg'])
       .pipe(gulp.dest(config.build));
-    gulp.src('node_modules/promise-polyfill/promise.js')
+    gulp.src(['node_modules/promise-polyfill/promise.js', 'polyfill.js'])
       .pipe(gulp.dest(config.build + '/vendor'));
     return gulp.src(['assets/fonts/*', 'assets/icons/fonts/*'])
       .pipe(gulp.dest(config.build + '/fonts'));
diff --git a/html/index.html b/html/index.html
index b44227de836252939ae2e895022d7432969ba299..c731ef5bc28a7b575b440feff634b6f17a05acc4 100644
--- a/html/index.html
+++ b/html/index.html
@@ -8,6 +8,7 @@
   <!-- inject:config -->
   <!-- contents of html partials will be injected here -->
   <!-- endinject -->
+  <script src="vendor/polyfill.js" inline></script>
   <script src="vendor/promise.js" inline></script>
   <script src="app.js"></script>
 </head>
diff --git a/lib/filters/nodefilter.js b/lib/filters/nodefilter.js
index 1b3e88254223e220fc5573b22cc850eab47cd71a..0cf7fd0ebc71dbd44cc972cab47504cd120a3359 100644
--- a/lib/filters/nodefilter.js
+++ b/lib/filters/nodefilter.js
@@ -7,7 +7,9 @@ define(function () {
       n.nodes = {};
 
       for (var key in data.nodes) {
-        n.nodes[key] = data.nodes[key].filter(filter);
+        if (data.nodes.hasOwnProperty(key)) {
+          n.nodes[key] = data.nodes[key].filter(filter);
+        }
       }
 
       var filteredIds = new Set();
diff --git a/lib/main.js b/lib/main.js
index 0eb99fb96318fa92523e68006b633e6927085fa8..9014e0202adbf02bbfa12942145a1b298f8e0556 100644
--- a/lib/main.js
+++ b/lib/main.js
@@ -140,8 +140,10 @@ define(['moment', 'utils/router', 'leaflet', 'gui', 'helper', 'utils/language'],
       }
 
       for (var i in config.dataPath) {
-        urls.push(config.dataPath[i] + 'nodes.json');
-        urls.push(config.dataPath[i] + 'graph.json');
+        if (config.dataPath.hasOwnProperty(i)) {
+          urls.push(config.dataPath[i] + 'nodes.json');
+          urls.push(config.dataPath[i] + 'graph.json');
+        }
       }
 
       function update() {
diff --git a/lib/utils/helper.js b/lib/utils/helper.js
index 76939071f0bdd959fb69755d7060a9c7065fbb18..1ee8ac24b5921b5777633ac5df243e6eb508f6a8 100644
--- a/lib/utils/helper.js
+++ b/lib/utils/helper.js
@@ -68,8 +68,10 @@ define({
 
   listReplace: function listReplace(s, subst) {
     for (var key in subst) {
-      var re = new RegExp(key, 'g');
-      s = s.replace(re, subst[key]);
+      if (subst.hasOwnProperty(key)) {
+        var re = new RegExp(key, 'g');
+        s = s.replace(re, subst[key]);
+      }
     }
     return s;
   },
diff --git a/polyfill.js b/polyfill.js
new file mode 100644
index 0000000000000000000000000000000000000000..dd5c71f80abfbc4f5616d9171d84ed5ffdfe10ed
--- /dev/null
+++ b/polyfill.js
@@ -0,0 +1,80 @@
+'use strict';
+// Polyfills for (old) mobile browsers and IE 11
+// From https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/
+if (!String.prototype.includes) {
+  String.prototype.includes = function () {
+    return String.prototype.indexOf.apply(this, arguments) !== -1;
+  };
+}
+
+if (!String.prototype.startsWith) {
+  String.prototype.startsWith = function (searchString, position) {
+    position = position || 0;
+    return this.substr(position, searchString.length) === searchString;
+  };
+}
+
+if (!String.prototype.repeat) {
+  String.prototype.repeat = function (count) {
+    'use strict';
+    if (this === null) {
+      throw new TypeError('can\'t convert ' + this + ' to object');
+    }
+    var str = '' + this;
+    count = +count;
+    if (count < 0) {
+      throw new RangeError('repeat count must be non-negative');
+    }
+    if (count === Infinity) {
+      throw new RangeError('repeat count must be less than infinity');
+    }
+    count = Math.floor(count);
+    if (str.length === 0 || count === 0) {
+      return '';
+    }
+    // Ensuring count is a 31-bit integer allows us to heavily optimize the
+    // main part. But anyway, most current (August 2014) browsers can't handle
+    // strings 1 << 28 chars or longer, so:
+    if (str.length * count >= 1 << 28) {
+      throw new RangeError('repeat count must not overflow maximum string size');
+    }
+    var rpt = '';
+    for (; ;) {
+      if ((count & 1) === 1) {
+        rpt += str;
+      }
+      count >>>= 1;
+      if (count === 0) {
+        break;
+      }
+      str += str;
+    }
+    // Could we try:
+    // return Array(count + 1).join(this);
+    return rpt;
+  };
+}
+
+if (typeof Object.assign !== 'function') {
+  Object.assign = function(target, varArgs) { // .length of function is 2
+    if (target == null) { // TypeError if undefined or null
+      throw new TypeError('Cannot convert undefined or null to object');
+    }
+
+    var to = Object(target);
+
+    for (var index = 1; index < arguments.length; index++) {
+      var nextSource = arguments[index];
+
+      if (nextSource != null) { // Skip over if undefined or null
+        for (var nextKey in nextSource) {
+          // Avoid bugs when hasOwnProperty is shadowed
+          if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
+            to[nextKey] = nextSource[nextKey];
+          }
+        }
+      }
+    }
+    return to;
+  };
+}