diff --git a/public/articles/software/index.json b/public/articles/software/index.json
index 82e6d2b1ed5bb0157a78a9086c26645301ae256f..62342bec242ba5597c7e857abf93d7e93341e41c 100755
--- a/public/articles/software/index.json
+++ b/public/articles/software/index.json
@@ -1,3 +1,8 @@
 {
-    "articles": ["watergun", "website-template", "make_frames"]
-}
+    "articles": [
+        "mentalo",
+        "object-to-html-renderer",
+        "make_frames",
+        "watergun"
+    ]
+}
\ No newline at end of file
diff --git a/public/articles/software/mentalo/images/mental-eau.png b/public/articles/software/mentalo/images/mental-eau.png
new file mode 100644
index 0000000000000000000000000000000000000000..ed6c2eeced7fbb226d7c30e1a526b7c0b09c6d93
Binary files /dev/null and b/public/articles/software/mentalo/images/mental-eau.png differ
diff --git a/public/articles/software/mentalo/mentalo.json b/public/articles/software/mentalo/mentalo.json
new file mode 100755
index 0000000000000000000000000000000000000000..0ba73167784a11c51f2756c0fac2cab74e3f8d2f
--- /dev/null
+++ b/public/articles/software/mentalo/mentalo.json
@@ -0,0 +1,19 @@
+{
+    "title": "Mentalo",
+    "date": "2021/07/18",
+    "subtitle": "Une application pour créer des jeux simples",
+    "body": "<file>mentalo.txt",
+    "technical": {
+        "stack": [
+            "Javascript",
+            "Nodejs",
+            "Sass"
+        ],
+        "license": "GNU GPL v3",
+        "repository": "https://gitlab.com/kuadrado-software/mentalo",
+        "version": "0.1.2"
+    },
+    "images": [
+        "mental-eau.png"
+    ]
+}
\ No newline at end of file
diff --git a/public/articles/software/mentalo/mentalo.txt b/public/articles/software/mentalo/mentalo.txt
new file mode 100755
index 0000000000000000000000000000000000000000..1e33e08448d4c3d0e0545819ceb0ec85aebd39ac
--- /dev/null
+++ b/public/articles/software/mentalo/mentalo.txt
@@ -0,0 +1,2 @@
+Mentalo est une application éducative qui permet de construire un raisonnement logique à travers la création de jeux simples basés sur des écrans statiques et des choix texte.
+Sortie d'une version beta prévue pour Septembre 2021.
\ No newline at end of file
diff --git a/public/articles/software/object-to-html-renderer/images/obj-to-html-logo.png b/public/articles/software/object-to-html-renderer/images/obj-to-html-logo.png
new file mode 100644
index 0000000000000000000000000000000000000000..8efda75f697267280b833f5aeb6b1a36b96cee67
Binary files /dev/null and b/public/articles/software/object-to-html-renderer/images/obj-to-html-logo.png differ
diff --git a/public/articles/software/object-to-html-renderer/object-to-html-renderer.json b/public/articles/software/object-to-html-renderer/object-to-html-renderer.json
new file mode 100755
index 0000000000000000000000000000000000000000..6ba1fd6f2641fc18da5f6ad838e786722a8193c6
--- /dev/null
+++ b/public/articles/software/object-to-html-renderer/object-to-html-renderer.json
@@ -0,0 +1,18 @@
+{
+    "title": "Object to HTML Renderer",
+    "date": "2021/07/18",
+    "subtitle": "Un moteur de rendu web dynamique",
+    "body": "<file>object-to-html-renderer.txt",
+    "technical": {
+        "stack": [
+            "Javascript",
+            "Nodejs"
+        ],
+        "license": "LGPL-3.0",
+        "repository": "https://gitlab.com/kuadrado-software/object-to-html-renderer",
+        "version": "1.0.3"
+    },
+    "images": [
+        "obj-to-html-logo.png"
+    ]
+}
\ No newline at end of file
diff --git a/public/articles/software/object-to-html-renderer/object-to-html-renderer.txt b/public/articles/software/object-to-html-renderer/object-to-html-renderer.txt
new file mode 100755
index 0000000000000000000000000000000000000000..34837d1ece16927b50fb23bb5ae75fc4aee71bd6
--- /dev/null
+++ b/public/articles/software/object-to-html-renderer/object-to-html-renderer.txt
@@ -0,0 +1 @@
+Une librairie minimaliste et sans aucune dépendances pour faire du rendu web html dynamique avec du Javascript.
\ No newline at end of file
diff --git a/public/articles/software/website-template/images/kuadrado-template-screen.png b/public/articles/software/website-template/images/kuadrado-template-screen.png
deleted file mode 100644
index 5bfef5aa520bcd8d9b130622d1bcbbf9915b962d..0000000000000000000000000000000000000000
Binary files a/public/articles/software/website-template/images/kuadrado-template-screen.png and /dev/null differ
diff --git a/public/articles/software/website-template/website-template.json b/public/articles/software/website-template/website-template.json
deleted file mode 100644
index e6e65def349017c52ab54afd3b29caeb9bbfe27f..0000000000000000000000000000000000000000
--- a/public/articles/software/website-template/website-template.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
-    "title": "Template web",
-    "date": "2021/01/28",
-    "subtitle": "Modèle de site statique simple et dynamique",
-    "body": "<file>website-template.txt",
-    "technical": {
-        "stack": ["Javascript", "Browserify", "Nginx", "Docker"],
-        "license": "MIT",
-        "repository": "https://gitlab.com/kuadrado-software/kuadrado-website-template",
-        "version": "0.1.0"
-    },
-    "images": ["kuadrado-template-screen.png"]
-}
diff --git a/public/articles/software/website-template/website-template.txt b/public/articles/software/website-template/website-template.txt
deleted file mode 100644
index c1610ade0201331a578dac1178f76c7b29e62eb9..0000000000000000000000000000000000000000
--- a/public/articles/software/website-template/website-template.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Basé sur les mêmes mécanismes de rendu dynamique que pour Watergun, ce modèle de site web propose une base réutilisable pour n'importe quel site statique simple et moderne.
-
-Ce modèle est celui qui a servi pour le présent site.
\ No newline at end of file
diff --git a/public/education/education.js b/public/education/education.js
index bc6aad73cd867f79a12d4e956ed8641b050f080c..9a7ac5221be5d8cd92a331e54e320d963753a5e4 100644
--- a/public/education/education.js
+++ b/public/education/education.js
@@ -1,11 +1,660 @@
-!function s(a,o,r){function i(t,e){if(!o[t]){if(!a[t]){var n="function"==typeof require&&require;if(!e&&n)return n(t,!0);if(c)return c(t,!0);throw(n=new Error("Cannot find module '"+t+"'")).code="MODULE_NOT_FOUND",n}n=o[t]={exports:{}},a[t][0].call(n.exports,function(e){return i(a[t][1][e]||e)},n,n.exports,s,a,o,r)}return o[t].exports}for(var c="function"==typeof require&&require,e=0;e<r.length;e++)i(r[e]);return i}({1:[function(e,t,n){t.exports={getServerUrl:function(){return`${location.origin}${"/"!==location.origin.charAt(location.origin.length-1)?"/":""}`},build:{protected_dirs:["assets","style","articles"],default_meta_keys:["title","description","image","open_graph","json_ld"]}}},{}],2:[function(e,t,n){const{getServerUrl:s}=e("./config");t.exports={images_url:`${s()}assets/images/`,articles_url:`${s()}articles/`}},{"./config":1}],3:[function(e,t,n){"use strict";t.exports={setRenderCycleRoot(e){this.renderCycleRoot=e},objectToHtml:function t(n){var{tag:e}=n;const s=document.createElement(e),a=["tag","contents","style_rules","state"];return Object.keys(n).filter(e=>!a.includes(e)).forEach(e=>{"class"===e?s.classList.add(...n[e].split(" ").filter(e=>""!==e)):s[e]=n[e]}),n.contents&&"string"==typeof n.contents?s.innerHTML=n.contents:n.contents&&0<n.contents.length&&n.contents.forEach(e=>{switch(typeof e){case"string":s.innerHTML=e;break;case"object":s.appendChild(t(e))}}),n.style_rules&&Object.keys(n.style_rules).forEach(e=>{s.style[e]=n.style_rules[e]}),s},renderCycle:function(){this.subRender(this.renderCycleRoot.render(),document.getElementsByTagName("main")[0],{mode:"replace"})},subRender(e,t,n={mode:"append"}){var s=this.objectToHtml(e);switch(n.mode){case"append":t.appendChild(s);break;case"override":t.innerHTML="",t.appendChild(s);break;case"insert-before":t.insertBefore(s,t.childNodes[n.insertIndex]);break;case"adjacent":t.insertAdjacentHTML(n.insertLocation,s);break;case"replace":t.parentNode.replaceChild(s,t);break;case"remove":t.remove()}}}},{}],4:[function(e,t,n){"use strict";t.exports=class{constructor(e){Object.assign(this,e)}}},{}],5:[function(e,t,n){"use strict";const{images_url:s}=e("../../../constants");e=e("../../lib/web-page");const a=[{title:"Programmation",description:`<b>Franchissez le mur du code !</b><br />
-        Apprenez à programmer avec différents langages (Python, Javascript, C ...), pour du web, du logiciel, du jeu vidéo ou autre.`,image:"learning_theme_coding.png"},{title:"Dessin numérique et animation 2D",description:`Apprenez à utiliser des logiciels libres de création graphique 2D et d'animation.<br />
-        Créez des personnages et des décors, menez votre projet de dessin animé, d'illustration ou de jeu vidéo.`,image:"learning_theme_2d.png"},{title:"Maths et physique",description:"Abordez les notions fondamentales de façon décontractée pour le plaisir de comprendre.",image:"learning_theme_math.png"},{title:"Aide informatique générale",description:"Perdu avec votre ordinateur ou votre smartphone, les logiciels, internet ? Je vous aide pas à pas à comprendre les fondamentaux et à utiliser sereinement la technologie.",image:"learning_theme_pc.png"},{title:"Stage GNU/Linux",description:`<b>Passez le cap du libre ! </b><br/>
+(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
+function getServerUrl() {
+    return `${location.origin}${location.origin.charAt(location.origin.length - 1) !== "/" ? "/" : ""
+        }`;
+}
+
+module.exports = {
+    getServerUrl,
+    build: {
+        protected_dirs: ["assets", "style", "articles"],
+        default_meta_keys: ["title", "description", "image", "open_graph", "json_ld"],
+    },
+};
+
+},{}],2:[function(require,module,exports){
+const { getServerUrl } = require("./config");
+
+module.exports = {
+    images_url: `${getServerUrl()}assets/images/`,
+    articles_url: `${getServerUrl()}articles/`,
+};
+
+},{"./config":1}],3:[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;
+        }
+    },
+};
+
+},{}],4:[function(require,module,exports){
+"use strict";
+
+class WebPage {
+    constructor(args) {
+        Object.assign(this, args);
+    }
+}
+
+module.exports = WebPage;
+},{}],5:[function(require,module,exports){
+"use strict";
+
+const { images_url } = require("../../../constants");
+const WebPage = require("../../lib/web-page");
+
+const EDU_THEMES = [
+    // {
+    //     title: "Création de jeux vidéo",
+    //     description: "Conception, graphisme et animation, programmation, je vous accompagne dans la découverte des techniques pour créer un jeu vidéo de A à Z",
+    //     image: "learning_theme_conception.png",
+    //     pageUrl: "gamedev",
+    // },
+    {
+        title: "Programmation",
+        description: `<b>Franchissez le mur du code !</b><br />
+        Apprenez à programmer avec différents langages (Python, Javascript, C ...), pour du web, du logiciel, du jeu vidéo ou autre.`,
+        image: "learning_theme_coding.png",
+        // pageUrl: "coding",
+    },
+    {
+        title: "Dessin numérique et animation 2D",
+        description: `Apprenez à utiliser des logiciels libres de création graphique 2D et d'animation.<br />
+        Créez des personnages et des décors, menez votre projet de dessin animé, d'illustration ou de jeu vidéo.`,
+        image: "learning_theme_2d.png",
+        // pageUrl: "2d",
+    },
+    {
+        title: "Maths et physique",
+        description: "Abordez les notions fondamentales de façon décontractée pour le plaisir de comprendre.",
+        image: "learning_theme_math.png",
+        // pageUrl: "math",
+    },
+    // {
+    //     title: "Musique et sons électroniques",
+    //     description: "Découvrez des logiciels libres de composition musicales, de synthèse sonore et de prise de son.",
+    //     image: "learning_theme_sound.png",
+    //     pageUrl: "sound",
+    // },
+    {
+        title: "Aide informatique générale",
+        description: "Perdu avec votre ordinateur ou votre smartphone, les logiciels, internet ? Je vous aide pas à pas à comprendre les fondamentaux et à utiliser sereinement la technologie.",
+        image: "learning_theme_pc.png",
+        // pageUrl: "popularization"
+    },
+    {
+        title: "Stage GNU/Linux",
+        description: `<b>Passez le cap du libre ! </b><br/>
         Stage de 4 séances pour installer Linux, faire ses premiers pas avec les logiciels libres et acquérir une autonomie suffisante pour une utilisation basique.
-        `,image:"learning_theme_linux.png"}];class o extends e{render(){return{tag:"div",id:"education-page",typeof:"EducationalOrganization",contents:[{tag:"div",class:"page-header logo-left",contents:[{tag:"div",class:"page-contents-center grid-wrapper",contents:[{tag:"div",class:"logo",contents:[{tag:"img",alt:"image brain",src:`${s}brain.svg`}]},{tag:"h1",contents:"Pédagogie"},{tag:"p",contents:`Animation d'ateliers informatiques accessibles à tous. 
-                                    Programmation, graphisme 2D, jeux vidéo, vulgarisation, accompagnement de projet, etc.`}]}]},{tag:"div",class:"title-banner"},{tag:"section",class:"bg-dark",contents:[{tag:"div",class:"page-contents-center",contents:[{tag:"ul",class:"edu-themes",contents:a.map(e=>({tag:"li",class:"edu-theme",contents:[{tag:"img",width:250,height:140,class:"pixelated",src:`${s}${e.image}`},{tag:"h3",contents:e.title},{tag:"p",contents:e.description}]}))}]}]},{tag:"section",class:"practical-info",contents:[{tag:"div",class:"page-contents-center",contents:[{tag:"div",class:"info-block",contents:[{tag:"h3",class:"info-title",contents:"Pour qui ?"},{tag:"p",class:"info-body",contents:`Les ateliers sont accessibles aux adultes comme aux enfants, plutôt à partir de 12 ans.<br/>
+        `,
+        image: "learning_theme_linux.png"
+    }
+];
+
+class EducationPage extends WebPage {
+    render() {
+        return {
+            tag: "div",
+            id: "education-page",
+            typeof: "EducationalOrganization",
+            contents: [
+                {
+                    tag: "div",
+                    class: "page-header logo-left",
+                    contents: [
+                        {
+                            tag: "div",
+                            class: "page-contents-center grid-wrapper",
+                            contents: [
+                                {
+                                    tag: "div",
+                                    class: "logo",
+                                    contents: [
+                                        {
+                                            tag: "img",
+                                            alt: "image brain",
+                                            src: `${images_url}brain.svg`,
+                                        },
+                                    ],
+                                },
+                                { tag: "h1", contents: "Pédagogie" },
+                                {
+                                    tag: "p",
+                                    contents: `Animation d'ateliers informatiques accessibles à tous. 
+                                    Programmation, graphisme 2D, jeux vidéo, vulgarisation, accompagnement de projet, etc.`,
+                                },
+                            ],
+                        },
+                    ],
+                },
+                {
+                    tag: "div",
+                    class: "title-banner",
+                },
+                {
+                    tag: "section",
+                    class: "bg-dark",
+                    contents: [
+                        {
+                            tag: "div",
+                            class: "page-contents-center",
+                            contents: [
+                                {
+                                    tag: "ul",
+                                    class: "edu-themes",
+                                    contents: EDU_THEMES.map(theme => {
+                                        return {
+                                            tag: "li",
+                                            class: "edu-theme",
+                                            contents: [
+                                                { tag: "img", width: 250, height: 140, class: "pixelated", src: `${images_url}${theme.image}` },
+                                                { tag: "h3", contents: theme.title },
+                                                { tag: "p", contents: theme.description },
+                                            ]
+                                        }
+                                    })
+                                },
+                            ]
+                        },
+                    ]
+                },
+                {
+                    tag: "section",
+                    class: "practical-info",
+                    contents: [
+                        {
+                            tag: "div",
+                            class: "page-contents-center",
+                            contents: [
+                                {
+                                    tag: "div",
+                                    class: "info-block",
+                                    contents: [
+                                        { tag: "h3", class: "info-title", contents: "Pour qui ?" },
+                                        {
+                                            tag: "p",
+                                            class: "info-body",
+                                            contents: `Les ateliers sont accessibles aux adultes comme aux enfants, plutôt à partir de 12 ans.<br/>
                                             Les séances ont lieu en groupes mixtes. Capacité limitée à 5 personnes.
-                                            `}]},{tag:"div",class:"info-block",contents:[{tag:"h3",class:"info-title",contents:"Où ça ?"},{tag:"p",class:"info-body",contents:"Dans mon local professionnel : <br /><blue>32 rue Simon Vialet, passage du Cheminou, 07240 Vernoux en Vivarais.</blue>"}]},{tag:"div",class:"info-block",contents:[{tag:"h3",class:"info-title",contents:"Quel matériel ?"},{tag:"p",class:"info-body",contents:`Le matériel informatique est fourni sur place (ordinateurs et tablettes graphique) 
+                                            `
+                                        }
+                                    ]
+                                },
+                                {
+                                    tag: "div",
+                                    class: "info-block",
+                                    contents: [
+                                        { tag: "h3", class: "info-title", contents: "Où ça ?" },
+                                        {
+                                            tag: "p",
+                                            class: "info-body",
+                                            contents: "Dans mon local professionnel : <br /><blue>32 rue Simon Vialet, passage du Cheminou, 07240 Vernoux en Vivarais.</blue>"
+                                        }
+                                    ]
+                                },
+                                {
+                                    tag: "div",
+                                    class: "info-block",
+                                    contents: [
+                                        { tag: "h3", class: "info-title", contents: "Quel matériel ?" },
+                                        {
+                                            tag: "p",
+                                            class: "info-body",
+                                            contents: `Le matériel informatique est fourni sur place (ordinateurs et tablettes graphique) 
                                             mais il est possible d'amener le sien. 
-                                            <br />Il est recommandé d'apporter au moins une clé USB pour faire ses sauvegardes.`}]},{tag:"div",class:"info-block",contents:[{tag:"h3",class:"info-title",contents:"Quand ?"},{tag:"ul",class:"info-body tabled",contents:[{tag:"li",contents:[{tag:"span",contents:"Mardi"},{tag:"span",contents:"16h - 18h"}]},{tag:"li",contents:[{tag:"span",contents:"Mercredi"},{tag:"span",contents:"14h - 16h"}]},{tag:"li",contents:[{tag:"span",contents:"Jeudi"},{tag:"span",contents:"16h - 18h"}]},{tag:"li",class:"fullwidth",contents:"<em><blue>Ouvert de Septembre à Juin, sauf vacances scolaires ou fermetures exceptionnelles</blue></em>"}]}]},{tag:"div",class:"info-block",contents:[{tag:"h3",class:"info-title",contents:"Combien ça coûte ?"},{tag:"ul",class:"info-body tabled",contents:[{tag:"li",contents:[{tag:"span",contents:"Inscription au mois"},{tag:"span",contents:"50€, accès à toutes les plages horaires."}]},{tag:"li",contents:[{tag:"span",contents:"Inscription à la séance"},{tag:"span",contents:"15€"}]},{tag:"li",contents:[{tag:"span",contents:"Cours particuliers"},{tag:"span",contents:"30€/h, sur place ou en visio. Horaires à définir."}]},{tag:"li",contents:[{tag:"span",contents:"Stage 4 séances de 2h"},{tag:"span",contents:"40€ par personne, horaires et dates à définir selon la demande."}]}]}]},{tag:"div",class:"info-block",contents:[{tag:"h3",class:"info-title",contents:"Pour s'inscrire ou en savoir plus"},{tag:"ul",class:"info-body",contents:[{tag:"li",contents:[{tag:"span",contents:"Me contacter"},{tag:"a",href:"mailto:contact@kuadrado-software.fr",contents:"contact@kuadrado-software.fr"}]},{tag:"li",contents:[{tag:"span",contents:""},{tag:"a",href:"tel:+33475780872",contents:"04 75 78 08 72",property:"telephone"}]},{tag:"li",contents:[{tag:"span",contents:"ou passer directement me voir au local !"}]}]}]}]}]}]}}}t.exports=o},{"../../../constants":2,"../../lib/web-page":4}],6:[function(e,t,n){"use strict";const s=e("../../run-page");e=e("./education");s(e)},{"../../run-page":7,"./education":5}],7:[function(e,t,n){"use strict";const s=e("object-to-html-renderer"),a=e("./template/template");t.exports=function(e){e=new a({page:new e});s.setRenderCycleRoot(e),s.renderCycle()}},{"./template/template":9,"object-to-html-renderer":3}],8:[function(e,t,n){"use strict";const{images_url:s}=e("../../../constants"),a=[{url:"/games/",text:"Jeux"},{url:"/education/",text:"Pédagogie"},{url:"/software-development/",text:"Software"}];t.exports=class{constructor(){this.initEventHandlers()}handleBurgerClick(){document.getElementById("nav-menu-list").classList.toggle("responsive-show")}initEventHandlers(){window.addEventListener("click",e=>{"nav-menu-list"===e.target.id||e.target.classList.contains("burger")||e.target.parentNode.classList.contains("burger")||document.getElementById("nav-menu-list").classList.remove("responsive-show")})}renderHome(){return{tag:"div",class:"home",contents:[{tag:"a",href:"/",contents:[{tag:"img",alt:"Logo Kuadrado",src:`${s}logo_kuadrado.svg`},{tag:"img",alt:"Kuadrado Software",class:"logo-text",src:`${s}logo_kuadrado_txt.svg`}]}]}}renderMenu(e,o=!1,r=""){return{tag:"ul",id:"nav-menu-list",class:o?"submenu":"",contents:e.map(e=>{const{url:t,text:n,submenu:s}=e,a=`${r}${t}`;return{tag:"li",class:o||window.location.pathname!==a?"":"active",contents:[{tag:"a",href:a,contents:n}].concat(s?[this.renderMenu(s,!0,t)]:[])}})}}renderResponsiveBurger(){return{tag:"div",class:"burger",onclick:this.handleBurgerClick.bind(this),contents:[{tag:"span",contents:"···"}]}}render(){return{tag:"nav",contents:[this.renderHome(),this.renderResponsiveBurger(),this.renderMenu(a)]}}}},{"../../../constants":2}],9:[function(e,t,n){"use strict";const{in_construction:s}=e("../../config"),{images_url:a}=e("../../constants"),o=e("./components/navbar");t.exports=class{constructor(e){this.props=e}render(){return{tag:"main",contents:[{tag:"header",contents:[(new o).render()]},s&&{tag:"section",class:"warning-banner",contents:[{tag:"strong",class:"page-contents-center",contents:"Site en construction ..."}]},{tag:"section",id:"page-container",contents:[this.props.page.render()]},{tag:"footer",contents:[{tag:"div",class:"logo",contents:[{tag:"img",alt:"logo Kuadrado",src:`${a}logo_kuadrado.svg`},{tag:"img",class:"text-logo",alt:"Kuadrado Software",src:`${a}logo_kuadrado_txt.svg`}]},{tag:"span",contents:"32 rue Simon Vialet, 07240 Vernoux en Vivarais. Ardèche, France"},{tag:"div",contents:[{tag:"strong",contents:"<blue>Contact : </blue>"},{tag:"a",href:"mailto:contact@kuadrado-software.fr",contents:"contact@kuadrado-software.fr"}]},{tag:"div",class:"social",contents:[{tag:"strong",contents:"<blue>Sur les réseaux : </blue>"},{tag:"a",href:"https://www.linkedin.com/company/kuadrado-software",target:"_blank",contents:"in",title:"Linkedin"},{tag:"a",href:"https://twitter.com/KuadradoSoft",target:"_blank",contents:"t",title:"Twitter",style_rules:{fontFamily:"serif"}}]},{tag:"span",contents:`Copyright © ${(new Date).getFullYear()} Kuadrado Software | 
-                                Toutes les images du site ont été réalisées par mes soins et peuvent être réutilisées pour un usage personnel.`}]}]}}}},{"../../config":1,"../../constants":2,"./components/navbar":8}]},{},[6]);
\ No newline at end of file
+                                            <br />Il est recommandé d'apporter au moins une clé USB pour faire ses sauvegardes.`
+                                        }
+                                    ]
+                                },
+                                {
+                                    tag: "div",
+                                    class: "info-block",
+                                    contents: [
+                                        { tag: "h3", class: "info-title", contents: "Quand ?" },
+                                        {
+                                            tag: "ul",
+                                            class: "info-body tabled",
+                                            contents: [
+                                                {
+                                                    tag: "li",
+                                                    contents: [
+                                                        { tag: "span", contents: "Mardi" },
+                                                        { tag: "span", contents: "16h - 18h" },
+                                                    ]
+                                                },
+                                                {
+                                                    tag: "li",
+                                                    contents: [
+                                                        { tag: "span", contents: "Mercredi" },
+                                                        { tag: "span", contents: "14h - 16h" },
+                                                    ]
+                                                },
+                                                {
+                                                    tag: "li",
+                                                    contents: [
+                                                        { tag: "span", contents: "Jeudi" },
+                                                        { tag: "span", contents: "16h - 18h" },
+                                                    ]
+                                                },
+                                                {
+                                                    tag: "li",
+                                                    class: "fullwidth",
+                                                    contents: "<em><blue>Ouvert de Septembre à Juin, sauf vacances scolaires ou fermetures exceptionnelles</blue></em>"
+                                                }
+                                            ]
+                                        },
+                                    ]
+                                },
+                                {
+                                    tag: "div",
+                                    class: "info-block",
+                                    contents: [
+                                        { tag: "h3", class: "info-title", contents: "Combien ça coûte ?" },
+                                        {
+                                            tag: "ul",
+                                            class: "info-body tabled",
+                                            contents: [
+                                                {
+                                                    tag: "li",
+                                                    contents: [
+                                                        { tag: "span", contents: "Inscription au mois" },
+                                                        { tag: "span", contents: "50€, accès à toutes les plages horaires." },
+                                                    ]
+                                                },
+                                                {
+                                                    tag: "li",
+                                                    contents: [
+                                                        { tag: "span", contents: "Inscription à la séance" },
+                                                        { tag: "span", contents: "15€" },
+                                                    ]
+                                                },
+                                                {
+                                                    tag: "li",
+                                                    contents: [
+                                                        { tag: "span", contents: "Cours particuliers" },
+                                                        { tag: "span", contents: "30€/h, sur place ou en visio. Horaires à définir." },
+                                                    ]
+                                                },
+                                                {
+                                                    tag: "li",
+                                                    contents: [
+                                                        { tag: "span", contents: "Stage 4 séances de 2h" },
+                                                        { tag: "span", contents: "40€ par personne, horaires et dates à définir selon la demande." },
+                                                    ]
+                                                }
+                                            ]
+                                        }
+                                    ]
+                                },
+                                {
+                                    tag: "div",
+                                    class: "info-block",
+                                    contents: [
+                                        { tag: "h3", class: "info-title", contents: "Pour s'inscrire ou en savoir plus" },
+                                        {
+                                            tag: "ul",
+                                            class: "info-body",
+                                            contents: [
+                                                {
+                                                    tag: "li",
+                                                    contents: [
+                                                        { tag: "span", contents: "Me contacter" },
+                                                        {
+                                                            tag: "a",
+                                                            href: "mailto:contact@kuadrado-software.fr",
+                                                            contents: "contact@kuadrado-software.fr",
+                                                        }
+                                                    ]
+                                                },
+                                                {
+                                                    tag: "li",
+                                                    contents: [
+                                                        { tag: "span", contents: "" },
+                                                        {
+                                                            tag: "a",
+                                                            href: "tel:+33475780872",
+                                                            contents: "04 75 78 08 72",
+                                                            property: "telephone",
+                                                        },
+                                                    ]
+                                                },
+                                                {
+                                                    tag: "li",
+                                                    contents: [
+                                                        { tag: "span", contents: "ou passer directement me voir au local !" }
+                                                    ]
+                                                }
+                                            ]
+                                        }
+                                    ]
+                                }
+                            ]
+                        }
+                    ]
+
+                },
+            ],
+        };
+    }
+}
+
+module.exports = EducationPage;
+
+},{"../../../constants":2,"../../lib/web-page":4}],6:[function(require,module,exports){
+"use strict";
+const runPage = require("../../run-page");
+const EducationPage = require("./education");
+runPage(EducationPage);
+
+},{"../../run-page":7,"./education":5}],7:[function(require,module,exports){
+"use strict";
+
+const objectHtmlRenderer = require("object-to-html-renderer")
+const Template = require("./template/template");
+
+module.exports = function runPage(PageComponent) {
+    const template = new Template({ page: new PageComponent() });
+    objectHtmlRenderer.setRenderCycleRoot(template);
+    objectHtmlRenderer.renderCycle();
+};
+
+},{"./template/template":9,"object-to-html-renderer":3}],8:[function(require,module,exports){
+"use strict";
+
+const { images_url } = require("../../../constants");
+
+const NAV_MENU_ITEMS = [
+    { url: "/games/", text: "Jeux" },
+    {
+        url: "/education/",
+        text: "Pédagogie",
+        // submenu: [
+        //     { url: "/gamedev", text: "Création de jeux vidéo" },
+        // ]
+    },
+    { url: "/software-development/", text: "Software" }
+];
+
+class NavBar {
+    constructor() {
+        this.initEventHandlers();
+    }
+
+    handleBurgerClick() {
+        document.getElementById("nav-menu-list").classList.toggle("responsive-show");
+    }
+
+    initEventHandlers() {
+        window.addEventListener("click", event => {
+            if (
+                event.target.id !== "nav-menu-list" &&
+                !event.target.classList.contains("burger") &&
+                !event.target.parentNode.classList.contains("burger")
+            ) {
+                document.getElementById("nav-menu-list").classList.remove("responsive-show");
+            }
+        });
+    }
+
+    renderHome() {
+        return {
+            tag: "div",
+            class: "home",
+            contents: [
+                {
+                    tag: "a",
+                    href: "/",
+                    contents: [
+                        {
+                            tag: "img",
+                            alt: "Logo Kuadrado",
+                            src: `${images_url}logo_kuadrado.svg`,
+                        },
+                        {
+                            tag: "img",
+                            alt: "Kuadrado Software",
+                            class: "logo-text",
+                            src: `${images_url}logo_kuadrado_txt.svg`,
+                        },
+                    ],
+                },
+            ],
+        };
+    }
+
+    renderMenu(menuItemsArray, isSubmenu = false, parentUrl = "") {
+        return {
+            tag: "ul",
+            id: "nav-menu-list",
+            class: isSubmenu ? "submenu" : "",
+            contents: menuItemsArray.map(item => {
+                const { url, text, submenu } = item;
+                const href = `${parentUrl}${url}`;
+                return {
+                    tag: "li",
+                    class: !isSubmenu && window.location.pathname === href ? "active" : "",
+                    contents: [
+                        {
+                            tag: "a",
+                            href,
+                            contents: text,
+                        },
+                    ].concat(submenu ? [this.renderMenu(submenu, true, url)] : []),
+                };
+            }),
+        };
+    }
+
+    renderResponsiveBurger() {
+        return {
+            tag: "div",
+            class: "burger",
+            onclick: this.handleBurgerClick.bind(this),
+            contents: [{ tag: "span", contents: "···" }],
+        };
+    }
+
+    render() {
+        return {
+            tag: "nav",
+            contents: [
+                this.renderHome(),
+                this.renderResponsiveBurger(),
+                this.renderMenu(NAV_MENU_ITEMS),
+            ],
+        };
+    }
+}
+
+module.exports = NavBar;
+
+},{"../../../constants":2}],9:[function(require,module,exports){
+"use strict";
+
+const { in_construction } = require("../../config");
+const { images_url } = require("../../constants");
+const NavBar = require("./components/navbar");
+
+class Template {
+    constructor(props) {
+        this.props = props;
+    }
+    render() {
+        return {
+            tag: "main",
+            contents: [
+                {
+                    tag: "header",
+                    contents: [new NavBar().render()],
+                },
+                in_construction && {
+                    tag: "section",
+                    class: "warning-banner",
+                    contents: [
+                        {
+                            tag: "strong",
+                            class: "page-contents-center",
+                            contents: "Site en construction ...",
+                        },
+                    ],
+                },
+                {
+                    tag: "section",
+                    id: "page-container",
+                    contents: [this.props.page.render()],
+                },
+                {
+                    tag: "footer",
+                    contents: [
+                        {
+                            tag: "div",
+                            class: "logo",
+                            contents: [
+                                {
+                                    tag: "img",
+                                    alt: `logo Kuadrado`,
+                                    src: `${images_url}logo_kuadrado.svg`,
+                                },
+                                {
+                                    tag: "img",
+                                    class: "text-logo",
+                                    alt: "Kuadrado Software",
+                                    src: `${images_url}logo_kuadrado_txt.svg`,
+                                },
+                            ],
+                        },
+                        {
+                            tag: "span",
+                            contents: "32 rue Simon Vialet, 07240 Vernoux en Vivarais. Ardèche, France",
+                        },
+                        {
+                            tag: "div",
+                            contents: [
+                                { tag: "strong", contents: "<blue>Contact : </blue>" },
+                                {
+                                    tag: "a",
+                                    href: "mailto:contact@kuadrado-software.fr",
+                                    contents: "contact@kuadrado-software.fr",
+                                },
+                            ],
+                        },
+                        {
+                            tag: "div",
+                            class: "social",
+                            contents: [
+                                {
+                                    tag: "strong",
+                                    contents: "<blue>Sur les réseaux : </blue>",
+                                },
+                                {
+                                    tag: "a",
+                                    href: "https://www.linkedin.com/company/kuadrado-software",
+                                    target: "_blank",
+                                    contents: "in",
+                                    title: "Linkedin",
+                                },
+                                {
+                                    tag: "a",
+                                    href: "https://twitter.com/KuadradoSoft",
+                                    target: "_blank",
+                                    contents: "t",
+                                    title: "Twitter",
+                                    style_rules: { fontFamily: "serif" },
+                                },
+                            ],
+                        },
+                        {
+                            tag: "span",
+                            contents: `Copyright © ${new Date()
+                                .getFullYear()} Kuadrado Software | 
+                                Toutes les images du site ont été réalisées par mes soins et peuvent être réutilisées pour un usage personnel.`,
+                        },
+                    ],
+                },
+            ],
+        };
+    }
+}
+
+module.exports = Template;
+
+},{"../../config":1,"../../constants":2,"./components/navbar":8}]},{},[6]);
diff --git a/public/games/games.js b/public/games/games.js
index 0d18235bc3ce0508537c80d774e7db3da3dcd7df..db8aa16d45b1b726ec2bb25da6bb322d8a9f73e4 100644
--- a/public/games/games.js
+++ b/public/games/games.js
@@ -1,3 +1,769 @@
-!function n(r,a,o){function c(t,e){if(!a[t]){if(!r[t]){var s="function"==typeof require&&require;if(!e&&s)return s(t,!0);if(i)return i(t,!0);throw(s=new Error("Cannot find module '"+t+"'")).code="MODULE_NOT_FOUND",s}s=a[t]={exports:{}},r[t][0].call(s.exports,function(e){return c(r[t][1][e]||e)},s,s.exports,n,r,a,o)}return a[t].exports}for(var i="function"==typeof require&&require,e=0;e<o.length;e++)c(o[e]);return c}({1:[function(e,t,s){t.exports={getServerUrl:function(){return`${location.origin}${"/"!==location.origin.charAt(location.origin.length-1)?"/":""}`},build:{protected_dirs:["assets","style","articles"],default_meta_keys:["title","description","image","open_graph","json_ld"]}}},{}],2:[function(e,t,s){const{getServerUrl:n}=e("./config");t.exports={images_url:`${n()}assets/images/`,articles_url:`${n()}articles/`}},{"./config":1}],3:[function(e,t,s){"use strict";t.exports={setRenderCycleRoot(e){this.renderCycleRoot=e},objectToHtml:function t(s){var{tag:e}=s;const n=document.createElement(e),r=["tag","contents","style_rules","state"];return Object.keys(s).filter(e=>!r.includes(e)).forEach(e=>{"class"===e?n.classList.add(...s[e].split(" ").filter(e=>""!==e)):n[e]=s[e]}),s.contents&&"string"==typeof s.contents?n.innerHTML=s.contents:s.contents&&0<s.contents.length&&s.contents.forEach(e=>{switch(typeof e){case"string":n.innerHTML=e;break;case"object":n.appendChild(t(e))}}),s.style_rules&&Object.keys(s.style_rules).forEach(e=>{n.style[e]=s.style_rules[e]}),n},renderCycle:function(){this.subRender(this.renderCycleRoot.render(),document.getElementsByTagName("main")[0],{mode:"replace"})},subRender(e,t,s={mode:"append"}){var n=this.objectToHtml(e);switch(s.mode){case"append":t.appendChild(n);break;case"override":t.innerHTML="",t.appendChild(n);break;case"insert-before":t.insertBefore(n,t.childNodes[s.insertIndex]);break;case"adjacent":t.insertAdjacentHTML(s.insertLocation,n);break;case"replace":t.parentNode.replaceChild(n,t);break;case"remove":t.remove()}}}},{}],4:[function(e,t,s){"use strict";const n=e("object-to-html-renderer");t.exports=class{constructor(e){this.props=e,this.id=performance.now(),this.state={showImageIndex:0},this.RUN_INTERVAL=5e3,1<this.props.images.length&&this.run()}run(){this.runningInterval=setInterval(()=>{var{showImageIndex:e}=this.state,{images:t}=this.props;this.state.showImageIndex=e<t.length-1?++e:0,this.refreshImage()},this.RUN_INTERVAL)}setImageIndex(e){clearInterval(this.runningInterval),this.state.showImageIndex=e,this.refreshImage()}refreshImage(){n.subRender(this.render(),document.getElementById(this.id),{mode:"replace"})}render(){const{showImageIndex:s}=this.state,{images:e}=this.props;return{tag:"div",id:this.id,class:"image-carousel",contents:[{tag:"img",property:"image",alt:`image carousel ${e[s].replace(/\.[A-Za-z]+/,"")}`,src:e[s]},1<e.length&&{tag:"div",class:"carousel-bullets",contents:e.map((e,t)=>{return{tag:"span",class:`bullet ${s===t?"active":""}`,onclick:this.setImageIndex.bind(this,t)}})}]}}}},{"object-to-html-renderer":3}],5:[function(e,t,s){"use strict";const{fetchjson:a,fetchtext:n}=e("./fetch");function o(e){return new Promise((t,s)=>{Promise.all(e.map(async e=>{var t;return-1!==e.body.indexOf("<file>")&&(t=e.body.replace("<file>",""),t=await n(`${e.path}/${t}`),e.body=t,e.date=e.date?new Date(e.date):void 0),e})).then(e=>t(e.sort((e,t)=>e.date-t.date))).catch(e=>s(e))})}t.exports={loadArticles:function(r){return new Promise((t,s)=>{a(`${r}/index.json`).then(e=>{Promise.all(e.articles.map(async e=>{const t=`${e}/${e}.json`;var s=await a(`${r}/${t}`);const n=t.split("/");n.pop();e=`${r}/${n.join("/")}`;return Object.assign(s,{path:e})})).then(e=>{o(e).then(e=>t(e)).catch(e=>s(e))}).catch(e=>s(e))}).catch(e=>console.log(e))})},getArticleBody:function(e){return e.replaceAll("\n","<br/>")},getArticleDate:function(e){return`${e.getDate()}-${e.getMonth()+1}-${e.getFullYear()}`},populateArticles:o}},{"./fetch":6}],6:[function(e,t,s){"use strict";t.exports={fetchjson:function(e){return new Promise((t,s)=>{fetch(e).then(e=>e.json()).then(e=>t(e)).catch(e=>s(e))})},fetchtext:function(e){return new Promise((t,s)=>{fetch(e).then(e=>e.text()).then(e=>t(e)).catch(e=>s(e))})}}},{}],7:[function(e,t,s){"use strict";t.exports=class{constructor(e){Object.assign(this,e)}}},{}],8:[function(e,t,s){"use strict";const i=e("../../../generic-components/image-carousel"),{getArticleBody:l}=e("../../../lib/article-utils");class g{constructor(e){this.props=e}render(){const{title:e,subtitle:t,body:s,images:n,path:r}=this.props;return{tag:"div",class:"team-member",typeof:"Person",property:"author",contents:[{tag:"div",class:"team-member-img",contents:[{tag:"img",alt:`ìmage team member ${e}`,src:n.map(e=>`${r}/images/${e}`)[0],property:"image"}]},{tag:"h3",class:"team-member-title",contents:e,property:"name"},{tag:"strong",class:"team-member-subtitle",contents:t,property:"jobTitle"},{tag:"p",class:"team-member-body",contents:l(s),property:"description"}]}}}t.exports=class{constructor(e){this.props=e}render(){const{title:e,tags:t,body:s,subtitle:n,images:r,path:a,team_subarticles:o,image_banner:c}=this.props;return{tag:"article",typeof:"VideoGame",additionalType:"Article",class:"game-article",contents:[{tag:"h2",property:"name",class:"game-title",contents:e},{tag:"div",class:"game-banner",contents:[{tag:"img",class:"pixelated",src:`${a}/images/${c}`}]},{tag:"div",class:"game-tags",contents:t.map(e=>({tag:"span",contents:e,property:"about"}))},{tag:"h3",class:"game-subtitle",contents:n,property:"alternativeHeadline"},{tag:"div",class:"game-description",property:"description",contents:l(s)},new i({images:r.map(e=>`${a}/images/${e}`)}).render(),{tag:"div",class:"game-team",contents:[{tag:"h2",contents:"L'équipe"},{tag:"div",class:"team-members",contents:o.map(e=>new g({...e}).render())}]}]}}}},{"../../../generic-components/image-carousel":4,"../../../lib/article-utils":5}],9:[function(e,t,s){"use strict";const{articles_url:n}=e("../../../../constants"),{loadArticles:r,populateArticles:a}=e("../../../lib/article-utils"),o=e("object-to-html-renderer"),c=e("./game-article");t.exports=class{constructor(e){this.props=e,this.state={articles:[]},this.id=performance.now(),this.loadArticles()}loadArticles(){r(`${n}games`).then(e=>{Promise.all(e.map(async t=>(t.team_subarticles&&(t.team_subarticles=await a(t.team_subarticles.map(e=>Object.assign(e,{path:t.path})))),t))).then(e=>{this.state.articles=e,this.refresh()})}).catch(e=>console.log(e))}renderPlaceholder(){return{tag:"article",class:"placeholder",contents:[{tag:"div"},{tag:"div"}]}}refresh(){o.subRender(this.render(),document.getElementById(this.id),{mode:"replace"})}render(){const{articles:e}=this.state;return{tag:"section",class:"game-articles page-contents-center",id:this.id,contents:0<e.length?e.map(e=>new c({...e}).render()):[this.renderPlaceholder()]}}}},{"../../../../constants":2,"../../../lib/article-utils":5,"./game-article":8,"object-to-html-renderer":3}],10:[function(e,t,s){"use strict";const{images_url:n}=e("../../../constants");var r=e("../../lib/web-page");const a=e("./components/game-articles");class o extends r{render(){return{tag:"div",id:"games-page",contents:[{tag:"div",class:"page-header logo-left",contents:[{tag:"div",class:"page-contents-center grid-wrapper",contents:[{tag:"div",class:"logo",contents:[{tag:"img",alt:"image game controller",src:`${n}game_controller.svg`}]},{tag:"h1",contents:"Jeux"},{tag:"p",contents:`Création de jeux vidéos indépendants.
-                                    <br/>Jeux web, PC et projets en cours de développement`}]}]},(new a).render()]}}}t.exports=o},{"../../../constants":2,"../../lib/web-page":7,"./components/game-articles":9}],11:[function(e,t,s){"use strict";const n=e("../../run-page");e=e("./games");n(e)},{"../../run-page":12,"./games":10}],12:[function(e,t,s){"use strict";const n=e("object-to-html-renderer"),r=e("./template/template");t.exports=function(e){e=new r({page:new e});n.setRenderCycleRoot(e),n.renderCycle()}},{"./template/template":14,"object-to-html-renderer":3}],13:[function(e,t,s){"use strict";const{images_url:n}=e("../../../constants"),r=[{url:"/games/",text:"Jeux"},{url:"/education/",text:"Pédagogie"},{url:"/software-development/",text:"Software"}];t.exports=class{constructor(){this.initEventHandlers()}handleBurgerClick(){document.getElementById("nav-menu-list").classList.toggle("responsive-show")}initEventHandlers(){window.addEventListener("click",e=>{"nav-menu-list"===e.target.id||e.target.classList.contains("burger")||e.target.parentNode.classList.contains("burger")||document.getElementById("nav-menu-list").classList.remove("responsive-show")})}renderHome(){return{tag:"div",class:"home",contents:[{tag:"a",href:"/",contents:[{tag:"img",alt:"Logo Kuadrado",src:`${n}logo_kuadrado.svg`},{tag:"img",alt:"Kuadrado Software",class:"logo-text",src:`${n}logo_kuadrado_txt.svg`}]}]}}renderMenu(e,a=!1,o=""){return{tag:"ul",id:"nav-menu-list",class:a?"submenu":"",contents:e.map(e=>{const{url:t,text:s,submenu:n}=e,r=`${o}${t}`;return{tag:"li",class:a||window.location.pathname!==r?"":"active",contents:[{tag:"a",href:r,contents:s}].concat(n?[this.renderMenu(n,!0,t)]:[])}})}}renderResponsiveBurger(){return{tag:"div",class:"burger",onclick:this.handleBurgerClick.bind(this),contents:[{tag:"span",contents:"···"}]}}render(){return{tag:"nav",contents:[this.renderHome(),this.renderResponsiveBurger(),this.renderMenu(r)]}}}},{"../../../constants":2}],14:[function(e,t,s){"use strict";const{in_construction:n}=e("../../config"),{images_url:r}=e("../../constants"),a=e("./components/navbar");t.exports=class{constructor(e){this.props=e}render(){return{tag:"main",contents:[{tag:"header",contents:[(new a).render()]},n&&{tag:"section",class:"warning-banner",contents:[{tag:"strong",class:"page-contents-center",contents:"Site en construction ..."}]},{tag:"section",id:"page-container",contents:[this.props.page.render()]},{tag:"footer",contents:[{tag:"div",class:"logo",contents:[{tag:"img",alt:"logo Kuadrado",src:`${r}logo_kuadrado.svg`},{tag:"img",class:"text-logo",alt:"Kuadrado Software",src:`${r}logo_kuadrado_txt.svg`}]},{tag:"span",contents:"32 rue Simon Vialet, 07240 Vernoux en Vivarais. Ardèche, France"},{tag:"div",contents:[{tag:"strong",contents:"<blue>Contact : </blue>"},{tag:"a",href:"mailto:contact@kuadrado-software.fr",contents:"contact@kuadrado-software.fr"}]},{tag:"div",class:"social",contents:[{tag:"strong",contents:"<blue>Sur les réseaux : </blue>"},{tag:"a",href:"https://www.linkedin.com/company/kuadrado-software",target:"_blank",contents:"in",title:"Linkedin"},{tag:"a",href:"https://twitter.com/KuadradoSoft",target:"_blank",contents:"t",title:"Twitter",style_rules:{fontFamily:"serif"}}]},{tag:"span",contents:`Copyright © ${(new Date).getFullYear()} Kuadrado Software | 
-                                Toutes les images du site ont été réalisées par mes soins et peuvent être réutilisées pour un usage personnel.`}]}]}}}},{"../../config":1,"../../constants":2,"./components/navbar":13}]},{},[11]);
\ No newline at end of file
+(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
+function getServerUrl() {
+    return `${location.origin}${location.origin.charAt(location.origin.length - 1) !== "/" ? "/" : ""
+        }`;
+}
+
+module.exports = {
+    getServerUrl,
+    build: {
+        protected_dirs: ["assets", "style", "articles"],
+        default_meta_keys: ["title", "description", "image", "open_graph", "json_ld"],
+    },
+};
+
+},{}],2:[function(require,module,exports){
+const { getServerUrl } = require("./config");
+
+module.exports = {
+    images_url: `${getServerUrl()}assets/images/`,
+    articles_url: `${getServerUrl()}articles/`,
+};
+
+},{"./config":1}],3:[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;
+        }
+    },
+};
+
+},{}],4:[function(require,module,exports){
+"use strict";
+
+const objectHtmlRenderer = require("object-to-html-renderer")
+
+class ImageCarousel {
+    constructor(props) {
+        this.props = props;
+        this.id = performance.now();
+        this.state = {
+            showImageIndex: 0,
+        };
+        this.RUN_INTERVAL = 5000;
+        this.props.images.length > 1 && this.run();
+    }
+
+    run() {
+        this.runningInterval = setInterval(() => {
+            let { showImageIndex } = this.state;
+            const { images } = this.props;
+            this.state.showImageIndex = showImageIndex < images.length - 1 ? ++showImageIndex : 0;
+            this.refreshImage();
+        }, this.RUN_INTERVAL);
+    }
+
+    setImageIndex(i) {
+        clearInterval(this.runningInterval);
+        this.state.showImageIndex = i;
+        this.refreshImage();
+    }
+
+    refreshImage() {
+        objectHtmlRenderer.subRender(this.render(), document.getElementById(this.id), {
+            mode: "replace",
+        });
+    }
+
+    render() {
+        const { showImageIndex } = this.state;
+        const { images } = this.props;
+        return {
+            tag: "div",
+            id: this.id,
+            class: "image-carousel",
+            contents: [
+                {
+                    tag: "img",
+                    property: "image",
+                    alt: `image carousel ${images[showImageIndex].replace(/\.[A-Za-z]+/, "")}`,
+                    src: images[showImageIndex],
+                },
+                images.length > 1 && {
+                    tag: "div",
+                    class: "carousel-bullets",
+                    contents: images.map((_, i) => {
+                        const active = showImageIndex === i;
+                        return {
+                            tag: "span",
+                            class: `bullet ${active ? "active" : ""}`,
+                            onclick: this.setImageIndex.bind(this, i),
+                        };
+                    }),
+                },
+            ],
+        };
+    }
+}
+
+module.exports = ImageCarousel;
+
+},{"object-to-html-renderer":3}],5:[function(require,module,exports){
+"use strict";
+
+const { fetchjson, fetchtext } = require("./fetch");
+
+function getArticleBody(text) {
+    return text.replaceAll("\n", "<br/>");
+}
+
+function getArticleDate(date) {
+    return `${date.getDate()}-${date.getMonth() + 1}-${date.getFullYear()}`;
+}
+
+function loadArticles(dir_url) {
+    return new Promise((resolve, reject) => {
+        fetchjson(`${dir_url}/index.json`)
+            .then(json => {
+                Promise.all(
+                    json.articles.map(async artDir => {
+                        const artPath = `${artDir}/${artDir}.json`;
+                        const art = await fetchjson(`${dir_url}/${artPath}`);
+                        const tmpSplit = artPath.split("/");
+                        tmpSplit.pop();
+                        const absArtPath = `${dir_url}/${tmpSplit.join("/")}`;
+                        return Object.assign(art, { path: absArtPath });
+                    })
+                )
+                    .then(articles => {
+                        populateArticles(articles)
+                            .then(completeArticles => resolve(completeArticles))
+                            .catch(e => reject(e));
+                    })
+                    .catch(e => reject(e));
+            })
+            .catch(e => console.log(e));
+    });
+}
+
+function populateArticles(articles) {
+    return new Promise((resolve, reject) => {
+        Promise.all(
+            articles.map(async article => {
+                if (article.body.indexOf("<file>") !== -1) {
+                    const txtPath = article.body.replace("<file>", "");
+                    const textValue = await fetchtext(`${article.path}/${txtPath}`);
+                    article.body = textValue;
+                    article.date = article.date ? new Date(article.date) : undefined;
+                }
+                return article;
+            })
+        )
+            .then(completeArticles => resolve(completeArticles.sort((a, b) => b.date - a.date)))
+            .catch(e => reject(e));
+    });
+}
+
+module.exports = {
+    loadArticles,
+    getArticleBody,
+    getArticleDate,
+    populateArticles,
+};
+
+},{"./fetch":6}],6:[function(require,module,exports){
+"use strict";
+
+function fetchjson(url) {
+    return new Promise((resolve, reject) => {
+        fetch(url)
+            .then(r => r.json())
+            .then(r => resolve(r))
+            .catch(e => reject(e));
+    });
+}
+
+function fetchtext(url) {
+    return new Promise((resolve, reject) => {
+        fetch(url)
+            .then(r => r.text())
+            .then(r => resolve(r))
+            .catch(e => reject(e));
+    });
+}
+
+module.exports = {
+    fetchjson,
+    fetchtext,
+};
+
+},{}],7:[function(require,module,exports){
+"use strict";
+
+class WebPage {
+    constructor(args) {
+        Object.assign(this, args);
+    }
+}
+
+module.exports = WebPage;
+},{}],8:[function(require,module,exports){
+"use strict";
+
+const ImageCarousel = require("../../../generic-components/image-carousel");
+const { getArticleBody } = require("../../../lib/article-utils");
+
+class TeamMember {
+    constructor(props) {
+        this.props = props;
+    }
+
+    render() {
+        const { title, subtitle, body, images, path } = this.props;
+        return {
+            tag: "div",
+            class: "team-member",
+            typeof: "Person",
+            property: "author",
+            contents: [
+                {
+                    tag: "div",
+                    class: "team-member-img",
+                    contents: [
+                        {
+                            tag: "img",
+                            alt: `ìmage team member ${title}`,
+                            src: images.map(im => `${path}/images/${im}`)[0],
+                            property: "image",
+                        },
+                    ],
+                },
+                {
+                    tag: "h3",
+                    class: "team-member-title",
+                    contents: title,
+                    property: "name",
+                },
+                {
+                    tag: "strong",
+                    class: "team-member-subtitle",
+                    contents: subtitle,
+                    property: "jobTitle",
+                },
+                {
+                    tag: "p",
+                    class: "team-member-body",
+                    contents: getArticleBody(body),
+                    property: "description",
+                },
+            ],
+        };
+    }
+}
+
+class GameArticle {
+    constructor(props) {
+        this.props = props;
+    }
+
+    render() {
+        const {
+            title,
+            tags,
+            body,
+            subtitle,
+            images,
+            path,
+            team_subarticles,
+            image_banner,
+        } = this.props;
+        return {
+            tag: "article",
+            typeof: "VideoGame",
+            additionalType: "Article",
+            class: "game-article",
+            contents: [
+                {
+                    tag: "h2",
+                    property: "name",
+                    class: "game-title",
+                    contents: title,
+                },
+                {
+                    tag: "div",
+                    class: "game-banner",
+                    contents: [
+                        { tag: "img", class: "pixelated", src: `${path}/images/${image_banner}` },
+                    ],
+                },
+                {
+                    tag: "div",
+                    class: "game-tags",
+                    contents: tags.map(tag => {
+                        return { tag: "span", contents: tag, property: "about" };
+                    }),
+                },
+                {
+                    tag: "h3",
+                    class: "game-subtitle",
+                    contents: subtitle,
+                    property: "alternativeHeadline",
+                },
+                {
+                    tag: "div",
+                    class: "game-description",
+                    property: "description",
+                    contents: getArticleBody(body),
+                },
+                new ImageCarousel({ images: images.map(img => `${path}/images/${img}`) }).render(),
+                {
+                    tag: "div",
+                    class: "game-team",
+                    contents: [
+                        {
+                            tag: "h2",
+                            contents: "L'équipe",
+                        },
+                        {
+                            tag: "div",
+                            class: "team-members",
+                            contents: team_subarticles.map(tsa =>
+                                new TeamMember({ ...tsa }).render()
+                            ),
+                        },
+                    ],
+                },
+            ],
+        };
+    }
+}
+
+module.exports = GameArticle;
+
+},{"../../../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("object-to-html-renderer")
+const GameArticle = require("./game-article");
+
+class GameArticles {
+    constructor(props) {
+        this.props = props;
+        this.state = {
+            articles: [],
+        };
+        this.id = performance.now();
+        this.loadArticles();
+    }
+
+    loadArticles() {
+        loadArticles(`${articles_url}games`)
+            .then(articles => {
+                Promise.all(
+                    articles.map(async a => {
+                        if (a.team_subarticles) {
+                            a.team_subarticles = await populateArticles(
+                                a.team_subarticles.map(sa => Object.assign(sa, { path: a.path }))
+                            );
+                        }
+                        return a;
+                    })
+                ).then(completeArticles => {
+                    this.state.articles = completeArticles;
+                    this.refresh();
+                });
+            })
+            .catch(e => console.log(e));
+    }
+
+    renderPlaceholder() {
+        return {
+            tag: "article",
+            class: "placeholder",
+            contents: [{ tag: "div" }, { tag: "div" }],
+        };
+    }
+
+    refresh() {
+        objectHtmlRenderer.subRender(this.render(), document.getElementById(this.id), {
+            mode: "replace",
+        });
+    }
+
+    render() {
+        const { articles } = this.state;
+        return {
+            tag: "section",
+            class: "game-articles page-contents-center",
+            id: this.id,
+            contents:
+                articles.length > 0
+                    ? articles.map(article => new GameArticle({ ...article }).render())
+                    : [this.renderPlaceholder()],
+        };
+    }
+}
+
+module.exports = GameArticles;
+
+},{"../../../../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");
+const WebPage = require("../../lib/web-page");
+const GameArticles = require("./components/game-articles");
+
+class GamesPage extends WebPage {
+    render() {
+        return {
+            tag: "div",
+            id: "games-page",
+            contents: [
+                {
+                    tag: "div",
+                    class: "page-header logo-left",
+                    contents: [
+                        {
+                            tag: "div",
+                            class: "page-contents-center grid-wrapper",
+                            contents: [
+                                {
+                                    tag: "div",
+                                    class: "logo",
+                                    contents: [
+                                        {
+                                            tag: "img",
+                                            alt: "image game controller",
+                                            src: `${images_url}game_controller.svg`,
+                                        },
+                                    ],
+                                },
+                                { tag: "h1", contents: "Jeux" },
+                                {
+                                    tag: "p",
+                                    contents: `Création de jeux vidéos indépendants.
+                                    <br/>Jeux web, PC et projets en cours de développement`,
+                                },
+                            ],
+                        },
+                    ],
+                },
+                new GameArticles().render(),
+            ],
+        };
+    }
+}
+
+module.exports = GamesPage;
+
+},{"../../../constants":2,"../../lib/web-page":7,"./components/game-articles":9}],11:[function(require,module,exports){
+"use strict";
+
+"use strict";
+const runPage = require("../../run-page");
+const GamesPage = require("./games");
+runPage(GamesPage);
+
+},{"../../run-page":12,"./games":10}],12:[function(require,module,exports){
+"use strict";
+
+const objectHtmlRenderer = require("object-to-html-renderer")
+const Template = require("./template/template");
+
+module.exports = function runPage(PageComponent) {
+    const template = new Template({ page: new PageComponent() });
+    objectHtmlRenderer.setRenderCycleRoot(template);
+    objectHtmlRenderer.renderCycle();
+};
+
+},{"./template/template":14,"object-to-html-renderer":3}],13:[function(require,module,exports){
+"use strict";
+
+const { images_url } = require("../../../constants");
+
+const NAV_MENU_ITEMS = [
+    { url: "/games/", text: "Jeux" },
+    {
+        url: "/education/",
+        text: "Pédagogie",
+        // submenu: [
+        //     { url: "/gamedev", text: "Création de jeux vidéo" },
+        // ]
+    },
+    { url: "/software-development/", text: "Software" }
+];
+
+class NavBar {
+    constructor() {
+        this.initEventHandlers();
+    }
+
+    handleBurgerClick() {
+        document.getElementById("nav-menu-list").classList.toggle("responsive-show");
+    }
+
+    initEventHandlers() {
+        window.addEventListener("click", event => {
+            if (
+                event.target.id !== "nav-menu-list" &&
+                !event.target.classList.contains("burger") &&
+                !event.target.parentNode.classList.contains("burger")
+            ) {
+                document.getElementById("nav-menu-list").classList.remove("responsive-show");
+            }
+        });
+    }
+
+    renderHome() {
+        return {
+            tag: "div",
+            class: "home",
+            contents: [
+                {
+                    tag: "a",
+                    href: "/",
+                    contents: [
+                        {
+                            tag: "img",
+                            alt: "Logo Kuadrado",
+                            src: `${images_url}logo_kuadrado.svg`,
+                        },
+                        {
+                            tag: "img",
+                            alt: "Kuadrado Software",
+                            class: "logo-text",
+                            src: `${images_url}logo_kuadrado_txt.svg`,
+                        },
+                    ],
+                },
+            ],
+        };
+    }
+
+    renderMenu(menuItemsArray, isSubmenu = false, parentUrl = "") {
+        return {
+            tag: "ul",
+            id: "nav-menu-list",
+            class: isSubmenu ? "submenu" : "",
+            contents: menuItemsArray.map(item => {
+                const { url, text, submenu } = item;
+                const href = `${parentUrl}${url}`;
+                return {
+                    tag: "li",
+                    class: !isSubmenu && window.location.pathname === href ? "active" : "",
+                    contents: [
+                        {
+                            tag: "a",
+                            href,
+                            contents: text,
+                        },
+                    ].concat(submenu ? [this.renderMenu(submenu, true, url)] : []),
+                };
+            }),
+        };
+    }
+
+    renderResponsiveBurger() {
+        return {
+            tag: "div",
+            class: "burger",
+            onclick: this.handleBurgerClick.bind(this),
+            contents: [{ tag: "span", contents: "···" }],
+        };
+    }
+
+    render() {
+        return {
+            tag: "nav",
+            contents: [
+                this.renderHome(),
+                this.renderResponsiveBurger(),
+                this.renderMenu(NAV_MENU_ITEMS),
+            ],
+        };
+    }
+}
+
+module.exports = NavBar;
+
+},{"../../../constants":2}],14:[function(require,module,exports){
+"use strict";
+
+const { in_construction } = require("../../config");
+const { images_url } = require("../../constants");
+const NavBar = require("./components/navbar");
+
+class Template {
+    constructor(props) {
+        this.props = props;
+    }
+    render() {
+        return {
+            tag: "main",
+            contents: [
+                {
+                    tag: "header",
+                    contents: [new NavBar().render()],
+                },
+                in_construction && {
+                    tag: "section",
+                    class: "warning-banner",
+                    contents: [
+                        {
+                            tag: "strong",
+                            class: "page-contents-center",
+                            contents: "Site en construction ...",
+                        },
+                    ],
+                },
+                {
+                    tag: "section",
+                    id: "page-container",
+                    contents: [this.props.page.render()],
+                },
+                {
+                    tag: "footer",
+                    contents: [
+                        {
+                            tag: "div",
+                            class: "logo",
+                            contents: [
+                                {
+                                    tag: "img",
+                                    alt: `logo Kuadrado`,
+                                    src: `${images_url}logo_kuadrado.svg`,
+                                },
+                                {
+                                    tag: "img",
+                                    class: "text-logo",
+                                    alt: "Kuadrado Software",
+                                    src: `${images_url}logo_kuadrado_txt.svg`,
+                                },
+                            ],
+                        },
+                        {
+                            tag: "span",
+                            contents: "32 rue Simon Vialet, 07240 Vernoux en Vivarais. Ardèche, France",
+                        },
+                        {
+                            tag: "div",
+                            contents: [
+                                { tag: "strong", contents: "<blue>Contact : </blue>" },
+                                {
+                                    tag: "a",
+                                    href: "mailto:contact@kuadrado-software.fr",
+                                    contents: "contact@kuadrado-software.fr",
+                                },
+                            ],
+                        },
+                        {
+                            tag: "div",
+                            class: "social",
+                            contents: [
+                                {
+                                    tag: "strong",
+                                    contents: "<blue>Sur les réseaux : </blue>",
+                                },
+                                {
+                                    tag: "a",
+                                    href: "https://www.linkedin.com/company/kuadrado-software",
+                                    target: "_blank",
+                                    contents: "in",
+                                    title: "Linkedin",
+                                },
+                                {
+                                    tag: "a",
+                                    href: "https://twitter.com/KuadradoSoft",
+                                    target: "_blank",
+                                    contents: "t",
+                                    title: "Twitter",
+                                    style_rules: { fontFamily: "serif" },
+                                },
+                            ],
+                        },
+                        {
+                            tag: "span",
+                            contents: `Copyright © ${new Date()
+                                .getFullYear()} Kuadrado Software | 
+                                Toutes les images du site ont été réalisées par mes soins et peuvent être réutilisées pour un usage personnel.`,
+                        },
+                    ],
+                },
+            ],
+        };
+    }
+}
+
+module.exports = Template;
+
+},{"../../config":1,"../../constants":2,"./components/navbar":13}]},{},[11]);
diff --git a/public/main.js b/public/main.js
index 82098e2b804afb1d1fa2d65807e4d06282780699..70aa45d3570158d901132eae3675066fe100f9fc 100644
--- a/public/main.js
+++ b/public/main.js
@@ -1,10 +1,501 @@
-!function n(r,a,o){function i(t,e){if(!a[t]){if(!r[t]){var s="function"==typeof require&&require;if(!e&&s)return s(t,!0);if(c)return c(t,!0);throw(s=new Error("Cannot find module '"+t+"'")).code="MODULE_NOT_FOUND",s}s=a[t]={exports:{}},r[t][0].call(s.exports,function(e){return i(r[t][1][e]||e)},s,s.exports,n,r,a,o)}return a[t].exports}for(var c="function"==typeof require&&require,e=0;e<o.length;e++)i(o[e]);return i}({1:[function(e,t,s){t.exports={getServerUrl:function(){return`${location.origin}${"/"!==location.origin.charAt(location.origin.length-1)?"/":""}`},build:{protected_dirs:["assets","style","articles"],default_meta_keys:["title","description","image","open_graph","json_ld"]}}},{}],2:[function(e,t,s){const{getServerUrl:n}=e("./config");t.exports={images_url:`${n()}assets/images/`,articles_url:`${n()}articles/`}},{"./config":1}],3:[function(e,t,s){"use strict";t.exports={setRenderCycleRoot(e){this.renderCycleRoot=e},objectToHtml:function t(s){var{tag:e}=s;const n=document.createElement(e),r=["tag","contents","style_rules","state"];return Object.keys(s).filter(e=>!r.includes(e)).forEach(e=>{"class"===e?n.classList.add(...s[e].split(" ").filter(e=>""!==e)):n[e]=s[e]}),s.contents&&"string"==typeof s.contents?n.innerHTML=s.contents:s.contents&&0<s.contents.length&&s.contents.forEach(e=>{switch(typeof e){case"string":n.innerHTML=e;break;case"object":n.appendChild(t(e))}}),s.style_rules&&Object.keys(s.style_rules).forEach(e=>{n.style[e]=s.style_rules[e]}),n},renderCycle:function(){this.subRender(this.renderCycleRoot.render(),document.getElementsByTagName("main")[0],{mode:"replace"})},subRender(e,t,s={mode:"append"}){var n=this.objectToHtml(e);switch(s.mode){case"append":t.appendChild(n);break;case"override":t.innerHTML="",t.appendChild(n);break;case"insert-before":t.insertBefore(n,t.childNodes[s.insertIndex]);break;case"adjacent":t.insertAdjacentHTML(s.insertLocation,n);break;case"replace":t.parentNode.replaceChild(n,t);break;case"remove":t.remove()}}}},{}],4:[function(e,t,s){"use strict";const n=e("object-to-html-renderer");t.exports=class{constructor(e){this.props=e,this.id=performance.now(),this.state={showImageIndex:0},this.RUN_INTERVAL=5e3,1<this.props.images.length&&this.run()}run(){this.runningInterval=setInterval(()=>{var{showImageIndex:e}=this.state,{images:t}=this.props;this.state.showImageIndex=e<t.length-1?++e:0,this.refreshImage()},this.RUN_INTERVAL)}setImageIndex(e){clearInterval(this.runningInterval),this.state.showImageIndex=e,this.refreshImage()}refreshImage(){n.subRender(this.render(),document.getElementById(this.id),{mode:"replace"})}render(){const{showImageIndex:s}=this.state,{images:e}=this.props;return{tag:"div",id:this.id,class:"image-carousel",contents:[{tag:"img",property:"image",alt:`image carousel ${e[s].replace(/\.[A-Za-z]+/,"")}`,src:e[s]},1<e.length&&{tag:"div",class:"carousel-bullets",contents:e.map((e,t)=>{return{tag:"span",class:`bullet ${s===t?"active":""}`,onclick:this.setImageIndex.bind(this,t)}})}]}}}},{"object-to-html-renderer":3}],5:[function(e,t,s){"use strict";t.exports=class{render(){return{tag:"section",class:"kuadrado-values",contents:[{tag:"div",class:"page-contents-center",contents:[{tag:"h2",contents:"<blue>Éthique</blue>"},{tag:"ul",class:"values-list",contents:[["<emoji>📖</emoji> <blue>Partage des connaissances</blue>",`Pour sortir de l'élitisme de l'ingénierie, pour sortir de la domination par l'obscurantisme et de la consommation aveugle, 
-                                    pour aller plus loin ensemble, le partage du savoir est fondamental.`],["<emoji>💻</emoji> <blue>Logiciels libres et open source</blue>",`Toutes mes productions numériques, jeux vidéo, web, software, sont 
+(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
+function getServerUrl() {
+    return `${location.origin}${location.origin.charAt(location.origin.length - 1) !== "/" ? "/" : ""
+        }`;
+}
+
+module.exports = {
+    getServerUrl,
+    build: {
+        protected_dirs: ["assets", "style", "articles"],
+        default_meta_keys: ["title", "description", "image", "open_graph", "json_ld"],
+    },
+};
+
+},{}],2:[function(require,module,exports){
+const { getServerUrl } = require("./config");
+
+module.exports = {
+    images_url: `${getServerUrl()}assets/images/`,
+    articles_url: `${getServerUrl()}articles/`,
+};
+
+},{"./config":1}],3:[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;
+        }
+    },
+};
+
+},{}],4:[function(require,module,exports){
+"use strict";
+
+const objectHtmlRenderer = require("object-to-html-renderer")
+
+class ImageCarousel {
+    constructor(props) {
+        this.props = props;
+        this.id = performance.now();
+        this.state = {
+            showImageIndex: 0,
+        };
+        this.RUN_INTERVAL = 5000;
+        this.props.images.length > 1 && this.run();
+    }
+
+    run() {
+        this.runningInterval = setInterval(() => {
+            let { showImageIndex } = this.state;
+            const { images } = this.props;
+            this.state.showImageIndex = showImageIndex < images.length - 1 ? ++showImageIndex : 0;
+            this.refreshImage();
+        }, this.RUN_INTERVAL);
+    }
+
+    setImageIndex(i) {
+        clearInterval(this.runningInterval);
+        this.state.showImageIndex = i;
+        this.refreshImage();
+    }
+
+    refreshImage() {
+        objectHtmlRenderer.subRender(this.render(), document.getElementById(this.id), {
+            mode: "replace",
+        });
+    }
+
+    render() {
+        const { showImageIndex } = this.state;
+        const { images } = this.props;
+        return {
+            tag: "div",
+            id: this.id,
+            class: "image-carousel",
+            contents: [
+                {
+                    tag: "img",
+                    property: "image",
+                    alt: `image carousel ${images[showImageIndex].replace(/\.[A-Za-z]+/, "")}`,
+                    src: images[showImageIndex],
+                },
+                images.length > 1 && {
+                    tag: "div",
+                    class: "carousel-bullets",
+                    contents: images.map((_, i) => {
+                        const active = showImageIndex === i;
+                        return {
+                            tag: "span",
+                            class: `bullet ${active ? "active" : ""}`,
+                            onclick: this.setImageIndex.bind(this, i),
+                        };
+                    }),
+                },
+            ],
+        };
+    }
+}
+
+module.exports = ImageCarousel;
+
+},{"object-to-html-renderer":3}],5:[function(require,module,exports){
+"use strict";
+
+class KuadradoValues {
+    render() {
+        return {
+            tag: "section",
+            class: "kuadrado-values",
+            contents: [
+                {
+                    tag: "div",
+                    class: "page-contents-center",
+                    contents: [
+                        {
+                            tag: "h2",
+                            contents: "<blue>Éthique</blue>",
+                        },
+                        {
+                            tag: "ul",
+                            class: "values-list",
+                            contents: [
+                                [
+                                    "<emoji>📖</emoji> <blue>Partage des connaissances</blue>",
+                                    `Pour sortir de l'élitisme de l'ingénierie, pour sortir de la domination par l'obscurantisme et de la consommation aveugle, 
+                                    pour aller plus loin ensemble, le partage du savoir est fondamental.`,
+                                ],
+                                [
+                                    "<emoji>💻</emoji> <blue>Logiciels libres et open source</blue>",
+                                    `Toutes mes productions numériques, jeux vidéo, web, software, sont 
                                     <b><a href="https://fr.wikipedia.org/wiki/Logiciel_libre" target="_blank">libres et open source</a></b>.
-                                    <br/> ainsi que les outils engagés dans leur fabrication.`],["<emoji>🌿</emoji> <blue>Écologie</blue>",`Nous vivons une époque ou l'utilisation de la technologie connaît une croissance exponentielle notament
+                                    <br/> ainsi que les outils engagés dans leur fabrication.`,
+                                ],
+                                [
+                                    "<emoji>🌿</emoji> <blue>Écologie</blue>",
+                                    `Nous vivons une époque ou l'utilisation de la technologie connaît une croissance exponentielle notament
                                     à travers internet.
                                     <br/>Il est primordial de construire le numérique dans une direction de légèreté et d'économie de 
-                                    ressources.`]].map(e=>{var[t,e]=e;return{tag:"li",contents:[{tag:"h3",contents:t},{tag:"p",contents:e}]}})}]}]}}}},{}],6:[function(e,t,s){"use strict";const{articles_url:n}=e("../../constants"),r=e("object-to-html-renderer"),a=e("../generic-components/image-carousel"),{loadArticles:o,getArticleDate:i,getArticleBody:c}=e("../lib/article-utils");t.exports=class{constructor(){this.id=performance.now().toString(),this.state={loading:!0,articles:[],showArticleIndex:-1},this.loadArticles()}loadArticles(){o(`${n}news`).then(e=>{this.state.articles=e,this.state.showArticleIndex=this.state.articles.length-1,this.refresh()})}refresh(){r.subRender(this.render(),document.getElementById(this.id),{mode:"replace"})}renderArticle(t){return{tag:"article",class:`${t.images?"grid-2":"grid-1"}`,typeof:"Article",contents:[{tag:"div",class:"date",contents:[{tag:"time",property:"datePublished",contents:i(t.date)}]},{tag:"div",class:"title",contents:[{tag:"h3",contents:t.title,property:"headline"}]},{tag:"div",class:"subtitle",contents:[{tag:"strong",contents:t.subtitle,property:"alternativeHeadline"}]},{tag:"div",class:"body",contents:[{tag:"p",contents:c(t.body),property:"articleBody"}]},t.images&&new a({images:t.images.map(e=>`${t.path}/images/${e}`)}).render()]}}renderArticlePlaceholder(){return{tag:"article",class:"article-placeholder",contents:[{tag:"div",class:"date"},{tag:"div",class:"title"},{tag:"div",class:"subtitle"},{tag:"div",class:"body"},{tag:"div",class:"image-carousel"}]}}handleChangeArticle(e){let{showArticleIndex:t,articles:s}=this.state;t="prev"===e?0<=t-1?t-1:0:t+1<=s.length-1?t+1:s.length-1,this.state.showArticleIndex=t,this.refresh()}render(){var{articles:e,showArticleIndex:t}=this.state,s=t<e.length-1,n=0<t;return{tag:"div",id:this.id,class:"articles-displayer page-contents-center",contents:0<e.length?[this.renderArticle(e[t]),{tag:"div",class:"prev-next-buttons",contents:[{tag:"button",class:`prev-btn ${n?"active":"disabled"}`,contents:"Précédent",onclick:this.handleChangeArticle.bind(this,"prev")},{tag:"button",class:`next-btn ${s?"active":"disabled"}`,contents:"Suivant",onclick:this.handleChangeArticle.bind(this,"next")}]}]:[this.renderArticlePlaceholder()]}}}},{"../../constants":2,"../generic-components/image-carousel":4,"../lib/article-utils":10,"object-to-html-renderer":3}],7:[function(e,t,s){"use strict";const{images_url:n}=e("../../constants");t.exports=class{constructor(e){this.props=e}render(){return{tag:"a",class:"theme-card",href:this.props.href,contents:[{tag:"div",class:"card-img",contents:[{tag:"img",alt:`thematic image ${this.props.img.replace(/\.[A-Za-z]+/,"")}`,src:`${n}${this.props.img}`}]},{tag:"div",class:"card-title",contents:[{tag:"h2",class:"section-title",contents:this.props.title}]},{tag:"div",class:"card-description",contents:[{tag:"p",contents:this.props.description}]}]}}}},{"../../constants":2}],8:[function(e,t,s){"use strict";t.exports=class{render(){return{tag:"section",id:"whoami",contents:[{tag:"div",class:"page-contents-center",contents:[{tag:"h2",contents:"Qui sommes-nous-je ?"},{tag:"div",class:"presentation-card",contents:[{tag:"div",class:"header",contents:[{tag:"div",class:"pic",contents:[{tag:"img",alt:"portrait Pierre Jarriges pixel art by Lucie Ventadour",src:"assets/images/pijar_profile_lt_square.png"}]},{tag:"div",class:"header-text",contents:[{tag:"h3",contents:"Pierre Jarriges"},{tag:"h4",contents:"Artiste, auteur BD, compositeur, développeur informatique"},{tag:"strong",contents:"Créateur de <blue>Kuadrado Software</blue> en Février 2021."}]}]},{tag:"div",class:"body",contents:[{tag:"p",contents:`
+                                    ressources.`,
+                                ],
+                            ].map(v => {
+                                const [title, body] = v;
+                                return {
+                                    tag: "li",
+                                    contents: [
+                                        { tag: "h3", contents: title },
+                                        { tag: "p", contents: body },
+                                    ],
+                                };
+                            }),
+                        },
+                    ],
+                },
+            ],
+        };
+    }
+}
+
+module.exports = KuadradoValues;
+
+},{}],6:[function(require,module,exports){
+"use strict";
+
+const { articles_url } = require("../../constants");
+const objectHtmlRenderer = require("object-to-html-renderer");
+const ImageCarousel = require("../generic-components/image-carousel");
+const { loadArticles, getArticleDate, getArticleBody } = require("../lib/article-utils");
+
+class NewsArticles {
+    constructor() {
+        this.id = performance.now().toString();
+        this.state = {
+            loading: true,
+            articles: [],
+            showArticleIndex: -1,
+        };
+        this.loadArticles();
+    }
+
+    loadArticles() {
+        loadArticles(`${articles_url}news`).then(articles => {
+            this.state.articles = articles;
+            this.state.showArticleIndex = this.state.articles.length - 1;
+            this.refresh();
+        });
+    }
+
+    refresh() {
+        objectHtmlRenderer.subRender(this.render(), document.getElementById(this.id), {
+            mode: "replace",
+        });
+    }
+
+    renderArticle(articleData) {
+        return {
+            tag: "article",
+            class: `${articleData.images ? "grid-2" : "grid-1"}`,
+            typeof: "Article",
+            contents: [
+                {
+                    tag: "div",
+                    class: "date",
+                    contents: [
+                        {
+                            tag: "time",
+                            property: "datePublished",
+                            contents: getArticleDate(articleData.date),
+                        },
+                    ],
+                },
+                {
+                    tag: "div",
+                    class: "title",
+                    contents: [
+                        {
+                            tag: "h3",
+                            contents: articleData.title,
+                            property: "headline",
+                        },
+                    ],
+                },
+                {
+                    tag: "div",
+                    class: "subtitle",
+                    contents: [
+                        {
+                            tag: "strong",
+                            contents: articleData.subtitle,
+                            property: "alternativeHeadline",
+                        },
+                    ],
+                },
+                {
+                    tag: "div",
+                    class: "body",
+                    contents: [
+                        {
+                            tag: "p",
+                            contents: getArticleBody(articleData.body),
+                            property: "articleBody",
+                        },
+                    ],
+                },
+                articleData.images &&
+                    new ImageCarousel({
+                        images: articleData.images.map(img => `${articleData.path}/images/${img}`),
+                    }).render(),
+            ],
+        };
+    }
+
+    renderArticlePlaceholder() {
+        return {
+            tag: "article",
+            class: "article-placeholder",
+            contents: [
+                { tag: "div", class: "date" },
+                { tag: "div", class: "title" },
+                { tag: "div", class: "subtitle" },
+                { tag: "div", class: "body" },
+                { tag: "div", class: "image-carousel" },
+            ],
+        };
+    }
+
+    handleChangeArticle(dir) {
+        let { showArticleIndex, articles } = this.state;
+        showArticleIndex =
+            dir === "prev"
+                ? showArticleIndex - 1 >= 0
+                    ? showArticleIndex - 1
+                    : 0
+                : showArticleIndex + 1 <= articles.length - 1
+                ? showArticleIndex + 1
+                : articles.length - 1;
+        this.state.showArticleIndex = showArticleIndex;
+        this.refresh();
+    }
+
+    render() {
+        const { articles, showArticleIndex } = this.state,
+            showNext = showArticleIndex < articles.length - 1,
+            showPrev = showArticleIndex > 0;
+        return {
+            tag: "div",
+            id: this.id,
+            class: "articles-displayer page-contents-center",
+            contents:
+                articles.length > 0
+                    ? [
+                          this.renderArticle(articles[showArticleIndex]),
+                          {
+                              tag: "div",
+                              class: "prev-next-buttons",
+                              contents: [
+                                  {
+                                      tag: "button",
+                                      class: `prev-btn ${!showPrev ? "disabled" : "active"}`,
+                                      contents: "Précédent",
+                                      onclick: this.handleChangeArticle.bind(this, "prev"),
+                                  },
+                                  {
+                                      tag: "button",
+                                      class: `next-btn ${!showNext ? "disabled" : "active"}`,
+                                      contents: "Suivant",
+                                      onclick: this.handleChangeArticle.bind(this, "next"),
+                                  },
+                              ],
+                          },
+                      ]
+                    : [this.renderArticlePlaceholder()],
+        };
+    }
+}
+
+module.exports = NewsArticles;
+
+},{"../../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");
+
+class ThemeCard {
+    constructor(props) {
+        this.props = props;
+    }
+
+    render() {
+        return {
+            tag: "a",
+            class: "theme-card",
+            href: this.props.href,
+            contents: [
+                {
+                    tag: "div",
+                    class: "card-img",
+                    contents: [{ tag: "img", alt:`thematic image ${this.props.img.replace(/\.[A-Za-z]+/, "")}`,src: `${images_url}${this.props.img}` }],
+                },
+                {
+                    tag: "div",
+                    class: "card-title",
+                    contents: [{ tag: "h2", class: "section-title", contents: this.props.title }],
+                },
+                {
+                    tag: "div",
+                    class: "card-description",
+                    contents: [{ tag: "p", contents: this.props.description }],
+                },
+            ],
+        };
+    }
+}
+
+module.exports = ThemeCard;
+
+},{"../../constants":2}],8:[function(require,module,exports){
+"use strict";
+
+class WhoAmI {
+    render() {
+        return {
+            tag: "section",
+            id: "whoami",
+            contents: [
+                {
+                    tag: "div",
+                    class: "page-contents-center",
+                    contents: [
+                        {
+                            tag: "h2",
+                            contents: "Qui sommes-nous-je ?",
+                        },
+                        {
+                            tag: "div",
+                            class: "presentation-card",
+                            contents: [
+                                {
+                                    tag: "div",
+                                    class: "header",
+                                    contents: [
+                                        {
+                                            tag: "div",
+                                            class: "pic",
+                                            contents: [
+                                                {
+                                                    tag: "img",
+                                                    alt:
+                                                        "portrait Pierre Jarriges pixel art by Lucie Ventadour",
+                                                    src: "assets/images/pijar_profile_lt_square.png",
+                                                },
+                                            ],
+                                        },
+                                        {
+                                            tag: "div",
+                                            class: "header-text",
+                                            contents: [
+                                                {
+                                                    tag: "h3",
+                                                    contents: "Pierre Jarriges",
+                                                },
+                                                {
+                                                    tag: "h4",
+                                                    contents:
+                                                        "Artiste, auteur BD, compositeur, développeur informatique",
+                                                },
+                                                {
+                                                    tag: "strong",
+                                                    contents:
+                                                        "Créateur de <blue>Kuadrado Software</blue> en Février 2021.",
+                                                },
+                                            ],
+                                        },
+                                    ],
+                                },
+                                {
+                                    tag: "div",
+                                    class: "body",
+                                    contents: [
+                                        {
+                                            tag: "p",
+                                            contents: `
                                             “ La création de <b><blue>Kuadrado Software</blue></b> vient de la volonté de développer différents axes ensembles :
                                             <br /><br />
                                             <emoji>🎮</emoji> D'une part exprimer une passion en créant des <b>jeux vidéo indépendants</b> sur un modèle léger et artisanal dans 
@@ -24,5 +515,467 @@
                                             dans le même état d'esprit, former des équipes de travail et de création, et s'inscrire dans un tissu 
                                             local de savoir-faire, tout en gardant un modèle d'entreprise basé sur l'indépendance, afin de rester aussi léger, libéral, 
                                             et modulaire que possible.”
-                                            `}]}]}]}]}}}},{}],9:[function(e,t,s){"use strict";const{images_url:n}=e("../constants"),r=e("./home-page-components/kuadrado-values"),a=e("./home-page-components/news-articles"),o=e("./home-page-components/theme-card"),i=e("./home-page-components/whoami");class c extends e("./lib/web-page"){render(){return{tag:"div",id:"home-page",contents:[{tag:"div",class:"page-header",contents:[{tag:"div",class:"big-logo page-contents-center",contents:[{tag:"img",alt:"logo Kuadrado",src:`${n}logo_kuadrado.svg`},{tag:"img",class:"logo-text",alt:"Kuadrado",src:`${n}logo_kuadrado_txt.svg`}]},{tag:"h1",contents:"Kuadrado Software",class:"page-contents-center"},{tag:"p",class:"page-contents-center",contents:"Créations numériques, jeux vidéo, pédagogie."},{tag:"ul",class:"philo-bubbles",contents:["Simplicité","Légèreté","Écologie"].map(e=>({tag:"li",contents:[{tag:"span",contents:e}]}))}]},{tag:"section",class:"page-contents-center poles",contents:[{title:"Jeux",img:"game_controller.svg",href:"/games/",description:"Créations vidéoludiques, jeux web et jeux PC, projets en cours."},{title:"Pédagogie",img:"brain.svg",href:"/education/",description:"S'approprier la technologie par le partage de connaissances."},{title:"Software",img:"meca_proc.svg",href:"/software-development/",description:"R&D, projets expérimentaux, web et outillage logiciel"}].map(e=>new o(e).render())},{tag:"section",class:"page-philo",contents:[{tag:"p",class:"page-contents-center",contents:"Travailler pour le plaisir de créer, de maîtriser et de comprendre."}]},{tag:"section",class:"page-contents-center",id:"news",contents:[{tag:"h2",contents:"Actu",class:"section-title"},(new a).render()]},(new r).render(),(new i).render()]}}}t.exports=c},{"../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(e,t,s){"use strict";const{fetchjson:a,fetchtext:n}=e("./fetch");function o(e){return new Promise((t,s)=>{Promise.all(e.map(async e=>{var t;return-1!==e.body.indexOf("<file>")&&(t=e.body.replace("<file>",""),t=await n(`${e.path}/${t}`),e.body=t,e.date=e.date?new Date(e.date):void 0),e})).then(e=>t(e.sort((e,t)=>e.date-t.date))).catch(e=>s(e))})}t.exports={loadArticles:function(r){return new Promise((t,s)=>{a(`${r}/index.json`).then(e=>{Promise.all(e.articles.map(async e=>{const t=`${e}/${e}.json`;var s=await a(`${r}/${t}`);const n=t.split("/");n.pop();e=`${r}/${n.join("/")}`;return Object.assign(s,{path:e})})).then(e=>{o(e).then(e=>t(e)).catch(e=>s(e))}).catch(e=>s(e))}).catch(e=>console.log(e))})},getArticleBody:function(e){return e.replaceAll("\n","<br/>")},getArticleDate:function(e){return`${e.getDate()}-${e.getMonth()+1}-${e.getFullYear()}`},populateArticles:o}},{"./fetch":11}],11:[function(e,t,s){"use strict";t.exports={fetchjson:function(e){return new Promise((t,s)=>{fetch(e).then(e=>e.json()).then(e=>t(e)).catch(e=>s(e))})},fetchtext:function(e){return new Promise((t,s)=>{fetch(e).then(e=>e.text()).then(e=>t(e)).catch(e=>s(e))})}}},{}],12:[function(e,t,s){"use strict";t.exports=class{constructor(e){Object.assign(this,e)}}},{}],13:[function(e,t,s){"use strict";var n=e("./homepage");const r=e("./run-page");r(n)},{"./homepage":9,"./run-page":14}],14:[function(e,t,s){"use strict";const n=e("object-to-html-renderer"),r=e("./template/template");t.exports=function(e){e=new r({page:new e});n.setRenderCycleRoot(e),n.renderCycle()}},{"./template/template":16,"object-to-html-renderer":3}],15:[function(e,t,s){"use strict";const{images_url:n}=e("../../../constants"),r=[{url:"/games/",text:"Jeux"},{url:"/education/",text:"Pédagogie"},{url:"/software-development/",text:"Software"}];t.exports=class{constructor(){this.initEventHandlers()}handleBurgerClick(){document.getElementById("nav-menu-list").classList.toggle("responsive-show")}initEventHandlers(){window.addEventListener("click",e=>{"nav-menu-list"===e.target.id||e.target.classList.contains("burger")||e.target.parentNode.classList.contains("burger")||document.getElementById("nav-menu-list").classList.remove("responsive-show")})}renderHome(){return{tag:"div",class:"home",contents:[{tag:"a",href:"/",contents:[{tag:"img",alt:"Logo Kuadrado",src:`${n}logo_kuadrado.svg`},{tag:"img",alt:"Kuadrado Software",class:"logo-text",src:`${n}logo_kuadrado_txt.svg`}]}]}}renderMenu(e,a=!1,o=""){return{tag:"ul",id:"nav-menu-list",class:a?"submenu":"",contents:e.map(e=>{const{url:t,text:s,submenu:n}=e,r=`${o}${t}`;return{tag:"li",class:a||window.location.pathname!==r?"":"active",contents:[{tag:"a",href:r,contents:s}].concat(n?[this.renderMenu(n,!0,t)]:[])}})}}renderResponsiveBurger(){return{tag:"div",class:"burger",onclick:this.handleBurgerClick.bind(this),contents:[{tag:"span",contents:"···"}]}}render(){return{tag:"nav",contents:[this.renderHome(),this.renderResponsiveBurger(),this.renderMenu(r)]}}}},{"../../../constants":2}],16:[function(e,t,s){"use strict";const{in_construction:n}=e("../../config"),{images_url:r}=e("../../constants"),a=e("./components/navbar");t.exports=class{constructor(e){this.props=e}render(){return{tag:"main",contents:[{tag:"header",contents:[(new a).render()]},n&&{tag:"section",class:"warning-banner",contents:[{tag:"strong",class:"page-contents-center",contents:"Site en construction ..."}]},{tag:"section",id:"page-container",contents:[this.props.page.render()]},{tag:"footer",contents:[{tag:"div",class:"logo",contents:[{tag:"img",alt:"logo Kuadrado",src:`${r}logo_kuadrado.svg`},{tag:"img",class:"text-logo",alt:"Kuadrado Software",src:`${r}logo_kuadrado_txt.svg`}]},{tag:"span",contents:"32 rue Simon Vialet, 07240 Vernoux en Vivarais. Ardèche, France"},{tag:"div",contents:[{tag:"strong",contents:"<blue>Contact : </blue>"},{tag:"a",href:"mailto:contact@kuadrado-software.fr",contents:"contact@kuadrado-software.fr"}]},{tag:"div",class:"social",contents:[{tag:"strong",contents:"<blue>Sur les réseaux : </blue>"},{tag:"a",href:"https://www.linkedin.com/company/kuadrado-software",target:"_blank",contents:"in",title:"Linkedin"},{tag:"a",href:"https://twitter.com/KuadradoSoft",target:"_blank",contents:"t",title:"Twitter",style_rules:{fontFamily:"serif"}}]},{tag:"span",contents:`Copyright © ${(new Date).getFullYear()} Kuadrado Software | 
-                                Toutes les images du site ont été réalisées par mes soins et peuvent être réutilisées pour un usage personnel.`}]}]}}}},{"../../config":1,"../../constants":2,"./components/navbar":15}]},{},[13]);
\ No newline at end of file
+                                            `,
+                                        },
+                                    ],
+                                },
+                            ],
+                        },
+                    ],
+                },
+            ],
+        };
+    }
+}
+
+module.exports = WhoAmI;
+
+},{}],9:[function(require,module,exports){
+"use strict";
+
+const { images_url } = require("../constants");
+const KuadradoValues = require("./home-page-components/kuadrado-values");
+const NewsArticles = require("./home-page-components/news-articles");
+const ThemeCard = require("./home-page-components/theme-card");
+const WhoAmI = require("./home-page-components/whoami");
+const WebPage = require("./lib/web-page");
+
+class HomePage extends WebPage {
+    render() {
+        return {
+            tag: "div",
+            id: "home-page",
+            contents: [
+                {
+                    tag: "div",
+                    class: "page-header",
+                    contents: [
+                        {
+                            tag: "div",
+                            class: "big-logo page-contents-center",
+                            contents: [
+                                {
+                                    tag: "img",
+                                    alt: "logo Kuadrado",
+                                    src: `${images_url}logo_kuadrado.svg`,
+                                },
+                                {
+                                    tag: "img",
+                                    class: "logo-text",
+                                    alt: "Kuadrado",
+                                    src: `${images_url}logo_kuadrado_txt.svg`,
+                                },
+                            ],
+                        },
+                        { tag: "h1", contents: "Kuadrado Software", class: "page-contents-center" },
+                        {
+                            tag: "p",
+                            class: "page-contents-center",
+                            contents: `Créations numériques, jeux vidéo, pédagogie.`,
+                        },
+                        {
+                            tag: "ul",
+                            class: "philo-bubbles",
+                            contents: ["Simplicité", "Légèreté", "Écologie"].map(word => {
+                                return {
+                                    tag: "li",
+                                    contents: [{ tag: "span", contents: word }],
+                                };
+                            }),
+                        },
+                    ],
+                },
+                {
+                    tag: "section",
+                    class: "page-contents-center poles",
+                    contents: [
+                        {
+                            title: "Jeux",
+                            img: "game_controller.svg",
+                            href: "/games/",
+                            description:
+                                "Créations vidéoludiques, jeux web et jeux PC, projets en cours.",
+                        },
+                        {
+                            title: "Pédagogie",
+                            img: "brain.svg",
+                            href: "/education/",
+                            description: `S'approprier la technologie par le partage de connaissances.`,
+                        },
+                        {
+                            title: "Software",
+                            img: "meca_proc.svg",
+                            href: "/software-development/",
+                            description: `R&D, projets expérimentaux, web et outillage logiciel`,
+                        },
+                    ].map(cardProps => new ThemeCard(cardProps).render()),
+                },
+                {
+                    tag: "section",
+                    class: "page-philo",
+                    contents: [
+                        {
+                            tag: "p",
+                            class: "page-contents-center",
+                            contents: `Travailler pour le plaisir de créer, de maîtriser et de comprendre.`,
+                        },
+                    ],
+                },
+                {
+                    tag: "section",
+                    class: "page-contents-center",
+                    id:"news",
+                    contents: [
+                        { tag: "h2", contents: "Actu", class: "section-title" },
+                        new NewsArticles().render(),
+                    ],
+                },
+                new KuadradoValues().render(),
+                new WhoAmI().render(),
+            ],
+        };
+    }
+}
+
+module.exports = HomePage;
+
+},{"../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");
+
+function getArticleBody(text) {
+    return text.replaceAll("\n", "<br/>");
+}
+
+function getArticleDate(date) {
+    return `${date.getDate()}-${date.getMonth() + 1}-${date.getFullYear()}`;
+}
+
+function loadArticles(dir_url) {
+    return new Promise((resolve, reject) => {
+        fetchjson(`${dir_url}/index.json`)
+            .then(json => {
+                Promise.all(
+                    json.articles.map(async artDir => {
+                        const artPath = `${artDir}/${artDir}.json`;
+                        const art = await fetchjson(`${dir_url}/${artPath}`);
+                        const tmpSplit = artPath.split("/");
+                        tmpSplit.pop();
+                        const absArtPath = `${dir_url}/${tmpSplit.join("/")}`;
+                        return Object.assign(art, { path: absArtPath });
+                    })
+                )
+                    .then(articles => {
+                        populateArticles(articles)
+                            .then(completeArticles => resolve(completeArticles))
+                            .catch(e => reject(e));
+                    })
+                    .catch(e => reject(e));
+            })
+            .catch(e => console.log(e));
+    });
+}
+
+function populateArticles(articles) {
+    return new Promise((resolve, reject) => {
+        Promise.all(
+            articles.map(async article => {
+                if (article.body.indexOf("<file>") !== -1) {
+                    const txtPath = article.body.replace("<file>", "");
+                    const textValue = await fetchtext(`${article.path}/${txtPath}`);
+                    article.body = textValue;
+                    article.date = article.date ? new Date(article.date) : undefined;
+                }
+                return article;
+            })
+        )
+            .then(completeArticles => resolve(completeArticles.sort((a, b) => b.date - a.date)))
+            .catch(e => reject(e));
+    });
+}
+
+module.exports = {
+    loadArticles,
+    getArticleBody,
+    getArticleDate,
+    populateArticles,
+};
+
+},{"./fetch":11}],11:[function(require,module,exports){
+"use strict";
+
+function fetchjson(url) {
+    return new Promise((resolve, reject) => {
+        fetch(url)
+            .then(r => r.json())
+            .then(r => resolve(r))
+            .catch(e => reject(e));
+    });
+}
+
+function fetchtext(url) {
+    return new Promise((resolve, reject) => {
+        fetch(url)
+            .then(r => r.text())
+            .then(r => resolve(r))
+            .catch(e => reject(e));
+    });
+}
+
+module.exports = {
+    fetchjson,
+    fetchtext,
+};
+
+},{}],12:[function(require,module,exports){
+"use strict";
+
+class WebPage {
+    constructor(args) {
+        Object.assign(this, args);
+    }
+}
+
+module.exports = WebPage;
+},{}],13:[function(require,module,exports){
+"use strict";
+
+const HomePage = require("./homepage");
+const runPage = require("./run-page");
+
+runPage(HomePage);
+
+},{"./homepage":9,"./run-page":14}],14:[function(require,module,exports){
+"use strict";
+
+const objectHtmlRenderer = require("object-to-html-renderer")
+const Template = require("./template/template");
+
+module.exports = function runPage(PageComponent) {
+    const template = new Template({ page: new PageComponent() });
+    objectHtmlRenderer.setRenderCycleRoot(template);
+    objectHtmlRenderer.renderCycle();
+};
+
+},{"./template/template":16,"object-to-html-renderer":3}],15:[function(require,module,exports){
+"use strict";
+
+const { images_url } = require("../../../constants");
+
+const NAV_MENU_ITEMS = [
+    { url: "/games/", text: "Jeux" },
+    {
+        url: "/education/",
+        text: "Pédagogie",
+        // submenu: [
+        //     { url: "/gamedev", text: "Création de jeux vidéo" },
+        // ]
+    },
+    { url: "/software-development/", text: "Software" }
+];
+
+class NavBar {
+    constructor() {
+        this.initEventHandlers();
+    }
+
+    handleBurgerClick() {
+        document.getElementById("nav-menu-list").classList.toggle("responsive-show");
+    }
+
+    initEventHandlers() {
+        window.addEventListener("click", event => {
+            if (
+                event.target.id !== "nav-menu-list" &&
+                !event.target.classList.contains("burger") &&
+                !event.target.parentNode.classList.contains("burger")
+            ) {
+                document.getElementById("nav-menu-list").classList.remove("responsive-show");
+            }
+        });
+    }
+
+    renderHome() {
+        return {
+            tag: "div",
+            class: "home",
+            contents: [
+                {
+                    tag: "a",
+                    href: "/",
+                    contents: [
+                        {
+                            tag: "img",
+                            alt: "Logo Kuadrado",
+                            src: `${images_url}logo_kuadrado.svg`,
+                        },
+                        {
+                            tag: "img",
+                            alt: "Kuadrado Software",
+                            class: "logo-text",
+                            src: `${images_url}logo_kuadrado_txt.svg`,
+                        },
+                    ],
+                },
+            ],
+        };
+    }
+
+    renderMenu(menuItemsArray, isSubmenu = false, parentUrl = "") {
+        return {
+            tag: "ul",
+            id: "nav-menu-list",
+            class: isSubmenu ? "submenu" : "",
+            contents: menuItemsArray.map(item => {
+                const { url, text, submenu } = item;
+                const href = `${parentUrl}${url}`;
+                return {
+                    tag: "li",
+                    class: !isSubmenu && window.location.pathname === href ? "active" : "",
+                    contents: [
+                        {
+                            tag: "a",
+                            href,
+                            contents: text,
+                        },
+                    ].concat(submenu ? [this.renderMenu(submenu, true, url)] : []),
+                };
+            }),
+        };
+    }
+
+    renderResponsiveBurger() {
+        return {
+            tag: "div",
+            class: "burger",
+            onclick: this.handleBurgerClick.bind(this),
+            contents: [{ tag: "span", contents: "···" }],
+        };
+    }
+
+    render() {
+        return {
+            tag: "nav",
+            contents: [
+                this.renderHome(),
+                this.renderResponsiveBurger(),
+                this.renderMenu(NAV_MENU_ITEMS),
+            ],
+        };
+    }
+}
+
+module.exports = NavBar;
+
+},{"../../../constants":2}],16:[function(require,module,exports){
+"use strict";
+
+const { in_construction } = require("../../config");
+const { images_url } = require("../../constants");
+const NavBar = require("./components/navbar");
+
+class Template {
+    constructor(props) {
+        this.props = props;
+    }
+    render() {
+        return {
+            tag: "main",
+            contents: [
+                {
+                    tag: "header",
+                    contents: [new NavBar().render()],
+                },
+                in_construction && {
+                    tag: "section",
+                    class: "warning-banner",
+                    contents: [
+                        {
+                            tag: "strong",
+                            class: "page-contents-center",
+                            contents: "Site en construction ...",
+                        },
+                    ],
+                },
+                {
+                    tag: "section",
+                    id: "page-container",
+                    contents: [this.props.page.render()],
+                },
+                {
+                    tag: "footer",
+                    contents: [
+                        {
+                            tag: "div",
+                            class: "logo",
+                            contents: [
+                                {
+                                    tag: "img",
+                                    alt: `logo Kuadrado`,
+                                    src: `${images_url}logo_kuadrado.svg`,
+                                },
+                                {
+                                    tag: "img",
+                                    class: "text-logo",
+                                    alt: "Kuadrado Software",
+                                    src: `${images_url}logo_kuadrado_txt.svg`,
+                                },
+                            ],
+                        },
+                        {
+                            tag: "span",
+                            contents: "32 rue Simon Vialet, 07240 Vernoux en Vivarais. Ardèche, France",
+                        },
+                        {
+                            tag: "div",
+                            contents: [
+                                { tag: "strong", contents: "<blue>Contact : </blue>" },
+                                {
+                                    tag: "a",
+                                    href: "mailto:contact@kuadrado-software.fr",
+                                    contents: "contact@kuadrado-software.fr",
+                                },
+                            ],
+                        },
+                        {
+                            tag: "div",
+                            class: "social",
+                            contents: [
+                                {
+                                    tag: "strong",
+                                    contents: "<blue>Sur les réseaux : </blue>",
+                                },
+                                {
+                                    tag: "a",
+                                    href: "https://www.linkedin.com/company/kuadrado-software",
+                                    target: "_blank",
+                                    contents: "in",
+                                    title: "Linkedin",
+                                },
+                                {
+                                    tag: "a",
+                                    href: "https://twitter.com/KuadradoSoft",
+                                    target: "_blank",
+                                    contents: "t",
+                                    title: "Twitter",
+                                    style_rules: { fontFamily: "serif" },
+                                },
+                            ],
+                        },
+                        {
+                            tag: "span",
+                            contents: `Copyright © ${new Date()
+                                .getFullYear()} Kuadrado Software | 
+                                Toutes les images du site ont été réalisées par mes soins et peuvent être réutilisées pour un usage personnel.`,
+                        },
+                    ],
+                },
+            ],
+        };
+    }
+}
+
+module.exports = Template;
+
+},{"../../config":1,"../../constants":2,"./components/navbar":15}]},{},[13]);
diff --git a/public/software-development/software-development.js b/public/software-development/software-development.js
index f17ce3634e0a1eb79b2aceae61fb550577198759..43b6a97df84ec8d519fe011949d1787adeb22352 100644
--- a/public/software-development/software-development.js
+++ b/public/software-development/software-development.js
@@ -1,2 +1,811 @@
-!function s(r,a,o){function c(t,e){if(!a[t]){if(!r[t]){var n="function"==typeof require&&require;if(!e&&n)return n(t,!0);if(i)return i(t,!0);throw(n=new Error("Cannot find module '"+t+"'")).code="MODULE_NOT_FOUND",n}n=a[t]={exports:{}},r[t][0].call(n.exports,function(e){return c(r[t][1][e]||e)},n,n.exports,s,r,a,o)}return a[t].exports}for(var i="function"==typeof require&&require,e=0;e<o.length;e++)c(o[e]);return c}({1:[function(e,t,n){t.exports={getServerUrl:function(){return`${location.origin}${"/"!==location.origin.charAt(location.origin.length-1)?"/":""}`},build:{protected_dirs:["assets","style","articles"],default_meta_keys:["title","description","image","open_graph","json_ld"]}}},{}],2:[function(e,t,n){const{getServerUrl:s}=e("./config");t.exports={images_url:`${s()}assets/images/`,articles_url:`${s()}articles/`}},{"./config":1}],3:[function(e,t,n){"use strict";t.exports={setRenderCycleRoot(e){this.renderCycleRoot=e},objectToHtml:function t(n){var{tag:e}=n;const s=document.createElement(e),r=["tag","contents","style_rules","state"];return Object.keys(n).filter(e=>!r.includes(e)).forEach(e=>{"class"===e?s.classList.add(...n[e].split(" ").filter(e=>""!==e)):s[e]=n[e]}),n.contents&&"string"==typeof n.contents?s.innerHTML=n.contents:n.contents&&0<n.contents.length&&n.contents.forEach(e=>{switch(typeof e){case"string":s.innerHTML=e;break;case"object":s.appendChild(t(e))}}),n.style_rules&&Object.keys(n.style_rules).forEach(e=>{s.style[e]=n.style_rules[e]}),s},renderCycle:function(){this.subRender(this.renderCycleRoot.render(),document.getElementsByTagName("main")[0],{mode:"replace"})},subRender(e,t,n={mode:"append"}){var s=this.objectToHtml(e);switch(n.mode){case"append":t.appendChild(s);break;case"override":t.innerHTML="",t.appendChild(s);break;case"insert-before":t.insertBefore(s,t.childNodes[n.insertIndex]);break;case"adjacent":t.insertAdjacentHTML(n.insertLocation,s);break;case"replace":t.parentNode.replaceChild(s,t);break;case"remove":t.remove()}}}},{}],4:[function(e,t,n){"use strict";const s=e("object-to-html-renderer");t.exports=class{constructor(e){this.props=e,this.id=performance.now(),this.state={showImageIndex:0},this.RUN_INTERVAL=5e3,1<this.props.images.length&&this.run()}run(){this.runningInterval=setInterval(()=>{var{showImageIndex:e}=this.state,{images:t}=this.props;this.state.showImageIndex=e<t.length-1?++e:0,this.refreshImage()},this.RUN_INTERVAL)}setImageIndex(e){clearInterval(this.runningInterval),this.state.showImageIndex=e,this.refreshImage()}refreshImage(){s.subRender(this.render(),document.getElementById(this.id),{mode:"replace"})}render(){const{showImageIndex:n}=this.state,{images:e}=this.props;return{tag:"div",id:this.id,class:"image-carousel",contents:[{tag:"img",property:"image",alt:`image carousel ${e[n].replace(/\.[A-Za-z]+/,"")}`,src:e[n]},1<e.length&&{tag:"div",class:"carousel-bullets",contents:e.map((e,t)=>{return{tag:"span",class:`bullet ${n===t?"active":""}`,onclick:this.setImageIndex.bind(this,t)}})}]}}}},{"object-to-html-renderer":3}],5:[function(e,t,n){"use strict";const{fetchjson:a,fetchtext:s}=e("./fetch");function o(e){return new Promise((t,n)=>{Promise.all(e.map(async e=>{var t;return-1!==e.body.indexOf("<file>")&&(t=e.body.replace("<file>",""),t=await s(`${e.path}/${t}`),e.body=t,e.date=e.date?new Date(e.date):void 0),e})).then(e=>t(e.sort((e,t)=>e.date-t.date))).catch(e=>n(e))})}t.exports={loadArticles:function(r){return new Promise((t,n)=>{a(`${r}/index.json`).then(e=>{Promise.all(e.articles.map(async e=>{const t=`${e}/${e}.json`;var n=await a(`${r}/${t}`);const s=t.split("/");s.pop();e=`${r}/${s.join("/")}`;return Object.assign(n,{path:e})})).then(e=>{o(e).then(e=>t(e)).catch(e=>n(e))}).catch(e=>n(e))}).catch(e=>console.log(e))})},getArticleBody:function(e){return e.replaceAll("\n","<br/>")},getArticleDate:function(e){return`${e.getDate()}-${e.getMonth()+1}-${e.getFullYear()}`},populateArticles:o}},{"./fetch":6}],6:[function(e,t,n){"use strict";t.exports={fetchjson:function(e){return new Promise((t,n)=>{fetch(e).then(e=>e.json()).then(e=>t(e)).catch(e=>n(e))})},fetchtext:function(e){return new Promise((t,n)=>{fetch(e).then(e=>e.text()).then(e=>t(e)).catch(e=>n(e))})}}},{}],7:[function(e,t,n){"use strict";t.exports=class{constructor(e){Object.assign(this,e)}}},{}],8:[function(e,t,n){"use strict";const{articles_url:s}=e("../../../../constants"),i=e("../../../generic-components/image-carousel"),{loadArticles:r,getArticleBody:l,getArticleDate:d}=e("../../../lib/article-utils"),a=e("object-to-html-renderer");class o{constructor(e){this.props=e}render(){const{title:e,date:t,body:n,subtitle:s,images:r,path:a,technical:o,releases:c}=this.props;return{tag:"article",class:"software-article",typeof:"SoftwareApplication",additionalType:"Article",contents:[{tag:"h2",class:"software-title",contents:e,property:"name"},{tag:"time",class:"software-date",contents:d(t),property:"datePublished"},{tag:"h3",class:"software-subtitle",contents:s,property:"alternativeHeadline"},{tag:"div",class:"software-description",contents:l(n),property:"description"},new i({images:r.map(e=>`${a}/images/${e}`)}).render(),{tag:"div",class:"software-technical",contents:[{tag:"h2",contents:"Details"},{tag:"ul",class:"technical-details",contents:[{tag:"li",class:"detail",contents:[{tag:"label",contents:"Stack"},{tag:"div",contents:[{tag:"ul",contents:o.stack.map(e=>({tag:"li",contents:e,property:"about"}))}]}]},{tag:"li",class:"detail",contents:[{tag:"label",contents:"Version actuelle"},{tag:"div",contents:o.version,property:"version"}]},{tag:"li",class:"detail",contents:[{tag:"label",contents:"License"},{tag:"div",contents:o.license,property:"license"}]},{tag:"li",class:"detail",contents:[{tag:"label",contents:"Code source"},{tag:"a",href:o.repository,target:"_blank",contents:o.repository.replace(/https?:\/\/(www\.)?/g,""),property:"url"}]}]},c&&{tag:"h2",contents:"Releases"},c&&{tag:"ul",class:"releases",contents:[{tag:"li",class:"detail",contents:[{tag:"label",class:"label",contents:"Plateforme"},{tag:"label",class:"label",contents:"Téléchargement"}]}].concat(c.map(e=>({tag:"li",class:"release detail",contents:[{tag:"label",contents:e.platform},{tag:"a",download:e.download,href:`${a}/release/${e.download}`,contents:e.download,property:"url"}]})))}]}]}}}t.exports=class{constructor(e){this.props=e,this.state={articles:[]},this.id=performance.now(),this.loadArticles()}loadArticles(){r(`${s}software`).then(e=>{this.state.articles=e,this.refresh(),this.fixScroll()}).catch(e=>console.log(e))}renderPlaceholder(){return{tag:"article",class:"placeholder",contents:[{tag:"div",class:"title"},{tag:"div",class:"body"},{tag:"div",class:"details"}]}}refresh(){a.subRender(this.render(),document.getElementById(this.id),{mode:"replace"})}fixScroll(){window.location.href.includes("#")&&window.scrollTo(0,document.getElementById(window.location.href.match(/#.+/)[0].replace("#","")).offsetTop)}render(){const{articles:e}=this.state;return{tag:"section",class:"software-articles page-contents-center",id:this.id,contents:0<e.length?e.map(e=>new o({...e}).render()):[this.renderPlaceholder()]}}}},{"../../../../constants":2,"../../../generic-components/image-carousel":4,"../../../lib/article-utils":5,"object-to-html-renderer":3}],9:[function(e,t,n){"use strict";const{images_url:s}=e("../../../constants");var r=e("../../lib/web-page");const a=e("./components/software-articles");class o extends r{render(){return{tag:"div",id:"software-page",contents:[{tag:"div",class:"page-header logo-left",contents:[{tag:"div",class:"page-contents-center grid-wrapper",contents:[{tag:"div",class:"logo",contents:[{tag:"img",alt:"image mechanic electronic",src:`${s}meca_proc.svg`}]},{tag:"h1",contents:"Software"},{tag:"p",contents:"R&D, projets expérimentaux, outillage logiciel pour le développement de jeu ou pour le web."}]}]},(new a).render()]}}}t.exports=o},{"../../../constants":2,"../../lib/web-page":7,"./components/software-articles":8}],10:[function(e,t,n){"use strict";const s=e("../../run-page");e=e("./software-development");s(e)},{"../../run-page":11,"./software-development":9}],11:[function(e,t,n){"use strict";const s=e("object-to-html-renderer"),r=e("./template/template");t.exports=function(e){e=new r({page:new e});s.setRenderCycleRoot(e),s.renderCycle()}},{"./template/template":13,"object-to-html-renderer":3}],12:[function(e,t,n){"use strict";const{images_url:s}=e("../../../constants"),r=[{url:"/games/",text:"Jeux"},{url:"/education/",text:"Pédagogie"},{url:"/software-development/",text:"Software"}];t.exports=class{constructor(){this.initEventHandlers()}handleBurgerClick(){document.getElementById("nav-menu-list").classList.toggle("responsive-show")}initEventHandlers(){window.addEventListener("click",e=>{"nav-menu-list"===e.target.id||e.target.classList.contains("burger")||e.target.parentNode.classList.contains("burger")||document.getElementById("nav-menu-list").classList.remove("responsive-show")})}renderHome(){return{tag:"div",class:"home",contents:[{tag:"a",href:"/",contents:[{tag:"img",alt:"Logo Kuadrado",src:`${s}logo_kuadrado.svg`},{tag:"img",alt:"Kuadrado Software",class:"logo-text",src:`${s}logo_kuadrado_txt.svg`}]}]}}renderMenu(e,a=!1,o=""){return{tag:"ul",id:"nav-menu-list",class:a?"submenu":"",contents:e.map(e=>{const{url:t,text:n,submenu:s}=e,r=`${o}${t}`;return{tag:"li",class:a||window.location.pathname!==r?"":"active",contents:[{tag:"a",href:r,contents:n}].concat(s?[this.renderMenu(s,!0,t)]:[])}})}}renderResponsiveBurger(){return{tag:"div",class:"burger",onclick:this.handleBurgerClick.bind(this),contents:[{tag:"span",contents:"···"}]}}render(){return{tag:"nav",contents:[this.renderHome(),this.renderResponsiveBurger(),this.renderMenu(r)]}}}},{"../../../constants":2}],13:[function(e,t,n){"use strict";const{in_construction:s}=e("../../config"),{images_url:r}=e("../../constants"),a=e("./components/navbar");t.exports=class{constructor(e){this.props=e}render(){return{tag:"main",contents:[{tag:"header",contents:[(new a).render()]},s&&{tag:"section",class:"warning-banner",contents:[{tag:"strong",class:"page-contents-center",contents:"Site en construction ..."}]},{tag:"section",id:"page-container",contents:[this.props.page.render()]},{tag:"footer",contents:[{tag:"div",class:"logo",contents:[{tag:"img",alt:"logo Kuadrado",src:`${r}logo_kuadrado.svg`},{tag:"img",class:"text-logo",alt:"Kuadrado Software",src:`${r}logo_kuadrado_txt.svg`}]},{tag:"span",contents:"32 rue Simon Vialet, 07240 Vernoux en Vivarais. Ardèche, France"},{tag:"div",contents:[{tag:"strong",contents:"<blue>Contact : </blue>"},{tag:"a",href:"mailto:contact@kuadrado-software.fr",contents:"contact@kuadrado-software.fr"}]},{tag:"div",class:"social",contents:[{tag:"strong",contents:"<blue>Sur les réseaux : </blue>"},{tag:"a",href:"https://www.linkedin.com/company/kuadrado-software",target:"_blank",contents:"in",title:"Linkedin"},{tag:"a",href:"https://twitter.com/KuadradoSoft",target:"_blank",contents:"t",title:"Twitter",style_rules:{fontFamily:"serif"}}]},{tag:"span",contents:`Copyright © ${(new Date).getFullYear()} Kuadrado Software | 
-                                Toutes les images du site ont été réalisées par mes soins et peuvent être réutilisées pour un usage personnel.`}]}]}}}},{"../../config":1,"../../constants":2,"./components/navbar":12}]},{},[10]);
\ No newline at end of file
+(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
+function getServerUrl() {
+    return `${location.origin}${location.origin.charAt(location.origin.length - 1) !== "/" ? "/" : ""
+        }`;
+}
+
+module.exports = {
+    getServerUrl,
+    build: {
+        protected_dirs: ["assets", "style", "articles"],
+        default_meta_keys: ["title", "description", "image", "open_graph", "json_ld"],
+    },
+};
+
+},{}],2:[function(require,module,exports){
+const { getServerUrl } = require("./config");
+
+module.exports = {
+    images_url: `${getServerUrl()}assets/images/`,
+    articles_url: `${getServerUrl()}articles/`,
+};
+
+},{"./config":1}],3:[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;
+        }
+    },
+};
+
+},{}],4:[function(require,module,exports){
+"use strict";
+
+const objectHtmlRenderer = require("object-to-html-renderer")
+
+class ImageCarousel {
+    constructor(props) {
+        this.props = props;
+        this.id = performance.now();
+        this.state = {
+            showImageIndex: 0,
+        };
+        this.RUN_INTERVAL = 5000;
+        this.props.images.length > 1 && this.run();
+    }
+
+    run() {
+        this.runningInterval = setInterval(() => {
+            let { showImageIndex } = this.state;
+            const { images } = this.props;
+            this.state.showImageIndex = showImageIndex < images.length - 1 ? ++showImageIndex : 0;
+            this.refreshImage();
+        }, this.RUN_INTERVAL);
+    }
+
+    setImageIndex(i) {
+        clearInterval(this.runningInterval);
+        this.state.showImageIndex = i;
+        this.refreshImage();
+    }
+
+    refreshImage() {
+        objectHtmlRenderer.subRender(this.render(), document.getElementById(this.id), {
+            mode: "replace",
+        });
+    }
+
+    render() {
+        const { showImageIndex } = this.state;
+        const { images } = this.props;
+        return {
+            tag: "div",
+            id: this.id,
+            class: "image-carousel",
+            contents: [
+                {
+                    tag: "img",
+                    property: "image",
+                    alt: `image carousel ${images[showImageIndex].replace(/\.[A-Za-z]+/, "")}`,
+                    src: images[showImageIndex],
+                },
+                images.length > 1 && {
+                    tag: "div",
+                    class: "carousel-bullets",
+                    contents: images.map((_, i) => {
+                        const active = showImageIndex === i;
+                        return {
+                            tag: "span",
+                            class: `bullet ${active ? "active" : ""}`,
+                            onclick: this.setImageIndex.bind(this, i),
+                        };
+                    }),
+                },
+            ],
+        };
+    }
+}
+
+module.exports = ImageCarousel;
+
+},{"object-to-html-renderer":3}],5:[function(require,module,exports){
+"use strict";
+
+const { fetchjson, fetchtext } = require("./fetch");
+
+function getArticleBody(text) {
+    return text.replaceAll("\n", "<br/>");
+}
+
+function getArticleDate(date) {
+    return `${date.getDate()}-${date.getMonth() + 1}-${date.getFullYear()}`;
+}
+
+function loadArticles(dir_url) {
+    return new Promise((resolve, reject) => {
+        fetchjson(`${dir_url}/index.json`)
+            .then(json => {
+                Promise.all(
+                    json.articles.map(async artDir => {
+                        const artPath = `${artDir}/${artDir}.json`;
+                        const art = await fetchjson(`${dir_url}/${artPath}`);
+                        const tmpSplit = artPath.split("/");
+                        tmpSplit.pop();
+                        const absArtPath = `${dir_url}/${tmpSplit.join("/")}`;
+                        return Object.assign(art, { path: absArtPath });
+                    })
+                )
+                    .then(articles => {
+                        populateArticles(articles)
+                            .then(completeArticles => resolve(completeArticles))
+                            .catch(e => reject(e));
+                    })
+                    .catch(e => reject(e));
+            })
+            .catch(e => console.log(e));
+    });
+}
+
+function populateArticles(articles) {
+    return new Promise((resolve, reject) => {
+        Promise.all(
+            articles.map(async article => {
+                if (article.body.indexOf("<file>") !== -1) {
+                    const txtPath = article.body.replace("<file>", "");
+                    const textValue = await fetchtext(`${article.path}/${txtPath}`);
+                    article.body = textValue;
+                    article.date = article.date ? new Date(article.date) : undefined;
+                }
+                return article;
+            })
+        )
+            .then(completeArticles => resolve(completeArticles.sort((a, b) => b.date - a.date)))
+            .catch(e => reject(e));
+    });
+}
+
+module.exports = {
+    loadArticles,
+    getArticleBody,
+    getArticleDate,
+    populateArticles,
+};
+
+},{"./fetch":6}],6:[function(require,module,exports){
+"use strict";
+
+function fetchjson(url) {
+    return new Promise((resolve, reject) => {
+        fetch(url)
+            .then(r => r.json())
+            .then(r => resolve(r))
+            .catch(e => reject(e));
+    });
+}
+
+function fetchtext(url) {
+    return new Promise((resolve, reject) => {
+        fetch(url)
+            .then(r => r.text())
+            .then(r => resolve(r))
+            .catch(e => reject(e));
+    });
+}
+
+module.exports = {
+    fetchjson,
+    fetchtext,
+};
+
+},{}],7:[function(require,module,exports){
+"use strict";
+
+class WebPage {
+    constructor(args) {
+        Object.assign(this, args);
+    }
+}
+
+module.exports = WebPage;
+},{}],8:[function(require,module,exports){
+"use strict";
+
+const { articles_url } = require("../../../../constants");
+const ImageCarousel = require("../../../generic-components/image-carousel");
+const { loadArticles, getArticleBody, getArticleDate } = require("../../../lib/article-utils");
+const objectHtmlRenderer = require("object-to-html-renderer")
+
+class SoftwareArticle {
+    constructor(props) {
+        this.props = props;
+    }
+
+    render() {
+        const { title, date, body, subtitle, images, path, technical, releases } = this.props;
+        return {
+            tag: "article",
+            class: "software-article",
+            typeof: "SoftwareApplication",
+            additionalType: "Article",
+            contents: [
+                {
+                    tag: "h2",
+                    class: "software-title",
+                    contents: title,
+                    property: "name",
+                },
+                {
+                    tag: "div", class: "software-image",
+                    contents: [
+                        {
+                            tag: "img", src: `${path}/images/${images[0]}`
+                        }
+                    ]
+                },
+                {
+                    tag: "h3",
+                    class: "software-subtitle",
+                    contents: subtitle,
+                    property: "alternativeHeadline",
+                },
+                {
+                    tag: "div",
+                    class: "software-description",
+                    contents: getArticleBody(body),
+                    property: "description",
+                },
+                {
+                    tag: "div",
+                    class: "software-technical",
+                    contents: [
+                        {
+                            tag: "h2",
+                            contents: "Details",
+                        },
+                        {
+                            tag: "ul",
+                            class: "technical-details",
+                            contents: [
+                                {
+                                    tag: "li",
+                                    class: "detail",
+                                    contents: [
+                                        { tag: "label", contents: "Stack" },
+                                        {
+                                            tag: "div",
+                                            contents: [
+                                                {
+                                                    tag: "ul",
+                                                    contents: technical.stack.map(tech => {
+                                                        return {
+                                                            tag: "li",
+                                                            contents: tech,
+                                                            property: "about",
+                                                        };
+                                                    }),
+                                                },
+                                            ],
+                                        },
+                                    ],
+                                },
+                                {
+                                    tag: "li",
+                                    class: "detail",
+                                    contents: [
+                                        { tag: "label", contents: "Version actuelle" },
+                                        {
+                                            tag: "div",
+                                            contents: technical.version,
+                                            property: "version",
+                                        },
+                                    ],
+                                },
+                                {
+                                    tag: "li",
+                                    class: "detail",
+                                    contents: [
+                                        { tag: "label", contents: "License" },
+                                        {
+                                            tag: "div",
+                                            contents: technical.license,
+                                            property: "license",
+                                        },
+                                    ],
+                                },
+                                {
+                                    tag: "li",
+                                    class: "detail",
+                                    contents: [
+                                        {
+                                            tag: "label",
+                                            contents: "Code source",
+                                        },
+                                        {
+                                            tag: "a",
+                                            href: technical.repository,
+                                            target: "_blank",
+                                            contents: technical.repository.replace(
+                                                /https?:\/\/(www\.)?/g,
+                                                ""
+                                            ),
+                                            property: "url",
+                                        },
+                                    ],
+                                },
+                            ],
+                        },
+                        releases && {
+                            tag: "h2",
+                            contents: "Releases",
+                        },
+                        releases && {
+                            tag: "ul",
+                            class: "releases",
+                            contents: [
+                                {
+                                    tag: "li",
+                                    class: "detail",
+                                    contents: [
+                                        {
+                                            tag: "label",
+                                            class: "label",
+                                            contents: "Plateforme",
+                                        },
+                                        {
+                                            tag: "label",
+                                            class: "label",
+                                            contents: "Téléchargement",
+                                        },
+                                    ],
+                                },
+                            ].concat(
+                                releases.map(rel => {
+                                    return {
+                                        tag: "li",
+                                        class: "release detail",
+                                        contents: [
+                                            {
+                                                tag: "label",
+                                                contents: rel.platform,
+                                            },
+                                            {
+                                                tag: "a",
+                                                download: rel.download,
+                                                href: `${path}/release/${rel.download}`,
+                                                contents: rel.download,
+                                                property: "url",
+                                            },
+                                        ],
+                                    };
+                                })
+                            ),
+                        },
+                    ],
+                },
+            ],
+        };
+    }
+}
+
+class SoftwareArticles {
+    constructor(props) {
+        this.props = props;
+        this.state = {
+            articles: [],
+        };
+        this.id = performance.now();
+        this.loadArticles();
+    }
+
+    loadArticles() {
+        loadArticles(`${articles_url}software`)
+            .then(articles => {
+                this.state.articles = articles;
+                this.refresh();
+                this.fixScroll();
+            })
+            .catch(e => console.log(e));
+    }
+
+    renderPlaceholder() {
+        return {
+            tag: "article",
+            class: "placeholder",
+            contents: [
+                { tag: "div", class: "title" },
+                { tag: "div", class: "body" },
+                { tag: "div", class: "details" },
+            ],
+        };
+    }
+
+    refresh() {
+        objectHtmlRenderer.subRender(this.render(), document.getElementById(this.id), {
+            mode: "replace",
+        });
+    }
+
+    fixScroll() {
+        if (window.location.href.includes("#")) {
+            window.scrollTo(
+                0,
+                document.getElementById(window.location.href.match(/#.+/)[0].replace("#", ""))
+                    .offsetTop
+            );
+        }
+    }
+
+    render() {
+        const { articles } = this.state;
+        return {
+            tag: "section",
+            class: "software-articles page-contents-center",
+            id: this.id,
+            contents:
+                articles.length > 0
+                    ? articles.map(article => new SoftwareArticle({ ...article }).render())
+                    : [this.renderPlaceholder()],
+        };
+    }
+}
+
+module.exports = SoftwareArticles;
+
+},{"../../../../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");
+const WebPage = require("../../lib/web-page");
+const SoftwareArticles = require("./components/software-articles");
+
+class SoftwareDevelopment extends WebPage {
+    render() {
+        return {
+            tag: "div",
+            id: "software-page",
+            contents: [
+                {
+                    tag: "div",
+                    class: "page-header logo-left",
+                    contents: [
+                        {
+                            tag: "div",
+                            class: "page-contents-center grid-wrapper",
+                            contents: [
+                                {
+                                    tag: "div",
+                                    class: "logo",
+                                    contents: [
+                                        {
+                                            tag: "img",
+                                            alt: `image mechanic electronic`,
+                                            src: `${images_url}meca_proc.svg`,
+                                        },
+                                    ],
+                                },
+                                { tag: "h1", contents: "Software" },
+                                {
+                                    tag: "p",
+                                    contents: `R&D, projets expérimentaux, outillage logiciel pour le développement de jeu ou pour le web.`,
+                                },
+                            ],
+                        },
+                    ],
+                },
+                new SoftwareArticles().render(),
+            ],
+        };
+    }
+}
+
+module.exports = SoftwareDevelopment;
+
+},{"../../../constants":2,"../../lib/web-page":7,"./components/software-articles":8}],10:[function(require,module,exports){
+"use strict";
+
+"use strict";
+const runPage = require("../../run-page");
+const SoftwareDevelopment = require("./software-development");
+runPage(SoftwareDevelopment);
+
+},{"../../run-page":11,"./software-development":9}],11:[function(require,module,exports){
+"use strict";
+
+const objectHtmlRenderer = require("object-to-html-renderer")
+const Template = require("./template/template");
+
+module.exports = function runPage(PageComponent) {
+    const template = new Template({ page: new PageComponent() });
+    objectHtmlRenderer.setRenderCycleRoot(template);
+    objectHtmlRenderer.renderCycle();
+};
+
+},{"./template/template":13,"object-to-html-renderer":3}],12:[function(require,module,exports){
+"use strict";
+
+const { images_url } = require("../../../constants");
+
+const NAV_MENU_ITEMS = [
+    { url: "/games/", text: "Jeux" },
+    {
+        url: "/education/",
+        text: "Pédagogie",
+        // submenu: [
+        //     { url: "/gamedev", text: "Création de jeux vidéo" },
+        // ]
+    },
+    { url: "/software-development/", text: "Software" }
+];
+
+class NavBar {
+    constructor() {
+        this.initEventHandlers();
+    }
+
+    handleBurgerClick() {
+        document.getElementById("nav-menu-list").classList.toggle("responsive-show");
+    }
+
+    initEventHandlers() {
+        window.addEventListener("click", event => {
+            if (
+                event.target.id !== "nav-menu-list" &&
+                !event.target.classList.contains("burger") &&
+                !event.target.parentNode.classList.contains("burger")
+            ) {
+                document.getElementById("nav-menu-list").classList.remove("responsive-show");
+            }
+        });
+    }
+
+    renderHome() {
+        return {
+            tag: "div",
+            class: "home",
+            contents: [
+                {
+                    tag: "a",
+                    href: "/",
+                    contents: [
+                        {
+                            tag: "img",
+                            alt: "Logo Kuadrado",
+                            src: `${images_url}logo_kuadrado.svg`,
+                        },
+                        {
+                            tag: "img",
+                            alt: "Kuadrado Software",
+                            class: "logo-text",
+                            src: `${images_url}logo_kuadrado_txt.svg`,
+                        },
+                    ],
+                },
+            ],
+        };
+    }
+
+    renderMenu(menuItemsArray, isSubmenu = false, parentUrl = "") {
+        return {
+            tag: "ul",
+            id: "nav-menu-list",
+            class: isSubmenu ? "submenu" : "",
+            contents: menuItemsArray.map(item => {
+                const { url, text, submenu } = item;
+                const href = `${parentUrl}${url}`;
+                return {
+                    tag: "li",
+                    class: !isSubmenu && window.location.pathname === href ? "active" : "",
+                    contents: [
+                        {
+                            tag: "a",
+                            href,
+                            contents: text,
+                        },
+                    ].concat(submenu ? [this.renderMenu(submenu, true, url)] : []),
+                };
+            }),
+        };
+    }
+
+    renderResponsiveBurger() {
+        return {
+            tag: "div",
+            class: "burger",
+            onclick: this.handleBurgerClick.bind(this),
+            contents: [{ tag: "span", contents: "···" }],
+        };
+    }
+
+    render() {
+        return {
+            tag: "nav",
+            contents: [
+                this.renderHome(),
+                this.renderResponsiveBurger(),
+                this.renderMenu(NAV_MENU_ITEMS),
+            ],
+        };
+    }
+}
+
+module.exports = NavBar;
+
+},{"../../../constants":2}],13:[function(require,module,exports){
+"use strict";
+
+const { in_construction } = require("../../config");
+const { images_url } = require("../../constants");
+const NavBar = require("./components/navbar");
+
+class Template {
+    constructor(props) {
+        this.props = props;
+    }
+    render() {
+        return {
+            tag: "main",
+            contents: [
+                {
+                    tag: "header",
+                    contents: [new NavBar().render()],
+                },
+                in_construction && {
+                    tag: "section",
+                    class: "warning-banner",
+                    contents: [
+                        {
+                            tag: "strong",
+                            class: "page-contents-center",
+                            contents: "Site en construction ...",
+                        },
+                    ],
+                },
+                {
+                    tag: "section",
+                    id: "page-container",
+                    contents: [this.props.page.render()],
+                },
+                {
+                    tag: "footer",
+                    contents: [
+                        {
+                            tag: "div",
+                            class: "logo",
+                            contents: [
+                                {
+                                    tag: "img",
+                                    alt: `logo Kuadrado`,
+                                    src: `${images_url}logo_kuadrado.svg`,
+                                },
+                                {
+                                    tag: "img",
+                                    class: "text-logo",
+                                    alt: "Kuadrado Software",
+                                    src: `${images_url}logo_kuadrado_txt.svg`,
+                                },
+                            ],
+                        },
+                        {
+                            tag: "span",
+                            contents: "32 rue Simon Vialet, 07240 Vernoux en Vivarais. Ardèche, France",
+                        },
+                        {
+                            tag: "div",
+                            contents: [
+                                { tag: "strong", contents: "<blue>Contact : </blue>" },
+                                {
+                                    tag: "a",
+                                    href: "mailto:contact@kuadrado-software.fr",
+                                    contents: "contact@kuadrado-software.fr",
+                                },
+                            ],
+                        },
+                        {
+                            tag: "div",
+                            class: "social",
+                            contents: [
+                                {
+                                    tag: "strong",
+                                    contents: "<blue>Sur les réseaux : </blue>",
+                                },
+                                {
+                                    tag: "a",
+                                    href: "https://www.linkedin.com/company/kuadrado-software",
+                                    target: "_blank",
+                                    contents: "in",
+                                    title: "Linkedin",
+                                },
+                                {
+                                    tag: "a",
+                                    href: "https://twitter.com/KuadradoSoft",
+                                    target: "_blank",
+                                    contents: "t",
+                                    title: "Twitter",
+                                    style_rules: { fontFamily: "serif" },
+                                },
+                            ],
+                        },
+                        {
+                            tag: "span",
+                            contents: `Copyright © ${new Date()
+                                .getFullYear()} Kuadrado Software | 
+                                Toutes les images du site ont été réalisées par mes soins et peuvent être réutilisées pour un usage personnel.`,
+                        },
+                    ],
+                },
+            ],
+        };
+    }
+}
+
+module.exports = Template;
+
+},{"../../config":1,"../../constants":2,"./components/navbar":12}]},{},[10]);
diff --git a/public/style/style.css b/public/style/style.css
index 450e8b2e36c098ab0823e450055dadd9a7bbdb3c..26da894da048815000b52f3e823e627e82045a2a 100644
--- a/public/style/style.css
+++ b/public/style/style.css
@@ -1 +1,1277 @@
-body{font-family:Arial,Helvetica,sans-serif;margin:0}body *{box-sizing:border-box;color:#35393c;line-height:1.3em}body ul{margin:0;padding:0;list-style-type:none}body a{color:#4baabb;text-decoration:none}body a:hover{color:#72e3f0}body blue{color:#4baabb}body red{color:#9c3030}body green{color:#368736}body emoji{font-style:initial;font-size:25px}body .bg-blue{background-color:#4baabb;color:#fff}body .bg-dark{background-color:#3c4144;color:#aabbc8}body #seo-title{visibility:hidden}body img.pixelated{image-rendering:pixelated;image-rendering:-moz-crisp-edges;image-rendering:crisp-edges}main{display:flex;flex-direction:column;align-items:center;min-height:100vh}main .warning-banner{background:url("/assets/images/wallpaper_warning.svg");width:100%;height:40px;padding:20px 10%;display:flex;justify-content:center;align-items:center;flex-direction:row}main .warning-banner strong{font-size:18px;color:#1c3db2}main .image-carousel{overflow:hidden;display:flex;justify-content:center;align-items:center;flex-direction:row;background-color:#000;position:relative}main .image-carousel img{position:absolute;max-width:100%;max-height:400px}main .image-carousel .carousel-bullets{position:absolute;bottom:0;padding:20px;display:flex;gap:10px}main .image-carousel .carousel-bullets .bullet{cursor:pointer;width:8px;height:8px;background-color:#6b7880;border-radius:100%;box-shadow:0 0 3px #000}main .image-carousel .carousel-bullets .bullet.active{background-color:#d4d9dd}@media screen and (max-width: 900px){main .image-carousel img{max-height:100%}main .image-carousel .carousel-bullets{gap:30px}main .image-carousel .carousel-bullets .bullet{width:12px;height:12px}}main header{width:100%;background-color:#fff;position:sticky;position:-webkit-sticky;top:0;z-index:10}main header nav{display:flex;align-items:center;height:60px}main header nav .home{margin:0 10px}main header nav .home a{display:flex;align-items:center;gap:10px}main header nav .home a img{height:40px;width:auto}main header nav .home a img.logo-text{width:120px;height:auto}main header nav ul{display:flex;padding:0;margin:0;list-style-type:none;height:100%}main header nav ul li{position:relative}main header nav ul li a{display:flex;align-items:center;height:100%;padding:10px 20px;color:#96a5ae;font-weight:800;text-decoration:none}main header nav ul li .submenu{visibility:hidden;overflow:hidden;position:absolute;height:auto;max-height:0;transition:max-height .6s;top:100%;left:50%;flex-direction:column;background-color:#fff;white-space:nowrap}main header nav ul li.active a{color:#3c4144;border-bottom:3px solid}main header nav ul li:hover a{color:#3c4144}main header nav ul li:hover .submenu{visibility:unset;max-height:1000px}main header nav ul li:hover .submenu a{color:#96a5ae;border:none}main header nav ul li:hover .submenu li:hover a{color:#3c4144}main header nav .burger{display:none}@media screen and (max-width: 560px){main header nav{justify-content:space-between}main header nav .burger{display:flex;justify-content:center;align-items:center;flex-direction:row;flex-direction:column;font-weight:bold;border:1px solid;margin:0 20px;cursor:pointer;border-radius:100%;width:35px;height:35px;color:#555d61;font-size:25px}main header nav ul{display:none}main header nav ul.responsive-show{display:flex;flex-direction:column;position:absolute;right:0;max-width:100vw;min-width:50vw;top:60px;background-color:#fff;box-shadow:0 4px 6px 2px #0000000a;height:unset}main header nav ul.responsive-show li.active a{border:none}main header nav ul.responsive-show li .submenu{display:flex;visibility:visible;position:relative;height:unset;max-height:unset;transition:max-height .6s;top:unset;left:unset;margin-left:20px}main header nav ul.responsive-show li .submenu li a{font-weight:400;font-size:14px;color:#96a5ae}}main #page-container{width:100%;flex:1}main #page-container .page-header{background-image:url("/assets/images/wallpaper_binary.png");padding:50px 0}main #page-container .page-header h1{padding:15px 40px 0;font-size:25px;color:#4baabb;margin:0 auto}main #page-container .page-header p{color:#72e3f0;font-style:italic;padding:15px 40px 15px 100px;margin:0 auto;font-size:18px}main #page-container .page-header p *{color:#72e3f0}main #page-container .page-header .big-logo{display:flex;justify-content:center;align-items:center;flex-direction:row;gap:20px;padding:20px}main #page-container .page-header .big-logo img{width:200px;max-width:100%}main #page-container .page-header .big-logo img.logo-text{width:300px;max-width:100%}main #page-container .page-header .logo{padding-left:30px;display:flex;justify-content:center;align-items:center;flex-direction:row}main #page-container .page-header .logo img{width:100%}@media screen and (max-width: 560px){main #page-container .page-header h1{padding:15px 20px 0}main #page-container .page-header p{padding:20px 20px 30px 40px;text-align:justify}main #page-container .page-header .big-logo{flex-direction:column}}main #page-container .page-header.logo-left .grid-wrapper{display:grid;grid-template-columns:120px 1fr;grid-template-rows:auto 1fr}main #page-container .page-header.logo-left .grid-wrapper h1{width:100%}main #page-container .page-header.logo-left .grid-wrapper .logo{grid-column:1;grid-row:1;width:100%}main #page-container .page-header.logo-left .grid-wrapper p{margin:0;grid-column:1/span 2}@media screen and (max-width: 780px){main #page-container .page-header.logo-left .grid-wrapper h1{padding:0 20px}main #page-container .page-header.logo-left .grid-wrapper .logo{padding:0 20px}}main #page-container .page-philo{background-image:url("/assets/images/wallpaper_binary.png");padding:120px 30px}main #page-container .page-philo p{width:100%;max-width:600px;font-size:18px;color:#aabbc8;text-align:center;font-style:italic;font-weight:bold}main #page-container .page-philo p *{color:#aabbc8}main #page-container .page-contents-center{width:1300px;max-width:100%;margin:0 auto}@media screen and (max-width: 1300px){main #page-container .page-contents-center{padding:20px 20px 0}}main #page-container h2.page-section-title{color:#4baabb;padding:20px 0 10px;width:1300px;max-width:100%;margin:0 auto}@media screen and (max-width: 1300px){main #page-container h2.page-section-title{padding:20px 20px 0}}main #page-container #home-page{display:flex;flex-direction:column}main #page-container #home-page .section-title{padding:10px;margin:0;color:#aabbc8}main #page-container #home-page .page-header .philo-bubbles{display:flex;justify-content:center;align-items:center;flex-direction:row;flex-wrap:wrap;gap:40px;margin:30px 20px}@media screen and (max-width: 780px){main #page-container #home-page .page-header .philo-bubbles{gap:20px}}main #page-container #home-page .page-header .philo-bubbles li{border-radius:100%;display:flex;justify-content:center;align-items:center;flex-direction:row;background-color:#d4d9dd;width:100px;height:100px}main #page-container #home-page .page-header .philo-bubbles li *{color:#6b7880}@media screen and (max-width: 560px){main #page-container #home-page .page-header .philo-bubbles li{width:75px;height:75px}main #page-container #home-page .page-header .philo-bubbles li *{font-size:12px}}main #page-container #home-page .page-header .philo-bubbles li:first-child{background-color:#6b7880}main #page-container #home-page .page-header .philo-bubbles li:first-child *{color:#fff}main #page-container #home-page .page-header .philo-bubbles li:last-child{background-color:#35393c}main #page-container #home-page .page-header .philo-bubbles li:last-child *{color:#96a5ae}main #page-container #home-page #news{padding:60px 20px}main #page-container #home-page #news .articles-displayer{margin:0 auto 40px}main #page-container #home-page #news .articles-displayer .prev-next-buttons{display:flex;justify-content:space-between}main #page-container #home-page #news .articles-displayer .prev-next-buttons .prev-btn,main #page-container #home-page #news .articles-displayer .prev-next-buttons .next-btn{border:none;background:none;display:flex;align-items:center;gap:10px;padding:5px 0}main #page-container #home-page #news .articles-displayer .prev-next-buttons .prev-btn.disabled,main #page-container #home-page #news .articles-displayer .prev-next-buttons .next-btn.disabled{visibility:hidden;pointer-events:none}main #page-container #home-page #news .articles-displayer .prev-next-buttons .prev-btn.active,main #page-container #home-page #news .articles-displayer .prev-next-buttons .next-btn.active{cursor:pointer;color:#6b7880}main #page-container #home-page #news .articles-displayer .prev-next-buttons .prev-btn.active:hover,main #page-container #home-page #news .articles-displayer .prev-next-buttons .next-btn.active:hover{color:#3c4144}main #page-container #home-page #news .articles-displayer .prev-next-buttons .next-btn.active::after{content:" ";border-style:solid;border-width:2px 2px 0 0;width:8px;height:8px;transform:rotate(45deg);display:flex;justify-content:center;align-items:center;flex-direction:row}main #page-container #home-page #news .articles-displayer .prev-next-buttons .prev-btn.active::before{content:" ";border-style:solid;border-width:2px 2px 0 0;width:8px;height:8px;transform:rotate(-135deg);display:flex;justify-content:center;align-items:center;flex-direction:row}main #page-container #home-page #news .articles-displayer article{display:grid;gap:5px 50px;grid-template-rows:auto auto auto 1fr;position:relative;padding-left:20px}main #page-container #home-page #news .articles-displayer article.grid-1{grid-template-columns:1fr}main #page-container #home-page #news .articles-displayer article.grid-2{grid-template-columns:1fr 1fr}main #page-container #home-page #news .articles-displayer article .date{grid-column:1;grid-row:1;text-align:right}main #page-container #home-page #news .articles-displayer article .date time{color:#6b7880;font-style:italic;font-size:12px}main #page-container #home-page #news .articles-displayer article .title{grid-column:1;grid-row:2}main #page-container #home-page #news .articles-displayer article .title h3{margin:0 0 10px}main #page-container #home-page #news .articles-displayer article .subtitle{grid-column:1;grid-row:3;font-style:italic;font-size:15px}main #page-container #home-page #news .articles-displayer article .body{grid-column:1;grid-row:4;min-height:200px;padding-bottom:40px;text-align:justify}main #page-container #home-page #news .articles-displayer article .image-carousel{grid-row:1/span 4;grid-column:2}main #page-container #home-page #news .articles-displayer article .image-carousel img{max-height:100%}main #page-container #home-page #news .articles-displayer article.article-placeholder{padding:0}main #page-container #home-page #news .articles-displayer article.article-placeholder *{background-color:#d4d9dd}main #page-container #home-page #news .articles-displayer article.article-placeholder .date{height:10px}main #page-container #home-page #news .articles-displayer article.article-placeholder .title{height:40px}main #page-container #home-page #news .articles-displayer article.article-placeholder .subtitle{height:30px}@media screen and (max-width: 900px){main #page-container #home-page #news .articles-displayer article{gap:5px;padding:0}main #page-container #home-page #news .articles-displayer article.grid-2{grid-template-columns:1fr;grid-template-rows:300px auto auto auto 1fr}main #page-container #home-page #news .articles-displayer article.grid-2 .date{grid-row:2}main #page-container #home-page #news .articles-displayer article.grid-2 .title{grid-row:3}main #page-container #home-page #news .articles-displayer article.grid-2 .subtitle{grid-row:4}main #page-container #home-page #news .articles-displayer article.grid-2 .body{grid-row:5}main #page-container #home-page #news .articles-displayer article.grid-2 .image-carousel{grid-row:1;grid-column:1}main #page-container #home-page #news .articles-displayer article.grid-1 .date{grid-row:1}main #page-container #home-page #news .articles-displayer article.grid-1 .title{grid-row:2}main #page-container #home-page #news .articles-displayer article.grid-1 .subtitle{grid-row:3}main #page-container #home-page #news .articles-displayer article.grid-1 .body{grid-row:4}main #page-container #home-page #news .articles-displayer article .date,main #page-container #home-page #news .articles-displayer article .title,main #page-container #home-page #news .articles-displayer article .subtitle{padding:0 10px}main #page-container #home-page #news .articles-displayer article .body{padding:0 10px 30px}}main #page-container #home-page .poles{display:grid;grid-template-columns:1fr 1fr 1fr;gap:30px;padding:100px 0}main #page-container #home-page .poles .theme-card{display:flex;flex-direction:column;width:100%;cursor:pointer;transition:transform .3s}main #page-container #home-page .poles .theme-card .card-img{width:100%;height:240px;overflow:hidden;display:flex;justify-content:center;align-items:center;flex-direction:row;flex-direction:column;position:relative}main #page-container #home-page .poles .theme-card .card-img img{position:absolute;max-width:100%;height:100%;padding:10px}main #page-container #home-page .poles .theme-card .card-title h2{margin:0;text-align:center;padding:10px 20px;color:#4baabb;display:block;background-color:#fff}main #page-container #home-page .poles .theme-card .card-description{flex:1;padding:30px 20px}main #page-container #home-page .poles .theme-card .card-description p{margin:0;color:#4baabb;text-align:center}main #page-container #home-page .poles .theme-card:hover{transform:scale(1.03)}main #page-container #home-page .kuadrado-values{background-image:url("/assets/images/wallpaper_binary_light.png");padding:100px 0 120px}main #page-container #home-page .kuadrado-values *:not(a,blue){color:#d4d9dd}main #page-container #home-page .kuadrado-values h2{display:flex;justify-content:center;align-items:center;flex-direction:row;margin:0 auto 60px;width:120px;height:120px;background-image:url("/assets/images/wallpaper_binary.png");border-radius:100%;color:#72e3f0}main #page-container #home-page .kuadrado-values ul.values-list{display:grid;grid-template-columns:repeat(3, 1fr);gap:30px}main #page-container #home-page .kuadrado-values ul.values-list li{background-image:url("/assets/images/wallpaper_binary.png");padding:30px 20px 40px}main #page-container #home-page .kuadrado-values ul.values-list li h3{text-align:center}main #page-container #home-page .kuadrado-values ul.values-list li p{text-align:justify}main #page-container #home-page #whoami{padding:20px 0 50px}main #page-container #home-page #whoami .page-contents-center{padding:40px;display:flex;justify-content:center;align-items:center;flex-direction:row;flex-direction:column}main #page-container #home-page #whoami .page-contents-center h2{text-align:center;background-color:#6b7880;display:flex;justify-content:center;align-items:center;flex-direction:row;flex-direction:column;width:220px;height:220px;border-radius:100%;padding:30px;margin:40px 0;color:#72e3f0}main #page-container #home-page #whoami .page-contents-center .presentation-card .header{display:grid;grid-template-columns:auto 1fr;gap:30px;padding:50px 0}main #page-container #home-page #whoami .page-contents-center .presentation-card .header .pic{display:flex;justify-content:center;align-items:center;flex-direction:row;flex-direction:column}main #page-container #home-page #whoami .page-contents-center .presentation-card .header .pic img{width:150px;height:auto;border-radius:100%}main #page-container #home-page #whoami .page-contents-center .presentation-card .header .header-text h3{font-size:22px;color:#96a5ae;margin:0}main #page-container #home-page #whoami .page-contents-center .presentation-card .header .header-text h4{font-size:18px}main #page-container #home-page #whoami .page-contents-center .presentation-card .header .header-text strong,main #page-container #home-page #whoami .page-contents-center .presentation-card .header .header-text h4{color:#96a5ae}main #page-container #home-page #whoami .page-contents-center .presentation-card .body p{font-size:18px;font-style:italic;font-family:serif;color:#555d61}main #page-container #home-page #whoami .page-contents-center .presentation-card .body p *:not(blue,a){color:#555d61}@media screen and (max-width: 560px){main #page-container #home-page #whoami .page-contents-center .presentation-card .header{display:flex;justify-content:center;align-items:center;flex-direction:row;flex-direction:column}main #page-container #home-page #whoami .page-contents-center .presentation-card .header .header-text{text-align:center}}@media screen and (max-width: 900px){main #page-container #home-page .poles{grid-template-columns:1fr;gap:40px}main #page-container #home-page .poles .theme-card{transition:transform .3s}main #page-container #home-page .poles .theme-card .card-img{height:300px}main #page-container #home-page .poles .theme-card .card-img img{min-width:unset;height:100%}main #page-container #home-page .poles .theme-card .card-title h2{padding:5px 20px}main #page-container #home-page .poles .theme-card .card-description{padding:20px 30px}main #page-container #home-page .poles .theme-card:hover{transform:none}main #page-container #home-page .kuadrado-values ul.values-list{grid-template-columns:1fr}}@media screen and (max-width: 1300px){main #page-container #home-page .poles{padding:20px}main #page-container #home-page .articles-displayer{padding:0}}main #page-container #education-page h3.big{font-size:30px}main #page-container #education-page .title-banner{display:flex;justify-content:flex-end;flex-direction:column;height:20vw;min-height:250px;background-image:url("/assets/images/popularization_banner.png");background-size:cover;background-repeat:no-repeat;background-position:center}main #page-container #education-page .title-banner h2{color:#fff;font-size:2.5em;margin:40px;text-shadow:0 0 6px #0003}main #page-container #education-page .special-announcement{background-color:#ffd000}main #page-container #education-page .special-announcement .page-contents-center{padding:0 20px;display:flex;justify-content:center;align-items:center;flex-direction:row}main #page-container #education-page .special-announcement .page-contents-center p{color:#555d61;font-size:20px;font-weight:600;margin:0;padding:40px 0}main #page-container #education-page .edu-themes{display:grid;grid-template-columns:1fr 1fr;gap:50px;font-family:monospace;padding:70px 0}main #page-container #education-page .edu-themes .edu-theme{display:grid;grid-template-columns:auto 1fr}main #page-container #education-page .edu-themes .edu-theme *{border-style:dashed;border-color:lime;border-width:0 0 0 0}main #page-container #education-page .edu-themes .edu-theme h3{color:lime;grid-row:1;margin:0;padding:10px;display:flex;align-items:center;border-width:0 0 0 1px}main #page-container #education-page .edu-themes .edu-theme img{width:100%;grid-row:1/span 2;border-width:1px 0 1px 1px}main #page-container #education-page .edu-themes .edu-theme p{text-align:justify;color:#72e3f0;grid-row:2;margin:0;padding:10px 30px 0 10px;border-width:1px 1px 1px 0}main #page-container #education-page .edu-themes .edu-theme p *{color:#72e3f0}main #page-container #education-page .practical-info{padding:50px 0}main #page-container #education-page .practical-info .page-contents-center{display:grid;grid-template-columns:1fr 1fr;gap:50px}main #page-container #education-page .practical-info .page-contents-center .info-block{display:grid;grid-template-rows:auto 1fr}main #page-container #education-page .practical-info .page-contents-center .info-block .info-title{color:#4baabb;margin:0;border-bottom:1px dashed #aabbc8;border-left:1px dashed #aabbc8;padding:10px}main #page-container #education-page .practical-info .page-contents-center .info-block .info-body{margin:0;padding:20px 10px;border-right:1px dashed #aabbc8;border-bottom:1px dashed #aabbc8}main #page-container #education-page .practical-info .page-contents-center .info-block ul{display:flex;flex-direction:column;gap:5px}main #page-container #education-page .practical-info .page-contents-center .info-block ul li:not(.fullwidth){display:grid;grid-template-columns:1fr 1fr;gap:10px}main #page-container #education-page .practical-info .page-contents-center .info-block ul.tabled li span{padding:3px 0}main #page-container #education-page .practical-info .page-contents-center .info-block ul.tabled li span:first-child{font-weight:bold;color:#6b7880}main #page-container #education-page .practical-info .page-contents-center .info-block ul.tabled li span:last-child{color:#4baabb}@media screen and (max-width: 1200px){main #page-container #education-page .edu-themes{grid-template-columns:1fr;gap:30px;padding:70px 0}}@media screen and (max-width: 780px){main #page-container #education-page .practical-info .page-contents-center{grid-template-columns:1fr;gap:30px}main #page-container #education-page .practical-info .page-contents-center .info-block .info-title{border-top:1px dashed #aabbc8}main #page-container #education-page .practical-info .page-contents-center .info-block .info-body{border-bottom:none}}@media screen and (max-width: 560px){main #page-container #education-page .edu-themes .edu-theme h3{border-width:0 0 1px 1px}main #page-container #education-page .edu-themes .edu-theme img{max-width:150px;height:auto;grid-row:1;border-width:1px 0 0 1px}main #page-container #education-page .edu-themes .edu-theme p{grid-row:2;grid-column:1/span 2;padding:20px 10px 30px 10px;border-width:0 1px 1px 1px}}main #page-container #games-page .game-articles article{display:grid;grid-template-columns:.7fr 1fr;gap:30px 50px;margin:20px 0}main #page-container #games-page .game-articles article.game-article{grid-template-rows:repeat(7, auto);width:100%}main #page-container #games-page .game-articles article.game-article .game-title{grid-column:1/span 2;margin:0;padding:30px 20px;color:#aabbc8;font-size:35px;font-style:italic}main #page-container #games-page .game-articles article.game-article .game-banner{grid-column:1/span 2;display:flex;justify-content:center;align-items:center;flex-direction:row;flex-direction:column;background-color:#000;overflow:hidden}main #page-container #games-page .game-articles article.game-article .game-banner img{height:500px}main #page-container #games-page .game-articles article.game-article .game-tags{display:flex;gap:10px;flex-wrap:wrap;margin:10px 20px}main #page-container #games-page .game-articles article.game-article .game-tags span{font-size:12px;padding:4px;background-color:#d4d9dd;color:#6b7880;border-radius:5px;font-weight:600}main #page-container #games-page .game-articles article.game-article .game-subtitle{grid-column:1;margin:10px 20px;color:#6b7880}main #page-container #games-page .game-articles article.game-article .game-description{grid-column:1;text-align:justify;margin:10px 20px 30px}main #page-container #games-page .game-articles article.game-article .image-carousel{grid-column:2;grid-row:3/span 4;height:100%}main #page-container #games-page .game-articles article.game-article .game-team{grid-column:1/span 2}main #page-container #games-page .game-articles article.game-article .game-team h2{color:#6b7880;padding:10px 20px;font-style:italic;font-size:20px;margin:0}main #page-container #games-page .game-articles article.game-article .game-team .team-members{display:flex;flex-direction:column}main #page-container #games-page .game-articles article.game-article .game-team .team-members .team-member{display:grid;grid-template-columns:80px 1fr;grid-template-rows:auto auto 1fr;margin:10px}main #page-container #games-page .game-articles article.game-article .game-team .team-members .team-member .team-member-img{grid-row:1/span 3;overflow:hidden}main #page-container #games-page .game-articles article.game-article .game-team .team-members .team-member .team-member-img img{width:100%;padding:0 10px 0 0}main #page-container #games-page .game-articles article.game-article .game-team .team-members .team-member .team-member-title{margin:0 0 5px;color:#6b7880}main #page-container #games-page .game-articles article.game-article .game-team .team-members .team-member .team-member-subtitle{margin:0 10px;font-size:14px;color:#96a5ae;font-style:italic}main #page-container #games-page .game-articles article.game-article .game-team .team-members .team-member .team-member-body{margin:10px 10px 20px 20px;text-align:justify}main #page-container #games-page .game-articles article.placeholder{height:400px}main #page-container #games-page .game-articles article.placeholder *{background-color:#d4d9dd}@media screen and (max-width: 900px){main #page-container #games-page .game-articles article{grid-template-columns:1fr}main #page-container #games-page .game-articles article.game-article{grid-template-rows:repeat(6, auto)}main #page-container #games-page .game-articles article.game-article .game-title{grid-column:1;padding:0;font-size:25px}main #page-container #games-page .game-articles article.game-article .game-banner{grid-column:1;margin:0 -20px}main #page-container #games-page .game-articles article.game-article .image-carousel{grid-column:1;grid-row:3;height:400px;margin:0 -20px}main #page-container #games-page .game-articles article.game-article .game-team{grid-column:1}main #page-container #games-page .game-articles article.game-article .game-team .team-members .team-member{grid-template-columns:70px 1fr}main #page-container #games-page .game-articles article.game-article .game-team .team-members .team-member .team-member-img{grid-row:1/span 2}main #page-container #games-page .game-articles article.game-article .game-team .team-members .team-member .team-member-body{grid-column:1/span 2}}main #page-container #software-page .software-articles{margin:20px auto 50px}main #page-container #software-page .software-articles article.software-article{display:grid;grid-template-columns:1fr .7fr;margin:0 0 30px;gap:10px 30px}main #page-container #software-page .software-articles article.software-article .software-title{grid-column:1/span 2;color:#aabbc8;margin:0;padding:10px}main #page-container #software-page .software-articles article.software-article .software-date{margin:0;color:#96a5ae;font-style:italic;text-align:right;color:#6b7880;font-style:italic;font-size:12px}main #page-container #software-page .software-articles article.software-article .software-subtitle{grid-column:1;margin:10px;color:#6b7880}main #page-container #software-page .software-articles article.software-article .software-description{grid-column:1;text-align:justify;margin:10px}main #page-container #software-page .software-articles article.software-article .image-carousel{grid-column:2;grid-row:2/span 6;min-height:250px}main #page-container #software-page .software-articles article.software-article .software-technical{grid-column:1}main #page-container #software-page .software-articles article.software-article .software-technical h2{color:#6b7880;margin:0 10px;padding:10px 0 0;font-size:16px}main #page-container #software-page .software-articles article.software-article .software-technical ul.technical-details{margin:10px}main #page-container #software-page .software-articles article.software-article .software-technical ul.technical-details .detail{display:grid;grid-template-columns:1fr auto;font-size:12px;border-bottom:1px solid #d4d9dd;padding:5px 0}main #page-container #software-page .software-articles article.software-article .software-technical ul.technical-details .detail label{font-weight:bold;color:#6b7880}main #page-container #software-page .software-articles article.software-article .software-technical ul.technical-details .detail ul{display:flex;flex-wrap:wrap;gap:10px}main #page-container #software-page .software-articles article.software-article .software-technical ul.releases{margin:10px}main #page-container #software-page .software-articles article.software-article .software-technical .detail{display:grid;grid-template-columns:1fr auto;font-size:12px;border-bottom:1px solid #d4d9dd;padding:5px 0}main #page-container #software-page .software-articles article.software-article .software-technical .detail label{font-weight:bold;color:#6b7880}main #page-container #software-page .software-articles article.software-article .software-technical .detail .label{color:#aabbc8}main #page-container #software-page .software-articles article.software-article .software-technical .detail ul{display:flex;flex-wrap:wrap;gap:10px}@media screen and (max-width: 900px){main #page-container #software-page .software-articles article.software-article{grid-template-columns:1fr}main #page-container #software-page .software-articles article.software-article .software-title{grid-column:1}main #page-container #software-page .software-articles article.software-article .image-carousel{grid-column:1;grid-row:2;height:200px}main #page-container #software-page .software-articles article.software-article .software-technical{grid-column:1}}main #page-container #software-page .software-articles article.placeholder{display:flex;flex-direction:column;gap:10px;margin:30px}main #page-container #software-page .software-articles article.placeholder *{background-color:#d4d9dd}main #page-container #software-page .software-articles article.placeholder .title{height:60px}main #page-container #software-page .software-articles article.placeholder .body{height:400px}main #page-container #software-page .software-articles article.placeholder .details{height:200px}main footer{display:flex;justify-content:center;align-items:center;flex-direction:row;flex-direction:column;width:100%;background-image:url("/assets/images/wallpaper_binary.png");padding:40px 20px;gap:20px;font-size:12px}main footer span{color:#96a5ae;text-align:center}main footer .logo{display:flex;justify-content:center;align-items:center;flex-direction:row;gap:10px}main footer .logo img{width:35px}main footer .logo img.text-logo{width:100px}main footer .social{display:flex;justify-content:center;align-items:center;flex-direction:row;gap:20px}main footer .social a{background-color:#555d61;display:flex;justify-content:center;align-items:center;flex-direction:row;width:25px;height:25px;font-weight:bold;font-size:16px;border-radius:100%}/*# sourceMappingURL=style.css.map */
+body {
+  font-family: Arial, Helvetica, sans-serif;
+  margin: 0;
+}
+body * {
+  box-sizing: border-box;
+  color: #35393c;
+  line-height: 1.3em;
+}
+body ul {
+  margin: 0;
+  padding: 0;
+  list-style-type: none;
+}
+body a {
+  color: #4baabb;
+  text-decoration: none;
+}
+body a:hover {
+  color: #72e3f0;
+}
+body blue {
+  color: #4baabb;
+}
+body red {
+  color: #9c3030;
+}
+body green {
+  color: #368736;
+}
+body emoji {
+  font-style: initial;
+  font-size: 25px;
+}
+body .bg-blue {
+  background-color: #4baabb;
+  color: white;
+}
+body .bg-dark {
+  background-color: #3c4144;
+  color: #aabbc8;
+}
+body #seo-title {
+  visibility: hidden;
+}
+body img.pixelated {
+  image-rendering: pixelated;
+  image-rendering: -moz-crisp-edges;
+  image-rendering: crisp-edges;
+}
+
+main {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  min-height: 100vh;
+}
+main .warning-banner {
+  background: url("/assets/images/wallpaper_warning.svg");
+  width: 100%;
+  height: 40px;
+  padding: 20px 10%;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  flex-direction: row;
+}
+main .warning-banner strong {
+  font-size: 18px;
+  color: #1c3db2;
+}
+main .image-carousel {
+  overflow: hidden;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  flex-direction: row;
+  background-color: black;
+  position: relative;
+}
+main .image-carousel img {
+  position: absolute;
+  max-width: 100%;
+  max-height: 400px;
+}
+main .image-carousel .carousel-bullets {
+  position: absolute;
+  bottom: 0;
+  padding: 20px;
+  display: flex;
+  gap: 10px;
+}
+main .image-carousel .carousel-bullets .bullet {
+  cursor: pointer;
+  width: 8px;
+  height: 8px;
+  background-color: #6b7880;
+  border-radius: 100%;
+  box-shadow: 0 0 3px black;
+}
+main .image-carousel .carousel-bullets .bullet.active {
+  background-color: #d4d9dd;
+}
+@media screen and (max-width: 900px) {
+  main .image-carousel img {
+    max-height: 100%;
+  }
+  main .image-carousel .carousel-bullets {
+    gap: 30px;
+  }
+  main .image-carousel .carousel-bullets .bullet {
+    width: 12px;
+    height: 12px;
+  }
+}
+main header {
+  width: 100%;
+  background-color: white;
+  position: sticky;
+  position: -webkit-sticky;
+  top: 0;
+  z-index: 10;
+}
+main header nav {
+  display: flex;
+  align-items: center;
+  height: 60px;
+}
+main header nav .home {
+  margin: 0 10px;
+}
+main header nav .home a {
+  display: flex;
+  align-items: center;
+  gap: 10px;
+}
+main header nav .home a img {
+  height: 40px;
+  width: auto;
+}
+main header nav .home a img.logo-text {
+  width: 120px;
+  height: auto;
+}
+main header nav ul {
+  display: flex;
+  padding: 0;
+  margin: 0;
+  list-style-type: none;
+  height: 100%;
+}
+main header nav ul li {
+  position: relative;
+}
+main header nav ul li a {
+  display: flex;
+  align-items: center;
+  height: 100%;
+  padding: 10px 20px;
+  color: #96a5ae;
+  font-weight: 800;
+  text-decoration: none;
+}
+main header nav ul li .submenu {
+  visibility: hidden;
+  overflow: hidden;
+  position: absolute;
+  height: auto;
+  max-height: 0;
+  transition: max-height 0.6s;
+  top: 100%;
+  left: 50%;
+  flex-direction: column;
+  background-color: white;
+  white-space: nowrap;
+}
+main header nav ul li.active a {
+  color: #3c4144;
+  border-bottom: 3px solid;
+}
+main header nav ul li:hover a {
+  color: #3c4144;
+}
+main header nav ul li:hover .submenu {
+  visibility: unset;
+  max-height: 1000px;
+}
+main header nav ul li:hover .submenu a {
+  color: #96a5ae;
+  border: none;
+}
+main header nav ul li:hover .submenu li:hover a {
+  color: #3c4144;
+}
+main header nav .burger {
+  display: none;
+}
+@media screen and (max-width: 560px) {
+  main header nav {
+    justify-content: space-between;
+  }
+  main header nav .burger {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    flex-direction: row;
+    flex-direction: column;
+    font-weight: bold;
+    border: 1px solid;
+    margin: 0 20px;
+    cursor: pointer;
+    border-radius: 100%;
+    width: 35px;
+    height: 35px;
+    color: #555d61;
+    font-size: 25px;
+  }
+  main header nav ul {
+    display: none;
+  }
+  main header nav ul.responsive-show {
+    display: flex;
+    flex-direction: column;
+    position: absolute;
+    right: 0;
+    max-width: 100vw;
+    min-width: 50vw;
+    top: 60px;
+    background-color: white;
+    box-shadow: 0 4px 6px 2px #0000000a;
+    height: unset;
+  }
+  main header nav ul.responsive-show li.active a {
+    border: none;
+  }
+  main header nav ul.responsive-show li .submenu {
+    display: flex;
+    visibility: visible;
+    position: relative;
+    height: unset;
+    max-height: unset;
+    transition: max-height 0.6s;
+    top: unset;
+    left: unset;
+    margin-left: 20px;
+  }
+  main header nav ul.responsive-show li .submenu li a {
+    font-weight: 400;
+    font-size: 14px;
+    color: #96a5ae;
+  }
+}
+main #page-container {
+  width: 100%;
+  flex: 1;
+}
+main #page-container .page-header {
+  background-image: url("/assets/images/wallpaper_binary.png");
+  padding: 50px 0;
+}
+main #page-container .page-header h1 {
+  padding: 15px 40px 0;
+  font-size: 25px;
+  color: #4baabb;
+  margin: 0 auto;
+}
+main #page-container .page-header p {
+  color: #72e3f0;
+  font-style: italic;
+  padding: 15px 40px 15px 100px;
+  margin: 0 auto;
+  font-size: 18px;
+}
+main #page-container .page-header p * {
+  color: #72e3f0;
+}
+main #page-container .page-header .big-logo {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  flex-direction: row;
+  gap: 20px;
+  padding: 20px;
+}
+main #page-container .page-header .big-logo img {
+  width: 200px;
+  max-width: 100%;
+}
+main #page-container .page-header .big-logo img.logo-text {
+  width: 300px;
+  max-width: 100%;
+}
+main #page-container .page-header .logo {
+  padding-left: 30px;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  flex-direction: row;
+}
+main #page-container .page-header .logo img {
+  width: 100%;
+}
+@media screen and (max-width: 560px) {
+  main #page-container .page-header h1 {
+    padding: 15px 20px 0;
+  }
+  main #page-container .page-header p {
+    padding: 20px 20px 30px 40px;
+    text-align: justify;
+  }
+  main #page-container .page-header .big-logo {
+    flex-direction: column;
+  }
+}
+main #page-container .page-header.logo-left .grid-wrapper {
+  display: grid;
+  grid-template-columns: 120px 1fr;
+  grid-template-rows: auto 1fr;
+}
+main #page-container .page-header.logo-left .grid-wrapper h1 {
+  width: 100%;
+}
+main #page-container .page-header.logo-left .grid-wrapper .logo {
+  grid-column: 1;
+  grid-row: 1;
+  width: 100%;
+}
+main #page-container .page-header.logo-left .grid-wrapper p {
+  margin: 0;
+  grid-column: 1/span 2;
+}
+@media screen and (max-width: 780px) {
+  main #page-container .page-header.logo-left .grid-wrapper h1 {
+    padding: 0 20px;
+  }
+  main #page-container .page-header.logo-left .grid-wrapper .logo {
+    padding: 0 20px;
+  }
+}
+main #page-container .page-philo {
+  background-image: url("/assets/images/wallpaper_binary.png");
+  padding: 120px 30px;
+}
+main #page-container .page-philo p {
+  width: 100%;
+  max-width: 600px;
+  font-size: 18px;
+  color: #aabbc8;
+  text-align: center;
+  font-style: italic;
+  font-weight: bold;
+}
+main #page-container .page-philo p * {
+  color: #aabbc8;
+}
+main #page-container .page-contents-center {
+  width: 1300px;
+  max-width: 100%;
+  margin: 0 auto;
+}
+@media screen and (max-width: 1300px) {
+  main #page-container .page-contents-center {
+    padding: 20px 20px 0;
+  }
+}
+main #page-container h2.page-section-title {
+  color: #4baabb;
+  padding: 20px 0 10px;
+  width: 1300px;
+  max-width: 100%;
+  margin: 0 auto;
+}
+@media screen and (max-width: 1300px) {
+  main #page-container h2.page-section-title {
+    padding: 20px 20px 0;
+  }
+}
+main #page-container #home-page {
+  display: flex;
+  flex-direction: column;
+}
+main #page-container #home-page .section-title {
+  padding: 10px;
+  margin: 0;
+  color: #aabbc8;
+}
+main #page-container #home-page .page-header .philo-bubbles {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  flex-direction: row;
+  flex-wrap: wrap;
+  gap: 40px;
+  margin: 30px 20px;
+}
+@media screen and (max-width: 780px) {
+  main #page-container #home-page .page-header .philo-bubbles {
+    gap: 20px;
+  }
+}
+main #page-container #home-page .page-header .philo-bubbles li {
+  border-radius: 100%;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  flex-direction: row;
+  background-color: #d4d9dd;
+  width: 100px;
+  height: 100px;
+}
+main #page-container #home-page .page-header .philo-bubbles li * {
+  color: #6b7880;
+}
+@media screen and (max-width: 560px) {
+  main #page-container #home-page .page-header .philo-bubbles li {
+    width: 75px;
+    height: 75px;
+  }
+  main #page-container #home-page .page-header .philo-bubbles li * {
+    font-size: 12px;
+  }
+}
+main #page-container #home-page .page-header .philo-bubbles li:first-child {
+  background-color: #6b7880;
+}
+main #page-container #home-page .page-header .philo-bubbles li:first-child * {
+  color: white;
+}
+main #page-container #home-page .page-header .philo-bubbles li:last-child {
+  background-color: #35393c;
+}
+main #page-container #home-page .page-header .philo-bubbles li:last-child * {
+  color: #96a5ae;
+}
+main #page-container #home-page #news {
+  padding: 60px 20px;
+}
+main #page-container #home-page #news .articles-displayer {
+  margin: 0 auto 40px;
+}
+main #page-container #home-page #news .articles-displayer .prev-next-buttons {
+  display: flex;
+  justify-content: space-between;
+}
+main #page-container #home-page #news .articles-displayer .prev-next-buttons .prev-btn,
+main #page-container #home-page #news .articles-displayer .prev-next-buttons .next-btn {
+  border: none;
+  background: none;
+  display: flex;
+  align-items: center;
+  gap: 10px;
+  padding: 5px 0;
+}
+main #page-container #home-page #news .articles-displayer .prev-next-buttons .prev-btn.disabled,
+main #page-container #home-page #news .articles-displayer .prev-next-buttons .next-btn.disabled {
+  visibility: hidden;
+  pointer-events: none;
+}
+main #page-container #home-page #news .articles-displayer .prev-next-buttons .prev-btn.active,
+main #page-container #home-page #news .articles-displayer .prev-next-buttons .next-btn.active {
+  cursor: pointer;
+  color: #6b7880;
+}
+main #page-container #home-page #news .articles-displayer .prev-next-buttons .prev-btn.active:hover,
+main #page-container #home-page #news .articles-displayer .prev-next-buttons .next-btn.active:hover {
+  color: #3c4144;
+}
+main #page-container #home-page #news .articles-displayer .prev-next-buttons .next-btn.active::after {
+  content: " ";
+  border-style: solid;
+  border-width: 2px 2px 0 0;
+  width: 8px;
+  height: 8px;
+  transform: rotate(45deg);
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  flex-direction: row;
+}
+main #page-container #home-page #news .articles-displayer .prev-next-buttons .prev-btn.active::before {
+  content: " ";
+  border-style: solid;
+  border-width: 2px 2px 0 0;
+  width: 8px;
+  height: 8px;
+  transform: rotate(-135deg);
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  flex-direction: row;
+}
+main #page-container #home-page #news .articles-displayer article {
+  display: grid;
+  gap: 5px 50px;
+  grid-template-rows: auto auto auto 1fr;
+  position: relative;
+  padding-left: 20px;
+}
+main #page-container #home-page #news .articles-displayer article.grid-1 {
+  grid-template-columns: 1fr;
+}
+main #page-container #home-page #news .articles-displayer article.grid-2 {
+  grid-template-columns: 1fr 1fr;
+}
+main #page-container #home-page #news .articles-displayer article .date {
+  grid-column: 1;
+  grid-row: 1;
+  text-align: right;
+}
+main #page-container #home-page #news .articles-displayer article .date time {
+  color: #6b7880;
+  font-style: italic;
+  font-size: 12px;
+}
+main #page-container #home-page #news .articles-displayer article .title {
+  grid-column: 1;
+  grid-row: 2;
+}
+main #page-container #home-page #news .articles-displayer article .title h3 {
+  margin: 0 0 10px;
+}
+main #page-container #home-page #news .articles-displayer article .subtitle {
+  grid-column: 1;
+  grid-row: 3;
+  font-style: italic;
+  font-size: 15px;
+}
+main #page-container #home-page #news .articles-displayer article .body {
+  grid-column: 1;
+  grid-row: 4;
+  min-height: 200px;
+  padding-bottom: 40px;
+  text-align: justify;
+}
+main #page-container #home-page #news .articles-displayer article .image-carousel {
+  grid-row: 1/span 4;
+  grid-column: 2;
+}
+main #page-container #home-page #news .articles-displayer article .image-carousel img {
+  max-height: 100%;
+}
+main #page-container #home-page #news .articles-displayer article.article-placeholder {
+  padding: 0;
+}
+main #page-container #home-page #news .articles-displayer article.article-placeholder * {
+  background-color: #d4d9dd;
+}
+main #page-container #home-page #news .articles-displayer article.article-placeholder .date {
+  height: 10px;
+}
+main #page-container #home-page #news .articles-displayer article.article-placeholder .title {
+  height: 40px;
+}
+main #page-container #home-page #news .articles-displayer article.article-placeholder .subtitle {
+  height: 30px;
+}
+@media screen and (max-width: 900px) {
+  main #page-container #home-page #news .articles-displayer article {
+    gap: 5px;
+    padding: 0;
+  }
+  main #page-container #home-page #news .articles-displayer article.grid-2 {
+    grid-template-columns: 1fr;
+    grid-template-rows: 300px auto auto auto 1fr;
+  }
+  main #page-container #home-page #news .articles-displayer article.grid-2 .date {
+    grid-row: 2;
+  }
+  main #page-container #home-page #news .articles-displayer article.grid-2 .title {
+    grid-row: 3;
+  }
+  main #page-container #home-page #news .articles-displayer article.grid-2 .subtitle {
+    grid-row: 4;
+  }
+  main #page-container #home-page #news .articles-displayer article.grid-2 .body {
+    grid-row: 5;
+  }
+  main #page-container #home-page #news .articles-displayer article.grid-2 .image-carousel {
+    grid-row: 1;
+    grid-column: 1;
+  }
+  main #page-container #home-page #news .articles-displayer article.grid-1 .date {
+    grid-row: 1;
+  }
+  main #page-container #home-page #news .articles-displayer article.grid-1 .title {
+    grid-row: 2;
+  }
+  main #page-container #home-page #news .articles-displayer article.grid-1 .subtitle {
+    grid-row: 3;
+  }
+  main #page-container #home-page #news .articles-displayer article.grid-1 .body {
+    grid-row: 4;
+  }
+  main #page-container #home-page #news .articles-displayer article .date,
+main #page-container #home-page #news .articles-displayer article .title,
+main #page-container #home-page #news .articles-displayer article .subtitle {
+    padding: 0 10px;
+  }
+  main #page-container #home-page #news .articles-displayer article .body {
+    padding: 0 10px 30px;
+  }
+}
+main #page-container #home-page .poles {
+  display: grid;
+  grid-template-columns: 1fr 1fr 1fr;
+  gap: 30px;
+  padding: 100px 0;
+}
+main #page-container #home-page .poles .theme-card {
+  display: flex;
+  flex-direction: column;
+  width: 100%;
+  cursor: pointer;
+  transition: transform 0.3s;
+}
+main #page-container #home-page .poles .theme-card .card-img {
+  width: 100%;
+  height: 240px;
+  overflow: hidden;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  flex-direction: row;
+  flex-direction: column;
+  position: relative;
+}
+main #page-container #home-page .poles .theme-card .card-img img {
+  position: absolute;
+  max-width: 100%;
+  height: 100%;
+  padding: 10px;
+}
+main #page-container #home-page .poles .theme-card .card-title h2 {
+  margin: 0;
+  text-align: center;
+  padding: 10px 20px;
+  color: #4baabb;
+  display: block;
+  background-color: white;
+}
+main #page-container #home-page .poles .theme-card .card-description {
+  flex: 1;
+  padding: 30px 20px;
+}
+main #page-container #home-page .poles .theme-card .card-description p {
+  margin: 0;
+  color: #4baabb;
+  text-align: center;
+}
+main #page-container #home-page .poles .theme-card:hover {
+  transform: scale(1.03);
+}
+main #page-container #home-page .kuadrado-values {
+  background-image: url("/assets/images/wallpaper_binary_light.png");
+  padding: 100px 0 120px;
+}
+main #page-container #home-page .kuadrado-values *:not(a, blue) {
+  color: #d4d9dd;
+}
+main #page-container #home-page .kuadrado-values h2 {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  flex-direction: row;
+  margin: 0 auto 60px;
+  width: 120px;
+  height: 120px;
+  background-image: url("/assets/images/wallpaper_binary.png");
+  border-radius: 100%;
+  color: #72e3f0;
+}
+main #page-container #home-page .kuadrado-values ul.values-list {
+  display: grid;
+  grid-template-columns: repeat(3, 1fr);
+  gap: 30px;
+}
+main #page-container #home-page .kuadrado-values ul.values-list li {
+  background-image: url("/assets/images/wallpaper_binary.png");
+  padding: 30px 20px 40px;
+}
+main #page-container #home-page .kuadrado-values ul.values-list li h3 {
+  text-align: center;
+}
+main #page-container #home-page .kuadrado-values ul.values-list li p {
+  text-align: justify;
+}
+main #page-container #home-page #whoami {
+  padding: 20px 0 50px;
+}
+main #page-container #home-page #whoami .page-contents-center {
+  padding: 40px;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  flex-direction: row;
+  flex-direction: column;
+}
+main #page-container #home-page #whoami .page-contents-center h2 {
+  text-align: center;
+  background-color: #6b7880;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  flex-direction: row;
+  flex-direction: column;
+  width: 220px;
+  height: 220px;
+  border-radius: 100%;
+  padding: 30px;
+  margin: 40px 0;
+  color: #72e3f0;
+}
+main #page-container #home-page #whoami .page-contents-center .presentation-card .header {
+  display: grid;
+  grid-template-columns: auto 1fr;
+  gap: 30px;
+  padding: 50px 0;
+}
+main #page-container #home-page #whoami .page-contents-center .presentation-card .header .pic {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  flex-direction: row;
+  flex-direction: column;
+}
+main #page-container #home-page #whoami .page-contents-center .presentation-card .header .pic img {
+  width: 150px;
+  height: auto;
+  border-radius: 100%;
+}
+main #page-container #home-page #whoami .page-contents-center .presentation-card .header .header-text h3 {
+  font-size: 22px;
+  color: #96a5ae;
+  margin: 0;
+}
+main #page-container #home-page #whoami .page-contents-center .presentation-card .header .header-text h4 {
+  font-size: 18px;
+}
+main #page-container #home-page #whoami .page-contents-center .presentation-card .header .header-text strong,
+main #page-container #home-page #whoami .page-contents-center .presentation-card .header .header-text h4 {
+  color: #96a5ae;
+}
+main #page-container #home-page #whoami .page-contents-center .presentation-card .body p {
+  font-size: 18px;
+  font-style: italic;
+  font-family: serif;
+  color: #555d61;
+}
+main #page-container #home-page #whoami .page-contents-center .presentation-card .body p *:not(blue, a) {
+  color: #555d61;
+}
+@media screen and (max-width: 560px) {
+  main #page-container #home-page #whoami .page-contents-center .presentation-card .header {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    flex-direction: row;
+    flex-direction: column;
+  }
+  main #page-container #home-page #whoami .page-contents-center .presentation-card .header .header-text {
+    text-align: center;
+  }
+}
+@media screen and (max-width: 900px) {
+  main #page-container #home-page .poles {
+    grid-template-columns: 1fr;
+    gap: 40px;
+  }
+  main #page-container #home-page .poles .theme-card {
+    transition: transform 0.3s;
+  }
+  main #page-container #home-page .poles .theme-card .card-img {
+    height: 300px;
+  }
+  main #page-container #home-page .poles .theme-card .card-img img {
+    min-width: unset;
+    height: 100%;
+  }
+  main #page-container #home-page .poles .theme-card .card-title h2 {
+    padding: 5px 20px;
+  }
+  main #page-container #home-page .poles .theme-card .card-description {
+    padding: 20px 30px;
+  }
+  main #page-container #home-page .poles .theme-card:hover {
+    transform: none;
+  }
+  main #page-container #home-page .kuadrado-values ul.values-list {
+    grid-template-columns: 1fr;
+  }
+}
+@media screen and (max-width: 1300px) {
+  main #page-container #home-page .poles {
+    padding: 20px;
+  }
+  main #page-container #home-page .articles-displayer {
+    padding: 0;
+  }
+}
+main #page-container #education-page h3.big {
+  font-size: 30px;
+}
+main #page-container #education-page .title-banner {
+  display: flex;
+  justify-content: flex-end;
+  flex-direction: column;
+  height: 20vw;
+  min-height: 250px;
+  background-image: url("/assets/images/popularization_banner.png");
+  background-size: cover;
+  background-repeat: no-repeat;
+  background-position: center;
+}
+main #page-container #education-page .title-banner h2 {
+  color: white;
+  font-size: 2.5em;
+  margin: 40px;
+  text-shadow: 0 0 6px #0003;
+}
+main #page-container #education-page .special-announcement {
+  background-color: #ffd000;
+}
+main #page-container #education-page .special-announcement .page-contents-center {
+  padding: 0 20px;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  flex-direction: row;
+}
+main #page-container #education-page .special-announcement .page-contents-center p {
+  color: #555d61;
+  font-size: 20px;
+  font-weight: 600;
+  margin: 0;
+  padding: 40px 0;
+}
+main #page-container #education-page .edu-themes {
+  display: grid;
+  grid-template-columns: 1fr 1fr;
+  gap: 50px;
+  font-family: monospace;
+  padding: 70px 0;
+}
+main #page-container #education-page .edu-themes .edu-theme {
+  display: grid;
+  grid-template-columns: auto 1fr;
+}
+main #page-container #education-page .edu-themes .edu-theme * {
+  border-style: dashed;
+  border-color: #00ff00;
+  border-width: 0 0 0 0;
+}
+main #page-container #education-page .edu-themes .edu-theme h3 {
+  color: #00ff00;
+  grid-row: 1;
+  margin: 0;
+  padding: 10px;
+  display: flex;
+  align-items: center;
+  border-width: 0 0 0 1px;
+}
+main #page-container #education-page .edu-themes .edu-theme img {
+  width: 100%;
+  grid-row: 1/span 2;
+  border-width: 1px 0 1px 1px;
+}
+main #page-container #education-page .edu-themes .edu-theme p {
+  text-align: justify;
+  color: #72e3f0;
+  grid-row: 2;
+  margin: 0;
+  padding: 10px 30px 0 10px;
+  border-width: 1px 1px 1px 0;
+}
+main #page-container #education-page .edu-themes .edu-theme p * {
+  color: #72e3f0;
+}
+main #page-container #education-page .practical-info {
+  padding: 50px 0;
+}
+main #page-container #education-page .practical-info .page-contents-center {
+  display: grid;
+  grid-template-columns: 1fr 1fr;
+  gap: 50px;
+}
+main #page-container #education-page .practical-info .page-contents-center .info-block {
+  display: grid;
+  grid-template-rows: auto 1fr;
+}
+main #page-container #education-page .practical-info .page-contents-center .info-block .info-title {
+  color: #4baabb;
+  margin: 0;
+  border-bottom: 1px dashed #aabbc8;
+  border-left: 1px dashed #aabbc8;
+  padding: 10px;
+}
+main #page-container #education-page .practical-info .page-contents-center .info-block .info-body {
+  margin: 0;
+  padding: 20px 10px;
+  border-right: 1px dashed #aabbc8;
+  border-bottom: 1px dashed #aabbc8;
+}
+main #page-container #education-page .practical-info .page-contents-center .info-block ul {
+  display: flex;
+  flex-direction: column;
+  gap: 5px;
+}
+main #page-container #education-page .practical-info .page-contents-center .info-block ul li:not(.fullwidth) {
+  display: grid;
+  grid-template-columns: 1fr 1fr;
+  gap: 10px;
+}
+main #page-container #education-page .practical-info .page-contents-center .info-block ul.tabled li span {
+  padding: 3px 0;
+}
+main #page-container #education-page .practical-info .page-contents-center .info-block ul.tabled li span:first-child {
+  font-weight: bold;
+  color: #6b7880;
+}
+main #page-container #education-page .practical-info .page-contents-center .info-block ul.tabled li span:last-child {
+  color: #4baabb;
+}
+@media screen and (max-width: 1200px) {
+  main #page-container #education-page .edu-themes {
+    grid-template-columns: 1fr;
+    gap: 30px;
+    padding: 70px 0;
+  }
+}
+@media screen and (max-width: 780px) {
+  main #page-container #education-page .practical-info .page-contents-center {
+    grid-template-columns: 1fr;
+    gap: 30px;
+  }
+  main #page-container #education-page .practical-info .page-contents-center .info-block .info-title {
+    border-top: 1px dashed #aabbc8;
+  }
+  main #page-container #education-page .practical-info .page-contents-center .info-block .info-body {
+    border-bottom: none;
+  }
+}
+@media screen and (max-width: 560px) {
+  main #page-container #education-page .edu-themes .edu-theme h3 {
+    border-width: 0 0 1px 1px;
+  }
+  main #page-container #education-page .edu-themes .edu-theme img {
+    max-width: 150px;
+    height: auto;
+    grid-row: 1;
+    border-width: 1px 0 0 1px;
+  }
+  main #page-container #education-page .edu-themes .edu-theme p {
+    grid-row: 2;
+    grid-column: 1/span 2;
+    padding: 20px 10px 30px 10px;
+    border-width: 0 1px 1px 1px;
+  }
+}
+main #page-container #games-page .game-articles article {
+  display: grid;
+  grid-template-columns: 0.7fr 1fr;
+  gap: 30px 50px;
+  margin: 20px 0;
+}
+main #page-container #games-page .game-articles article.game-article {
+  grid-template-rows: repeat(7, auto);
+  width: 100%;
+}
+main #page-container #games-page .game-articles article.game-article .game-title {
+  grid-column: 1/span 2;
+  margin: 0;
+  padding: 30px 20px;
+  color: #aabbc8;
+  font-size: 35px;
+  font-style: italic;
+}
+main #page-container #games-page .game-articles article.game-article .game-banner {
+  grid-column: 1/span 2;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  flex-direction: row;
+  flex-direction: column;
+  background-color: black;
+  overflow: hidden;
+}
+main #page-container #games-page .game-articles article.game-article .game-banner img {
+  height: 500px;
+}
+main #page-container #games-page .game-articles article.game-article .game-tags {
+  display: flex;
+  gap: 10px;
+  flex-wrap: wrap;
+  margin: 10px 20px;
+}
+main #page-container #games-page .game-articles article.game-article .game-tags span {
+  font-size: 12px;
+  padding: 4px;
+  background-color: #d4d9dd;
+  color: #6b7880;
+  border-radius: 5px;
+  font-weight: 600;
+}
+main #page-container #games-page .game-articles article.game-article .game-subtitle {
+  grid-column: 1;
+  margin: 10px 20px;
+  color: #6b7880;
+}
+main #page-container #games-page .game-articles article.game-article .game-description {
+  grid-column: 1;
+  text-align: justify;
+  margin: 10px 20px 30px;
+}
+main #page-container #games-page .game-articles article.game-article .image-carousel {
+  grid-column: 2;
+  grid-row: 3/span 4;
+  height: 100%;
+}
+main #page-container #games-page .game-articles article.game-article .game-team {
+  grid-column: 1/span 2;
+}
+main #page-container #games-page .game-articles article.game-article .game-team h2 {
+  color: #6b7880;
+  padding: 10px 20px;
+  font-style: italic;
+  font-size: 20px;
+  margin: 0;
+}
+main #page-container #games-page .game-articles article.game-article .game-team .team-members {
+  display: flex;
+  flex-direction: column;
+}
+main #page-container #games-page .game-articles article.game-article .game-team .team-members .team-member {
+  display: grid;
+  grid-template-columns: 80px 1fr;
+  grid-template-rows: auto auto 1fr;
+  margin: 10px;
+}
+main #page-container #games-page .game-articles article.game-article .game-team .team-members .team-member .team-member-img {
+  grid-row: 1/span 3;
+  overflow: hidden;
+}
+main #page-container #games-page .game-articles article.game-article .game-team .team-members .team-member .team-member-img img {
+  width: 100%;
+  padding: 0 10px 0 0;
+}
+main #page-container #games-page .game-articles article.game-article .game-team .team-members .team-member .team-member-title {
+  margin: 0 0 5px;
+  color: #6b7880;
+}
+main #page-container #games-page .game-articles article.game-article .game-team .team-members .team-member .team-member-subtitle {
+  margin: 0 10px;
+  font-size: 14px;
+  color: #96a5ae;
+  font-style: italic;
+}
+main #page-container #games-page .game-articles article.game-article .game-team .team-members .team-member .team-member-body {
+  margin: 10px 10px 20px 20px;
+  text-align: justify;
+}
+main #page-container #games-page .game-articles article.placeholder {
+  height: 400px;
+}
+main #page-container #games-page .game-articles article.placeholder * {
+  background-color: #d4d9dd;
+}
+@media screen and (max-width: 900px) {
+  main #page-container #games-page .game-articles article {
+    grid-template-columns: 1fr;
+  }
+  main #page-container #games-page .game-articles article.game-article {
+    grid-template-rows: repeat(6, auto);
+  }
+  main #page-container #games-page .game-articles article.game-article .game-title {
+    grid-column: 1;
+    padding: 0;
+    font-size: 25px;
+  }
+  main #page-container #games-page .game-articles article.game-article .game-banner {
+    grid-column: 1;
+    margin: 0 -20px;
+  }
+  main #page-container #games-page .game-articles article.game-article .image-carousel {
+    grid-column: 1;
+    grid-row: 3;
+    height: 400px;
+    margin: 0 -20px;
+  }
+  main #page-container #games-page .game-articles article.game-article .game-team {
+    grid-column: 1;
+  }
+  main #page-container #games-page .game-articles article.game-article .game-team .team-members .team-member {
+    grid-template-columns: 70px 1fr;
+  }
+  main #page-container #games-page .game-articles article.game-article .game-team .team-members .team-member .team-member-img {
+    grid-row: 1/span 2;
+  }
+  main #page-container #games-page .game-articles article.game-article .game-team .team-members .team-member .team-member-body {
+    grid-column: 1/span 2;
+  }
+}
+main #page-container #software-page .software-articles {
+  margin: 20px auto 50px;
+}
+main #page-container #software-page .software-articles article.software-article {
+  display: grid;
+  grid-template-columns: auto 1fr;
+  margin: 0 0 50px;
+  gap: 10px 30px;
+}
+main #page-container #software-page .software-articles article.software-article .software-title {
+  grid-column: 2;
+  color: #aabbc8;
+  margin: 0;
+  padding: 10px;
+}
+main #page-container #software-page .software-articles article.software-article .software-subtitle {
+  grid-column: 2;
+  margin: 10px;
+  color: #6b7880;
+}
+main #page-container #software-page .software-articles article.software-article .software-description {
+  grid-column: 2;
+  text-align: justify;
+  margin: 10px;
+}
+main #page-container #software-page .software-articles article.software-article .software-image {
+  padding: 20px;
+  background-color: black;
+  grid-column: 1;
+  grid-row: 1/span 3;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  flex-direction: row;
+  width: 200px;
+  height: 200px;
+  overflow: hidden;
+  border-radius: 100%;
+}
+main #page-container #software-page .software-articles article.software-article .software-image img {
+  max-width: 100%;
+  max-height: 400px;
+}
+main #page-container #software-page .software-articles article.software-article .software-technical {
+  grid-column: 1/span 2;
+}
+main #page-container #software-page .software-articles article.software-article .software-technical h2 {
+  color: #6b7880;
+  margin: 0 10px;
+  padding: 10px 0 0;
+  font-size: 16px;
+}
+main #page-container #software-page .software-articles article.software-article .software-technical ul.technical-details {
+  margin: 10px;
+}
+main #page-container #software-page .software-articles article.software-article .software-technical ul.technical-details .detail {
+  display: grid;
+  grid-template-columns: 1fr auto;
+  font-size: 12px;
+  border-bottom: 1px solid #d4d9dd;
+  padding: 5px 0;
+}
+main #page-container #software-page .software-articles article.software-article .software-technical ul.technical-details .detail label {
+  font-weight: bold;
+  color: #6b7880;
+}
+main #page-container #software-page .software-articles article.software-article .software-technical ul.technical-details .detail ul {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 10px;
+}
+main #page-container #software-page .software-articles article.software-article .software-technical ul.releases {
+  margin: 10px;
+}
+main #page-container #software-page .software-articles article.software-article .software-technical .detail {
+  display: grid;
+  grid-template-columns: 1fr auto;
+  font-size: 12px;
+  border-bottom: 1px solid #d4d9dd;
+  padding: 5px 0;
+}
+main #page-container #software-page .software-articles article.software-article .software-technical .detail label {
+  font-weight: bold;
+  color: #6b7880;
+}
+main #page-container #software-page .software-articles article.software-article .software-technical .detail .label {
+  color: #aabbc8;
+}
+main #page-container #software-page .software-articles article.software-article .software-technical .detail ul {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 10px;
+}
+@media screen and (max-width: 900px) {
+  main #page-container #software-page .software-articles article.software-article .software-title {
+    display: flex;
+    align-items: center;
+  }
+  main #page-container #software-page .software-articles article.software-article .software-subtitle,
+main #page-container #software-page .software-articles article.software-article .software-description {
+    grid-column: 1/span 2;
+  }
+  main #page-container #software-page .software-articles article.software-article .software-image {
+    width: 100px;
+    height: 100px;
+    grid-row: 1;
+  }
+}
+main #page-container #software-page .software-articles article.placeholder {
+  display: flex;
+  flex-direction: column;
+  gap: 10px;
+  margin: 30px;
+}
+main #page-container #software-page .software-articles article.placeholder * {
+  background-color: #d4d9dd;
+}
+main #page-container #software-page .software-articles article.placeholder .title {
+  height: 60px;
+}
+main #page-container #software-page .software-articles article.placeholder .body {
+  height: 400px;
+}
+main #page-container #software-page .software-articles article.placeholder .details {
+  height: 200px;
+}
+main footer {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  flex-direction: row;
+  flex-direction: column;
+  width: 100%;
+  background-image: url("/assets/images/wallpaper_binary.png");
+  padding: 40px 20px;
+  gap: 20px;
+  font-size: 12px;
+}
+main footer span {
+  color: #96a5ae;
+  text-align: center;
+}
+main footer .logo {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  flex-direction: row;
+  gap: 10px;
+}
+main footer .logo img {
+  width: 35px;
+}
+main footer .logo img.text-logo {
+  width: 100px;
+}
+main footer .social {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  flex-direction: row;
+  gap: 20px;
+}
+main footer .social a {
+  background-color: #555d61;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  flex-direction: row;
+  width: 25px;
+  height: 25px;
+  font-weight: bold;
+  font-size: 16px;
+  border-radius: 100%;
+}
+
+/*# sourceMappingURL=style.css.map */
diff --git a/src/lib/article-utils.js b/src/lib/article-utils.js
index 3a7d83f773806cc6779d6bfef87fd438972badf8..2d182cab9eaecdf620cb1a751e44462f9b3d6233 100644
--- a/src/lib/article-utils.js
+++ b/src/lib/article-utils.js
@@ -48,7 +48,7 @@ function populateArticles(articles) {
                 return article;
             })
         )
-            .then(completeArticles => resolve(completeArticles.sort((a, b) => a.date - b.date)))
+            .then(completeArticles => resolve(completeArticles.sort((a, b) => b.date - a.date)))
             .catch(e => reject(e));
     });
 }
diff --git a/src/pages/software-development/components/software-articles.js b/src/pages/software-development/components/software-articles.js
index d33ac02749a2a8ca9df0c3a385df1cb6bc3d7307..5ef3c6f61d7249570a5d2adb04bd6c5d7f07b7f9 100644
--- a/src/pages/software-development/components/software-articles.js
+++ b/src/pages/software-development/components/software-articles.js
@@ -25,10 +25,12 @@ class SoftwareArticle {
                     property: "name",
                 },
                 {
-                    tag: "time",
-                    class: "software-date",
-                    contents: getArticleDate(date),
-                    property: "datePublished",
+                    tag: "div", class: "software-image",
+                    contents: [
+                        {
+                            tag: "img", src: `${path}/images/${images[0]}`
+                        }
+                    ]
                 },
                 {
                     tag: "h3",
@@ -42,7 +44,6 @@ class SoftwareArticle {
                     contents: getArticleBody(body),
                     property: "description",
                 },
-                new ImageCarousel({ images: images.map(img => `${path}/images/${img}`) }).render(),
                 {
                     tag: "div",
                     class: "software-technical",
diff --git a/src/pages/software-development/software-development.scss b/src/pages/software-development/software-development.scss
index 87fdc63dc227b842f6f97289c52ad56c764967ba..c6f66707f8c865554a51448ed027a5b72fc50ff6 100644
--- a/src/pages/software-development/software-development.scss
+++ b/src/pages/software-development/software-development.scss
@@ -3,43 +3,47 @@
         margin: 20px auto 50px;
         article.software-article {
             display: grid;
-            grid-template-columns: 1fr 0.7fr;
-            margin: 0 0 30px;
+            grid-template-columns: auto 1fr;
+            margin: 0 0 50px;
             gap: 10px 30px;
+
             .software-title {
-                grid-column: 1 / span 2;
+                grid-column: 2;
                 color: $light_2;
                 margin: 0;
                 padding: 10px;
             }
-            .software-date {
-                margin: 0;
-                color: $light_1;
-                font-style: italic;
-                text-align: right;
-                color: $medium_grey;
-                font-style: italic;
-                font-size: 12px;
-            }
 
             .software-subtitle {
-                grid-column: 1;
+                grid-column: 2;
                 margin: 10px;
                 color: $medium_grey;
             }
 
             .software-description {
-                grid-column: 1;
+                grid-column: 2;
                 text-align: justify;
                 margin: 10px;
             }
-            .image-carousel {
-                grid-column: 2;
-                grid-row: 2 / span 6;
-                min-height: 250px;
+
+            .software-image {
+                padding: 20px;
+                background-color: black;
+                grid-column: 1;
+                grid-row: 1 / span 3;
+                @include flex-center;
+                width: 200px;
+                height: 200px;
+                overflow: hidden;
+                border-radius: 100%;
+                img {
+                    max-width: 100%;
+                    max-height: 400px;
+                }
             }
+
             .software-technical {
-                grid-column: 1;
+                grid-column: 1 / span 2;
                 h2 {
                     color: $medium_grey;
                     margin: 0 10px;
@@ -91,17 +95,18 @@
                 }
             }
             @media screen and (max-width: $screen_l) {
-                grid-template-columns: 1fr;
                 .software-title {
-                    grid-column: 1;
+                    display: flex;
+                    align-items: center;
                 }
-                .image-carousel {
-                    grid-column: 1;
-                    grid-row: 2;
-                    height: 200px;
+                .software-subtitle,
+                .software-description {
+                    grid-column: 1 / span 2;
                 }
-                .software-technical {
-                    grid-column: 1;
+                .software-image {
+                    width: 100px;
+                    height: 100px;
+                    grid-row: 1;
                 }
             }
         }