From 67503be8209510a268343f8d4792a9ab6fb538cc Mon Sep 17 00:00:00 2001
From: Pierre Jarriges <pierre.jarriges@tutanota.com>
Date: Wed, 26 May 2021 09:57:46 +0200
Subject: [PATCH] use object-to-html-renderer as npm node module

---
 package-lock.json                             |   7 +-
 package.json                                  |   4 +-
 public/education/education.js                 |   4 +-
 public/education/index.html                   |   2 +-
 public/games/games.js                         | 188 ++++++++---------
 public/main.js                                | 196 +++++++++---------
 .../software-development.js                   | 186 ++++++++---------
 src/generic-components/image-carousel.js      |   2 +-
 src/home-page-components/news-articles.js     |   2 +-
 src/lib/object-html-renderer.js               |  84 --------
 src/pages/games/components/game-articles.js   |   2 +-
 .../components/software-articles.js           |   2 +-
 src/run-page.js                               |   2 +-
 13 files changed, 302 insertions(+), 379 deletions(-)
 delete mode 100644 src/lib/object-html-renderer.js

diff --git a/package-lock.json b/package-lock.json
index 624b1f3..e9126f7 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
 {
     "name": "kuadrado-website",
-    "version": "0.1.0",
+    "version": "1.0.3",
     "lockfileVersion": 1,
     "requires": true,
     "dependencies": {
@@ -1118,6 +1118,11 @@
             "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
             "dev": true
         },
+        "object-to-html-renderer": {
+            "version": "1.0.0",
+            "resolved": "https://registry.npmjs.org/object-to-html-renderer/-/object-to-html-renderer-1.0.0.tgz",
+            "integrity": "sha512-ZB+jYQ0cjH+I4YWx6UcifaOP26ZY/KEdIzYZc9h96L/hGWbBx/aSBSnR/rn30+Y/0SaR/JNfLZiBhKorJNJ7Rg=="
+        },
         "object.assign": {
             "version": "4.1.2",
             "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz",
diff --git a/package.json b/package.json
index 5255912..8be3810 100644
--- a/package.json
+++ b/package.json
@@ -12,7 +12,9 @@
     "author": "Kuadrado",
     "license": "MIT",
     "homepage": "https://gitlab.com/peter_rabbit/kuadrado-website#readme",
-    "dependencies": {},
+    "dependencies": {
+        "object-to-html-renderer": "^1.0.0"
+    },
     "devDependencies": {
         "browserify": "^17.0.0",
         "sass": "^1.32.0"
diff --git a/public/education/education.js b/public/education/education.js
index e7c82f1..c32aa79 100644
--- a/public/education/education.js
+++ b/public/education/education.js
@@ -416,7 +416,7 @@ runPage(EducationPage);
 },{"../../run-page":7,"./education":5}],7:[function(require,module,exports){
 "use strict";
 
-const objectHtmlRenderer = require("./lib/object-html-renderer");
+const objectHtmlRenderer = require("object-to-html-renderer")
 const Template = require("./template/template");
 
 module.exports = function runPage(PageComponent) {
@@ -425,7 +425,7 @@ module.exports = function runPage(PageComponent) {
     objectHtmlRenderer.renderCycle();
 };
 
-},{"./lib/object-html-renderer":3,"./template/template":9}],8:[function(require,module,exports){
+},{"./template/template":9,"object-to-html-renderer":3}],8:[function(require,module,exports){
 "use strict";
 
 const { images_url } = require("../../../constants");
diff --git a/public/education/index.html b/public/education/index.html
index 5d00de7..31ad664 100644
--- a/public/education/index.html
+++ b/public/education/index.html
@@ -23,7 +23,7 @@
         <meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
         <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
         <link href="/style/style.css" rel="stylesheet" />
-        <script type="application/ld+json">{"@context":"https://schema.org","type":"WebPage","description":"Animations autour de la création de jeux vidéos, vulgarisation numérique. Découvrez nos initiatives pédagogiques.","image":["https://kuadrado-software.fr/assets/images/brain.svg","https://kuadrado-software.fr/assets/images/brain.png","https://kuadrado-software.fr/assets/images/game_studio_banner.png","https://kuadrado-software.fr/assets/images/popularization_banner.png"],"keywords":"Animations, pédagogie, éducation, vulgarisation, popularization, numérique, Ardèche, Rhone-Alpes, apprendre, learn, gamedev, coding, informatique, programmation, code, apprentissage, formation, activité, ado, adultes, adolescents, jeunesse","name":"Kuadrado Software - Pédagogie","url":"https://kuadrado-software.fr/education","@graph":[{"@type":"EducationalOrganization","name":"Game Studio Club","url":"https://kuadrado-software.fr/education/#game-studio-club","address":"32 rue Simon Vialet, 07240 Vernoux en Vivarais, France","email":"contact@kuadrado-software.fr","parentOrganization":{"type":"Corporation","description":"Créations numériques, jeu vidéo, web, software et pédagogie. Made in Ardèche, Vernoux en Vivarais.","image":["https://kuadrado-software.fr/assets/images/logo_kuadrado.svg","https://kuadrado-software.fr/assets/images/logo_kuadrado.png","https://kuadrado-software.fr/assets/images/logo_kuadrado_txt.svg","https://kuadrado-software.fr/assets/images/logo_kuadrado_txt.png"],"keywords":"Entreprise, Ardèche, numérique, jeux vidéos, gamedev, software, pédagogie, Rhone-Alpes, éthique, software, développement","name":"Kuadrado Software","url":"https://kuadrado-software.fr","location":"07240 Vernoux en Vivarais, France","email":"contact@kuadrado-software.fr","logo":"https://kuadrado-software.fr/assets/images/logo_kuadrado.png"}},{"@type":"EducationalOrganization","name":"Vulgarisation numérique","url":"https://kuadrado-software.fr/education/#popularization","address":"32 rue Simon Vialet, 07240 Vernoux en Vivarais, France","email":"contact@kuadrado-software.fr","parentOrganization":{"type":"Corporation","description":"Créations numériques, jeu vidéo, web, software et pédagogie. Made in Ardèche, Vernoux en Vivarais.","image":["https://kuadrado-software.fr/assets/images/logo_kuadrado.svg","https://kuadrado-software.fr/assets/images/logo_kuadrado.png","https://kuadrado-software.fr/assets/images/logo_kuadrado_txt.svg","https://kuadrado-software.fr/assets/images/logo_kuadrado_txt.png"],"keywords":"Entreprise, Ardèche, numérique, jeux vidéos, gamedev, software, pédagogie, Rhone-Alpes, éthique, software, développemnt","name":"Kuadrado Software","url":"https://kuadrado-software.fr","location":"07240 Vernoux en Vivarais, France","email":"contact@kuadrado-software.fr","logo":"https://kuadrado-software.fr/assets/images/logo_kuadrado.png"}}]}</script>
+        <script type="application/ld+json">{"@context":"https://schema.org","type":"WebPage","description":"Animations autour de la création de jeux vidéos, vulgarisation numérique. Découvrez nos initiatives pédagogiques.","image":["https://kuadrado-software.fr/assets/images/brain.svg","https://kuadrado-software.fr/assets/images/brain.png","https://kuadrado-software.fr/assets/images/game_studio_banner.png","https://kuadrado-software.fr/assets/images/popularization_banner.png"],"keywords":"Animations, pédagogie, éducation, vulgarisation, numérique, Ardèche, Rhone-Alpes, apprendre, learn, gamedev, coding, informatique, programmation, code, apprentissage, formation, activité, ado, adultes, adolescents, jeunesse","name":"Kuadrado Software - Pédagogie","url":"https://kuadrado-software.fr/education"}</script>
     </head>
     <!-- The vocab attribute defines the standard vocabulary used for RDFa standard.
     The DOM may contain properties such as "typeof" and "property" accordinly to the schema.org vocabulary -->
diff --git a/public/games/games.js b/public/games/games.js
index 38cc7a6..f7a742b 100644
--- a/public/games/games.js
+++ b/public/games/games.js
@@ -25,7 +25,93 @@ module.exports = {
 },{"./config":1}],3:[function(require,module,exports){
 "use strict";
 
-const objectHtmlRenderer = require("../lib/object-html-renderer");
+module.exports = {
+    setRenderCycleRoot(renderCycleRoot) {
+        this.renderCycleRoot = renderCycleRoot;
+    },
+    objectToHtml: function objectToHtml(obj) {
+        const { tag } = obj;
+
+        const node = document.createElement(tag);
+        const excludeKeys = ["tag", "contents", "style_rules", "state"];
+
+        Object.keys(obj)
+            .filter(attr => !excludeKeys.includes(attr))
+            .forEach(attr => {
+                if (attr === "class") {
+                    node.classList.add(...obj[attr].split(" ").filter(s => s !== ""));
+                } else {
+                    node[attr] = obj[attr];
+                }
+            });
+        if (obj.contents && typeof obj.contents === "string") {
+            node.innerHTML = obj.contents;
+        } else {
+            obj.contents &&
+                obj.contents.length > 0 &&
+                obj.contents.forEach(el => {
+                    switch (typeof el) {
+                        case "string":
+                            node.innerHTML = el;
+                            break;
+                        case "object":
+                            node.appendChild(objectToHtml(el));
+                            break;
+                    }
+                });
+        }
+
+        if (obj.style_rules) {
+            Object.keys(obj.style_rules).forEach(rule => {
+                node.style[rule] = obj.style_rules[rule];
+            });
+        }
+
+        return node;
+    },
+    renderCycle: function () {
+        this.subRender(this.renderCycleRoot.render(), document.getElementsByTagName("main")[0], {
+            mode: "replace",
+        });
+    },
+    subRender(object, htmlNode, options = { mode: "append" }) {
+        const insert = this.objectToHtml(object);
+        switch (options.mode) {
+            case "append":
+                htmlNode.appendChild(insert);
+                break;
+            case "override":
+                htmlNode.innerHTML = "";
+                htmlNode.appendChild(insert);
+                break;
+            case "insert-before":
+                htmlNode.insertBefore(insert, htmlNode.childNodes[options.insertIndex]);
+                break;
+            case "adjacent":
+                /**
+                 * options.insertLocation must be one of:
+                 *
+                 * afterbegin
+                 * afterend
+                 * beforebegin
+                 * beforeend
+                 */
+                htmlNode.insertAdjacentHTML(options.insertLocation, insert);
+                break;
+            case "replace":
+                htmlNode.parentNode.replaceChild(insert, htmlNode);
+                break;
+            case "remove":
+                htmlNode.remove();
+                break;
+        }
+    },
+};
+
+},{}],4:[function(require,module,exports){
+"use strict";
+
+const objectHtmlRenderer = require("object-to-html-renderer")
 
 class ImageCarousel {
     constructor(props) {
@@ -92,7 +178,7 @@ class ImageCarousel {
 
 module.exports = ImageCarousel;
 
-},{"../lib/object-html-renderer":6}],4:[function(require,module,exports){
+},{"object-to-html-renderer":3}],5:[function(require,module,exports){
 "use strict";
 
 const { fetchjson, fetchtext } = require("./fetch");
@@ -155,7 +241,7 @@ module.exports = {
     populateArticles,
 };
 
-},{"./fetch":5}],5:[function(require,module,exports){
+},{"./fetch":6}],6:[function(require,module,exports){
 "use strict";
 
 function fetchjson(url) {
@@ -181,92 +267,6 @@ module.exports = {
     fetchtext,
 };
 
-},{}],6:[function(require,module,exports){
-"use strict";
-
-module.exports = {
-    setRenderCycleRoot(renderCycleRoot) {
-        this.renderCycleRoot = renderCycleRoot;
-    },
-    objectToHtml: function objectToHtml(obj) {
-        const { tag } = obj;
-
-        const node = document.createElement(tag);
-        const excludeKeys = ["tag", "contents", "style_rules", "state"];
-
-        Object.keys(obj)
-            .filter(attr => !excludeKeys.includes(attr))
-            .forEach(attr => {
-                if (attr === "class") {
-                    node.classList.add(...obj[attr].split(" ").filter(s => s !== ""));
-                } else {
-                    node[attr] = obj[attr];
-                }
-            });
-        if (obj.contents && typeof obj.contents === "string") {
-            node.innerHTML = obj.contents;
-        } else {
-            obj.contents &&
-                obj.contents.length > 0 &&
-                obj.contents.forEach(el => {
-                    switch (typeof el) {
-                        case "string":
-                            node.innerHTML = el;
-                            break;
-                        case "object":
-                            node.appendChild(objectToHtml(el));
-                            break;
-                    }
-                });
-        }
-
-        if (obj.style_rules) {
-            Object.keys(obj.style_rules).forEach(rule => {
-                node.style[rule] = obj.style_rules[rule];
-            });
-        }
-
-        return node;
-    },
-    renderCycle: function () {
-        this.subRender(this.renderCycleRoot.render(), document.getElementsByTagName("main")[0], {
-            mode: "replace",
-        });
-    },
-    subRender(object, htmlNode, options = { mode: "append" }) {
-        const insert = this.objectToHtml(object);
-        switch (options.mode) {
-            case "append":
-                htmlNode.appendChild(insert);
-                break;
-            case "override":
-                htmlNode.innerHTML = "";
-                htmlNode.appendChild(insert);
-                break;
-            case "insert-before":
-                htmlNode.insertBefore(insert, htmlNode.childNodes[options.insertIndex]);
-                break;
-            case "adjacent":
-                /**
-                 * options.insertLocation must be one of:
-                 *
-                 * afterbegin
-                 * afterend
-                 * beforebegin
-                 * beforeend
-                 */
-                htmlNode.insertAdjacentHTML(options.insertLocation, insert);
-                break;
-            case "replace":
-                htmlNode.parentNode.replaceChild(insert, htmlNode);
-                break;
-            case "remove":
-                htmlNode.remove();
-                break;
-        }
-    },
-};
-
 },{}],7:[function(require,module,exports){
 "use strict";
 
@@ -410,12 +410,12 @@ class GameArticle {
 
 module.exports = GameArticle;
 
-},{"../../../generic-components/image-carousel":3,"../../../lib/article-utils":4}],9:[function(require,module,exports){
+},{"../../../generic-components/image-carousel":4,"../../../lib/article-utils":5}],9:[function(require,module,exports){
 "use strict";
 
 const { articles_url } = require("../../../../constants");
 const { loadArticles, populateArticles } = require("../../../lib/article-utils");
-const objectHtmlRenderer = require("../../../lib/object-html-renderer");
+const objectHtmlRenderer = require("object-to-html-renderer")
 const GameArticle = require("./game-article");
 
 class GameArticles {
@@ -478,7 +478,7 @@ class GameArticles {
 
 module.exports = GameArticles;
 
-},{"../../../../constants":2,"../../../lib/article-utils":4,"../../../lib/object-html-renderer":6,"./game-article":8}],10:[function(require,module,exports){
+},{"../../../../constants":2,"../../../lib/article-utils":5,"./game-article":8,"object-to-html-renderer":3}],10:[function(require,module,exports){
 "use strict";
 
 const { images_url } = require("../../../constants");
@@ -539,7 +539,7 @@ runPage(GamesPage);
 },{"../../run-page":12,"./games":10}],12:[function(require,module,exports){
 "use strict";
 
-const objectHtmlRenderer = require("./lib/object-html-renderer");
+const objectHtmlRenderer = require("object-to-html-renderer")
 const Template = require("./template/template");
 
 module.exports = function runPage(PageComponent) {
@@ -548,7 +548,7 @@ module.exports = function runPage(PageComponent) {
     objectHtmlRenderer.renderCycle();
 };
 
-},{"./lib/object-html-renderer":6,"./template/template":14}],13:[function(require,module,exports){
+},{"./template/template":14,"object-to-html-renderer":3}],13:[function(require,module,exports){
 "use strict";
 
 const { images_url } = require("../../../constants");
diff --git a/public/main.js b/public/main.js
index bc1ea8a..cdb3d0f 100644
--- a/public/main.js
+++ b/public/main.js
@@ -25,7 +25,93 @@ module.exports = {
 },{"./config":1}],3:[function(require,module,exports){
 "use strict";
 
-const objectHtmlRenderer = require("../lib/object-html-renderer");
+module.exports = {
+    setRenderCycleRoot(renderCycleRoot) {
+        this.renderCycleRoot = renderCycleRoot;
+    },
+    objectToHtml: function objectToHtml(obj) {
+        const { tag } = obj;
+
+        const node = document.createElement(tag);
+        const excludeKeys = ["tag", "contents", "style_rules", "state"];
+
+        Object.keys(obj)
+            .filter(attr => !excludeKeys.includes(attr))
+            .forEach(attr => {
+                if (attr === "class") {
+                    node.classList.add(...obj[attr].split(" ").filter(s => s !== ""));
+                } else {
+                    node[attr] = obj[attr];
+                }
+            });
+        if (obj.contents && typeof obj.contents === "string") {
+            node.innerHTML = obj.contents;
+        } else {
+            obj.contents &&
+                obj.contents.length > 0 &&
+                obj.contents.forEach(el => {
+                    switch (typeof el) {
+                        case "string":
+                            node.innerHTML = el;
+                            break;
+                        case "object":
+                            node.appendChild(objectToHtml(el));
+                            break;
+                    }
+                });
+        }
+
+        if (obj.style_rules) {
+            Object.keys(obj.style_rules).forEach(rule => {
+                node.style[rule] = obj.style_rules[rule];
+            });
+        }
+
+        return node;
+    },
+    renderCycle: function () {
+        this.subRender(this.renderCycleRoot.render(), document.getElementsByTagName("main")[0], {
+            mode: "replace",
+        });
+    },
+    subRender(object, htmlNode, options = { mode: "append" }) {
+        const insert = this.objectToHtml(object);
+        switch (options.mode) {
+            case "append":
+                htmlNode.appendChild(insert);
+                break;
+            case "override":
+                htmlNode.innerHTML = "";
+                htmlNode.appendChild(insert);
+                break;
+            case "insert-before":
+                htmlNode.insertBefore(insert, htmlNode.childNodes[options.insertIndex]);
+                break;
+            case "adjacent":
+                /**
+                 * options.insertLocation must be one of:
+                 *
+                 * afterbegin
+                 * afterend
+                 * beforebegin
+                 * beforeend
+                 */
+                htmlNode.insertAdjacentHTML(options.insertLocation, insert);
+                break;
+            case "replace":
+                htmlNode.parentNode.replaceChild(insert, htmlNode);
+                break;
+            case "remove":
+                htmlNode.remove();
+                break;
+        }
+    },
+};
+
+},{}],4:[function(require,module,exports){
+"use strict";
+
+const objectHtmlRenderer = require("object-to-html-renderer")
 
 class ImageCarousel {
     constructor(props) {
@@ -92,7 +178,7 @@ class ImageCarousel {
 
 module.exports = ImageCarousel;
 
-},{"../lib/object-html-renderer":11}],4:[function(require,module,exports){
+},{"object-to-html-renderer":3}],5:[function(require,module,exports){
 "use strict";
 
 class KuadradoValues {
@@ -151,11 +237,11 @@ class KuadradoValues {
 
 module.exports = KuadradoValues;
 
-},{}],5:[function(require,module,exports){
+},{}],6:[function(require,module,exports){
 "use strict";
 
 const { articles_url } = require("../../constants");
-const objectHtmlRenderer = require("../lib/object-html-renderer");
+const objectHtmlRenderer = require("object-to-html-renderer");
 const ImageCarousel = require("../generic-components/image-carousel");
 const { loadArticles, getArticleDate, getArticleBody } = require("../lib/article-utils");
 
@@ -308,7 +394,7 @@ class NewsArticles {
 
 module.exports = NewsArticles;
 
-},{"../../constants":2,"../generic-components/image-carousel":3,"../lib/article-utils":9,"../lib/object-html-renderer":11}],6:[function(require,module,exports){
+},{"../../constants":2,"../generic-components/image-carousel":4,"../lib/article-utils":10,"object-to-html-renderer":3}],7:[function(require,module,exports){
 "use strict";
 
 const { images_url } = require("../../constants");
@@ -346,7 +432,7 @@ class ThemeCard {
 
 module.exports = ThemeCard;
 
-},{"../../constants":2}],7:[function(require,module,exports){
+},{"../../constants":2}],8:[function(require,module,exports){
 "use strict";
 
 class WhoAmI {
@@ -446,7 +532,7 @@ class WhoAmI {
 
 module.exports = WhoAmI;
 
-},{}],8:[function(require,module,exports){
+},{}],9:[function(require,module,exports){
 "use strict";
 
 const { images_url } = require("../constants");
@@ -555,7 +641,7 @@ class HomePage extends WebPage {
 
 module.exports = HomePage;
 
-},{"../constants":2,"./home-page-components/kuadrado-values":4,"./home-page-components/news-articles":5,"./home-page-components/theme-card":6,"./home-page-components/whoami":7,"./lib/web-page":12}],9:[function(require,module,exports){
+},{"../constants":2,"./home-page-components/kuadrado-values":5,"./home-page-components/news-articles":6,"./home-page-components/theme-card":7,"./home-page-components/whoami":8,"./lib/web-page":12}],10:[function(require,module,exports){
 "use strict";
 
 const { fetchjson, fetchtext } = require("./fetch");
@@ -618,7 +704,7 @@ module.exports = {
     populateArticles,
 };
 
-},{"./fetch":10}],10:[function(require,module,exports){
+},{"./fetch":11}],11:[function(require,module,exports){
 "use strict";
 
 function fetchjson(url) {
@@ -644,92 +730,6 @@ module.exports = {
     fetchtext,
 };
 
-},{}],11:[function(require,module,exports){
-"use strict";
-
-module.exports = {
-    setRenderCycleRoot(renderCycleRoot) {
-        this.renderCycleRoot = renderCycleRoot;
-    },
-    objectToHtml: function objectToHtml(obj) {
-        const { tag } = obj;
-
-        const node = document.createElement(tag);
-        const excludeKeys = ["tag", "contents", "style_rules", "state"];
-
-        Object.keys(obj)
-            .filter(attr => !excludeKeys.includes(attr))
-            .forEach(attr => {
-                if (attr === "class") {
-                    node.classList.add(...obj[attr].split(" ").filter(s => s !== ""));
-                } else {
-                    node[attr] = obj[attr];
-                }
-            });
-        if (obj.contents && typeof obj.contents === "string") {
-            node.innerHTML = obj.contents;
-        } else {
-            obj.contents &&
-                obj.contents.length > 0 &&
-                obj.contents.forEach(el => {
-                    switch (typeof el) {
-                        case "string":
-                            node.innerHTML = el;
-                            break;
-                        case "object":
-                            node.appendChild(objectToHtml(el));
-                            break;
-                    }
-                });
-        }
-
-        if (obj.style_rules) {
-            Object.keys(obj.style_rules).forEach(rule => {
-                node.style[rule] = obj.style_rules[rule];
-            });
-        }
-
-        return node;
-    },
-    renderCycle: function () {
-        this.subRender(this.renderCycleRoot.render(), document.getElementsByTagName("main")[0], {
-            mode: "replace",
-        });
-    },
-    subRender(object, htmlNode, options = { mode: "append" }) {
-        const insert = this.objectToHtml(object);
-        switch (options.mode) {
-            case "append":
-                htmlNode.appendChild(insert);
-                break;
-            case "override":
-                htmlNode.innerHTML = "";
-                htmlNode.appendChild(insert);
-                break;
-            case "insert-before":
-                htmlNode.insertBefore(insert, htmlNode.childNodes[options.insertIndex]);
-                break;
-            case "adjacent":
-                /**
-                 * options.insertLocation must be one of:
-                 *
-                 * afterbegin
-                 * afterend
-                 * beforebegin
-                 * beforeend
-                 */
-                htmlNode.insertAdjacentHTML(options.insertLocation, insert);
-                break;
-            case "replace":
-                htmlNode.parentNode.replaceChild(insert, htmlNode);
-                break;
-            case "remove":
-                htmlNode.remove();
-                break;
-        }
-    },
-};
-
 },{}],12:[function(require,module,exports){
 "use strict";
 
@@ -748,10 +748,10 @@ const runPage = require("./run-page");
 
 runPage(HomePage);
 
-},{"./homepage":8,"./run-page":14}],14:[function(require,module,exports){
+},{"./homepage":9,"./run-page":14}],14:[function(require,module,exports){
 "use strict";
 
-const objectHtmlRenderer = require("./lib/object-html-renderer");
+const objectHtmlRenderer = require("object-to-html-renderer")
 const Template = require("./template/template");
 
 module.exports = function runPage(PageComponent) {
@@ -760,7 +760,7 @@ module.exports = function runPage(PageComponent) {
     objectHtmlRenderer.renderCycle();
 };
 
-},{"./lib/object-html-renderer":11,"./template/template":16}],15:[function(require,module,exports){
+},{"./template/template":16,"object-to-html-renderer":3}],15:[function(require,module,exports){
 "use strict";
 
 const { images_url } = require("../../../constants");
diff --git a/public/software-development/software-development.js b/public/software-development/software-development.js
index 19b47a4..c78fd15 100644
--- a/public/software-development/software-development.js
+++ b/public/software-development/software-development.js
@@ -25,7 +25,93 @@ module.exports = {
 },{"./config":1}],3:[function(require,module,exports){
 "use strict";
 
-const objectHtmlRenderer = require("../lib/object-html-renderer");
+module.exports = {
+    setRenderCycleRoot(renderCycleRoot) {
+        this.renderCycleRoot = renderCycleRoot;
+    },
+    objectToHtml: function objectToHtml(obj) {
+        const { tag } = obj;
+
+        const node = document.createElement(tag);
+        const excludeKeys = ["tag", "contents", "style_rules", "state"];
+
+        Object.keys(obj)
+            .filter(attr => !excludeKeys.includes(attr))
+            .forEach(attr => {
+                if (attr === "class") {
+                    node.classList.add(...obj[attr].split(" ").filter(s => s !== ""));
+                } else {
+                    node[attr] = obj[attr];
+                }
+            });
+        if (obj.contents && typeof obj.contents === "string") {
+            node.innerHTML = obj.contents;
+        } else {
+            obj.contents &&
+                obj.contents.length > 0 &&
+                obj.contents.forEach(el => {
+                    switch (typeof el) {
+                        case "string":
+                            node.innerHTML = el;
+                            break;
+                        case "object":
+                            node.appendChild(objectToHtml(el));
+                            break;
+                    }
+                });
+        }
+
+        if (obj.style_rules) {
+            Object.keys(obj.style_rules).forEach(rule => {
+                node.style[rule] = obj.style_rules[rule];
+            });
+        }
+
+        return node;
+    },
+    renderCycle: function () {
+        this.subRender(this.renderCycleRoot.render(), document.getElementsByTagName("main")[0], {
+            mode: "replace",
+        });
+    },
+    subRender(object, htmlNode, options = { mode: "append" }) {
+        const insert = this.objectToHtml(object);
+        switch (options.mode) {
+            case "append":
+                htmlNode.appendChild(insert);
+                break;
+            case "override":
+                htmlNode.innerHTML = "";
+                htmlNode.appendChild(insert);
+                break;
+            case "insert-before":
+                htmlNode.insertBefore(insert, htmlNode.childNodes[options.insertIndex]);
+                break;
+            case "adjacent":
+                /**
+                 * options.insertLocation must be one of:
+                 *
+                 * afterbegin
+                 * afterend
+                 * beforebegin
+                 * beforeend
+                 */
+                htmlNode.insertAdjacentHTML(options.insertLocation, insert);
+                break;
+            case "replace":
+                htmlNode.parentNode.replaceChild(insert, htmlNode);
+                break;
+            case "remove":
+                htmlNode.remove();
+                break;
+        }
+    },
+};
+
+},{}],4:[function(require,module,exports){
+"use strict";
+
+const objectHtmlRenderer = require("object-to-html-renderer")
 
 class ImageCarousel {
     constructor(props) {
@@ -92,7 +178,7 @@ class ImageCarousel {
 
 module.exports = ImageCarousel;
 
-},{"../lib/object-html-renderer":6}],4:[function(require,module,exports){
+},{"object-to-html-renderer":3}],5:[function(require,module,exports){
 "use strict";
 
 const { fetchjson, fetchtext } = require("./fetch");
@@ -155,7 +241,7 @@ module.exports = {
     populateArticles,
 };
 
-},{"./fetch":5}],5:[function(require,module,exports){
+},{"./fetch":6}],6:[function(require,module,exports){
 "use strict";
 
 function fetchjson(url) {
@@ -181,92 +267,6 @@ module.exports = {
     fetchtext,
 };
 
-},{}],6:[function(require,module,exports){
-"use strict";
-
-module.exports = {
-    setRenderCycleRoot(renderCycleRoot) {
-        this.renderCycleRoot = renderCycleRoot;
-    },
-    objectToHtml: function objectToHtml(obj) {
-        const { tag } = obj;
-
-        const node = document.createElement(tag);
-        const excludeKeys = ["tag", "contents", "style_rules", "state"];
-
-        Object.keys(obj)
-            .filter(attr => !excludeKeys.includes(attr))
-            .forEach(attr => {
-                if (attr === "class") {
-                    node.classList.add(...obj[attr].split(" ").filter(s => s !== ""));
-                } else {
-                    node[attr] = obj[attr];
-                }
-            });
-        if (obj.contents && typeof obj.contents === "string") {
-            node.innerHTML = obj.contents;
-        } else {
-            obj.contents &&
-                obj.contents.length > 0 &&
-                obj.contents.forEach(el => {
-                    switch (typeof el) {
-                        case "string":
-                            node.innerHTML = el;
-                            break;
-                        case "object":
-                            node.appendChild(objectToHtml(el));
-                            break;
-                    }
-                });
-        }
-
-        if (obj.style_rules) {
-            Object.keys(obj.style_rules).forEach(rule => {
-                node.style[rule] = obj.style_rules[rule];
-            });
-        }
-
-        return node;
-    },
-    renderCycle: function () {
-        this.subRender(this.renderCycleRoot.render(), document.getElementsByTagName("main")[0], {
-            mode: "replace",
-        });
-    },
-    subRender(object, htmlNode, options = { mode: "append" }) {
-        const insert = this.objectToHtml(object);
-        switch (options.mode) {
-            case "append":
-                htmlNode.appendChild(insert);
-                break;
-            case "override":
-                htmlNode.innerHTML = "";
-                htmlNode.appendChild(insert);
-                break;
-            case "insert-before":
-                htmlNode.insertBefore(insert, htmlNode.childNodes[options.insertIndex]);
-                break;
-            case "adjacent":
-                /**
-                 * options.insertLocation must be one of:
-                 *
-                 * afterbegin
-                 * afterend
-                 * beforebegin
-                 * beforeend
-                 */
-                htmlNode.insertAdjacentHTML(options.insertLocation, insert);
-                break;
-            case "replace":
-                htmlNode.parentNode.replaceChild(insert, htmlNode);
-                break;
-            case "remove":
-                htmlNode.remove();
-                break;
-        }
-    },
-};
-
 },{}],7:[function(require,module,exports){
 "use strict";
 
@@ -283,7 +283,7 @@ module.exports = WebPage;
 const { articles_url } = require("../../../../constants");
 const ImageCarousel = require("../../../generic-components/image-carousel");
 const { loadArticles, getArticleBody, getArticleDate } = require("../../../lib/article-utils");
-const objectHtmlRenderer = require("../../../lib/object-html-renderer");
+const objectHtmlRenderer = require("object-to-html-renderer")
 
 class SoftwareArticle {
     constructor(props) {
@@ -520,7 +520,7 @@ class SoftwareArticles {
 
 module.exports = SoftwareArticles;
 
-},{"../../../../constants":2,"../../../generic-components/image-carousel":3,"../../../lib/article-utils":4,"../../../lib/object-html-renderer":6}],9:[function(require,module,exports){
+},{"../../../../constants":2,"../../../generic-components/image-carousel":4,"../../../lib/article-utils":5,"object-to-html-renderer":3}],9:[function(require,module,exports){
 "use strict";
 
 const { images_url } = require("../../../constants");
@@ -580,7 +580,7 @@ runPage(SoftwareDevelopment);
 },{"../../run-page":11,"./software-development":9}],11:[function(require,module,exports){
 "use strict";
 
-const objectHtmlRenderer = require("./lib/object-html-renderer");
+const objectHtmlRenderer = require("object-to-html-renderer")
 const Template = require("./template/template");
 
 module.exports = function runPage(PageComponent) {
@@ -589,7 +589,7 @@ module.exports = function runPage(PageComponent) {
     objectHtmlRenderer.renderCycle();
 };
 
-},{"./lib/object-html-renderer":6,"./template/template":13}],12:[function(require,module,exports){
+},{"./template/template":13,"object-to-html-renderer":3}],12:[function(require,module,exports){
 "use strict";
 
 const { images_url } = require("../../../constants");
diff --git a/src/generic-components/image-carousel.js b/src/generic-components/image-carousel.js
index d3a9ada..e3e0352 100644
--- a/src/generic-components/image-carousel.js
+++ b/src/generic-components/image-carousel.js
@@ -1,6 +1,6 @@
 "use strict";
 
-const objectHtmlRenderer = require("../lib/object-html-renderer");
+const objectHtmlRenderer = require("object-to-html-renderer")
 
 class ImageCarousel {
     constructor(props) {
diff --git a/src/home-page-components/news-articles.js b/src/home-page-components/news-articles.js
index f94aa65..69ee7ac 100644
--- a/src/home-page-components/news-articles.js
+++ b/src/home-page-components/news-articles.js
@@ -1,7 +1,7 @@
 "use strict";
 
 const { articles_url } = require("../../constants");
-const objectHtmlRenderer = require("../lib/object-html-renderer");
+const objectHtmlRenderer = require("object-to-html-renderer");
 const ImageCarousel = require("../generic-components/image-carousel");
 const { loadArticles, getArticleDate, getArticleBody } = require("../lib/article-utils");
 
diff --git a/src/lib/object-html-renderer.js b/src/lib/object-html-renderer.js
deleted file mode 100644
index 0f348d7..0000000
--- a/src/lib/object-html-renderer.js
+++ /dev/null
@@ -1,84 +0,0 @@
-"use strict";
-
-module.exports = {
-    setRenderCycleRoot(renderCycleRoot) {
-        this.renderCycleRoot = renderCycleRoot;
-    },
-    objectToHtml: function objectToHtml(obj) {
-        const { tag } = obj;
-
-        const node = document.createElement(tag);
-        const excludeKeys = ["tag", "contents", "style_rules", "state"];
-
-        Object.keys(obj)
-            .filter(attr => !excludeKeys.includes(attr))
-            .forEach(attr => {
-                if (attr === "class") {
-                    node.classList.add(...obj[attr].split(" ").filter(s => s !== ""));
-                } else {
-                    node[attr] = obj[attr];
-                }
-            });
-        if (obj.contents && typeof obj.contents === "string") {
-            node.innerHTML = obj.contents;
-        } else {
-            obj.contents &&
-                obj.contents.length > 0 &&
-                obj.contents.forEach(el => {
-                    switch (typeof el) {
-                        case "string":
-                            node.innerHTML = el;
-                            break;
-                        case "object":
-                            node.appendChild(objectToHtml(el));
-                            break;
-                    }
-                });
-        }
-
-        if (obj.style_rules) {
-            Object.keys(obj.style_rules).forEach(rule => {
-                node.style[rule] = obj.style_rules[rule];
-            });
-        }
-
-        return node;
-    },
-    renderCycle: function () {
-        this.subRender(this.renderCycleRoot.render(), document.getElementsByTagName("main")[0], {
-            mode: "replace",
-        });
-    },
-    subRender(object, htmlNode, options = { mode: "append" }) {
-        const insert = this.objectToHtml(object);
-        switch (options.mode) {
-            case "append":
-                htmlNode.appendChild(insert);
-                break;
-            case "override":
-                htmlNode.innerHTML = "";
-                htmlNode.appendChild(insert);
-                break;
-            case "insert-before":
-                htmlNode.insertBefore(insert, htmlNode.childNodes[options.insertIndex]);
-                break;
-            case "adjacent":
-                /**
-                 * options.insertLocation must be one of:
-                 *
-                 * afterbegin
-                 * afterend
-                 * beforebegin
-                 * beforeend
-                 */
-                htmlNode.insertAdjacentHTML(options.insertLocation, insert);
-                break;
-            case "replace":
-                htmlNode.parentNode.replaceChild(insert, htmlNode);
-                break;
-            case "remove":
-                htmlNode.remove();
-                break;
-        }
-    },
-};
diff --git a/src/pages/games/components/game-articles.js b/src/pages/games/components/game-articles.js
index db633f0..0f377e9 100644
--- a/src/pages/games/components/game-articles.js
+++ b/src/pages/games/components/game-articles.js
@@ -2,7 +2,7 @@
 
 const { articles_url } = require("../../../../constants");
 const { loadArticles, populateArticles } = require("../../../lib/article-utils");
-const objectHtmlRenderer = require("../../../lib/object-html-renderer");
+const objectHtmlRenderer = require("object-to-html-renderer")
 const GameArticle = require("./game-article");
 
 class GameArticles {
diff --git a/src/pages/software-development/components/software-articles.js b/src/pages/software-development/components/software-articles.js
index 730011a..d33ac02 100644
--- a/src/pages/software-development/components/software-articles.js
+++ b/src/pages/software-development/components/software-articles.js
@@ -3,7 +3,7 @@
 const { articles_url } = require("../../../../constants");
 const ImageCarousel = require("../../../generic-components/image-carousel");
 const { loadArticles, getArticleBody, getArticleDate } = require("../../../lib/article-utils");
-const objectHtmlRenderer = require("../../../lib/object-html-renderer");
+const objectHtmlRenderer = require("object-to-html-renderer")
 
 class SoftwareArticle {
     constructor(props) {
diff --git a/src/run-page.js b/src/run-page.js
index 5a305d5..d0b0af0 100644
--- a/src/run-page.js
+++ b/src/run-page.js
@@ -1,6 +1,6 @@
 "use strict";
 
-const objectHtmlRenderer = require("./lib/object-html-renderer");
+const objectHtmlRenderer = require("object-to-html-renderer")
 const Template = require("./template/template");
 
 module.exports = function runPage(PageComponent) {
-- 
GitLab