From 24d6e2689210fd212b491fdcf4e3345df6c24842 Mon Sep 17 00:00:00 2001
From: ncamera <nico_camera98@hotmail.com>
Date: Tue, 8 Nov 2022 22:21:57 -0300
Subject: [PATCH] Se actualizan modales y editor CodeMirror
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

 - Ya no se usa más la dependencia ng2-bootstrap-modal para diseñar los modales.

 - Los modales fueron rediseñados completamente como Web Components usando el compilador StencilJS. Estos Web components funcionaran correctamente en las siguientes versiones de Angular, ya que no dependen de la versión de Angular para funcionar; más aún, dichos Web Components pueden funcionar en varios framework (React, Vue y Ember) y JavaScript, con minima configuración.
  La UI de los modales están en los Web Components y el compartamiento y comunicación con el Back-end están implementados del lado de Angular. La interacción entre los Web Components para consumir servicios del Back-end se realiza capturando los eventos que exponen los Web Components.

 - Ya no se usa más la dependencia ng2-codemirror para modelar el editor de texto.

 - El editor de texto ahora se modela con las dependencias codemirror y lt-codemirror, las cuales tienen una configuración prácticamente idéntica a la antigua dependencia ng2-codemirror.
---
 Frontend Angular 4/angular.json               |    8 +-
 Frontend Angular 4/browserslist               |   12 +
 .../custom codemirror/jump-to-line.js         |   59 +-
 .../custom codemirror/search.js               |  349 +++--
 .../custom codemirror/show-hint.js            |  452 ++++--
 Frontend Angular 4/package-lock.json          | 1353 ++++++-----------
 Frontend Angular 4/package.json               |    6 +-
 .../layout/archivos/archivos.component.html   |  127 +-
 .../app/layout/archivos/archivos.component.ts |  681 ++++++---
 .../app/layout/archivos/archivos.module.ts    |   32 +-
 .../archivos/compartirArchivo.component.ts    |  111 --
 .../archivos/confirmarEliminar.component.ts   |   91 --
 .../layout/archivos/nuevoArchivo.component.ts |  126 --
 .../seleccionarDirectorio.component.ts        |  134 --
 .../archivos/verCalificacion.component.ts     |   59 -
 .../grupos/calificarEntrega.component.ts      |  150 --
 .../app/layout/grupos/grupos.component.html   |   59 +-
 .../src/app/layout/grupos/grupos.component.ts |   95 +-
 .../src/app/layout/grupos/grupos.module.ts    |   15 +-
 .../src/app/layout/layout.module.ts           |    4 +-
 .../app/layout/matefun/confirm.component.ts   |   44 -
 .../app/layout/matefun/matefun.component.html |   56 +-
 .../app/layout/matefun/matefun.component.ts   |  165 +-
 .../src/app/layout/matefun/matefun.module.ts  |   14 +-
 .../seleccionarDirectorio.component.ts        |  199 ---
 .../src/app/shared/modal/confirm.component.ts |   49 -
 .../src/app/shared/objects/archivo.ts         |    9 +
 Frontend Angular 4/src/assets/i18n/en.json    |  296 ++--
 Frontend Angular 4/src/assets/i18n/es.json    |  294 ++--
 .../src/styles/_responsive.scss               |  163 +-
 30 files changed, 2386 insertions(+), 2826 deletions(-)
 create mode 100644 Frontend Angular 4/browserslist
 delete mode 100755 Frontend Angular 4/src/app/layout/archivos/compartirArchivo.component.ts
 delete mode 100755 Frontend Angular 4/src/app/layout/archivos/confirmarEliminar.component.ts
 delete mode 100755 Frontend Angular 4/src/app/layout/archivos/nuevoArchivo.component.ts
 delete mode 100755 Frontend Angular 4/src/app/layout/archivos/seleccionarDirectorio.component.ts
 delete mode 100755 Frontend Angular 4/src/app/layout/archivos/verCalificacion.component.ts
 delete mode 100755 Frontend Angular 4/src/app/layout/grupos/calificarEntrega.component.ts
 delete mode 100755 Frontend Angular 4/src/app/layout/matefun/confirm.component.ts
 delete mode 100755 Frontend Angular 4/src/app/layout/matefun/seleccionarDirectorio.component.ts
 delete mode 100755 Frontend Angular 4/src/app/shared/modal/confirm.component.ts

diff --git a/Frontend Angular 4/angular.json b/Frontend Angular 4/angular.json
index 105f7599..85e0379e 100644
--- a/Frontend Angular 4/angular.json	
+++ b/Frontend Angular 4/angular.json	
@@ -90,10 +90,10 @@
               "src/styles/console.css",
               "src/styles/hints.css",
               "node_modules/tippy.js/dist/tippy.css",
-              "node_modules/codemirror/lib/codemirror.css",
-              "node_modules/codemirror/addon/hint/show-hint.css",
-              "node_modules/codemirror/addon/dialog/dialog.css",
-              "node_modules/codemirror/addon/search/matchesonscrollbar.css"
+              "node_modules/lt-codemirror/lib/lt-codemirror.css",
+              "node_modules/lt-codemirror/addon/hint/show-hint.css",
+              "node_modules/lt-codemirror/addon/dialog/dialog.css",
+              "node_modules/lt-codemirror/addon/search/matchesonscrollbar.css"
             ],
             "assets": ["src/assets", "src/favicon.ico", "src/.htaccess"]
           }
diff --git a/Frontend Angular 4/browserslist b/Frontend Angular 4/browserslist
new file mode 100644
index 00000000..80848532
--- /dev/null
+++ b/Frontend Angular 4/browserslist	
@@ -0,0 +1,12 @@
+# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
+# For additional information regarding the format and rule options, please see:
+# https://github.com/browserslist/browserslist#queries
+
+# You can see what browsers were selected by your queries by running:
+#   npx browserslist
+
+> 0.5%
+last 2 versions
+Firefox ESR
+not dead
+not IE 9-11 # For IE 9-11 support, remove 'not'.
\ No newline at end of file
diff --git a/Frontend Angular 4/custom codemirror/jump-to-line.js b/Frontend Angular 4/custom codemirror/jump-to-line.js
index 696bbd40..b867b327 100755
--- a/Frontend Angular 4/custom codemirror/jump-to-line.js	
+++ b/Frontend Angular 4/custom codemirror/jump-to-line.js	
@@ -3,46 +3,55 @@
 
 // Defines jumpToLine command. Uses dialog.js if present.
 
-(function(mod) {
-  if (typeof exports == "object" && typeof module == "object") // CommonJS
+(function (mod) {
+  if (typeof exports == "object" && typeof module == "object")
+    // CommonJS
     mod(require("../../lib/codemirror"), require("../dialog/dialog"));
-  else if (typeof define == "function" && define.amd) // AMD
+  else if (typeof define == "function" && define.amd)
+    // AMD
     define(["../../lib/codemirror", "../dialog/dialog"], mod);
-  else // Plain browser env
-    mod(CodeMirror);
-})(function(CodeMirror) {
+  // Plain browser env
+  else mod(CodeMirror);
+})(function (CodeMirror) {
   "use strict";
 
   function dialog(cm, text, shortText, deflt, f) {
-    if (cm.openDialog) cm.openDialog(text, f, {value: deflt, selectValueOnOpen: true});
+    if (cm.openDialog)
+      cm.openDialog(text, f, { value: deflt, selectValueOnOpen: true });
     else f(prompt(shortText, deflt));
   }
 
   var jumpDialog =
-      'Ir a la línea: <input type="text" style="width: 10em" class="CodeMirror-search-field"/> <span style="color: #888" class="CodeMirror-search-hint"></span>';
+    'Ir a la línea: <input type="text" style="width: 10em" class="CodeMirror-search-field"/> <span style="color: #888" class="CodeMirror-search-hint"></span>';
 
   function interpretLine(cm, string) {
-    var num = Number(string)
-    if (/^[-+]/.test(string)) return cm.getCursor().line + num
-    else return num - 1
+    var num = Number(string);
+    if (/^[-+]/.test(string)) return cm.getCursor().line + num;
+    else return num - 1;
   }
 
-  CodeMirror.commands.jumpToLine = function(cm) {
+  CodeMirror.commands.jumpToLine = function (cm) {
     var cur = cm.getCursor();
-    dialog(cm, jumpDialog, "Jump to line:", (cur.line + 1) + ":" + cur.ch, function(posStr) {
-      if (!posStr) return;
-
-      var match;
-      if (match = /^\s*([\+\-]?\d+)\s*\:\s*(\d+)\s*$/.exec(posStr)) {
-        cm.setCursor(interpretLine(cm, match[1]), Number(match[2]))
-      } else if (match = /^\s*([\+\-]?\d+(\.\d+)?)\%\s*/.exec(posStr)) {
-        var line = Math.round(cm.lineCount() * Number(match[1]) / 100);
-        if (/^[-+]/.test(match[1])) line = cur.line + line + 1;
-        cm.setCursor(line - 1, cur.ch);
-      } else if (match = /^\s*\:?\s*([\+\-]?\d+)\s*/.exec(posStr)) {
-        cm.setCursor(interpretLine(cm, match[1]), cur.ch);
+    dialog(
+      cm,
+      jumpDialog,
+      "Jump to line:",
+      cur.line + 1 + ":" + cur.ch,
+      function (posStr) {
+        if (!posStr) return;
+
+        var match;
+        if ((match = /^\s*([\+\-]?\d+)\s*\:\s*(\d+)\s*$/.exec(posStr))) {
+          cm.setCursor(interpretLine(cm, match[1]), Number(match[2]));
+        } else if ((match = /^\s*([\+\-]?\d+(\.\d+)?)\%\s*/.exec(posStr))) {
+          var line = Math.round((cm.lineCount() * Number(match[1])) / 100);
+          if (/^[-+]/.test(match[1])) line = cur.line + line + 1;
+          cm.setCursor(line - 1, cur.ch);
+        } else if ((match = /^\s*\:?\s*([\+\-]?\d+)\s*/.exec(posStr))) {
+          cm.setCursor(interpretLine(cm, match[1]), cur.ch);
+        }
       }
-    });
+    );
   };
 
   CodeMirror.keyMap["default"]["Alt-G"] = "jumpToLine";
diff --git a/Frontend Angular 4/custom codemirror/search.js b/Frontend Angular 4/custom codemirror/search.js
index 08b24d26..82806abe 100755
--- a/Frontend Angular 4/custom codemirror/search.js	
+++ b/Frontend Angular 4/custom codemirror/search.js	
@@ -9,34 +9,45 @@
 // replace by making sure the match is no longer selected when hitting
 // Ctrl-G.
 
-(function(mod) {
-  if (typeof exports == "object" && typeof module == "object") // CommonJS
-    mod(require("../../lib/codemirror"), require("./searchcursor"), require("../dialog/dialog"));
-  else if (typeof define == "function" && define.amd) // AMD
+(function (mod) {
+  if (typeof exports == "object" && typeof module == "object")
+    // CommonJS
+    mod(
+      require("../../lib/codemirror"),
+      require("./searchcursor"),
+      require("../dialog/dialog")
+    );
+  else if (typeof define == "function" && define.amd)
+    // AMD
     define(["../../lib/codemirror", "./searchcursor", "../dialog/dialog"], mod);
-  else // Plain browser env
-    mod(CodeMirror);
-})(function(CodeMirror) {
+  // Plain browser env
+  else mod(CodeMirror);
+})(function (CodeMirror) {
   "use strict";
 
   function searchOverlay(query, caseInsensitive) {
     if (typeof query == "string")
-      query = new RegExp(query.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"), caseInsensitive ? "gi" : "g");
+      query = new RegExp(
+        query.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"),
+        caseInsensitive ? "gi" : "g"
+      );
     else if (!query.global)
       query = new RegExp(query.source, query.ignoreCase ? "gi" : "g");
 
-    return {token: function(stream) {
-      query.lastIndex = stream.pos;
-      var match = query.exec(stream.string);
-      if (match && match.index == stream.pos) {
-        stream.pos += match[0].length || 1;
-        return "searching";
-      } else if (match) {
-        stream.pos = match.index;
-      } else {
-        stream.skipToEnd();
-      }
-    }};
+    return {
+      token: function (stream) {
+        query.lastIndex = stream.pos;
+        var match = query.exec(stream.string);
+        if (match && match.index == stream.pos) {
+          stream.pos += match[0].length || 1;
+          return "searching";
+        } else if (match) {
+          stream.pos = match.index;
+        } else {
+          stream.skipToEnd();
+        }
+      },
+    };
   }
 
   function SearchState() {
@@ -54,7 +65,10 @@
 
   function getSearchCursor(cm, query, pos) {
     // Heuristic: if the query string is all lowercase, do a case insensitive search.
-    return cm.getSearchCursor(query, pos, {caseFold: queryCaseInsensitive(query), multiline: true});
+    return cm.getSearchCursor(query, pos, {
+      caseFold: queryCaseInsensitive(query),
+      multiline: true,
+    });
   }
 
   function persistentDialog(cm, text, deflt, onEnter, onKeyDown) {
@@ -62,13 +76,16 @@
       value: deflt,
       selectValueOnOpen: true,
       closeOnEnter: false,
-      onClose: function() { clearSearch(cm); },
-      onKeyDown: onKeyDown
+      onClose: function () {
+        clearSearch(cm);
+      },
+      onKeyDown: onKeyDown,
     });
   }
 
   function dialog(cm, text, shortText, deflt, f) {
-    if (cm.openDialog) cm.openDialog(text, f, {value: deflt, selectValueOnOpen: true});
+    if (cm.openDialog)
+      cm.openDialog(text, f, { value: deflt, selectValueOnOpen: true });
     else f(prompt(shortText, deflt));
   }
 
@@ -78,23 +95,23 @@
   }
 
   function parseString(string) {
-    return string.replace(/\\(.)/g, function(_, ch) {
-      if (ch == "n") return "\n"
-      if (ch == "r") return "\r"
-      return ch
-    })
+    return string.replace(/\\(.)/g, function (_, ch) {
+      if (ch == "n") return "\n";
+      if (ch == "r") return "\r";
+      return ch;
+    });
   }
 
   function parseQuery(query) {
     var isRE = query.match(/^\/(.*)\/([a-z]*)$/);
     if (isRE) {
-      try { query = new RegExp(isRE[1], isRE[2].indexOf("i") == -1 ? "" : "i"); }
-      catch(e) {} // Not a regular expression after all, do a string search
+      try {
+        query = new RegExp(isRE[1], isRE[2].indexOf("i") == -1 ? "" : "i");
+      } catch (e) {} // Not a regular expression after all, do a string search
     } else {
-      query = parseString(query)
+      query = parseString(query);
     }
-    if (typeof query == "string" ? query == "" : query.test(""))
-      query = /x^/;
+    if (typeof query == "string" ? query == "" : query.test("")) query = /x^/;
     return query;
   }
 
@@ -105,11 +122,20 @@
     state.queryText = query;
     state.query = parseQuery(query);
     cm.removeOverlay(state.overlay, queryCaseInsensitive(state.query));
-    state.overlay = searchOverlay(state.query, queryCaseInsensitive(state.query));
+    state.overlay = searchOverlay(
+      state.query,
+      queryCaseInsensitive(state.query)
+    );
     cm.addOverlay(state.overlay);
     if (cm.showMatchesOnScrollbar) {
-      if (state.annotate) { state.annotate.clear(); state.annotate = null; }
-      state.annotate = cm.showMatchesOnScrollbar(state.query, queryCaseInsensitive(state.query));
+      if (state.annotate) {
+        state.annotate.clear();
+        state.annotate = null;
+      }
+      state.annotate = cm.showMatchesOnScrollbar(
+        state.query,
+        queryCaseInsensitive(state.query)
+      );
     }
   }
 
@@ -118,29 +144,37 @@
     if (state.query) return findNext(cm, rev);
     var q = cm.getSelection() || state.lastQuery;
     if (persistent && cm.openDialog) {
-      var hiding = null
-      var searchNext = function(query, event) {
+      var hiding = null;
+      var searchNext = function (query, event) {
         CodeMirror.e_stop(event);
         if (!query) return;
         if (query != state.queryText) {
           startSearch(cm, state, query);
           state.posFrom = state.posTo = cm.getCursor();
         }
-        if (hiding) hiding.style.opacity = 1
-        findNext(cm, event.shiftKey, function(_, to) {
-          var dialog
-          if (to.line < 3 && document.querySelector &&
-              (dialog = cm.display.wrapper.querySelector(".CodeMirror-dialog")) &&
-              dialog.getBoundingClientRect().bottom - 4 > cm.cursorCoords(to, "window").top)
-            (hiding = dialog).style.opacity = .4
-        })
+        if (hiding) hiding.style.opacity = 1;
+        findNext(cm, event.shiftKey, function (_, to) {
+          var dialog;
+          if (
+            to.line < 3 &&
+            document.querySelector &&
+            (dialog = cm.display.wrapper.querySelector(".CodeMirror-dialog")) &&
+            dialog.getBoundingClientRect().bottom - 4 >
+              cm.cursorCoords(to, "window").top
+          )
+            (hiding = dialog).style.opacity = 0.4;
+        });
       };
-      persistentDialog(cm, queryDialog, q, searchNext, function(event, query) {
-        var keyName = CodeMirror.keyName(event)
-        var cmd = CodeMirror.keyMap[cm.getOption("keyMap")][keyName]
-        if (!cmd) cmd = cm.getOption('extraKeys')[keyName]
-        if (cmd == "findNext" || cmd == "findPrev" ||
-          cmd == "findPersistentNext" || cmd == "findPersistentPrev") {
+      persistentDialog(cm, queryDialog, q, searchNext, function (event, query) {
+        var keyName = CodeMirror.keyName(event);
+        var cmd = CodeMirror.keyMap[cm.getOption("keyMap")][keyName];
+        if (!cmd) cmd = cm.getOption("extraKeys")[keyName];
+        if (
+          cmd == "findNext" ||
+          cmd == "findPrev" ||
+          cmd == "findPersistentNext" ||
+          cmd == "findPersistentPrev"
+        ) {
           CodeMirror.e_stop(event);
           startSearch(cm, getSearchState(cm), query);
           cm.execCommand(cmd);
@@ -154,49 +188,74 @@
         findNext(cm, rev);
       }
     } else {
-      dialog(cm, queryDialog, "Buscar por:", q, function(query) {
-        if (query && !state.query) cm.operation(function() {
-          startSearch(cm, state, query);
-          state.posFrom = state.posTo = cm.getCursor();
-          findNext(cm, rev);
-        });
+      dialog(cm, queryDialog, "Buscar por:", q, function (query) {
+        if (query && !state.query)
+          cm.operation(function () {
+            startSearch(cm, state, query);
+            state.posFrom = state.posTo = cm.getCursor();
+            findNext(cm, rev);
+          });
       });
     }
   }
 
-  function findNext(cm, rev, callback) {cm.operation(function() {
-    var state = getSearchState(cm);
-    var cursor = getSearchCursor(cm, state.query, rev ? state.posFrom : state.posTo);
-    if (!cursor.find(rev)) {
-      cursor = getSearchCursor(cm, state.query, rev ? CodeMirror.Pos(cm.lastLine()) : CodeMirror.Pos(cm.firstLine(), 0));
-      if (!cursor.find(rev)) return;
-    }
-    cm.setSelection(cursor.from(), cursor.to());
-    cm.scrollIntoView({from: cursor.from(), to: cursor.to()}, 20);
-    state.posFrom = cursor.from(); state.posTo = cursor.to();
-    if (callback) callback(cursor.from(), cursor.to())
-  });}
+  function findNext(cm, rev, callback) {
+    cm.operation(function () {
+      var state = getSearchState(cm);
+      var cursor = getSearchCursor(
+        cm,
+        state.query,
+        rev ? state.posFrom : state.posTo
+      );
+      if (!cursor.find(rev)) {
+        cursor = getSearchCursor(
+          cm,
+          state.query,
+          rev
+            ? CodeMirror.Pos(cm.lastLine())
+            : CodeMirror.Pos(cm.firstLine(), 0)
+        );
+        if (!cursor.find(rev)) return;
+      }
+      cm.setSelection(cursor.from(), cursor.to());
+      cm.scrollIntoView({ from: cursor.from(), to: cursor.to() }, 20);
+      state.posFrom = cursor.from();
+      state.posTo = cursor.to();
+      if (callback) callback(cursor.from(), cursor.to());
+    });
+  }
 
-  function clearSearch(cm) {cm.operation(function() {
-    var state = getSearchState(cm);
-    state.lastQuery = state.query;
-    if (!state.query) return;
-    state.query = state.queryText = null;
-    cm.removeOverlay(state.overlay);
-    if (state.annotate) { state.annotate.clear(); state.annotate = null; }
-  });}
+  function clearSearch(cm) {
+    cm.operation(function () {
+      var state = getSearchState(cm);
+      state.lastQuery = state.query;
+      if (!state.query) return;
+      state.query = state.queryText = null;
+      cm.removeOverlay(state.overlay);
+      if (state.annotate) {
+        state.annotate.clear();
+        state.annotate = null;
+      }
+    });
+  }
 
   var replaceQueryDialog =
     ' <input type="text" style="width: 10em" class="CodeMirror-search-field"/> <span style="color: #888" class="CodeMirror-search-hint"></span>';
-  var replacementQueryDialog = '<span class="CodeMirror-search-label">Con:</span> <input type="text" style="width: 10em" class="CodeMirror-search-field"/>';
-  var doReplaceConfirm = '<span class="CodeMirror-search-label">Reemplazar?</span> <button>Si</button> <button>No</button> <button>Todos</button> <button>Cancelar</button>';
+  var replacementQueryDialog =
+    '<span class="CodeMirror-search-label">Con:</span> <input type="text" style="width: 10em" class="CodeMirror-search-field"/>';
+  var doReplaceConfirm =
+    '<span class="CodeMirror-search-label">Reemplazar?</span> <button>Si</button> <button>No</button> <button>Todos</button> <button>Cancelar</button>';
 
   function replaceAll(cm, query, text) {
-    cm.operation(function() {
-      for (var cursor = getSearchCursor(cm, query); cursor.findNext();) {
+    cm.operation(function () {
+      for (var cursor = getSearchCursor(cm, query); cursor.findNext(); ) {
         if (typeof query != "string") {
           var match = cm.getRange(cursor.from(), cursor.to()).match(query);
-          cursor.replace(text.replace(/\$(\d)/g, function(_, i) {return match[i];}));
+          cursor.replace(
+            text.replace(/\$(\d)/g, function (_, i) {
+              return match[i];
+            })
+          );
         } else cursor.replace(text);
       }
     });
@@ -205,48 +264,94 @@
   function replace(cm, all) {
     if (cm.getOption("readOnly")) return;
     var query = cm.getSelection() || getSearchState(cm).lastQuery;
-    var dialogText = '<span class="CodeMirror-search-label">' + (all ? 'Reemplazar todo:' : 'Reemplazar:') + '</span>';
-    dialog(cm, dialogText + replaceQueryDialog, dialogText, query, function(query) {
-      if (!query) return;
-      query = parseQuery(query);
-      dialog(cm, replacementQueryDialog, "Reemplazar con:", "", function(text) {
-        text = parseString(text)
-        if (all) {
-          replaceAll(cm, query, text)
-        } else {
-          clearSearch(cm);
-          var cursor = getSearchCursor(cm, query, cm.getCursor("from"));
-          var advance = function() {
-            var start = cursor.from(), match;
-            if (!(match = cursor.findNext())) {
-              cursor = getSearchCursor(cm, query);
-              if (!(match = cursor.findNext()) ||
-                  (start && cursor.from().line == start.line && cursor.from().ch == start.ch)) return;
+    var dialogText =
+      '<span class="CodeMirror-search-label">' +
+      (all ? "Reemplazar todo:" : "Reemplazar:") +
+      "</span>";
+    dialog(
+      cm,
+      dialogText + replaceQueryDialog,
+      dialogText,
+      query,
+      function (query) {
+        if (!query) return;
+        query = parseQuery(query);
+        dialog(
+          cm,
+          replacementQueryDialog,
+          "Reemplazar con:",
+          "",
+          function (text) {
+            text = parseString(text);
+            if (all) {
+              replaceAll(cm, query, text);
+            } else {
+              clearSearch(cm);
+              var cursor = getSearchCursor(cm, query, cm.getCursor("from"));
+              var advance = function () {
+                var start = cursor.from(),
+                  match;
+                if (!(match = cursor.findNext())) {
+                  cursor = getSearchCursor(cm, query);
+                  if (
+                    !(match = cursor.findNext()) ||
+                    (start &&
+                      cursor.from().line == start.line &&
+                      cursor.from().ch == start.ch)
+                  )
+                    return;
+                }
+                cm.setSelection(cursor.from(), cursor.to());
+                cm.scrollIntoView({ from: cursor.from(), to: cursor.to() });
+                confirmDialog(cm, doReplaceConfirm, "Reemplazar?", [
+                  function () {
+                    doReplace(match);
+                  },
+                  advance,
+                  function () {
+                    replaceAll(cm, query, text);
+                  },
+                ]);
+              };
+              var doReplace = function (match) {
+                cursor.replace(
+                  typeof query == "string"
+                    ? text
+                    : text.replace(/\$(\d)/g, function (_, i) {
+                        return match[i];
+                      })
+                );
+                advance();
+              };
+              advance();
             }
-            cm.setSelection(cursor.from(), cursor.to());
-            cm.scrollIntoView({from: cursor.from(), to: cursor.to()});
-            confirmDialog(cm, doReplaceConfirm, "Reemplazar?",
-                          [function() {doReplace(match);}, advance,
-                           function() {replaceAll(cm, query, text)}]);
-          };
-          var doReplace = function(match) {
-            cursor.replace(typeof query == "string" ? text :
-                           text.replace(/\$(\d)/g, function(_, i) {return match[i];}));
-            advance();
-          };
-          advance();
-        }
-      });
-    });
+          }
+        );
+      }
+    );
   }
 
-  CodeMirror.commands.find = function(cm) {clearSearch(cm); doSearch(cm);};
-  CodeMirror.commands.findPersistent = function(cm) {clearSearch(cm); doSearch(cm, false, true);};
-  CodeMirror.commands.findPersistentNext = function(cm) {doSearch(cm, false, true, true);};
-  CodeMirror.commands.findPersistentPrev = function(cm) {doSearch(cm, true, true, true);};
+  CodeMirror.commands.find = function (cm) {
+    clearSearch(cm);
+    doSearch(cm);
+  };
+  CodeMirror.commands.findPersistent = function (cm) {
+    clearSearch(cm);
+    doSearch(cm, false, true);
+  };
+  CodeMirror.commands.findPersistentNext = function (cm) {
+    doSearch(cm, false, true, true);
+  };
+  CodeMirror.commands.findPersistentPrev = function (cm) {
+    doSearch(cm, true, true, true);
+  };
   CodeMirror.commands.findNext = doSearch;
-  CodeMirror.commands.findPrev = function(cm) {doSearch(cm, true);};
+  CodeMirror.commands.findPrev = function (cm) {
+    doSearch(cm, true);
+  };
   CodeMirror.commands.clearSearch = clearSearch;
   CodeMirror.commands.replace = replace;
-  CodeMirror.commands.replaceAll = function(cm) {replace(cm, true);};
+  CodeMirror.commands.replaceAll = function (cm) {
+    replace(cm, true);
+  };
 });
diff --git a/Frontend Angular 4/custom codemirror/show-hint.js b/Frontend Angular 4/custom codemirror/show-hint.js
index 28025775..193bb293 100755
--- a/Frontend Angular 4/custom codemirror/show-hint.js	
+++ b/Frontend Angular 4/custom codemirror/show-hint.js	
@@ -1,32 +1,34 @@
 // CodeMirror, copyright (c) by Marijn Haverbeke and others
 // Distributed under an MIT license: https://codemirror.net/LICENSE
 
-(function(mod) {
-  if (typeof exports == "object" && typeof module == "object") // CommonJS
+(function (mod) {
+  if (typeof exports == "object" && typeof module == "object")
+    // CommonJS
     mod(require("../../lib/codemirror"));
-  else if (typeof define == "function" && define.amd) // AMD
+  else if (typeof define == "function" && define.amd)
+    // AMD
     define(["../../lib/codemirror"], mod);
-  else // Plain browser env
-    mod(CodeMirror);
-})(function(CodeMirror) {
+  // Plain browser env
+  else mod(CodeMirror);
+})(function (CodeMirror) {
   "use strict";
 
-  var HINT_ELEMENT_CLASS        = "CodeMirror-hint";
+  var HINT_ELEMENT_CLASS = "CodeMirror-hint";
   var ACTIVE_HINT_ELEMENT_CLASS = "CodeMirror-hint-active";
 
   // This is the old interface, kept around for now to stay
   // backwards-compatible.
-  CodeMirror.showHint = function(cm, getHints, options) {
+  CodeMirror.showHint = function (cm, getHints, options) {
     if (!getHints) return cm.showHint(options);
     if (options && options.async) getHints.async = true;
-    var newOpts = {hint: getHints};
+    var newOpts = { hint: getHints };
     if (options) for (var prop in options) newOpts[prop] = options[prop];
     return cm.showHint(newOpts);
   };
 
-  CodeMirror.defineExtension("showHint", function(options) {
+  CodeMirror.defineExtension("showHint", function (options) {
     options = parseOptions(this, this.getCursor("start"), options);
-    var selections = this.listSelections()
+    var selections = this.listSelections();
     if (selections.length > 1) return;
     // By default, don't allow completion when something is selected.
     // A hint function can have a `supportsSelection` property to
@@ -39,7 +41,10 @@
     }
 
     if (this.state.completionActive) this.state.completionActive.close();
-    var completion = this.state.completionActive = new Completion(this, options);
+    var completion = (this.state.completionActive = new Completion(
+      this,
+      options
+    ));
     if (!completion.options.hint) return;
 
     CodeMirror.signal(this, "startCompletion", this);
@@ -53,19 +58,28 @@
     this.debounce = 0;
     this.tick = 0;
     this.startPos = this.cm.getCursor("start");
-    this.startLen = this.cm.getLine(this.startPos.line).length - this.cm.getSelection().length;
+    this.startLen =
+      this.cm.getLine(this.startPos.line).length -
+      this.cm.getSelection().length;
 
     var self = this;
-    cm.on("cursorActivity", this.activityFunc = function() { self.cursorActivity(); });
+    cm.on(
+      "cursorActivity",
+      (this.activityFunc = function () {
+        self.cursorActivity();
+      })
+    );
   }
 
-  var requestAnimationFrame = window.requestAnimationFrame || function(fn) {
-    return setTimeout(fn, 1000/60);
-  };
+  var requestAnimationFrame =
+    window.requestAnimationFrame ||
+    function (fn) {
+      return setTimeout(fn, 1000 / 60);
+    };
   var cancelAnimationFrame = window.cancelAnimationFrame || clearTimeout;
 
   Completion.prototype = {
-    close: function() {
+    close: function () {
       if (!this.active()) return;
       this.cm.state.completionActive = null;
       this.tick = null;
@@ -76,49 +90,65 @@
       CodeMirror.signal(this.cm, "endCompletion", this.cm);
     },
 
-    active: function() {
+    active: function () {
       return this.cm.state.completionActive == this;
     },
 
-    pick: function(data, i) {
+    pick: function (data, i) {
       var completion = data.list[i];
       if (completion.hint) completion.hint(this.cm, data, completion);
-      else this.cm.replaceRange(getText(completion), completion.from || data.from,
-                                completion.to || data.to, "complete");
+      else
+        this.cm.replaceRange(
+          getText(completion),
+          completion.from || data.from,
+          completion.to || data.to,
+          "complete"
+        );
       CodeMirror.signal(data, "pick", completion);
       this.close();
     },
 
-    cursorActivity: function() {
+    cursorActivity: function () {
       if (this.debounce) {
         cancelAnimationFrame(this.debounce);
         this.debounce = 0;
       }
 
-      var pos = this.cm.getCursor(), line = this.cm.getLine(pos.line);
-      if (pos.line != this.startPos.line || line.length - pos.ch != this.startLen - this.startPos.ch ||
-          pos.ch < this.startPos.ch || this.cm.somethingSelected() ||
-          (!pos.ch || this.options.closeCharacters.test(line.charAt(pos.ch - 1)))) {
+      var pos = this.cm.getCursor(),
+        line = this.cm.getLine(pos.line);
+      if (
+        pos.line != this.startPos.line ||
+        line.length - pos.ch != this.startLen - this.startPos.ch ||
+        pos.ch < this.startPos.ch ||
+        this.cm.somethingSelected() ||
+        !pos.ch ||
+        this.options.closeCharacters.test(line.charAt(pos.ch - 1))
+      ) {
         this.close();
       } else {
         var self = this;
-        this.debounce = requestAnimationFrame(function() {self.update();});
+        this.debounce = requestAnimationFrame(function () {
+          self.update();
+        });
         if (this.widget) this.widget.disable();
       }
     },
 
-    update: function(first) {
-      if (this.tick == null) return
-      var self = this, myTick = ++this.tick
-      fetchHints(this.options.hint, this.cm, this.options, function(data) {
-        if (self.tick == myTick) self.finishUpdate(data, first)
-      })
+    update: function (first) {
+      if (this.tick == null) return;
+      var self = this,
+        myTick = ++this.tick;
+      fetchHints(this.options.hint, this.cm, this.options, function (data) {
+        if (self.tick == myTick) self.finishUpdate(data, first);
+      });
     },
 
-    finishUpdate: function(data, first) {
+    finishUpdate: function (data, first) {
       if (this.data) CodeMirror.signal(this.data, "update");
 
-      var picked = (this.widget && this.widget.picked) || (first && this.options.completeSingle);
+      var picked =
+        (this.widget && this.widget.picked) ||
+        (first && this.options.completeSingle);
       if (this.widget) this.widget.close();
 
       this.data = data;
@@ -131,18 +161,20 @@
           CodeMirror.signal(data, "shown");
         }
       }
-    }
+    },
   };
 
   function parseOptions(cm, pos, options) {
     var editor = cm.options.hintOptions;
     var out = {};
     for (var prop in defaultOptions) out[prop] = defaultOptions[prop];
-    if (editor) for (var prop in editor)
-      if (editor[prop] !== undefined) out[prop] = editor[prop];
-    if (options) for (var prop in options)
-      if (options[prop] !== undefined) out[prop] = options[prop];
-    if (out.hint.resolve) out.hint = out.hint.resolve(cm, pos)
+    if (editor)
+      for (var prop in editor)
+        if (editor[prop] !== undefined) out[prop] = editor[prop];
+    if (options)
+      for (var prop in options)
+        if (options[prop] !== undefined) out[prop] = options[prop];
+    if (out.hint.resolve) out.hint = out.hint.resolve(cm, pos);
     return out;
   }
 
@@ -153,42 +185,55 @@
 
   function buildKeyMap(completion, handle) {
     var baseMap = {
-      Up: function() {handle.moveFocus(-1);},
-      Down: function() {handle.moveFocus(1);},
-      PageUp: function() {handle.moveFocus(-handle.menuSize() + 1, true);},
-      PageDown: function() {handle.moveFocus(handle.menuSize() - 1, true);},
-      Home: function() {handle.setFocus(0);},
-      End: function() {handle.setFocus(handle.length - 1);},
+      Up: function () {
+        handle.moveFocus(-1);
+      },
+      Down: function () {
+        handle.moveFocus(1);
+      },
+      PageUp: function () {
+        handle.moveFocus(-handle.menuSize() + 1, true);
+      },
+      PageDown: function () {
+        handle.moveFocus(handle.menuSize() - 1, true);
+      },
+      Home: function () {
+        handle.setFocus(0);
+      },
+      End: function () {
+        handle.setFocus(handle.length - 1);
+      },
       Enter: handle.pick,
       Tab: handle.pick,
-      Esc: handle.close
+      Esc: handle.close,
     };
     var custom = completion.options.customKeys;
     var ourMap = custom ? {} : baseMap;
     function addBinding(key, val) {
       var bound;
       if (typeof val != "string")
-        bound = function(cm) { return val(cm, handle); };
+        bound = function (cm) {
+          return val(cm, handle);
+        };
       // This mechanism is deprecated
-      else if (baseMap.hasOwnProperty(val))
-        bound = baseMap[val];
-      else
-        bound = val;
+      else if (baseMap.hasOwnProperty(val)) bound = baseMap[val];
+      else bound = val;
       ourMap[key] = bound;
     }
     if (custom)
-      for (var key in custom) if (custom.hasOwnProperty(key))
-        addBinding(key, custom[key]);
+      for (var key in custom)
+        if (custom.hasOwnProperty(key)) addBinding(key, custom[key]);
     var extra = completion.options.extraKeys;
     if (extra)
-      for (var key in extra) if (extra.hasOwnProperty(key))
-        addBinding(key, extra[key]);
+      for (var key in extra)
+        if (extra.hasOwnProperty(key)) addBinding(key, extra[key]);
     return ourMap;
   }
 
   function getHintElement(hintsElement, el) {
     while (el && el != hintsElement) {
-      if (el.nodeName.toUpperCase() === "LI" && el.parentNode == hintsElement) return el;
+      if (el.nodeName.toUpperCase() === "LI" && el.parentNode == hintsElement)
+        return el;
       el = el.parentNode;
     }
   }
@@ -197,45 +242,69 @@
     this.completion = completion;
     this.data = data;
     this.picked = false;
-    var widget = this, cm = completion.cm;
+    var widget = this,
+      cm = completion.cm;
     var ownerDocument = cm.getInputField().ownerDocument;
     var parentWindow = ownerDocument.defaultView || ownerDocument.parentWindow;
 
-    var hints = this.hints = ownerDocument.createElement("ul");
+    var hints = (this.hints = ownerDocument.createElement("ul"));
     var theme = completion.cm.options.theme;
     hints.className = "CodeMirror-hints " + theme;
     this.selectedHint = data.selectedHint || 0;
 
     var completions = data.list;
     for (var i = 0; i < completions.length; ++i) {
-      var elt = hints.appendChild(ownerDocument.createElement("li")), cur = completions[i];
-      var className = HINT_ELEMENT_CLASS + (i != this.selectedHint ? "" : " " + ACTIVE_HINT_ELEMENT_CLASS);
+      var elt = hints.appendChild(ownerDocument.createElement("li")),
+        cur = completions[i];
+      var className =
+        HINT_ELEMENT_CLASS +
+        (i != this.selectedHint ? "" : " " + ACTIVE_HINT_ELEMENT_CLASS);
       if (cur.className != null) className = cur.className + " " + className;
       elt.className = className;
       if (cur.render) cur.render(elt, data, cur);
-      else elt.appendChild(ownerDocument.createTextNode(cur.displayText || getText(cur)));
+      else
+        elt.appendChild(
+          ownerDocument.createTextNode(cur.displayText || getText(cur))
+        );
       elt.hintId = i;
     }
 
-    var pos = cm.cursorCoords(completion.options.alignWithWord ? data.from : null);
-    var left = pos.left, top = pos.bottom, below = true;
+    var pos = cm.cursorCoords(
+      completion.options.alignWithWord ? data.from : null
+    );
+    var left = pos.left,
+      top = pos.bottom,
+      below = true;
     hints.style.left = left + "px";
     hints.style.top = top + "px";
     // If we're at the edge of the screen, then we want the menu to appear on the left of the cursor.
-    var winW = parentWindow.innerWidth || Math.max(ownerDocument.body.offsetWidth, ownerDocument.documentElement.offsetWidth);
-    var winH = parentWindow.innerHeight || Math.max(ownerDocument.body.offsetHeight, ownerDocument.documentElement.offsetHeight);
+    var winW =
+      parentWindow.innerWidth ||
+      Math.max(
+        ownerDocument.body.offsetWidth,
+        ownerDocument.documentElement.offsetWidth
+      );
+    var winH =
+      parentWindow.innerHeight ||
+      Math.max(
+        ownerDocument.body.offsetHeight,
+        ownerDocument.documentElement.offsetHeight
+      );
     (completion.options.container || ownerDocument.body).appendChild(hints);
-    var box = hints.getBoundingClientRect(), overlapY = box.bottom - winH;
-    var scrolls = hints.scrollHeight > hints.clientHeight + 1
+    var box = hints.getBoundingClientRect(),
+      overlapY = box.bottom - winH;
+    var scrolls = hints.scrollHeight > hints.clientHeight + 1;
     var startScroll = cm.getScrollInfo();
 
     if (overlapY > 0) {
-      var height = box.bottom - box.top, curTop = pos.top - (pos.bottom - box.top);
-      if (curTop - height > 0) { // Fits above cursor
+      var height = box.bottom - box.top,
+        curTop = pos.top - (pos.bottom - box.top);
+      if (curTop - height > 0) {
+        // Fits above cursor
         hints.style.top = (top = pos.top - height) + "px";
         below = false;
       } else if (height > winH) {
-        hints.style.height = (winH - 5) + "px";
+        hints.style.height = winH - 5 + "px";
         hints.style.top = (top = pos.bottom - box.top) + "px";
         var cursor = cm.getCursor();
         if (data.from.ch != cursor.ch) {
@@ -248,46 +317,82 @@
     var overlapX = box.right - winW;
     if (overlapX > 0) {
       if (box.right - box.left > winW) {
-        hints.style.width = (winW - 5) + "px";
-        overlapX -= (box.right - box.left) - winW;
+        hints.style.width = winW - 5 + "px";
+        overlapX -= box.right - box.left - winW;
       }
       hints.style.left = (left = pos.left - overlapX) + "px";
     }
-    if (scrolls) for (var node = hints.firstChild; node; node = node.nextSibling)
-      node.style.paddingRight = cm.display.nativeBarWidth + "px"
-
-    cm.addKeyMap(this.keyMap = buildKeyMap(completion, {
-      moveFocus: function(n, avoidWrap) { widget.changeActive(widget.selectedHint + n, avoidWrap); },
-      setFocus: function(n) { widget.changeActive(n); },
-      menuSize: function() { return widget.screenAmount(); },
-      length: completions.length,
-      close: function() { completion.close(); },
-      pick: function() { widget.pick(); },
-      data: data
-    }));
+    if (scrolls)
+      for (var node = hints.firstChild; node; node = node.nextSibling)
+        node.style.paddingRight = cm.display.nativeBarWidth + "px";
+
+    cm.addKeyMap(
+      (this.keyMap = buildKeyMap(completion, {
+        moveFocus: function (n, avoidWrap) {
+          widget.changeActive(widget.selectedHint + n, avoidWrap);
+        },
+        setFocus: function (n) {
+          widget.changeActive(n);
+        },
+        menuSize: function () {
+          return widget.screenAmount();
+        },
+        length: completions.length,
+        close: function () {
+          completion.close();
+        },
+        pick: function () {
+          widget.pick();
+        },
+        data: data,
+      }))
+    );
 
     if (completion.options.closeOnUnfocus) {
       var closingOnBlur;
-      cm.on("blur", this.onBlur = function() { closingOnBlur = setTimeout(function() { completion.close(); }, 100); });
-      cm.on("focus", this.onFocus = function() { clearTimeout(closingOnBlur); });
+      cm.on(
+        "blur",
+        (this.onBlur = function () {
+          closingOnBlur = setTimeout(function () {
+            completion.close();
+          }, 100);
+        })
+      );
+      cm.on(
+        "focus",
+        (this.onFocus = function () {
+          clearTimeout(closingOnBlur);
+        })
+      );
     }
 
-    cm.on("scroll", this.onScroll = function() {
-      var curScroll = cm.getScrollInfo(), editor = cm.getWrapperElement().getBoundingClientRect();
-      var newTop = top + startScroll.top - curScroll.top;
-      var point = newTop - (parentWindow.pageYOffset || (ownerDocument.documentElement || ownerDocument.body).scrollTop);
-      if (!below) point += hints.offsetHeight;
-      if (point <= editor.top || point >= editor.bottom) return completion.close();
-      hints.style.top = newTop + "px";
-      hints.style.left = (left + startScroll.left - curScroll.left) + "px";
-    });
+    cm.on(
+      "scroll",
+      (this.onScroll = function () {
+        var curScroll = cm.getScrollInfo(),
+          editor = cm.getWrapperElement().getBoundingClientRect();
+        var newTop = top + startScroll.top - curScroll.top;
+        var point =
+          newTop -
+          (parentWindow.pageYOffset ||
+            (ownerDocument.documentElement || ownerDocument.body).scrollTop);
+        if (!below) point += hints.offsetHeight;
+        if (point <= editor.top || point >= editor.bottom)
+          return completion.close();
+        hints.style.top = newTop + "px";
+        hints.style.left = left + startScroll.left - curScroll.left + "px";
+      })
+    );
 
-    CodeMirror.on(hints, "dblclick", function(e) {
+    CodeMirror.on(hints, "dblclick", function (e) {
       var t = getHintElement(hints, e.target || e.srcElement);
-      if (t && t.hintId != null) {widget.changeActive(t.hintId); widget.pick();}
+      if (t && t.hintId != null) {
+        widget.changeActive(t.hintId);
+        widget.pick();
+      }
     });
 
-    CodeMirror.on(hints, "click", function(e) {
+    CodeMirror.on(hints, "click", function (e) {
       var t = getHintElement(hints, e.target || e.srcElement);
       if (t && t.hintId != null) {
         widget.changeActive(t.hintId);
@@ -295,16 +400,23 @@
       }
     });
 
-    CodeMirror.on(hints, "mousedown", function() {
-      setTimeout(function(){cm.focus();}, 20);
+    CodeMirror.on(hints, "mousedown", function () {
+      setTimeout(function () {
+        cm.focus();
+      }, 20);
     });
 
-    CodeMirror.signal(data, "select", completions[this.selectedHint], hints.childNodes[this.selectedHint]);
+    CodeMirror.signal(
+      data,
+      "select",
+      completions[this.selectedHint],
+      hints.childNodes[this.selectedHint]
+    );
     return true;
   }
 
   Widget.prototype = {
-    close: function() {
+    close: function () {
       if (this.completion.widget != this) return;
       this.completion.widget = null;
       this.hints.parentNode.removeChild(this.hints);
@@ -318,104 +430,134 @@
       cm.off("scroll", this.onScroll);
     },
 
-    disable: function() {
+    disable: function () {
       this.completion.cm.removeKeyMap(this.keyMap);
       var widget = this;
-      this.keyMap = {Enter: function() { widget.picked = true; }};
+      this.keyMap = {
+        Enter: function () {
+          widget.picked = true;
+        },
+      };
       this.completion.cm.addKeyMap(this.keyMap);
     },
 
-    pick: function() {
+    pick: function () {
       this.completion.pick(this.data, this.selectedHint);
     },
 
-    changeActive: function(i, avoidWrap) {
+    changeActive: function (i, avoidWrap) {
       if (i >= this.data.list.length)
         i = avoidWrap ? this.data.list.length - 1 : 0;
-      else if (i < 0)
-        i = avoidWrap ? 0  : this.data.list.length - 1;
+      else if (i < 0) i = avoidWrap ? 0 : this.data.list.length - 1;
       if (this.selectedHint == i) return;
       var node = this.hints.childNodes[this.selectedHint];
-      if (node) node.className = node.className.replace(" " + ACTIVE_HINT_ELEMENT_CLASS, "");
-      node = this.hints.childNodes[this.selectedHint = i];
+      if (node)
+        node.className = node.className.replace(
+          " " + ACTIVE_HINT_ELEMENT_CLASS,
+          ""
+        );
+      node = this.hints.childNodes[(this.selectedHint = i)];
       node.className += " " + ACTIVE_HINT_ELEMENT_CLASS;
       if (node.offsetTop < this.hints.scrollTop)
         this.hints.scrollTop = node.offsetTop - 3;
-      else if (node.offsetTop + node.offsetHeight > this.hints.scrollTop + this.hints.clientHeight)
-        this.hints.scrollTop = node.offsetTop + node.offsetHeight - this.hints.clientHeight + 3;
-      CodeMirror.signal(this.data, "select", this.data.list[this.selectedHint], node);
+      else if (
+        node.offsetTop + node.offsetHeight >
+        this.hints.scrollTop + this.hints.clientHeight
+      )
+        this.hints.scrollTop =
+          node.offsetTop + node.offsetHeight - this.hints.clientHeight + 3;
+      CodeMirror.signal(
+        this.data,
+        "select",
+        this.data.list[this.selectedHint],
+        node
+      );
     },
 
-    screenAmount: function() {
-      return Math.floor(this.hints.clientHeight / this.hints.firstChild.offsetHeight) || 1;
-    }
+    screenAmount: function () {
+      return (
+        Math.floor(
+          this.hints.clientHeight / this.hints.firstChild.offsetHeight
+        ) || 1
+      );
+    },
   };
 
   function applicableHelpers(cm, helpers) {
-    if (!cm.somethingSelected()) return helpers
-    var result = []
+    if (!cm.somethingSelected()) return helpers;
+    var result = [];
     for (var i = 0; i < helpers.length; i++)
-      if (helpers[i].supportsSelection) result.push(helpers[i])
-    return result
+      if (helpers[i].supportsSelection) result.push(helpers[i]);
+    return result;
   }
 
   function fetchHints(hint, cm, options, callback) {
     if (hint.async) {
-      hint(cm, callback, options)
+      hint(cm, callback, options);
     } else {
-      var result = hint(cm, options)
-      if (result && result.then) result.then(callback)
-      else callback(result)
+      var result = hint(cm, options);
+      if (result && result.then) result.then(callback);
+      else callback(result);
     }
   }
 
   function resolveAutoHints(cm, pos) {
-    var helpers = cm.getHelpers(pos, "hint"), words
+    var helpers = cm.getHelpers(pos, "hint"),
+      words;
     if (helpers.length) {
-      var resolved = function(cm, callback, options) {
+      var resolved = function (cm, callback, options) {
         var app = applicableHelpers(cm, helpers);
         function run(i) {
-          if (i == app.length) return callback(null)
-          fetchHints(app[i], cm, options, function(result) {
-            if (result && result.list.length > 0) callback(result)
-            else run(i + 1)
-          })
+          if (i == app.length) return callback(null);
+          fetchHints(app[i], cm, options, function (result) {
+            if (result && result.list.length > 0) callback(result);
+            else run(i + 1);
+          });
         }
-        run(0)
-      }
-      resolved.async = true
-      resolved.supportsSelection = true
-      return resolved
-    } else if (words = cm.getHelper(cm.getCursor(), "hintWords")) {
-      return function(cm) { return CodeMirror.hint.fromList(cm, {words: words}) }
+        run(0);
+      };
+      resolved.async = true;
+      resolved.supportsSelection = true;
+      return resolved;
+    } else if ((words = cm.getHelper(cm.getCursor(), "hintWords"))) {
+      return function (cm) {
+        return CodeMirror.hint.fromList(cm, { words: words });
+      };
     } else if (CodeMirror.hint.anyword) {
-      return function(cm, options) { return CodeMirror.hint.anyword(cm, options) }
+      return function (cm, options) {
+        return CodeMirror.hint.anyword(cm, options);
+      };
     } else {
-      return function() {}
+      return function () {};
     }
   }
 
   CodeMirror.registerHelper("hint", "auto", {
-    resolve: resolveAutoHints
+    resolve: resolveAutoHints,
   });
 
-  CodeMirror.registerHelper("hint", "fromList", function(cm, options) {
-    var cur = cm.getCursor(), token = cm.getTokenAt(cur)
-    var term, from = CodeMirror.Pos(cur.line, token.start), to = cur
-    if (token.start < cur.ch && /\w/.test(token.string.charAt(cur.ch - token.start - 1))) {
-      term = token.string.substr(0, cur.ch - token.start)
+  CodeMirror.registerHelper("hint", "fromList", function (cm, options) {
+    var cur = cm.getCursor(),
+      token = cm.getTokenAt(cur);
+    var term,
+      from = CodeMirror.Pos(cur.line, token.start),
+      to = cur;
+    if (
+      token.start < cur.ch &&
+      /\w/.test(token.string.charAt(cur.ch - token.start - 1))
+    ) {
+      term = token.string.substr(0, cur.ch - token.start);
     } else {
-      term = ""
-      from = cur
+      term = "";
+      from = cur;
     }
     var found = [];
     for (var i = 0; i < options.words.length; i++) {
       var word = options.words[i];
-      if (word.slice(0, term.length) == term)
-        found.push(word);
+      if (word.slice(0, term.length) == term) found.push(word);
     }
 
-    if (found.length) return {list: found, from: from, to: to};
+    if (found.length) return { list: found, from: from, to: to };
   });
 
   CodeMirror.commands.autocomplete = CodeMirror.showHint;
@@ -429,7 +571,7 @@
     completeOnSingleClick: true,
     container: null,
     customKeys: null,
-    extraKeys: null
+    extraKeys: null,
   };
 
   CodeMirror.defineOption("hintOptions", null);
diff --git a/Frontend Angular 4/package-lock.json b/Frontend Angular 4/package-lock.json
index 0578b86d..f623d9f6 100644
--- a/Frontend Angular 4/package-lock.json	
+++ b/Frontend Angular 4/package-lock.json	
@@ -95,20 +95,6 @@
           "integrity": "sha512-4paDGScNgZP2IXXilaffL9X7968RuvwlkK3xWtZRVqgd8SYNiVKRJvkFd1aqqEuPfN7E68ZHEp9hDj6lHj4Hyw==",
           "dev": true
         },
-        "glob": {
-          "version": "7.1.4",
-          "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz",
-          "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==",
-          "dev": true,
-          "requires": {
-            "fs.realpath": "^1.0.0",
-            "inflight": "^1.0.4",
-            "inherits": "2",
-            "minimatch": "^3.0.4",
-            "once": "^1.3.0",
-            "path-is-absolute": "^1.0.0"
-          }
-        },
         "rxjs": {
           "version": "6.4.0",
           "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.4.0.tgz",
@@ -126,12 +112,6 @@
           "requires": {
             "chokidar": ">=2.0.0 <4.0.0"
           }
-        },
-        "semver": {
-          "version": "6.3.0",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
-          "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
-          "dev": true
         }
       }
     },
@@ -223,6 +203,14 @@
         }
       }
     },
+    "@angular/animations": {
+      "version": "8.2.14",
+      "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-8.2.14.tgz",
+      "integrity": "sha512-3Vc9TnNpKdtvKIXcWDFINSsnwgEMiDmLzjceWg1iYKwpeZGQahUXPoesLwQazBMmxJzQiA4HOMj0TTXKZ+Jzkg==",
+      "requires": {
+        "tslib": "^1.9.0"
+      }
+    },
     "@angular/cli": {
       "version": "8.3.29",
       "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-8.3.29.tgz",
@@ -257,21 +245,6 @@
           "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==",
           "dev": true
         },
-        "debug": {
-          "version": "4.3.4",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
-          "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
-          "dev": true,
-          "requires": {
-            "ms": "2.1.2"
-          }
-        },
-        "ms": {
-          "version": "2.1.2",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-          "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
-          "dev": true
-        },
         "rimraf": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.0.tgz",
@@ -280,12 +253,6 @@
           "requires": {
             "glob": "^7.1.3"
           }
-        },
-        "semver": {
-          "version": "6.3.0",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
-          "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
-          "dev": true
         }
       }
     },
@@ -711,25 +678,16 @@
         "source-map": "^0.5.0"
       },
       "dependencies": {
-        "debug": {
-          "version": "4.3.4",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
-          "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
-          "dev": true,
-          "requires": {
-            "ms": "2.1.2"
-          }
-        },
         "json5": {
           "version": "2.2.1",
           "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
           "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==",
           "dev": true
         },
-        "ms": {
-          "version": "2.1.2",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-          "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+        "semver": {
+          "version": "5.7.1",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+          "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
           "dev": true
         },
         "source-map": {
@@ -795,15 +753,9 @@
           }
         },
         "caniuse-lite": {
-          "version": "1.0.30001414",
-          "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001414.tgz",
-          "integrity": "sha512-t55jfSaWjCdocnFdKQoO+d2ct9C59UZg4dY3OnUlSZ447r8pUtIKdp0hpAzrGFultmTC+Us+KpKi4GZl/LXlFg==",
-          "dev": true
-        },
-        "semver": {
-          "version": "6.3.0",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
-          "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+          "version": "1.0.30001416",
+          "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001416.tgz",
+          "integrity": "sha512-06wzzdAkCPZO+Qm4e/eNghZBDfVNDsCgw33T27OwBH9unE9S478OYw//Q2L7Npf/zBzs7rjZOszIFQkwQKAEqA==",
           "dev": true
         }
       }
@@ -1003,14 +955,6 @@
         "@babel/helper-validator-identifier": "^7.18.6",
         "chalk": "^2.0.0",
         "js-tokens": "^4.0.0"
-      },
-      "dependencies": {
-        "js-tokens": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
-          "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
-          "dev": true
-        }
       }
     },
     "@babel/parser": {
@@ -1548,6 +1492,14 @@
         "invariant": "^2.2.2",
         "levenary": "^1.1.1",
         "semver": "^5.5.0"
+      },
+      "dependencies": {
+        "semver": {
+          "version": "5.7.1",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+          "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+          "dev": true
+        }
       }
     },
     "@babel/runtime": {
@@ -1594,23 +1546,6 @@
         "@babel/types": "^7.19.3",
         "debug": "^4.1.0",
         "globals": "^11.1.0"
-      },
-      "dependencies": {
-        "debug": {
-          "version": "4.3.4",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
-          "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
-          "dev": true,
-          "requires": {
-            "ms": "2.1.2"
-          }
-        },
-        "ms": {
-          "version": "2.1.2",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-          "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
-          "dev": true
-        }
       }
     },
     "@babel/types": {
@@ -1772,9 +1707,9 @@
           }
         },
         "semver": {
-          "version": "7.3.7",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
-          "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
+          "version": "7.3.8",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
+          "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
           "dev": true,
           "requires": {
             "lru-cache": "^6.0.0"
@@ -1849,12 +1784,6 @@
           "requires": {
             "tslib": "^1.9.0"
           }
-        },
-        "semver": {
-          "version": "6.3.0",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
-          "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
-          "dev": true
         }
       }
     },
@@ -1865,9 +1794,9 @@
       "dev": true
     },
     "@stencil/core": {
-      "version": "2.18.0",
-      "resolved": "https://registry.npmjs.org/@stencil/core/-/core-2.18.0.tgz",
-      "integrity": "sha512-NLEY8Jq59smyiivBAxHKipsp9YkkW/K/Vm90zAyXQqukb12i2SFucWHJ1Ik7ropVlhmMVvigyxXgRfQ9quIqtg=="
+      "version": "2.19.2",
+      "resolved": "https://registry.npmjs.org/@stencil/core/-/core-2.19.2.tgz",
+      "integrity": "sha512-TK3sHqyQAACwcac4fWntypFtN9c/y+y9ioZojeCnNDY3dxF33Ax70lL9ZLDyQnWWR+aTh1WFoqB5sYOnZIUKMA=="
     },
     "@types/cookie": {
       "version": "0.4.1",
@@ -2355,13 +2284,10 @@
       "integrity": "sha512-shdaI1zT3CVNL2hnx9c0JMc0ZogGaxDs5e85akgHWKYa0yVbIyp06Ind3dVkTj/uuFrzaHBOyqFzo+VV6aXgtA=="
     },
     "array-union": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
-      "integrity": "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==",
-      "dev": true,
-      "requires": {
-        "array-uniq": "^1.0.1"
-      }
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
+      "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
+      "dev": true
     },
     "array-uniq": {
       "version": "1.0.3",
@@ -2699,6 +2625,21 @@
           "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
           "dev": true
         },
+        "debug": {
+          "version": "2.6.9",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+          "dev": true,
+          "requires": {
+            "ms": "2.0.0"
+          }
+        },
+        "ms": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+          "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+          "dev": true
+        },
         "qs": {
           "version": "6.10.3",
           "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz",
@@ -2943,31 +2884,6 @@
         "ssri": "^6.0.1",
         "unique-filename": "^1.1.1",
         "y18n": "^4.0.0"
-      },
-      "dependencies": {
-        "glob": {
-          "version": "7.2.3",
-          "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
-          "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
-          "dev": true,
-          "requires": {
-            "fs.realpath": "^1.0.0",
-            "inflight": "^1.0.4",
-            "inherits": "2",
-            "minimatch": "^3.1.1",
-            "once": "^1.3.0",
-            "path-is-absolute": "^1.0.0"
-          }
-        },
-        "minimatch": {
-          "version": "3.1.2",
-          "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
-          "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
-          "dev": true,
-          "requires": {
-            "brace-expansion": "^1.1.7"
-          }
-        }
       }
     },
     "cache-base": {
@@ -3054,17 +2970,6 @@
         "ansi-styles": "^3.2.1",
         "escape-string-regexp": "^1.0.5",
         "supports-color": "^5.3.0"
-      },
-      "dependencies": {
-        "supports-color": {
-          "version": "5.5.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
-          "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
-          "dev": true,
-          "requires": {
-            "has-flag": "^3.0.0"
-          }
-        }
       }
     },
     "chardet": {
@@ -3349,6 +3254,23 @@
         "on-headers": "~1.0.2",
         "safe-buffer": "5.1.2",
         "vary": "~1.1.2"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "2.6.9",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+          "dev": true,
+          "requires": {
+            "ms": "2.0.0"
+          }
+        },
+        "ms": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+          "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+          "dev": true
+        }
       }
     },
     "concat-map": {
@@ -3381,6 +3303,15 @@
         "utils-merge": "1.0.1"
       },
       "dependencies": {
+        "debug": {
+          "version": "2.6.9",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+          "dev": true,
+          "requires": {
+            "ms": "2.0.0"
+          }
+        },
         "finalhandler": {
           "version": "1.1.2",
           "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
@@ -3396,6 +3327,12 @@
             "unpipe": "~1.0.0"
           }
         },
+        "ms": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+          "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+          "dev": true
+        },
         "on-finished": {
           "version": "2.3.0",
           "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
@@ -3563,20 +3500,6 @@
             "pkg-dir": "^4.1.0"
           }
         },
-        "glob": {
-          "version": "7.2.3",
-          "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
-          "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
-          "dev": true,
-          "requires": {
-            "fs.realpath": "^1.0.0",
-            "inflight": "^1.0.4",
-            "inherits": "2",
-            "minimatch": "^3.1.1",
-            "once": "^1.3.0",
-            "path-is-absolute": "^1.0.0"
-          }
-        },
         "json5": {
           "version": "2.2.1",
           "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
@@ -3603,24 +3526,6 @@
             "yallist": "^4.0.0"
           }
         },
-        "make-dir": {
-          "version": "3.1.0",
-          "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
-          "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
-          "dev": true,
-          "requires": {
-            "semver": "^6.0.0"
-          }
-        },
-        "minimatch": {
-          "version": "3.1.2",
-          "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
-          "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
-          "dev": true,
-          "requires": {
-            "brace-expansion": "^1.1.7"
-          }
-        },
         "mkdirp": {
           "version": "1.0.4",
           "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
@@ -3645,12 +3550,6 @@
             "glob": "^7.1.3"
           }
         },
-        "semver": {
-          "version": "6.3.0",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
-          "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
-          "dev": true
-        },
         "ssri": {
           "version": "8.0.1",
           "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz",
@@ -3674,9 +3573,9 @@
       "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ=="
     },
     "core-js-compat": {
-      "version": "3.25.4",
-      "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.25.4.tgz",
-      "integrity": "sha512-gCEcIEEqCR6230WroNunK/653CWKhqyCKJ9b+uESqOt/WFJA8B4lTnnQFdpYY5vmBcwJAA90Bo5vXs+CVsf6iA==",
+      "version": "3.25.5",
+      "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.25.5.tgz",
+      "integrity": "sha512-ovcyhs2DEBUIE0MGEKHP4olCUW/XYte3Vroyxuh38rD1wAO4dHohsovUC4eAOuzFxE6b+RXvBU3UZ9o0YhUTkA==",
       "dev": true,
       "requires": {
         "browserslist": "^4.21.4"
@@ -3695,9 +3594,9 @@
           }
         },
         "caniuse-lite": {
-          "version": "1.0.30001414",
-          "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001414.tgz",
-          "integrity": "sha512-t55jfSaWjCdocnFdKQoO+d2ct9C59UZg4dY3OnUlSZ447r8pUtIKdp0hpAzrGFultmTC+Us+KpKi4GZl/LXlFg==",
+          "version": "1.0.30001416",
+          "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001416.tgz",
+          "integrity": "sha512-06wzzdAkCPZO+Qm4e/eNghZBDfVNDsCgw33T27OwBH9unE9S478OYw//Q2L7Npf/zBzs7rjZOszIFQkwQKAEqA==",
           "dev": true
         }
       }
@@ -3728,18 +3627,6 @@
         "is-directory": "^0.3.1",
         "js-yaml": "^3.13.1",
         "parse-json": "^4.0.0"
-      },
-      "dependencies": {
-        "parse-json": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
-          "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==",
-          "dev": true,
-          "requires": {
-            "error-ex": "^1.3.1",
-            "json-parse-better-errors": "^1.0.1"
-          }
-        }
       }
     },
     "coverage-istanbul-loader": {
@@ -3811,6 +3698,14 @@
         "semver": "^5.5.0",
         "shebang-command": "^1.2.0",
         "which": "^1.2.9"
+      },
+      "dependencies": {
+        "semver": {
+          "version": "5.7.1",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+          "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+          "dev": true
+        }
       }
     },
     "crypto-browserify": {
@@ -4152,12 +4047,12 @@
       "dev": true
     },
     "debug": {
-      "version": "2.6.9",
-      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
-      "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+      "version": "4.3.4",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+      "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
       "dev": true,
       "requires": {
-        "ms": "2.0.0"
+        "ms": "2.1.2"
       }
     },
     "debuglog": {
@@ -4273,6 +4168,15 @@
         "rimraf": "^2.6.3"
       },
       "dependencies": {
+        "array-union": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
+          "integrity": "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==",
+          "dev": true,
+          "requires": {
+            "array-uniq": "^1.0.1"
+          }
+        },
         "globby": {
           "version": "6.1.0",
           "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz",
@@ -4294,30 +4198,6 @@
             }
           }
         },
-        "is-path-cwd": {
-          "version": "2.2.0",
-          "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz",
-          "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==",
-          "dev": true
-        },
-        "is-path-in-cwd": {
-          "version": "2.1.0",
-          "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz",
-          "integrity": "sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ==",
-          "dev": true,
-          "requires": {
-            "is-path-inside": "^2.1.0"
-          }
-        },
-        "is-path-inside": {
-          "version": "2.1.0",
-          "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-2.1.0.tgz",
-          "integrity": "sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg==",
-          "dev": true,
-          "requires": {
-            "path-is-inside": "^1.0.2"
-          }
-        },
         "p-map": {
           "version": "2.1.0",
           "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz",
@@ -4493,9 +4373,9 @@
       "dev": true
     },
     "electron-to-chromium": {
-      "version": "1.4.270",
-      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.270.tgz",
-      "integrity": "sha512-KNhIzgLiJmDDC444dj9vEOpZEgsV96ult9Iff98Vanumn+ShJHd5se8aX6KeVxdc0YQeqdrezBZv89rleDbvSg==",
+      "version": "1.4.274",
+      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.274.tgz",
+      "integrity": "sha512-Fgn7JZQzq85I81FpKUNxVLAzoghy8JZJ4NIue+YfUYBbu1AkpgzFvNwzF/ZNZH9ElkmJD0TSWu1F2gTpw/zZlg==",
       "dev": true
     },
     "elliptic": {
@@ -4522,9 +4402,9 @@
       }
     },
     "emoji-regex": {
-      "version": "8.0.0",
-      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
-      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+      "version": "7.0.3",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
+      "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
       "dev": true
     },
     "emojis-list": {
@@ -4587,9 +4467,9 @@
       },
       "dependencies": {
         "@types/node": {
-          "version": "18.8.0",
-          "resolved": "https://registry.npmjs.org/@types/node/-/node-18.8.0.tgz",
-          "integrity": "sha512-u+h43R6U8xXDt2vzUaVP3VwjjLyOJk6uEciZS8OSyziUQGOwmk+l+4drxcsDboHXwyTaqS1INebghmWMRxq3LA==",
+          "version": "18.8.2",
+          "resolved": "https://registry.npmjs.org/@types/node/-/node-18.8.2.tgz",
+          "integrity": "sha512-cRMwIgdDN43GO4xMWAfJAecYn8wV4JbsOGHNfNUIDiuYkUYAR5ec4Rj7IO2SAhFPEfpPtLtUTbbny/TCT7aDwA==",
           "dev": true
         },
         "cookie": {
@@ -4598,19 +4478,10 @@
           "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==",
           "dev": true
         },
-        "debug": {
-          "version": "4.3.4",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
-          "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
-          "dev": true,
-          "requires": {
-            "ms": "2.1.2"
-          }
-        },
-        "ms": {
-          "version": "2.1.2",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-          "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+        "ws": {
+          "version": "8.2.3",
+          "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz",
+          "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==",
           "dev": true
         }
       }
@@ -4853,6 +4724,15 @@
         "to-regex": "^3.0.1"
       },
       "dependencies": {
+        "debug": {
+          "version": "2.6.9",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+          "dev": true,
+          "requires": {
+            "ms": "2.0.0"
+          }
+        },
         "define-property": {
           "version": "0.2.5",
           "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
@@ -4870,6 +4750,12 @@
           "requires": {
             "is-extendable": "^0.1.0"
           }
+        },
+        "ms": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+          "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+          "dev": true
         }
       }
     },
@@ -4918,6 +4804,21 @@
           "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==",
           "dev": true
         },
+        "debug": {
+          "version": "2.6.9",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+          "dev": true,
+          "requires": {
+            "ms": "2.0.0"
+          }
+        },
+        "ms": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+          "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+          "dev": true
+        },
         "qs": {
           "version": "6.10.3",
           "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz",
@@ -4970,17 +4871,6 @@
         "chardet": "^0.7.0",
         "iconv-lite": "^0.4.24",
         "tmp": "^0.0.33"
-      },
-      "dependencies": {
-        "tmp": {
-          "version": "0.0.33",
-          "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
-          "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
-          "dev": true,
-          "requires": {
-            "os-tmpdir": "~1.0.2"
-          }
-        }
       }
     },
     "extglob": {
@@ -5150,8 +5040,25 @@
         "parseurl": "~1.3.3",
         "statuses": "2.0.1",
         "unpipe": "~1.0.0"
-      }
-    },
+      },
+      "dependencies": {
+        "debug": {
+          "version": "2.6.9",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+          "dev": true,
+          "requires": {
+            "ms": "2.0.0"
+          }
+        },
+        "ms": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+          "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+          "dev": true
+        }
+      }
+    },
     "find-cache-dir": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.0.0.tgz",
@@ -5161,23 +5068,6 @@
         "commondir": "^1.0.1",
         "make-dir": "^3.0.0",
         "pkg-dir": "^4.1.0"
-      },
-      "dependencies": {
-        "make-dir": {
-          "version": "3.1.0",
-          "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
-          "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
-          "dev": true,
-          "requires": {
-            "semver": "^6.0.0"
-          }
-        },
-        "semver": {
-          "version": "6.3.0",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
-          "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
-          "dev": true
-        }
       }
     },
     "find-up": {
@@ -5426,9 +5316,9 @@
       }
     },
     "glob": {
-      "version": "7.1.3",
-      "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
-      "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
+      "version": "7.1.4",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz",
+      "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==",
       "dev": true,
       "requires": {
         "fs.realpath": "^1.0.0",
@@ -5466,14 +5356,6 @@
         "ignore": "^5.2.0",
         "merge2": "^1.4.1",
         "slash": "^3.0.0"
-      },
-      "dependencies": {
-        "array-union": {
-          "version": "2.1.0",
-          "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
-          "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
-          "dev": true
-        }
       }
     },
     "graceful-fs": {
@@ -6455,26 +6337,6 @@
       "requires": {
         "ajv": "^6.12.3",
         "har-schema": "^2.0.0"
-      },
-      "dependencies": {
-        "ajv": {
-          "version": "6.12.6",
-          "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
-          "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
-          "dev": true,
-          "requires": {
-            "fast-deep-equal": "^3.1.1",
-            "fast-json-stable-stringify": "^2.0.0",
-            "json-schema-traverse": "^0.4.1",
-            "uri-js": "^4.2.2"
-          }
-        },
-        "fast-deep-equal": {
-          "version": "3.1.3",
-          "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
-          "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
-          "dev": true
-        }
       }
     },
     "has": {
@@ -6718,6 +6580,12 @@
           "requires": {
             "ms": "2.0.0"
           }
+        },
+        "ms": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+          "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+          "dev": true
         }
       }
     },
@@ -6873,12 +6741,6 @@
           "requires": {
             "ms": "^2.1.1"
           }
-        },
-        "ms": {
-          "version": "2.1.3",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
-          "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
-          "dev": true
         }
       }
     },
@@ -7055,6 +6917,12 @@
           "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
           "dev": true
         },
+        "emoji-regex": {
+          "version": "8.0.0",
+          "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+          "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+          "dev": true
+        },
         "is-fullwidth-code-point": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
@@ -7134,9 +7002,9 @@
       }
     },
     "interval-arithmetic": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/interval-arithmetic/-/interval-arithmetic-1.1.0.tgz",
-      "integrity": "sha512-NyKZf/l4wAKB/Z7bURh0TNdiZycKQSEQ1VrPkcaZK8Lrn6X+ZHDqXDTPjYezhYC0Cubrj0qUatomUu4xte26nw==",
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/interval-arithmetic/-/interval-arithmetic-1.1.2.tgz",
+      "integrity": "sha512-FmonKqVk5HVc4G79d16rQmCb6zOwv0o4LidhJKtdGTwpc3Kk9UZ5t6UE1AQHFF5RdQaSIQs0AYe5rySFT8C1Ww==",
       "requires": {
         "nextafter": "^1.0.0"
       }
@@ -7403,27 +7271,27 @@
       "integrity": "sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA=="
     },
     "is-path-cwd": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz",
-      "integrity": "sha512-cnS56eR9SPAscL77ik76ATVqoPARTqPIVkMDVxRaWH06zT+6+CzIroYRJ0VVvm0Z1zfAvxvz9i/D3Ppjaqt5Nw==",
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz",
+      "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==",
       "dev": true
     },
     "is-path-in-cwd": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz",
-      "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==",
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz",
+      "integrity": "sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ==",
       "dev": true,
       "requires": {
-        "is-path-inside": "^1.0.0"
+        "is-path-inside": "^2.1.0"
       }
     },
     "is-path-inside": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz",
-      "integrity": "sha512-qhsCR/Esx4U4hg/9I19OVUAJkGWtjRYHMRgUMZE2TDdj+Ag+kttZanLupfddNyglzz50cUlmWzUaI37GDfNx/g==",
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-2.1.0.tgz",
+      "integrity": "sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg==",
       "dev": true,
       "requires": {
-        "path-is-inside": "^1.0.1"
+        "path-is-inside": "^1.0.2"
       }
     },
     "is-plain-obj": {
@@ -7563,14 +7431,6 @@
         "@istanbuljs/schema": "^0.1.2",
         "istanbul-lib-coverage": "^3.0.0",
         "semver": "^6.3.0"
-      },
-      "dependencies": {
-        "semver": {
-          "version": "6.3.0",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
-          "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
-          "dev": true
-        }
       }
     },
     "istanbul-lib-report": {
@@ -7590,27 +7450,6 @@
           "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
           "dev": true
         },
-        "istanbul-lib-coverage": {
-          "version": "3.2.0",
-          "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz",
-          "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==",
-          "dev": true
-        },
-        "make-dir": {
-          "version": "3.1.0",
-          "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
-          "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
-          "dev": true,
-          "requires": {
-            "semver": "^6.0.0"
-          }
-        },
-        "semver": {
-          "version": "6.3.0",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
-          "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
-          "dev": true
-        },
         "supports-color": {
           "version": "7.2.0",
           "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
@@ -7635,25 +7474,26 @@
         "source-map": "^0.6.1"
       },
       "dependencies": {
-        "debug": {
-          "version": "4.3.4",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
-          "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
-          "dev": true,
-          "requires": {
-            "ms": "2.1.2"
-          }
-        },
         "istanbul-lib-coverage": {
           "version": "2.0.5",
           "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz",
           "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==",
           "dev": true
         },
-        "ms": {
-          "version": "2.1.2",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-          "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+        "make-dir": {
+          "version": "2.1.0",
+          "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz",
+          "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==",
+          "dev": true,
+          "requires": {
+            "pify": "^4.0.1",
+            "semver": "^5.6.0"
+          }
+        },
+        "semver": {
+          "version": "5.7.1",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+          "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
           "dev": true
         },
         "source-map": {
@@ -7722,6 +7562,17 @@
       "requires": {
         "merge-stream": "^2.0.0",
         "supports-color": "^6.1.0"
+      },
+      "dependencies": {
+        "supports-color": {
+          "version": "6.1.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
+          "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^3.0.0"
+          }
+        }
       }
     },
     "jq-console": {
@@ -7881,47 +7732,6 @@
             "color-convert": "^2.0.1"
           }
         },
-        "anymatch": {
-          "version": "3.1.2",
-          "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
-          "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
-          "dev": true,
-          "requires": {
-            "normalize-path": "^3.0.0",
-            "picomatch": "^2.0.4"
-          }
-        },
-        "binary-extensions": {
-          "version": "2.2.0",
-          "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
-          "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
-          "dev": true
-        },
-        "braces": {
-          "version": "3.0.2",
-          "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
-          "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
-          "dev": true,
-          "requires": {
-            "fill-range": "^7.0.1"
-          }
-        },
-        "chokidar": {
-          "version": "3.5.3",
-          "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
-          "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
-          "dev": true,
-          "requires": {
-            "anymatch": "~3.1.2",
-            "braces": "~3.0.2",
-            "fsevents": "~2.3.2",
-            "glob-parent": "~5.1.2",
-            "is-binary-path": "~2.1.0",
-            "is-glob": "~4.0.1",
-            "normalize-path": "~3.0.0",
-            "readdirp": "~3.6.0"
-          }
-        },
         "cliui": {
           "version": "7.0.4",
           "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
@@ -7948,26 +7758,10 @@
           "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
           "dev": true
         },
-        "fill-range": {
-          "version": "7.0.1",
-          "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
-          "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
-          "dev": true,
-          "requires": {
-            "to-regex-range": "^5.0.1"
-          }
-        },
-        "fsevents": {
-          "version": "2.3.2",
-          "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
-          "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
-          "dev": true,
-          "optional": true
-        },
-        "get-caller-file": {
-          "version": "2.0.5",
-          "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
-          "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+        "emoji-regex": {
+          "version": "8.0.0",
+          "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+          "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
           "dev": true
         },
         "glob": {
@@ -7995,57 +7789,18 @@
             }
           }
         },
-        "glob-parent": {
-          "version": "5.1.2",
-          "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
-          "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
-          "dev": true,
-          "requires": {
-            "is-glob": "^4.0.1"
-          }
-        },
-        "is-binary-path": {
-          "version": "2.1.0",
-          "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
-          "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
-          "dev": true,
-          "requires": {
-            "binary-extensions": "^2.0.0"
-          }
-        },
         "is-fullwidth-code-point": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
           "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
           "dev": true
         },
-        "is-number": {
-          "version": "7.0.0",
-          "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
-          "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
-          "dev": true
-        },
         "mime": {
           "version": "2.6.0",
           "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz",
           "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==",
           "dev": true
         },
-        "normalize-path": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
-          "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
-          "dev": true
-        },
-        "readdirp": {
-          "version": "3.6.0",
-          "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
-          "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
-          "dev": true,
-          "requires": {
-            "picomatch": "^2.2.1"
-          }
-        },
         "rimraf": {
           "version": "3.0.2",
           "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
@@ -8081,13 +7836,13 @@
             "ansi-regex": "^5.0.1"
           }
         },
-        "to-regex-range": {
-          "version": "5.0.1",
-          "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
-          "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+        "tmp": {
+          "version": "0.2.1",
+          "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz",
+          "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==",
           "dev": true,
           "requires": {
-            "is-number": "^7.0.0"
+            "rimraf": "^3.0.0"
           }
         },
         "wrap-ansi": {
@@ -8159,14 +7914,6 @@
         "istanbul-lib-source-maps": "^3.0.6",
         "istanbul-reports": "^3.0.2",
         "minimatch": "^3.0.4"
-      },
-      "dependencies": {
-        "istanbul-lib-coverage": {
-          "version": "3.2.0",
-          "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz",
-          "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==",
-          "dev": true
-        }
       }
     },
     "karma-jasmine": {
@@ -8358,23 +8105,6 @@
         "flatted": "^3.2.7",
         "rfdc": "^1.3.0",
         "streamroller": "^3.1.3"
-      },
-      "dependencies": {
-        "debug": {
-          "version": "4.3.4",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
-          "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
-          "dev": true,
-          "requires": {
-            "ms": "2.1.2"
-          }
-        },
-        "ms": {
-          "version": "2.1.2",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-          "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
-          "dev": true
-        }
       }
     },
     "loglevel": {
@@ -8409,6 +8139,35 @@
         "yallist": "^3.0.2"
       }
     },
+    "lt-codemirror": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/lt-codemirror/-/lt-codemirror-5.0.0.tgz",
+      "integrity": "sha512-vJN4pUx3lWfyYpfPx1LAl216EAjiXT1s2mV7qAzn9y+1/gkHF6iOao6dReBd3/SXF8cVTq+YAgbo9sUxhSumWg==",
+      "requires": {
+        "@angular/animations": "~8.2.14",
+        "@angular/common": "~8.2.14",
+        "@angular/compiler": "~8.2.14",
+        "@angular/core": "~8.2.14",
+        "@angular/forms": "~8.2.14",
+        "@angular/platform-browser": "~8.2.14",
+        "@angular/platform-browser-dynamic": "~8.2.14",
+        "@angular/router": "~8.2.14",
+        "codemirror": "^5.56.0",
+        "rxjs": "~6.4.0",
+        "tslib": "^1.10.0",
+        "zone.js": "~0.9.1"
+      },
+      "dependencies": {
+        "rxjs": {
+          "version": "6.4.0",
+          "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.4.0.tgz",
+          "integrity": "sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw==",
+          "requires": {
+            "tslib": "^1.9.0"
+          }
+        }
+      }
+    },
     "magic-string": {
       "version": "0.25.3",
       "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.3.tgz",
@@ -8419,13 +8178,12 @@
       }
     },
     "make-dir": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz",
-      "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==",
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
+      "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
       "dev": true,
       "requires": {
-        "pify": "^4.0.1",
-        "semver": "^5.6.0"
+        "semver": "^6.0.0"
       }
     },
     "make-error": {
@@ -8484,9 +8242,9 @@
       }
     },
     "matefun-components": {
-      "version": "0.1.0",
-      "resolved": "https://registry.npmjs.org/matefun-components/-/matefun-components-0.1.0.tgz",
-      "integrity": "sha512-KVrXcO2qWjSkKGbb552THGRBqIHsJ6Ap0MAOFAT/PSxbOTyoyQBqyc1SMG6g5JE0nYiYGBNETYg/KI99SWuzHQ==",
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/matefun-components/-/matefun-components-0.3.0.tgz",
+      "integrity": "sha512-Bs9rbDQLn2woI08tSjGyEDGIQ3clYq0zjXvmlq4W8r0SZaTKQPk7pP88kwc+ud/z7Z2fTfHxkhZLX7OD/7BRuw==",
       "requires": {
         "@stencil/core": "^2.13.0"
       }
@@ -8824,9 +8582,9 @@
       "integrity": "sha512-hug+mpbSSKnH13rFqy3zm+XiG+QTStiDAgMTHK355TIstQE0qBkBtSJsa5YHP94AuarVX9b/4dcebdTRZ9YiEw=="
     },
     "ms": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
-      "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+      "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
       "dev": true
     },
     "multicast-dns": {
@@ -8890,19 +8648,6 @@
         "double-bits": "^1.1.0"
       }
     },
-    "ng2-bootstrap-modal": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/ng2-bootstrap-modal/-/ng2-bootstrap-modal-1.0.1.tgz",
-      "integrity": "sha512-F/NABjMJtmhSfgLIJmGdpgBeU13jPwAw7+mtcKBUFQ38zXY3Ydq/vzjprQ3zJFWIcSwckbEOF4b/7AvSJcRbzA=="
-    },
-    "ng2-codemirror": {
-      "version": "1.1.3",
-      "resolved": "https://registry.npmjs.org/ng2-codemirror/-/ng2-codemirror-1.1.3.tgz",
-      "integrity": "sha512-aqBTOTCo1poOMKxh1hil4ehCN7NgnaxGKG0Hu6Mwe9ya7yN3SQpPUCznw0kWBdN8ir1esbn13vh8y1bSewim4A==",
-      "requires": {
-        "codemirror": "^5.22.2"
-      }
-    },
     "ng2-slideable-directive": {
       "version": "1.0.13",
       "resolved": "https://registry.npmjs.org/ng2-slideable-directive/-/ng2-slideable-directive-1.0.13.tgz",
@@ -9003,6 +8748,14 @@
         "resolve": "^1.10.0",
         "semver": "2 || 3 || 4 || 5",
         "validate-npm-package-license": "^3.0.1"
+      },
+      "dependencies": {
+        "semver": {
+          "version": "5.7.1",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+          "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+          "dev": true
+        }
       }
     },
     "normalize-path": {
@@ -9054,6 +8807,14 @@
         "osenv": "^0.1.5",
         "semver": "^5.5.0",
         "validate-npm-package-name": "^3.0.0"
+      },
+      "dependencies": {
+        "semver": {
+          "version": "5.7.1",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+          "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+          "dev": true
+        }
       }
     },
     "npm-packlist": {
@@ -9076,6 +8837,14 @@
         "figgy-pudding": "^3.5.1",
         "npm-package-arg": "^6.0.0",
         "semver": "^5.4.1"
+      },
+      "dependencies": {
+        "semver": {
+          "version": "5.7.1",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+          "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+          "dev": true
+        }
       }
     },
     "npm-registry-fetch": {
@@ -9484,6 +9253,12 @@
             "semver": "^5.4.1"
           }
         },
+        "semver": {
+          "version": "5.7.1",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+          "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+          "dev": true
+        },
         "tar": {
           "version": "4.4.19",
           "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.19.tgz",
@@ -9540,12 +9315,13 @@
       }
     },
     "parse-json": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
-      "integrity": "sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==",
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
+      "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==",
       "dev": true,
       "requires": {
-        "error-ex": "^1.2.0"
+        "error-ex": "^1.3.1",
+        "json-parse-better-errors": "^1.0.1"
       }
     },
     "parse5": {
@@ -9750,12 +9526,6 @@
           "requires": {
             "ms": "^2.1.1"
           }
-        },
-        "ms": {
-          "version": "2.1.3",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
-          "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
-          "dev": true
         }
       }
     },
@@ -9781,6 +9551,15 @@
           "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
           "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
           "dev": true
+        },
+        "supports-color": {
+          "version": "6.1.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
+          "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^3.0.0"
+          }
         }
       }
     },
@@ -9935,6 +9714,15 @@
           "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==",
           "dev": true
         },
+        "array-union": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
+          "integrity": "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==",
+          "dev": true,
+          "requires": {
+            "array-uniq": "^1.0.1"
+          }
+        },
         "chalk": {
           "version": "1.1.3",
           "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
@@ -9977,12 +9765,42 @@
             "pinkie-promise": "^2.0.0"
           }
         },
-        "pify": {
+        "is-path-cwd": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz",
+          "integrity": "sha512-cnS56eR9SPAscL77ik76ATVqoPARTqPIVkMDVxRaWH06zT+6+CzIroYRJ0VVvm0Z1zfAvxvz9i/D3Ppjaqt5Nw==",
+          "dev": true
+        },
+        "is-path-in-cwd": {
+          "version": "1.0.1",
+          "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz",
+          "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==",
+          "dev": true,
+          "requires": {
+            "is-path-inside": "^1.0.0"
+          }
+        },
+        "is-path-inside": {
+          "version": "1.0.1",
+          "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz",
+          "integrity": "sha512-qhsCR/Esx4U4hg/9I19OVUAJkGWtjRYHMRgUMZE2TDdj+Ag+kttZanLupfddNyglzz50cUlmWzUaI37GDfNx/g==",
+          "dev": true,
+          "requires": {
+            "path-is-inside": "^1.0.1"
+          }
+        },
+        "pify": {
           "version": "2.3.0",
           "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
           "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
           "dev": true
         },
+        "semver": {
+          "version": "5.7.1",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+          "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+          "dev": true
+        },
         "source-map": {
           "version": "0.5.7",
           "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
@@ -10611,113 +10429,6 @@
         "chokidar": ">=3.0.0 <4.0.0",
         "immutable": "^4.0.0",
         "source-map-js": ">=0.6.2 <2.0.0"
-      },
-      "dependencies": {
-        "anymatch": {
-          "version": "3.1.2",
-          "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
-          "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
-          "dev": true,
-          "requires": {
-            "normalize-path": "^3.0.0",
-            "picomatch": "^2.0.4"
-          }
-        },
-        "binary-extensions": {
-          "version": "2.2.0",
-          "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
-          "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
-          "dev": true
-        },
-        "braces": {
-          "version": "3.0.2",
-          "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
-          "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
-          "dev": true,
-          "requires": {
-            "fill-range": "^7.0.1"
-          }
-        },
-        "chokidar": {
-          "version": "3.5.3",
-          "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
-          "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
-          "dev": true,
-          "requires": {
-            "anymatch": "~3.1.2",
-            "braces": "~3.0.2",
-            "fsevents": "~2.3.2",
-            "glob-parent": "~5.1.2",
-            "is-binary-path": "~2.1.0",
-            "is-glob": "~4.0.1",
-            "normalize-path": "~3.0.0",
-            "readdirp": "~3.6.0"
-          }
-        },
-        "fill-range": {
-          "version": "7.0.1",
-          "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
-          "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
-          "dev": true,
-          "requires": {
-            "to-regex-range": "^5.0.1"
-          }
-        },
-        "fsevents": {
-          "version": "2.3.2",
-          "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
-          "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
-          "dev": true,
-          "optional": true
-        },
-        "glob-parent": {
-          "version": "5.1.2",
-          "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
-          "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
-          "dev": true,
-          "requires": {
-            "is-glob": "^4.0.1"
-          }
-        },
-        "is-binary-path": {
-          "version": "2.1.0",
-          "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
-          "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
-          "dev": true,
-          "requires": {
-            "binary-extensions": "^2.0.0"
-          }
-        },
-        "is-number": {
-          "version": "7.0.0",
-          "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
-          "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
-          "dev": true
-        },
-        "normalize-path": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
-          "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
-          "dev": true
-        },
-        "readdirp": {
-          "version": "3.6.0",
-          "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
-          "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
-          "dev": true,
-          "requires": {
-            "picomatch": "^2.2.1"
-          }
-        },
-        "to-regex-range": {
-          "version": "5.0.1",
-          "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
-          "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
-          "dev": true,
-          "requires": {
-            "is-number": "^7.0.0"
-          }
-        }
       }
     },
     "sass-loader": {
@@ -10731,6 +10442,14 @@
         "neo-async": "^2.5.0",
         "pify": "^4.0.1",
         "semver": "^5.5.0"
+      },
+      "dependencies": {
+        "semver": {
+          "version": "5.7.1",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+          "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+          "dev": true
+        }
       }
     },
     "saucelabs": {
@@ -10752,6 +10471,15 @@
             "semver": "~5.0.1"
           }
         },
+        "debug": {
+          "version": "2.6.9",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+          "dev": true,
+          "requires": {
+            "ms": "2.0.0"
+          }
+        },
         "https-proxy-agent": {
           "version": "1.0.0",
           "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz",
@@ -10763,6 +10491,12 @@
             "extend": "3"
           }
         },
+        "ms": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+          "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+          "dev": true
+        },
         "semver": {
           "version": "5.0.3",
           "resolved": "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz",
@@ -10841,9 +10575,9 @@
       }
     },
     "semver": {
-      "version": "5.6.0",
-      "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz",
-      "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==",
+      "version": "6.3.0",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+      "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
       "dev": true
     },
     "semver-dsl": {
@@ -10853,6 +10587,14 @@
       "dev": true,
       "requires": {
         "semver": "^5.3.0"
+      },
+      "dependencies": {
+        "semver": {
+          "version": "5.7.1",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+          "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+          "dev": true
+        }
       }
     },
     "semver-intersect": {
@@ -10862,6 +10604,14 @@
       "dev": true,
       "requires": {
         "semver": "^5.0.0"
+      },
+      "dependencies": {
+        "semver": {
+          "version": "5.7.1",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+          "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+          "dev": true
+        }
       }
     },
     "send": {
@@ -10885,6 +10635,23 @@
         "statuses": "2.0.1"
       },
       "dependencies": {
+        "debug": {
+          "version": "2.6.9",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+          "dev": true,
+          "requires": {
+            "ms": "2.0.0"
+          },
+          "dependencies": {
+            "ms": {
+              "version": "2.0.0",
+              "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+              "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+              "dev": true
+            }
+          }
+        },
         "ms": {
           "version": "2.1.3",
           "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
@@ -10917,6 +10684,15 @@
         "parseurl": "~1.3.2"
       },
       "dependencies": {
+        "debug": {
+          "version": "2.6.9",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+          "dev": true,
+          "requires": {
+            "ms": "2.0.0"
+          }
+        },
         "depd": {
           "version": "1.1.2",
           "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
@@ -10941,6 +10717,12 @@
           "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==",
           "dev": true
         },
+        "ms": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+          "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+          "dev": true
+        },
         "setprototypeof": {
           "version": "1.1.0",
           "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz",
@@ -11087,6 +10869,15 @@
         "use": "^3.1.0"
       },
       "dependencies": {
+        "debug": {
+          "version": "2.6.9",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+          "dev": true,
+          "requires": {
+            "ms": "2.0.0"
+          }
+        },
         "define-property": {
           "version": "0.2.5",
           "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
@@ -11105,6 +10896,12 @@
             "is-extendable": "^0.1.0"
           }
         },
+        "ms": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+          "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+          "dev": true
+        },
         "source-map": {
           "version": "0.5.7",
           "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
@@ -11196,23 +10993,6 @@
         "engine.io": "~6.2.0",
         "socket.io-adapter": "~2.4.0",
         "socket.io-parser": "~4.2.0"
-      },
-      "dependencies": {
-        "debug": {
-          "version": "4.3.4",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
-          "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
-          "dev": true,
-          "requires": {
-            "ms": "2.1.2"
-          }
-        },
-        "ms": {
-          "version": "2.1.2",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-          "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
-          "dev": true
-        }
       }
     },
     "socket.io-adapter": {
@@ -11229,23 +11009,6 @@
       "requires": {
         "@socket.io/component-emitter": "~3.1.0",
         "debug": "~4.3.1"
-      },
-      "dependencies": {
-        "debug": {
-          "version": "4.3.4",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
-          "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
-          "dev": true,
-          "requires": {
-            "ms": "2.1.2"
-          }
-        },
-        "ms": {
-          "version": "2.1.2",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-          "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
-          "dev": true
-        }
       }
     },
     "sockjs": {
@@ -11290,12 +11053,6 @@
           "requires": {
             "websocket-driver": ">=0.5.1"
           }
-        },
-        "ms": {
-          "version": "2.1.3",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
-          "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
-          "dev": true
         }
       }
     },
@@ -11461,23 +11218,6 @@
         "http-deceiver": "^1.2.7",
         "select-hose": "^2.0.0",
         "spdy-transport": "^3.0.0"
-      },
-      "dependencies": {
-        "debug": {
-          "version": "4.3.4",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
-          "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
-          "dev": true,
-          "requires": {
-            "ms": "2.1.2"
-          }
-        },
-        "ms": {
-          "version": "2.1.2",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-          "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
-          "dev": true
-        }
       }
     },
     "spdy-transport": {
@@ -11494,21 +11234,6 @@
         "wbuf": "^1.7.3"
       },
       "dependencies": {
-        "debug": {
-          "version": "4.3.4",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
-          "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
-          "dev": true,
-          "requires": {
-            "ms": "2.1.2"
-          }
-        },
-        "ms": {
-          "version": "2.1.2",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-          "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
-          "dev": true
-        },
         "readable-stream": {
           "version": "3.6.0",
           "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
@@ -11647,23 +11372,6 @@
         "date-format": "^4.0.14",
         "debug": "^4.3.4",
         "fs-extra": "^8.1.0"
-      },
-      "dependencies": {
-        "debug": {
-          "version": "4.3.4",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
-          "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
-          "dev": true,
-          "requires": {
-            "ms": "2.1.2"
-          }
-        },
-        "ms": {
-          "version": "2.1.2",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-          "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
-          "dev": true
-        }
       }
     },
     "strict-uri-encode": {
@@ -11689,12 +11397,6 @@
           "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==",
           "dev": true
         },
-        "emoji-regex": {
-          "version": "7.0.3",
-          "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
-          "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
-          "dev": true
-        },
         "strip-ansi": {
           "version": "5.2.0",
           "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
@@ -11828,9 +11530,9 @@
       }
     },
     "supports-color": {
-      "version": "6.1.0",
-      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
-      "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
+      "version": "5.5.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+      "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
       "dev": true,
       "requires": {
         "has-flag": "^3.0.0"
@@ -11967,20 +11669,6 @@
             "pkg-dir": "^4.1.0"
           }
         },
-        "glob": {
-          "version": "7.2.3",
-          "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
-          "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
-          "dev": true,
-          "requires": {
-            "fs.realpath": "^1.0.0",
-            "inflight": "^1.0.4",
-            "inherits": "2",
-            "minimatch": "^3.1.1",
-            "once": "^1.3.0",
-            "path-is-absolute": "^1.0.0"
-          }
-        },
         "has-flag": {
           "version": "4.0.0",
           "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
@@ -12007,24 +11695,6 @@
             "yallist": "^4.0.0"
           }
         },
-        "make-dir": {
-          "version": "3.1.0",
-          "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
-          "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
-          "dev": true,
-          "requires": {
-            "semver": "^6.0.0"
-          }
-        },
-        "minimatch": {
-          "version": "3.1.2",
-          "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
-          "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
-          "dev": true,
-          "requires": {
-            "brace-expansion": "^1.1.7"
-          }
-        },
         "mkdirp": {
           "version": "1.0.4",
           "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
@@ -12040,12 +11710,6 @@
             "glob": "^7.1.3"
           }
         },
-        "semver": {
-          "version": "6.3.0",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
-          "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
-          "dev": true
-        },
         "serialize-javascript": {
           "version": "3.1.0",
           "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-3.1.0.tgz",
@@ -12138,23 +11802,12 @@
       }
     },
     "tmp": {
-      "version": "0.2.1",
-      "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz",
-      "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==",
+      "version": "0.0.33",
+      "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
+      "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
       "dev": true,
       "requires": {
-        "rimraf": "^3.0.0"
-      },
-      "dependencies": {
-        "rimraf": {
-          "version": "3.0.2",
-          "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
-          "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
-          "dev": true,
-          "requires": {
-            "glob": "^7.1.3"
-          }
-        }
+        "os-tmpdir": "~1.0.2"
       }
     },
     "to-arraybuffer": {
@@ -12304,6 +11957,17 @@
         "parse-json": "^2.2.0",
         "strip-bom": "^2.0.0",
         "strip-json-comments": "^2.0.0"
+      },
+      "dependencies": {
+        "parse-json": {
+          "version": "2.2.0",
+          "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
+          "integrity": "sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==",
+          "dev": true,
+          "requires": {
+            "error-ex": "^1.2.0"
+          }
+        }
       }
     },
     "tslib": {
@@ -12337,6 +12001,12 @@
           "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
           "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
           "dev": true
+        },
+        "semver": {
+          "version": "5.7.1",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+          "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+          "dev": true
         }
       }
     },
@@ -12489,23 +12159,6 @@
         "debug": "^4.1.1",
         "request": "^2.88.2",
         "uuid": "^3.0.0"
-      },
-      "dependencies": {
-        "debug": {
-          "version": "4.3.4",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
-          "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
-          "dev": true,
-          "requires": {
-            "ms": "2.1.2"
-          }
-        },
-        "ms": {
-          "version": "2.1.2",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-          "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
-          "dev": true
-        }
       }
     },
     "universalify": {
@@ -12567,9 +12220,9 @@
       "dev": true
     },
     "update-browserslist-db": {
-      "version": "1.0.9",
-      "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.9.tgz",
-      "integrity": "sha512-/xsqn21EGVdXI3EXSum1Yckj3ZVZugqyOZQ/CxYPBD/R+ko9NSUScf8tFF4dOKY+2pvSSJA/S+5B8s4Zr4kyvg==",
+      "version": "1.0.10",
+      "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz",
+      "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==",
       "dev": true,
       "requires": {
         "escalade": "^3.1.1",
@@ -13174,6 +12827,16 @@
             }
           }
         },
+        "make-dir": {
+          "version": "2.1.0",
+          "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz",
+          "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==",
+          "dev": true,
+          "requires": {
+            "pify": "^4.0.1",
+            "semver": "^5.6.0"
+          }
+        },
         "micromatch": {
           "version": "3.1.10",
           "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
@@ -13215,6 +12878,12 @@
             "ajv-keywords": "^3.1.0"
           }
         },
+        "semver": {
+          "version": "5.7.1",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+          "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+          "dev": true
+        },
         "source-map": {
           "version": "0.6.1",
           "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
@@ -13415,15 +13084,6 @@
             "upath": "^1.1.1"
           }
         },
-        "debug": {
-          "version": "4.3.4",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
-          "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
-          "dev": true,
-          "requires": {
-            "ms": "2.1.2"
-          }
-        },
         "fill-range": {
           "version": "4.0.0",
           "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
@@ -13525,12 +13185,6 @@
             "to-regex": "^3.0.2"
           }
         },
-        "ms": {
-          "version": "2.1.2",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-          "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
-          "dev": true
-        },
         "readdirp": {
           "version": "2.2.1",
           "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz",
@@ -13553,11 +13207,14 @@
             "ajv-keywords": "^3.1.0"
           }
         },
-        "semver": {
-          "version": "6.3.0",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
-          "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
-          "dev": true
+        "supports-color": {
+          "version": "6.1.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
+          "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^3.0.0"
+          }
         },
         "to-regex-range": {
           "version": "2.1.1",
@@ -13568,15 +13225,6 @@
             "is-number": "^3.0.0",
             "repeat-string": "^1.6.1"
           }
-        },
-        "ws": {
-          "version": "6.2.2",
-          "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.2.tgz",
-          "integrity": "sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==",
-          "dev": true,
-          "requires": {
-            "async-limiter": "~1.0.0"
-          }
         }
       }
     },
@@ -13734,10 +13382,13 @@
       "dev": true
     },
     "ws": {
-      "version": "8.2.3",
-      "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz",
-      "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==",
-      "dev": true
+      "version": "6.2.2",
+      "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.2.tgz",
+      "integrity": "sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==",
+      "dev": true,
+      "requires": {
+        "async-limiter": "~1.0.0"
+      }
     },
     "xml2js": {
       "version": "0.4.23",
diff --git a/Frontend Angular 4/package.json b/Frontend Angular 4/package.json
index 5ee6f950..629bb658 100755
--- a/Frontend Angular 4/package.json	
+++ b/Frontend Angular 4/package.json	
@@ -22,6 +22,7 @@
     "@ng-bootstrap/ng-bootstrap": "^5.3.1",
     "@ngx-translate/core": "^12.0.0",
     "@ngx-translate/http-loader": "^4.0.0",
+    "codemirror": "^5.65.9",
     "core-js": "^2.4.1",
     "d3": "^4.12.2",
     "flag-icon-css": "^3.2.1",
@@ -31,10 +32,9 @@
     "ionicons": "^3.0.0",
     "jq-console": "^2.13.2",
     "jquery": "^3.2.1",
-    "matefun-components": "0.1.0",
+    "lt-codemirror": "^5.0.0",
+    "matefun-components": "^0.3.0",
     "mathjs": "1.6.0",
-    "ng2-bootstrap-modal": "^1.0.1",
-    "ng2-codemirror": "^1.1.1",
     "ng2-slider-component": "^1.0.9",
     "rxjs": "6.6.7",
     "tippy.js": "^1.2.0",
diff --git a/Frontend Angular 4/src/app/layout/archivos/archivos.component.html b/Frontend Angular 4/src/app/layout/archivos/archivos.component.html
index 850e4f1a..81fac874 100755
--- a/Frontend Angular 4/src/app/layout/archivos/archivos.component.html	
+++ b/Frontend Angular 4/src/app/layout/archivos/archivos.component.html	
@@ -70,11 +70,11 @@
                     <i class="fa fa-plus"></i>
                   </button>
                   <div class="dropdown-menu">
-                    <a class="dropdown-item" (click)="mkFile()">
+                    <a class="dropdown-item" (click)="mkFile(true)">
                       {{ "i18n.object.file" | translate | titleCase }}
                     </a>
                     <div class="dropdown-divider"></div>
-                    <a class="dropdown-item" (click)="mkdir()">
+                    <a class="dropdown-item" (click)="mkFile(false)">
                       {{ "i18n.object.folder" | translate | titleCase }}
                     </a>
                   </div>
@@ -133,22 +133,19 @@
                         | filter: 'nombre':filtroNombre
                     "
                     (click)="seleccionarArchivo(arch)"
-                    class="col-sm-3 col-4"
-                    style="text-align: center"
+                    class="col-sm-3 col-4 matefun-file-wrapper"
                   >
                     <i
                       *ngIf="arch.directorio"
-                      class="fa fa-folder"
-                      style="font-size: 3em; cursor: pointer; color: #f95e5e"
+                      class="fa fa-folder matefun-fa-folder"
                       aria-hidden="true"
                     ></i>
                     <i
                       *ngIf="!arch.directorio"
-                      class="fa fa-file-text"
-                      style="font-size: 3em; cursor: pointer; color: #ff8383"
+                      class="fa fa-file-text matefun-fa-file"
                       aria-hidden="true"
                     ></i>
-                    <p style="cursor: pointer">{{ arch.nombre }}</p>
+                    <p class="matefun-p">{{ arch.nombre }}</p>
                   </div>
                 </div>
               </div>
@@ -215,8 +212,7 @@
                         | filter: 'nombre':filtroNombre
                     "
                     (click)="seleccionarArchivo(arch)"
-                    class="col-sm-3 col-4"
-                    style="text-align: center"
+                    class="col-sm-3 col-4 matefun-file-wrapper"
                   >
                     <i
                       class="fa fa-file-text"
@@ -293,7 +289,7 @@
             "
             (click)="confirmarEntrega()"
           >
-            {{ "i18n.action.send" | translate }}
+            {{ "i18n.action.send" | translate | titleCase }}
           </button>
 
           <div
@@ -366,15 +362,118 @@
             ></i>
           </div>
         </div>
-        <codemirror
+        <lt-codemirror
           class="codemirrorArchivo"
           *ngIf="archivoSeleccionado"
           [(ngModel)]="preview"
           [config]="configCodeMirror"
           [ngStyle]="{ 'font-size': configCodeMirror.fontSize + 'px' }"
         >
-        </codemirror>
+        </lt-codemirror>
       </div>
     </div>
   </div>
 </div>
+<matefun-modal-nuevo-archivo
+  confirmLabel="{{ 'i18n.action.create' | translate | titleCase }}"
+  fileDescriptionLabel="{{ 'i18n.object.descr' | translate | titleCase }}:"
+  fileNameLabel="{{ 'i18n.object.name' | translate | titleCase }}:"
+  header="{{ 'i18n.action.new' | translate | titleCase }} 
+  {{
+    (modalTypeIsFile ? 'i18n.object.file' : 'i18n.object.folder')
+      | translate
+      | titleCase
+  }} "
+  [opened]="modalCreateFileOpened"
+  [typeOfFile]="modalTypeIsFile ? 'file' : 'directory'"
+  (close)="modalCreateFile = false"
+  (confirmFileCreation)="confirmFileCreation($event)"
+  *ngIf="modalCreateFile"
+>
+</matefun-modal-nuevo-archivo>
+
+<matefun-modal-seleccionar-directorio
+  confirmLabel="{{ 'i18n.action.move' | translate | titleCase }} {{
+    'i18n.object.here' | translate
+  }}"
+  [currentDirectory]="currentDirOfFileToMove"
+  [fileIdToMove]="archivoSeleccionado ? archivoSeleccionado.id : -1"
+  fileNameLabel="{{ 'i18n.object.name' | translate | titleCase }}"
+  header="{{ 'i18n.msg.file.move' | translate }}"
+  [initialPath]="currentPath"
+  navigateBackLabel="{{ 'i18n.action.goBack' | translate | titleCase }}"
+  [opened]="modalMoveFileOpened"
+  type-of-modal="move"
+  (close)="modalMoveFile = false"
+  (confirmFileCreation)="confirmFileMove($event)"
+  (navBack)="navigateBackModal($event)"
+  (navTo)="currentDirOfFileToMove = $event.detail"
+  *ngIf="modalMoveFile"
+>
+</matefun-modal-seleccionar-directorio>
+
+<matefun-modal-borrar-archivo
+  bodyDescription="{{ 'i18n.msg.file.delete' | translate: fileNameToRemove }}"
+  cancelLabel="{{ 'i18n.action.cancel' | translate | titleCase }}"
+  confirmLabel="{{ 'i18n.action.delete' | translate | titleCase }}"
+  header="{{ 'i18n.action.delete' | translate | titleCase }} 
+  {{
+    (modalTypeIsFile ? 'i18n.object.file' : 'i18n.object.folder')
+      | translate
+      | titleCase
+  }}"
+  [opened]="modalRemoveFileOpened"
+  [typeOfFile]="modalTypeIsFile ? 'file' : 'directory'"
+  (close)="modalRemoveFile = false"
+  (cancelAction)="modalRemoveFileOpened = false"
+  (removeFile)="confirmFileDeletion()"
+  *ngIf="modalRemoveFile"
+>
+</matefun-modal-borrar-archivo>
+
+<matefun-modal-compartir-archivo
+  confirmLabel="{{ 'i18n.action.share' | translate | titleCase }}"
+  [groups]="groupsToShareFile"
+  header="{{ 'i18n.msg.file.share' | translate: fileNameToShare }}"
+  [opened]="modalShareFileOpened"
+  (close)="modalShareFile = false"
+  (confirmFileShare)="confirmFileShare($event)"
+  *ngIf="modalShareFile"
+>
+</matefun-modal-compartir-archivo>
+
+<matefun-modal-enviar-archivo
+  bodyDescriptionTop="{{
+    'i18n.msg.file.toSend' | translate: { fileName: archivoSeleccionado.nombre }
+  }}"
+  bodyDescriptionBottom="{{ 'i18n.msg.file.toSendInfo' | translate }}"
+  cancelLabel="{{ 'i18n.action.cancel' | translate | titleCase }}"
+  confirmLabel="{{ 'i18n.action.confirm' | translate | titleCase }}"
+  header="{{ 'i18n.action.send' | translate | titleCase }} {{
+    'i18n.object.file' | translate | titleCase
+  }}"
+  [opened]="modalSendFileOpened"
+  (cancelAction)="modalSendFileOpened = false"
+  (close)="modalSendFile = false"
+  (confirmFileSend)="entregarArchivo()"
+  *ngIf="modalSendFile"
+>
+</matefun-modal-enviar-archivo>
+
+<matefun-modal-ver-calificacion
+  detail=" {{ archivoSeleccionado.evaluacion.descripcion }}"
+  detailLabel="{{ 'i18n.object.detail' | translate | titleCase }}: "
+  date=" {{ archivoSeleccionado.evaluacion.fecha | date }}"
+  dateLabel="{{ 'i18n.object.date' | translate | titleCase }}: "
+  confirmLabel="{{ 'i18n.action.close' | translate | titleCase }}"
+  header="{{ 'i18n.object.qualification' | translate | titleCase }} &quot;{{
+    archivoSeleccionado.nombre
+  }}&quot;:"
+  [opened]="modalSeeScoreOpened"
+  score=" {{ archivoSeleccionado.evaluacion.nota }}"
+  scoreLabel="{{ 'i18n.object.score' | translate | titleCase }} (0-100): "
+  (close)="modalSeeScore = false"
+  (confirmClose)="modalSeeScoreOpened = false"
+  *ngIf="modalSeeScore"
+>
+</matefun-modal-ver-calificacion>
diff --git a/Frontend Angular 4/src/app/layout/archivos/archivos.component.ts b/Frontend Angular 4/src/app/layout/archivos/archivos.component.ts
index 186cbbfb..94229216 100755
--- a/Frontend Angular 4/src/app/layout/archivos/archivos.component.ts	
+++ b/Frontend Angular 4/src/app/layout/archivos/archivos.component.ts	
@@ -1,22 +1,14 @@
 import { Component, ViewChild } from "@angular/core";
-import { Archivo } from "../../shared/objects/archivo";
+import { Archivo, Grupo } from "../../shared/objects/archivo";
 import { AuthenticationService } from "../../shared/services/authentication.service";
 import { HaskellService } from "../../shared/services/haskell.service";
 import { SessionService } from "../../shared/services/session.service";
 import { NotificacionService } from "../../shared/services/notificacion.service";
 import { Router, ActivatedRoute } from "@angular/router";
-import { NuevoArchivo } from "./nuevoArchivo.component";
-import { VerCalificacionComponent } from "./verCalificacion.component";
-import { CompartirArchivoComponent } from "./compartirArchivo.component";
-import { ConfirmarEliminar } from "./confirmarEliminar.component";
-import { DialogService } from "ng2-bootstrap-modal";
-import { ConfirmComponent } from "../../shared/modal/confirm.component";
-import { SeleccionarDirectorioMove } from "./seleccionarDirectorio.component";
-import { CodemirrorComponent } from "ng2-codemirror";
+import { LtCodemirrorComponent } from "lt-codemirror";
 import { NgbPopoverConfig, NgbPopover } from "@ng-bootstrap/ng-bootstrap";
 import { TranslateService } from "@ngx-translate/core";
 import { TitleCasePipe } from "../../shared/pipes/titlecase.pipe";
-import { map } from "rxjs/operators";
 
 import "codemirror/mode/haskell/haskell";
 import "codemirror/addon/display/panel";
@@ -24,6 +16,10 @@ import "codemirror/addon/hint/show-hint";
 import "codemirror/addon/hint/anyword-hint";
 import "codemirror/mode/markdown/markdown";
 
+const STARTS_WITH_CAPITAL_LETTER_REGEX = /^[A-Z]/;
+
+const ID_ROOT_DIR = -1;
+
 @Component({
   moduleId: module.id,
   selector: "archivos",
@@ -47,13 +43,127 @@ export class ArchivosComponent {
   sortFunction: any;
   configCodeMirror = JSON.parse(sessionStorage.getItem("codeMirrorConfig"));
 
+  /**
+   * Determina la ruta en donde se encuentra ubicado el archivo/directorio
+   * seleccionado actualmente.
+   */
+  currentPath: string = "/";
+
+  /**
+   * Con `true` se configura el modal para que se muestre la interfaz de
+   * agregar/borrar archivo. De otro modo, se muestra la interfaz de
+   * agregar/borrar directorio
+   */
+  modalTypeIsFile = true;
+
+  // - - - - - - - - - - - - - Modal create file - - - - - - - - - - - - -
+  /**
+   * Con `true` se renderiza el modal de crear un archivo
+   */
+  modalCreateFile = false;
+
+  /**
+   * Con `true` se indica que el modal -de crear un archivo- se quiere abrir.
+   * Útil para avisar al modal que anime el dismiss antes de que se elimine del
+   * DOM
+   */
+  modalCreateFileOpened = true;
+
+  // - - - - - - - - - - - - -  Modal move file  - - - - - - - - - - - - -
+  /**
+   * Con `true` se renderiza el modal de mover un archivo
+   */
+  modalMoveFile = false;
+
+  /**
+   * Con `true` se indica que el modal -de mover un archivo- se quiere abrir.
+   * Útil para avisar al modal que anime el dismiss antes de que se elimine del
+   * DOM
+   */
+  modalMoveFileOpened = true;
+
+  /**
+   * Directorio actual sobre el cual será desplegada la lista de directorios
+   * del modal mover archivo.
+   */
+  currentDirOfFileToMove: Archivo;
+
+  // - - - - - - - - - - - - - Modal remove file - - - - - - - - - - - - -
+  /**
+   * Con `true` se renderiza el modal de borrar un archivo
+   */
+  modalRemoveFile = false;
+
+  /**
+   * Con `true` se indica que el modal -de borrar un archivo- se quiere abrir.
+   * Útil para avisar al modal que anime el dismiss antes de que se elimine del
+   * DOM
+   */
+  modalRemoveFileOpened = true;
+
+  /**
+   * Nombre del archivo que se desea borrar en el modal de borrar
+   * archivos/directorios.
+   */
+  fileNameToRemove: { fileName: string };
+
+  // - - - - - - - - - - - - - Modal share file - - - - - - - - - - - - -
+  /**
+   * Con `true` se renderiza el modal de compartir un archivo
+   */
+  modalShareFile = false;
+
+  /**
+   * Con `true` se indica que el modal -de compartir un archivo- se quiere abrir.
+   * Útil para avisar al modal que anime el dismiss antes de que se elimine del
+   * DOM
+   */
+  modalShareFileOpened = true;
+
+  /**
+   * Nombre del archivo que se desea compartir en el modal de compartir archivo.
+   */
+  fileNameToShare: { fileName: string };
+
+  /**
+   * Arreglo de grupos sobre los cuales se puede compartir el archivo
+   * seleccionado en el modal de compartir archivo.
+   */
+  groupsToShareFile: Grupo[];
+
+  // - - - - - - - - - - - - - Modal send file - - - - - - - - - - - - -
+  /**
+   * Con `true` se renderiza el modal de enviar un archivo para calificar
+   */
+  modalSendFile = false;
+
+  /**
+   * Con `true` se indica que el modal -de enviar un archivo para calificar-
+   * se quiere abrir.
+   * Útil para avisar al modal que anime el dismiss antes de que se elimine del
+   * DOM
+   */
+  modalSendFileOpened = true;
+
+  // - - - - - - - - - - - - - Modal see score - - - - - - - - - - - - -
+  /**
+   * Con `true` se renderiza el modal de ver calificacion
+   */
+  modalSeeScore = false;
+
+  /**
+   * Con `true` se indica que el modal -de ver calificacion- se quiere abrir.
+   * Útil para avisar al modal que anime el dismiss antes de que se elimine del
+   * DOM
+   */
+  modalSeeScoreOpened = true;
+
   constructor(
     private router: Router,
     private notifService: NotificacionService,
     private authService: AuthenticationService,
     private haskellService: HaskellService,
     private sessionService: SessionService,
-    private dialogService: DialogService,
     public translate: TranslateService,
     private route: ActivatedRoute
   ) {
@@ -66,7 +176,8 @@ export class ArchivosComponent {
     this.directorioActual.archivos = [];
     this.configCodeMirror.readOnly = true;
   }
-  @ViewChild(CodemirrorComponent, { static: false }) codemirror: CodemirrorComponent;
+  @ViewChild(LtCodemirrorComponent, { static: false })
+  codemirror: LtCodemirrorComponent;
 
   ngOnInit() {
     this.sortFunction = "tipo";
@@ -183,73 +294,67 @@ export class ArchivosComponent {
   }
 
   mostrarEliminarDialogo() {
-    if (this.archivoSeleccionado) {
-      //Si el archivo es del alumno lo puedo eliminar.
-      //(No se controla por creador dado que los compartidos mantienen este atributo)
-      if (
-        this.archivos.some((arch) => arch.id == this.archivoSeleccionado.id)
-      ) {
-        var that = this;
-        let disposable = this.dialogService
-          .addDialog(ConfirmarEliminar, {
-            nombreArchivo: { fileName: that.archivoSeleccionado.nombre },
-            esDirectorio: that.archivoSeleccionado.directorio,
-            parentContext: that,
-          })
-          .subscribe((isConfirmed) => {
-            if (isConfirmed) {
-              //codeMirrorRef.options.readOnly = false;
-              //componentRef.editDialogFired = true;
-            }
-          });
-        console.log(disposable);
-      } else {
-        this.notifService.warning(
-          this.translateService.get("i18n.warning.file.noPermissionDelete")
-            .value
-        );
-      }
-    } else {
+    // Chequear si se seleccionó un archivo
+    if (!this.archivoSeleccionado) {
       this.notifService.warning(
         this.translateService.get("i18n.warning.file.noSelected").value
       );
+      return;
+    }
+
+    // Si el archivo es del alumno, se puede eliminar.
+    // No se controla por creador, dado que los compartidos mantienen este atributo
+    if (!this.archivos.some((arch) => arch.id == this.archivoSeleccionado.id)) {
+      this.notifService.warning(
+        this.translateService.get("i18n.warning.file.noPermissionDelete").value
+      );
+      return;
     }
+
+    this.fileNameToRemove = { fileName: this.archivoSeleccionado.nombre };
+
+    // Determina el tipo de modal a renderizar
+    this.modalTypeIsFile = !this.archivoSeleccionado.directorio;
+
+    // Mostrar el modal
+    this.modalRemoveFile = true;
+    this.modalRemoveFileOpened = true;
   }
+
   seleccionarDirectorioAMover() {
-    if (this.archivoSeleccionado) {
-      //Si el archivo es del alumno lo puedo eliminar.
-      //(No se controla por creador dado que los compartidos mantienen este atributo)
-      if (
-        this.archivos.some((arch) => arch.id == this.archivoSeleccionado.id)
-      ) {
-        var that = this;
-        let disposable = this.dialogService
-          .addDialog(SeleccionarDirectorioMove, {
-            archivos: that.tree,
-            directorioActual: that.directorioActual,
-            nombre: that.archivoSeleccionado.nombre,
-            directorio: that.archivoSeleccionado.directorio,
-            parent: that,
-          })
-          .subscribe((isConfirmed) => {
-            if (isConfirmed) {
-            }
-          });
-      } else {
-        this.notifService.warning(
-          this.translateService.get("i18n.warning.file.noPermissionMove").value
-        );
-      }
-    } else {
+    if (!this.archivoSeleccionado) {
       this.notifService.warning(
         this.translateService.get("i18n.warning.file.noSelected").value
       );
+      return;
+    }
+
+    // Si el archivo es del alumno, se puede mover.
+    // No se controla por creador, dado que los compartidos mantienen este atributo
+    if (!this.archivos.some((arch) => arch.id == this.archivoSeleccionado.id)) {
+      this.notifService.warning(
+        this.translateService.get("i18n.warning.file.noPermissionMove").value
+      );
+      return;
     }
+
+    this.navBack(false);
+    this.currentDirOfFileToMove = this.directorioActual;
+
+    // Mostrar el modal
+    this.modalMoveFile = true;
+    this.modalMoveFileOpened = true;
   }
 
+  /**
+   * Dado un ID de directorio, refresca la UI con el contenido del directorio
+   * identificado por `idDirectorioActual`
+   * @param idDirectorioActual ID del directorio sobre el cual se quiere mostrar los archivos
+   */
   recargarArchivos(idDirectorioActual) {
     let cedula = this.authService.getUser().cedula;
     this.loading = true;
+
     this.haskellService.getArchivos(cedula).subscribe(
       (archivos) => {
         this.archivos = archivos;
@@ -260,14 +365,58 @@ export class ArchivosComponent {
     );
   }
 
-  navBack() {
-    var that = this;
-    if (this.directorioActual.padreId !== -1) {
-      var padre = this.archivos.filter(function (a) {
-        return a.id === that.directorioActual.padreId;
-      })[0];
-      this.directorioActual = padre;
+  /**
+   * Navega hacia el directorio padre en la vista principal de directorios.
+   * @param shouldUpdateSelectedFile Determina si se debe actualizar el archivo seleccionado cuando se navega hacia atrás
+   */
+  navBack(shouldUpdateSelectedFile = true) {
+    const { padreId } = this.directorioActual;
+
+    if (padreId === ID_ROOT_DIR) {
+      return;
+    }
+
+    // Actualiza el current path
+    const lastDirectoryIndex = this.currentPath.lastIndexOf(
+      `${this.directorioActual.nombre}`
+    );
+
+    this.currentPath = this.currentPath.substring(0, lastDirectoryIndex);
+
+    const padre = this.archivos.filter((file) => file.id === padreId)[0];
+
+    if (shouldUpdateSelectedFile) {
+      // Cuando se selecciona un directorio cuyo id es el root, significa que ese
+      // es el último archivo de la rama de directorios. En otras palabras, el
+      // root se identifica porque su padreId es ID_ROOT_DIR.
+      const archivoSeleccionado =
+        padre.padreId == ID_ROOT_DIR ? undefined : padre;
+      this.actualizarArchivoSeleccionado(archivoSeleccionado);
+    }
+
+    // Actualiza la vista de directorios y archivos
+    this.directorioActual = padre;
+  }
+
+  /**
+   * Localmente en la vista de directorios del modal, navega hacia el
+   * directorio padre.
+   * @param event Archivo sobre el cual se quiere navegar hacia su directorio padre
+   */
+  navigateBackModal(event: CustomEvent<Archivo>) {
+    const { padreId } = event.detail;
+
+    // No se puede navegar al padre de root
+    if (padreId == ID_ROOT_DIR) {
+      return;
     }
+
+    const archivosList: Archivo[] = this.sessionService.getArchivosList();
+
+    // Se queda con el archivo identificado por padreId
+    this.currentDirOfFileToMove = archivosList.filter(
+      (file) => file.id === padreId
+    )[0];
   }
 
   setSoloLectura = function (arch: Archivo) {
@@ -336,42 +485,9 @@ export class ArchivosComponent {
   }
 
   confirmarEntrega() {
-    var title =
-      this.titlecasePipe.transform(
-        this.translateService.get("i18n.action.send").value
-      ) +
-      " " +
-      this.titlecasePipe.transform(
-        this.translateService.get("i18n.object.file").value
-      );
-    var msg = "";
-    this.translateService
-      .get("i18n.msg.file.toSend", {
-        fileName: this.archivoSeleccionado.nombre,
-      })
-      .subscribe((res: string) => {
-        msg =
-          res +
-          "\n" +
-          this.translateService.get("i18n.msg.file.toSendInfo").value;
-      });
-
-    let disposable = this.dialogService
-      .addDialog(ConfirmComponent, {
-        title: title,
-        message: msg,
-        confirmText: this.titlecasePipe.transform(
-          this.translateService.get("i18n.action.send")
-        ),
-        cancelText: this.titlecasePipe.transform(
-          this.translateService.get("i18n.action.cancel")
-        ),
-      })
-      .subscribe((isConfirmed) => {
-        if (isConfirmed) {
-          this.entregarArchivo();
-        }
-      });
+    // Mostrar el modal
+    this.modalSendFile = true;
+    this.modalSendFileOpened = true;
   }
 
   entregarArchivo() {
@@ -381,9 +497,15 @@ export class ArchivosComponent {
       .subscribe(
         (archivo) => {
           this.archivoSeleccionado = archivo;
+
+          // Cerrar el modal en caso de éxito
+          this.modalSendFileOpened = false;
         },
         (error) => {
           this.notifService.error(error);
+
+          // Cerrar el modal en caso de falla
+          this.modalSendFileOpened = false;
         }
       );
   }
@@ -476,94 +598,275 @@ export class ArchivosComponent {
     }
   }
 
-  mkdir() {
-    var that = this;
-    let disposable = this.dialogService
-      .addDialog(NuevoArchivo, {
-        nombre: "",
-        descripcion: "",
-        esDirectorio: true,
-        parentContext: that,
-      })
-      .subscribe((isConfirmed) => {
-        if (isConfirmed) {
-          //codeMirrorRef.options.readOnly = false;
-          //componentRef.editDialogFired = true;
+  /**
+   * Renderiza en pantalla el modal de agregar archivos o directorios,
+   * dependiendo del valor de `modalTypeIsFile`.
+   * @param modalTypeIsFile Con `true` se indica que el modal a renderizar es el de agregar archivo. De otro modo, se renderiza el de agregar directorio.
+   */
+  mkFile(modalTypeIsFile: boolean) {
+    this.modalTypeIsFile = modalTypeIsFile;
+
+    // Mostrar el modal
+    this.modalCreateFile = true;
+    this.modalCreateFileOpened = true;
+  }
+
+  /**
+   * Valida y confirma la creación del archivo.
+   * @param event Evento devuelto por el modal asociado para crear el archivo. En el detalle contiene el `nombre` y `descripcion` del archivo que se desea agregar.
+   */
+  confirmFileCreation(event: CustomEvent) {
+    const { nombre, descripcion } = event.detail;
+
+    // Antes que nada, se chequea que empiece con mayúscula
+    if (!STARTS_WITH_CAPITAL_LETTER_REGEX.test(nombre)) {
+      alert(this.translateService.get("i18n.warning.file.capitalLetter").value);
+      return;
+    }
+
+    const archivo = new Archivo();
+    archivo.cedulaCreador = this.directorioActual.cedulaCreador;
+    archivo.contenido = this.modalTypeIsFile ? "" : descripcion;
+    archivo.directorio = !this.modalTypeIsFile;
+    archivo.editable = true;
+    archivo.fechaCreacion = new Date();
+    archivo.nombre = nombre;
+    archivo.padreId = this.directorioActual.id;
+
+    const that = this;
+    const idDirectorioActual = this.directorioActual.id;
+
+    this.haskellService.crearArchivo(archivo).subscribe(
+      () => {
+        that.recargarArchivos(idDirectorioActual);
+
+        // Cerrar el modal en caso de éxito
+        that.modalCreateFileOpened = false;
+      },
+      (error) => {
+        that.notifService.error(error.text());
+
+        // Cerrar el modal en caso de error
+        that.modalCreateFileOpened = false;
+      }
+    );
+  }
+
+  /**
+   * Valida y confirma la operación de mover el archivo/carpeta.
+   * @param event Evento devuelto por el modal asociado para mover el archivo. El detalle contiene el `idPadre` del archivo que se desea mover.
+   */
+  confirmFileMove(event: CustomEvent) {
+    if (!this.archivoSeleccionado) {
+      this.notifService.warning(
+        this.translateService.get("i18n.warning.file.noSelected").value
+      );
+      return;
+    }
+
+    const nuevoDirectorioPadreId = event.detail.padreId;
+
+    // Se actualiza en el cliente el directorio padre del archivo a mover
+    this.archivoSeleccionado.padreId = nuevoDirectorioPadreId;
+
+    if (this.archivoSeleccionado.directorio) {
+      delete this.archivoSeleccionado["archivos"];
+    }
+
+    this.haskellService
+      .editarArchivo(this.archivoSeleccionado.id, this.archivoSeleccionado)
+      .subscribe(
+        () => {
+          this.recargarArchivos(this.directorioActual.id);
+
+          // Dado que se cambia la ubicación del directorio actual, hay que
+          // rearmar el currentPath
+          if (this.archivoSeleccionado.directorio) {
+            this.inicializarCurrentPath(this.directorioActual);
+          }
+
+          this.archivoSeleccionado = null;
+
+          // Cerrar el modal en caso de éxito
+          this.modalMoveFileOpened = false;
+        },
+        (error) => {
+          this.notifService.error(error.text());
+
+          // Cerrar el modal en caso de error
+          this.modalMoveFileOpened = false;
+        }
+      );
+  }
+
+  /**
+   * Valida y confirma la operación de borrar el archivo/carpeta.
+   */
+  confirmFileDeletion() {
+    const directorio = this.archivoSeleccionado.directorio;
+
+    this.haskellService.eliminarArchivo(this.archivoSeleccionado.id).subscribe(
+      () => {
+        let idDirActual;
+
+        this.archivoSeleccionado.eliminado = true;
+
+        // Si el archivo seleccionado es un directorio, se borran todos los
+        // archivos del directorio
+        if (directorio) {
+          delete this.archivoSeleccionado["archivos"];
+
+          // Actualiza el current path
+          const lastDirectoryIndex = this.currentPath.lastIndexOf(
+            `${this.directorioActual.nombre}`
+          );
+          this.currentPath = this.currentPath.substring(0, lastDirectoryIndex);
+
+          idDirActual = this.directorioActual.padreId;
+
+          // Si se borra el directorio actual, se selecciona el directorio
+          // padre en caso de que este no sea el root
+          this.archivoSeleccionado =
+            idDirActual !== ID_ROOT_DIR ? idDirActual : null;
+        } else {
+          idDirActual = this.directorioActual.id;
+          this.archivoSeleccionado = null;
         }
-      });
-  }
-  mkFile() {
-    var that = this;
-    let disposable = this.dialogService
-      .addDialog(NuevoArchivo, {
-        nombre: "",
-        descripcion: "",
-        esDirectorio: false,
-        parentContext: that,
-      })
-      .subscribe((isConfirmed) => {
-        if (isConfirmed) {
-          //codeMirrorRef.options.readOnly = false;
-          //componentRef.editDialogFired = true;
+
+        this.recargarArchivos(idDirActual);
+
+        // Cerrar el modal en caso de éxito
+        this.modalRemoveFileOpened = false;
+      },
+      (error) => {
+        this.notifService.error(error);
+
+        // Cerrar el modal en caso de error
+        this.modalRemoveFileOpened = false;
+      }
+    );
+  }
+
+  confirmFileShare(event: CustomEvent<Grupo>) {
+    const selectedGroup = event.detail;
+
+    if (!selectedGroup) {
+      this.notifService.error(
+        this.translateService.get("i18n.warning.group.select").value
+      );
+      return;
+    }
+
+    this.haskellService
+      .compartirArchivoGrupo(selectedGroup, this.archivoSeleccionado.id)
+      .subscribe(
+        () => {
+          this.notifService.success(
+            this.translateService.get("i18n.msg.file.shared").value
+          );
+
+          // Cerrar el modal en caso de éxito
+          this.modalShareFileOpened = false;
+        },
+        (error) => {
+          this.notifService.error(error);
+
+          // Cerrar el modal en caso de error
+          this.modalShareFileOpened = false;
         }
-      });
+      );
   }
 
-  seleccionarArchivo = function (arch: Archivo) {
-    if (arch.directorio) {
-      this.directorioActual = arch;
+  /**
+   * Dado el directorio actual, se contruye el path absoluto (se actualiza
+   * currentPath) que identifica al directorio. Esta función es útil cuando un
+   * directorio es movido de lugar y se desconoce la nueva ubicación del
+   * directorio.
+   * @param lastDirectory Directorio sobre el cual se quiere obtener el path
+   */
+  inicializarCurrentPath(lastDirectory: Archivo) {
+    // Si el directorio está en root, el currentPath es "/"
+    if (lastDirectory.padreId === ID_ROOT_DIR) {
+      this.currentPath = "/";
+      return;
+    }
+
+    let path = "/";
+    let currentDirectory = lastDirectory;
+
+    const archivosList: Archivo[] = this.sessionService.getArchivosList();
+
+    // Se recorren los ancestros de currentDirectory
+    while (currentDirectory.padreId !== ID_ROOT_DIR) {
+      path = "/" + currentDirectory.nombre + path;
+
+      // Se queda con el archivo identificado por padreId
+      currentDirectory = archivosList.filter(
+        (file) => file.id === currentDirectory.padreId
+      )[0];
+    }
+
+    this.currentPath = path;
+  }
+
+  seleccionarArchivo(archivo: Archivo) {
+    if (archivo.directorio) {
+      this.directorioActual = archivo;
+
+      // Actualizar el currentPath para así siempre lo puede recibir el modal de
+      // mover archivo
+      this.currentPath += `${archivo.nombre}/`;
     } else {
       this.sessionService.setDirectorioActual(this.directorioActual);
       this.sessionService.setArchivosCompartidos(this.archivosCompartidos);
-      this.sessionService.cargarDependencias(arch);
+      this.sessionService.cargarDependencias(archivo);
     }
-    this.archivoSeleccionado = arch;
-    this.preview = arch.contenido;
+
+    this.actualizarArchivoSeleccionado(archivo);
+
     //this.ordenarArchivos();
-  };
+  }
+
+  /**
+   * Actualiza el estado del archivo seleccionado, así como la preview del
+   * contenido de dicho archivo.
+   * @param archivo Archivo a seleccionar
+   */
+  actualizarArchivoSeleccionado(archivo: Archivo) {
+    this.archivoSeleccionado = archivo;
+    this.preview = archivo ? archivo.contenido : "";
+  }
 
   compartirArchivo() {
-    if (this.archivoSeleccionado) {
-      var grupos = this.sessionService.getGrupos();
-      if (grupos == undefined) {
-        this.haskellService
-          .getGrupos(this.authService.getUser().cedula)
-          .subscribe(
-            (gruposRest) => {
-              this.sessionService.setGrupos(grupos);
-              this.dialogService
-                .addDialog(CompartirArchivoComponent, {
-                  grupos: gruposRest,
-                  archivo: this.archivoSeleccionado,
-                  nombreArchivo: { fileName: this.archivoSeleccionado.nombre },
-                  parent: this,
-                })
-                .subscribe((isConfirmed) => {
-                  if (isConfirmed) {
-                    this.notifService.success("confirmado?");
-                  }
-                });
-            },
-            (error) => {}
-          );
-      } else {
-        this.dialogService
-          .addDialog(CompartirArchivoComponent, {
-            grupos: grupos,
-            archivo: this.archivoSeleccionado,
-            nombreArchivo: { fileName: this.archivoSeleccionado.nombre },
-            parent: this,
-          })
-          .subscribe((isConfirmed) => {
-            if (isConfirmed) {
-              this.notifService.success("confirmado?");
-            }
-          });
-      }
-    } else {
+    if (!this.archivoSeleccionado) {
       this.notifService.warning(
         this.translateService.get("i18n.warning.file.noSelected").value
       );
+      return;
+    }
+
+    const grupos = this.sessionService.getGrupos();
+    this.fileNameToShare = { fileName: this.archivoSeleccionado.nombre };
+
+    if (grupos == undefined) {
+      this.haskellService
+        .getGrupos(this.authService.getUser().cedula)
+        .subscribe((gruposRest) => {
+          // Se guardan los grupos en la sesión
+          this.sessionService.setGrupos(gruposRest);
+
+          this.groupsToShareFile = gruposRest;
+
+          // Mostrar el modal
+          this.modalShareFile = true;
+          this.modalShareFileOpened = true;
+        });
+    } else {
+      this.groupsToShareFile = grupos;
+
+      // Mostrar el modal
+      this.modalShareFile = true;
+      this.modalShareFileOpened = true;
     }
   }
 
@@ -600,14 +903,12 @@ export class ArchivosComponent {
   }
 
   verCalificacion() {
-    this.dialogService
-      .addDialog(VerCalificacionComponent, {
-        archivo: this.archivoSeleccionado,
-      })
-      .subscribe((isConfirmed) => {
-        if (isConfirmed) {
-          this.notifService.success("confirmado?");
-        }
-      });
+    if (!this.archivoSeleccionado) {
+      return;
+    }
+
+    // Mostrar el modal
+    this.modalSeeScore = true;
+    this.modalSeeScoreOpened = true;
   }
 }
diff --git a/Frontend Angular 4/src/app/layout/archivos/archivos.module.ts b/Frontend Angular 4/src/app/layout/archivos/archivos.module.ts
index babc52fd..fba00559 100755
--- a/Frontend Angular 4/src/app/layout/archivos/archivos.module.ts	
+++ b/Frontend Angular 4/src/app/layout/archivos/archivos.module.ts	
@@ -4,16 +4,8 @@ import { ArchivosComponent } from "./archivos.component";
 import { CommonModule } from "@angular/common";
 import { ArchivosRoutingModule } from "./archivos-routing.module";
 import { FilterPipe } from "../../shared/pipes/filter.pipe";
-import { ConfirmComponent } from "../../shared/modal/confirm.component";
-import { NuevoArchivo } from "./nuevoArchivo.component";
-import { VerCalificacionComponent } from "./verCalificacion.component";
-import { CompartirArchivoComponent } from "./compartirArchivo.component";
-import { SeleccionarDirectorioMove } from "./seleccionarDirectorio.component";
-import { ConfirmarEliminar } from "./confirmarEliminar.component";
-import { DialogService } from "ng2-bootstrap-modal";
-import { BootstrapModalModule } from "ng2-bootstrap-modal";
 import { NgbModule } from "@ng-bootstrap/ng-bootstrap";
-import { CodemirrorModule } from "ng2-codemirror";
+import { LtCodemirrorModule } from "lt-codemirror";
 import { NotificacionModule } from "../../notificacion/notificacion.module";
 import { I18nModule } from "../../shared/modules/translate/i18n.module";
 import { TitleCaseModule } from "../../shared/modules/titlecase.module";
@@ -23,31 +15,13 @@ import { TitleCaseModule } from "../../shared/modules/titlecase.module";
     CommonModule,
     ArchivosRoutingModule,
     FormsModule,
-    BootstrapModalModule,
     NgbModule,
-    CodemirrorModule,
+    LtCodemirrorModule,
     NotificacionModule,
     I18nModule,
     TitleCaseModule,
   ],
-  declarations: [
-    ArchivosComponent,
-    FilterPipe,
-    NuevoArchivo,
-    VerCalificacionComponent,
-    ConfirmComponent,
-    CompartirArchivoComponent,
-    ConfirmarEliminar,
-    SeleccionarDirectorioMove,
-  ],
-  entryComponents: [
-    NuevoArchivo,
-    VerCalificacionComponent,
-    ConfirmComponent,
-    CompartirArchivoComponent,
-    ConfirmarEliminar,
-    SeleccionarDirectorioMove,
-  ],
+  declarations: [ArchivosComponent, FilterPipe],
   exports: [ArchivosComponent],
   schemas: [CUSTOM_ELEMENTS_SCHEMA],
 })
diff --git a/Frontend Angular 4/src/app/layout/archivos/compartirArchivo.component.ts b/Frontend Angular 4/src/app/layout/archivos/compartirArchivo.component.ts
deleted file mode 100755
index be9ee07f..00000000
--- a/Frontend Angular 4/src/app/layout/archivos/compartirArchivo.component.ts	
+++ /dev/null
@@ -1,111 +0,0 @@
-import { Component } from "@angular/core";
-import { DialogComponent, DialogService } from "ng2-bootstrap-modal";
-import { Archivo } from "../../shared/objects/archivo";
-import { Grupo } from "../../shared/objects/grupo";
-import { TranslateService } from "@ngx-translate/core";
-
-export interface ConfirmModel {
-  archivo: Archivo;
-  grupos: any;
-  parent: any;
-  nombreArchivo: { fileName: string };
-}
-@Component({
-  selector: "confirm",
-  template: `<div class="modal-dialog" style="margin-top:100px;">
-    <div class="modal-content">
-      <div class="modal-header">
-        <h6 class="modal-title pull-lefth">
-          {{ "i18n.msg.file.share" | translate: nombreArchivo }}
-        </h6>
-        <button
-          type="button"
-          class="close"
-          (click)="close()"
-          style="margin-rigth:8px;"
-        >
-          &times;
-        </button>
-      </div>
-      <div class="modal-body" style="height:350px;overflow-y: scroll;">
-        <div>
-          <div class="list-group">
-            <button
-              *ngFor="let g of grupos"
-              type="button"
-              (click)="seleccionarGrupo(g)"
-              style="cursor:pointer"
-              class="list-group-item list-group-item-action"
-              [ngClass]="{
-                active:
-                  grupo != undefined &&
-                  g.grado == grupo.grado &&
-                  g.grupo == grupo.grupo &&
-                  g.anio == grupo.anio &&
-                  g.liceoId == grupo.liceoId
-              }"
-            >
-              <i
-                class="fa fa-group"
-                style="margin-right:10px; font-size: 3em; cursor: pointer;"
-                aria-hidden="true"
-              ></i>
-              {{ g.grado + "°" + g.grupo + " - " + g.anio }}
-            </button>
-          </div>
-        </div>
-      </div>
-      <div class="modal-footer">
-        <button type="button" class="btn btn-primary" (click)="compartir()">
-          {{ "i18n.action.share" | translate | titleCase }}
-        </button>
-      </div>
-    </div>
-  </div>`,
-})
-export class CompartirArchivoComponent
-  extends DialogComponent<ConfirmModel, boolean>
-  implements ConfirmModel
-{
-  archivo: Archivo;
-  grupos: any;
-  grupo: Grupo;
-  parent: any;
-  nombreArchivo: { fileName: string };
-  translateService: any;
-
-  constructor(
-    dialogService: DialogService,
-    public translate: TranslateService
-  ) {
-    super(dialogService);
-    this.translateService = translate;
-  }
-
-  seleccionarGrupo(grupo) {
-    this.grupo = grupo;
-  }
-
-  compartir() {
-    this.nombreArchivo = { fileName: this.archivo.nombre };
-    if (this.grupo) {
-      this.parent.haskellService
-        .compartirArchivoGrupo(this.grupo, this.archivo.id)
-        .subscribe(
-          (success) => {
-            this.parent.notifService.success(
-              this.translateService.get("i18n.msg.file.shared").value
-            );
-            this.close();
-          },
-          (error) => {
-            this.parent.notifService.error(error);
-          }
-        );
-    } else {
-      this.parent.notifService.error(
-        this.translateService.get("i18n.warning.group.select").value
-      );
-    }
-  }
-}
diff --git a/Frontend Angular 4/src/app/layout/archivos/confirmarEliminar.component.ts b/Frontend Angular 4/src/app/layout/archivos/confirmarEliminar.component.ts
deleted file mode 100755
index 81834a81..00000000
--- a/Frontend Angular 4/src/app/layout/archivos/confirmarEliminar.component.ts	
+++ /dev/null
@@ -1,91 +0,0 @@
-import { Component } from "@angular/core";
-import { DialogComponent, DialogService } from "ng2-bootstrap-modal";
-import { Archivo } from "../../shared/objects/archivo";
-
-export interface ConfirmModel {
-  nombreArchivo: { fileName: string };
-  esDirectorio: boolean;
-  parentContext: any;
-}
-@Component({
-  selector: "confirm",
-  template: `<div class="modal-dialog" style="margin-top:100px;">
-    <div class="modal-content">
-      <div class="modal-header">
-        <h6 class="modal-title" *ngIf="!esDirectorio">
-          {{ "i18n.action.delete" | translate | titleCase }}
-          {{ "i18n.object.file" | translate | titleCase }}
-        </h6>
-        <h6 class="modal-title" *ngIf="esDirectorio">
-          {{ "i18n.action.delete" | translate | titleCase }}
-          {{ "i18n.object.folder" | translate | titleCase }}
-        </h6>
-        <button
-          type="button"
-          class="close"
-          (click)="close()"
-          style="margin-left:8px;"
-        >
-          &times;
-        </button>
-      </div>
-      <div class="modal-body">
-        <p *ngIf="!esDirectorio">
-          {{ "i18n.msg.file.delete" | translate: nombreArchivo }}
-        </p>
-        <p *ngIf="esDirectorio">
-          {{ "i18n.msg.file.delete" | translate: nombreArchivo }}
-        </p>
-      </div>
-      <div class="modal-footer">
-        <button type="button" class="btn btn-default" (click)="close()">
-          {{ "i18n.action.cancel" | translate | titleCase }}
-        </button>
-        <button
-          type="button"
-          class="btn btn-success"
-          (click)="confirmarEliminar()"
-        >
-          {{ "i18n.action.delete" | translate | titleCase }}
-        </button>
-      </div>
-    </div>
-  </div>`,
-})
-export class ConfirmarEliminar
-  extends DialogComponent<ConfirmModel, boolean>
-  implements ConfirmModel
-{
-  nombreArchivo: { fileName: string };
-  esDirectorio: boolean;
-  parentContext: any;
-
-  constructor(dialogService: DialogService) {
-    super(dialogService);
-  }
-  confirmarEliminar() {
-    var that = this.parentContext;
-    var directorio = this.parentContext.archivoSeleccionado.directorio;
-    this.parentContext.archivoSeleccionado.eliminado = true;
-    if (directorio) {
-      delete this.parentContext.archivoSeleccionado["archivos"];
-    }
-    this.parentContext.haskellService
-      .eliminarArchivo(this.parentContext.archivoSeleccionado.id)
-      .subscribe(
-        (archivo) => {
-          if (directorio) {
-            var idDirActual = that.directorioActual.padreId;
-          } else {
-            var idDirActual = that.directorioActual.id;
-          }
-          that.recargarArchivos(idDirActual);
-          that.archivoSeleccionado = null;
-        },
-        (error) => {
-          this.parentContext.notifService.error(error);
-        }
-      );
-    this.close();
-  }
-}
diff --git a/Frontend Angular 4/src/app/layout/archivos/nuevoArchivo.component.ts b/Frontend Angular 4/src/app/layout/archivos/nuevoArchivo.component.ts
deleted file mode 100755
index b4f8ebdf..00000000
--- a/Frontend Angular 4/src/app/layout/archivos/nuevoArchivo.component.ts	
+++ /dev/null
@@ -1,126 +0,0 @@
-import { Component } from "@angular/core";
-import { DialogComponent, DialogService } from "ng2-bootstrap-modal";
-import { Archivo } from "../../shared/objects/archivo";
-import { TranslateService } from "@ngx-translate/core";
-
-export interface ConfirmModel {
-  nombre: string;
-  descripcion: string;
-  parentContext: any;
-  esDirectorio: boolean;
-}
-@Component({
-  selector: "confirm",
-  template: `<div class="modal-dialog" style="margin-top:100px;">
-    <div class="modal-content">
-      <div class="modal-header">
-        <h6 class="modal-title" *ngIf="esDirectorio">
-          {{ "i18n.action.new" | translate | titleCase }}
-          {{ "i18n.object.folder" | translate | titleCase }}
-        </h6>
-        <h6 class="modal-title" *ngIf="!esDirectorio">
-          {{ "i18n.action.new" | translate | titleCase }}
-          {{ "i18n.object.file" | translate | titleCase }}
-        </h6>
-        <button
-          type="button"
-          class="close"
-          (click)="close()"
-          style="margin-left:8px;"
-        >
-          &times;
-        </button>
-      </div>
-
-      <div class="modal-body">
-        <form>
-          <div class="form-group">
-            <label for="recipient-name" class="form-control-label">
-              {{ "i18n.object.name" | translate | titleCase }}:
-            </label>
-            <input
-              type="text"
-              class="form-control"
-              id="recipient-name"
-              [(ngModel)]="nombre"
-              [ngModelOptions]="{ standalone: true }"
-            />
-          </div>
-          <div class="form-group" *ngIf="esDirectorio">
-            <label for="message-text" class="form-control-label">
-              {{ "i18n.object.descr" | translate | titleCase }}:
-            </label>
-            <textarea
-              class="form-control"
-              id="message-text"
-              [(ngModel)]="descripcion"
-              [ngModelOptions]="{ standalone: true }"
-            ></textarea>
-          </div>
-        </form>
-      </div>
-
-      <div class="modal-footer">
-        <button
-          [disabled]="this.nombre == ''"
-          type="button"
-          class="btn btn-success"
-          (click)="confirm()"
-        >
-          {{ "i18n.action.create" | translate | titleCase }}
-        </button>
-      </div>
-    </div>
-  </div>`,
-})
-export class NuevoArchivo
-  extends DialogComponent<ConfirmModel, boolean>
-  implements ConfirmModel
-{
-  nombre: string;
-  esDirectorio: boolean;
-  descripcion: string;
-  parentContext: any;
-  translateService: any;
-
-  constructor(
-    dialogService: DialogService,
-    public translate: TranslateService
-  ) {
-    super(dialogService);
-    this.translateService = translate;
-  }
-  confirm() {
-    var nombre = this.nombre;
-    var desc = this.descripcion;
-    var archivo: Archivo;
-    archivo = new Archivo();
-    archivo.cedulaCreador = this.parentContext.directorioActual.cedulaCreador;
-    if (this.esDirectorio) {
-      archivo.contenido = desc;
-    } else {
-      archivo.contenido = "";
-    }
-    archivo.directorio = this.esDirectorio;
-    archivo.editable = true;
-    archivo.fechaCreacion = new Date();
-    archivo.nombre = nombre;
-    archivo.padreId = this.parentContext.directorioActual.id;
-    var that = this.parentContext;
-    var regex = /^[A-Z]/;
-    if (regex.test(nombre)) {
-      this.parentContext.haskellService.crearArchivo(archivo).subscribe(
-        (archivo) => {
-          var id = that.directorioActual.id;
-          that.recargarArchivos(id);
-        },
-        (error) => {
-          this.parentContext.notifService.error(error.text());
-        }
-      );
-      this.close();
-    } else {
-      alert(this.translateService.get("i18n.warning.file.capitalLetter").value);
-    }
-  }
-}
diff --git a/Frontend Angular 4/src/app/layout/archivos/seleccionarDirectorio.component.ts b/Frontend Angular 4/src/app/layout/archivos/seleccionarDirectorio.component.ts
deleted file mode 100755
index a49b1a1f..00000000
--- a/Frontend Angular 4/src/app/layout/archivos/seleccionarDirectorio.component.ts	
+++ /dev/null
@@ -1,134 +0,0 @@
-import { Component } from "@angular/core";
-import { DialogComponent, DialogService } from "ng2-bootstrap-modal";
-import { Archivo } from "../../shared/objects/archivo";
-
-export interface ConfirmModel {
-  directorio: boolean;
-  archivos: any;
-  directorioActual: any;
-  parent: any;
-  nombre: string;
-}
-@Component({
-  selector: "confirm",
-  template: `<div class="modal-dialog" style="margin-top:100px;">
-    <div class="modal-content">
-      <div class="modal-header">
-        <h6 class="modal-title pull-lefth">
-          {{ "i18n.msg.file.move" | translate }}
-        </h6>
-        <button
-          type="button"
-          class="close"
-          (click)="close()"
-          style="margin-rigth:8px;"
-        >
-          &times;
-        </button>
-      </div>
-      <div class="modal-body" style="height:350px;overflow-y: scroll;">
-        <div>
-          <div class="list-group">
-            <button
-              *ngFor="
-                let arch of directorioActual.archivos.filter(esDirectorio)
-              "
-              type="button"
-              (click)="navToDir(arch)"
-              style="cursor:pointer"
-              class="list-group-item list-group-item-action"
-            >
-              <i
-                *ngIf="arch.directorio"
-                class="fa fa-folder"
-                style="margin-right:10px; font-size: 3em; cursor: pointer;"
-                aria-hidden="true"
-              ></i>
-              <i
-                *ngIf="!arch.directorio"
-                class="fa fa-file-text"
-                style="margin-right:10px;font-size: 3em; cursor: pointer;"
-                aria-hidden="true"
-              ></i>
-              {{ arch.nombre }}
-            </button>
-          </div>
-        </div>
-      </div>
-      <div class="modal-footer">
-        <button
-          [disabled]="this.directorioActual.padreId == -1"
-          type="button"
-          class="btn btn-default"
-          (click)="navBack()"
-        >
-          {{ "i18n.action.goBack" | translate | titleCase }}
-        </button>
-        <button type="button" class="btn btn-primary" (click)="move()">
-          {{ "i18n.action.move" | translate | titleCase }}
-          {{ "i18n.object.here" | translate }}
-        </button>
-      </div>
-    </div>
-  </div>`,
-})
-export class SeleccionarDirectorioMove
-  extends DialogComponent<ConfirmModel, boolean>
-  implements ConfirmModel
-{
-  directorio: boolean;
-  archivos: any;
-  directorioActual: any;
-  parent: any;
-  nombre: string;
-
-  constructor(dialogService: DialogService) {
-    super(dialogService);
-  }
-
-  esDirectorio(archivo) {
-    return archivo.directorio;
-  }
-
-  move() {
-    // we set dialog result as true on click on confirm button,
-    // then we can get dialog result from caller code
-    var that = this;
-    if (this.nombre !== undefined && this.nombre !== "") {
-      this.parent.archivoSeleccionado.padreId = this.directorioActual.id;
-      if (this.parent.archivoSeleccionado.directorio) {
-        delete this.parent.archivoSeleccionado["archivos"];
-      }
-      this.parent.haskellService
-        .editarArchivo(
-          this.parent.archivoSeleccionado.id,
-          this.parent.archivoSeleccionado
-        )
-        .subscribe(
-          (archivo) => {
-            that.parent.recargarArchivos(this.directorioActual.id);
-            that.parent.archivoSeleccionado = null;
-          },
-          (error) => {
-            this.parent.notifService.error(error.text());
-          }
-        );
-    }
-    this.close();
-  }
-
-  navToDir(arch) {
-    if (arch.directorio) {
-      this.directorioActual = arch;
-    }
-  }
-
-  navBack() {
-    var idPadre = this.directorioActual.padreId;
-    var archivosList = this.parent.sessionService.getArchivosList();
-    var nuevoDirectorioActual = archivosList.filter(function (a) {
-      return a.id === idPadre;
-    })[0];
-    this.directorioActual = nuevoDirectorioActual;
-  }
-}
diff --git a/Frontend Angular 4/src/app/layout/archivos/verCalificacion.component.ts b/Frontend Angular 4/src/app/layout/archivos/verCalificacion.component.ts
deleted file mode 100755
index 844cc7e5..00000000
--- a/Frontend Angular 4/src/app/layout/archivos/verCalificacion.component.ts	
+++ /dev/null
@@ -1,59 +0,0 @@
-import { Component } from "@angular/core";
-import { DialogComponent, DialogService } from "ng2-bootstrap-modal";
-import { Archivo, Evaluacion } from "../../shared/objects/archivo";
-
-export interface ConfirmModel {
-  archivo: Archivo;
-}
-@Component({
-  selector: "confirm",
-  template: `<div class="modal-dialog" style="margin-top:100px;">
-    <div class="modal-content">
-      <div class="modal-header">
-        <h6 class="modal-title pull-lefth">
-          {{ "i18n.object.qualification" | translate | titleCase }} &quot;{{
-            archivo.nombre
-          }}&quot;:
-        </h6>
-        <button
-          type="button"
-          class="close"
-          (click)="close()"
-          style="margin-rigth:8px;"
-        >
-          &times;
-        </button>
-      </div>
-      <div class="modal-body">
-        <div>
-          <label
-            ><b>{{ "i18n.object.date" | translate | titleCase }}: </b></label
-          >&nbsp; {{ archivo.evaluacion.fecha | date }}<br />
-          <label
-            ><b
-              >{{ "i18n.object.score" | translate | titleCase }} (0-100):
-            </b></label
-          >&nbsp; {{ archivo.evaluacion.nota }}<br />
-          <label
-            ><b>{{ "i18n.object.detail" | translate | titleCase }}: </b></label
-          >&nbsp; {{ archivo.evaluacion.descripcion }}
-        </div>
-      </div>
-      <div class="modal-footer">
-        <button type="button" class="btn btn-primary" (click)="close()">
-          {{ "i18n.action.close" | translate | titleCase }}
-        </button>
-      </div>
-    </div>
-  </div>`,
-})
-export class VerCalificacionComponent
-  extends DialogComponent<ConfirmModel, boolean>
-  implements ConfirmModel
-{
-  archivo: Archivo;
-
-  constructor(dialogService: DialogService) {
-    super(dialogService);
-  }
-}
diff --git a/Frontend Angular 4/src/app/layout/grupos/calificarEntrega.component.ts b/Frontend Angular 4/src/app/layout/grupos/calificarEntrega.component.ts
deleted file mode 100755
index 924070d2..00000000
--- a/Frontend Angular 4/src/app/layout/grupos/calificarEntrega.component.ts	
+++ /dev/null
@@ -1,150 +0,0 @@
-import { Component } from "@angular/core";
-import { DialogComponent, DialogService } from "ng2-bootstrap-modal";
-import { Archivo, Evaluacion } from "../../shared/objects/archivo";
-import { TranslateService } from "@ngx-translate/core";
-
-export interface ConfirmModel {
-  cedula: string;
-  archivo: Archivo;
-  parentContext: any;
-}
-@Component({
-  selector: "confirm",
-  template: `<div class="modal-dialog" style="margin-top:100px;">
-    <div class="modal-content">
-      <div class="modal-header">
-        <h5 class="modal-title">{{ "i18n.msg.file.qualify" | translate }}</h5>
-        <button
-          type="button"
-          class="close"
-          (click)="close()"
-          style="margin-left:8px;"
-        >
-          &times;
-        </button>
-      </div>
-
-      <div class="modal-body">
-        <form>
-          <div class="form-group">
-            <label for="message-text" class="form-control-label"
-              >{{ "i18n.object.score" | translate | titleCase }} (0-100):</label
-            >
-            <input
-              type="number"
-              class="form-control"
-              [(ngModel)]="nota"
-              min="1"
-              max="100"
-              [ngModelOptions]="{ standalone: true }"
-            />
-          </div>
-          <div class="form-group">
-            <label for="message-text" class="form-control-label"
-              >{{ "i18n.object.detail" | translate | titleCase }}:</label
-            >
-            <textarea
-              class="form-control"
-              id="message-text"
-              [(ngModel)]="descripcion"
-              [ngModelOptions]="{ standalone: true }"
-            ></textarea>
-          </div>
-          <div class="form-group">
-            <label for="message-text" class="form-control-label"
-              >{{ "i18n.object.state" | translate | titleCase }}:</label
-            >
-            <select
-              name="estado"
-              id="estado"
-              class="form-control"
-              [(ngModel)]="estado"
-            >
-              <option *ngFor="let st of estados" [value]="st.value">
-                {{ st.label }}
-              </option>
-            </select>
-          </div>
-        </form>
-      </div>
-
-      <div class="modal-footer">
-        <button type="button" class="btn btn-secondary" (click)="cancel()">
-          {{ "i18n.action.cancel" | translate | titleCase }}
-        </button>
-        <button type="button" class="btn btn-success" (click)="confirm()">
-          {{ "i18n.action.qualify" | translate | titleCase }}
-        </button>
-      </div>
-    </div>
-  </div>`,
-})
-export class CalificarEntrega
-  extends DialogComponent<ConfirmModel, boolean>
-  implements ConfirmModel
-{
-  descripcion: string = "";
-  cedula: string;
-  archivo: Archivo;
-  nota: number = 0;
-  estado: string = "Corregido";
-  estados: any;
-  translateService: any;
-  parentContext: any;
-
-  constructor(
-    dialogService: DialogService,
-    public translate: TranslateService
-  ) {
-    super(dialogService);
-    this.translateService = translate;
-    this.estados = [
-      {
-        value: "Corregido",
-        label: this.translateService.get("i18n.msg.file.evaluated").value,
-      },
-      {
-        value: "Devuelto",
-        label: this.translateService.get("i18n.msg.file.returned").value,
-      },
-    ];
-  }
-
-  ngOnInit() {
-    if (this.archivo.evaluacion) {
-      this.descripcion = this.archivo.evaluacion.descripcion;
-      this.nota = this.archivo.evaluacion.nota;
-    }
-  }
-
-  confirm() {
-    var evaluacion = new Evaluacion();
-    evaluacion.cedulaDocente = this.cedula;
-    evaluacion.descripcion = this.descripcion;
-    evaluacion.nota = this.nota;
-    if (this.nota >= 0 && this.nota <= 100) {
-      this.parentContext.haskellService
-        .calificarArchivo(this.archivo.id, this.estado, evaluacion)
-        .subscribe(
-          (evaluacion) => {
-            this.parentContext.notifService.success(
-              this.translateService.get("i18n.msg.file.evaluated").value
-            );
-            this.archivo.evaluacion = evaluacion;
-            this.close();
-          },
-          (error) => {
-            this.parentContext.notifService.error(error);
-          }
-        );
-    } else {
-      this.parentContext.notifService.error(
-        this.translateService.get("i18n.warning.file.qualifyOutRange").value
-      );
-    }
-  }
-
-  cancel() {
-    this.close();
-  }
-}
diff --git a/Frontend Angular 4/src/app/layout/grupos/grupos.component.html b/Frontend Angular 4/src/app/layout/grupos/grupos.component.html
index 50d865f7..b12cc21b 100755
--- a/Frontend Angular 4/src/app/layout/grupos/grupos.component.html	
+++ b/Frontend Angular 4/src/app/layout/grupos/grupos.component.html	
@@ -30,15 +30,10 @@
             <div
               *ngFor="let grupo of grupos"
               (click)="seleccionarGrupo(grupo)"
-              class="col-sm-3 col-4"
-              style="text-align: center"
+              class="col-sm-3 col-4 matefun-group-wrapper"
             >
-              <i
-                class="fa fa-users"
-                style="font-size: 3em; cursor: pointer; color: #f95e5e"
-                aria-hidden="true"
-              ></i>
-              <p style="cursor: pointer">
+              <i class="fa fa-users matefun-fa-user" aria-hidden="true"></i>
+              <p>
                 {{ grupo.grado + "°" + grupo.grupo + " - " + grupo.anio }}
               </p>
             </div>
@@ -83,15 +78,13 @@
                   <div
                     *ngFor="let alumno of grupoSeleccionado.alumnos"
                     (click)="seleccionarAlumno(alumno)"
-                    class="col-sm-3"
-                    style="text-align: center"
+                    class="col-sm-3 matefun-group-wrapper"
                   >
                     <i
-                      class="fa fa-user"
-                      style="font-size: 3em; cursor: pointer; color: #f95e5e"
+                      class="fa fa-user matefun-fa-user"
                       aria-hidden="true"
                     ></i>
-                    <p style="cursor: pointer">
+                    <p>
                       {{ alumno.apellido + ", " + alumno.nombre }}
                     </p>
                   </div>
@@ -137,15 +130,13 @@
                   <div
                     *ngFor="let archivo of grupoSeleccionado.archivos"
                     (click)="seleccionarArchivo(archivo)"
-                    class="col-sm-3 col-4"
-                    style="text-align: center"
+                    class="col-sm-3 col-4 matefun-group-wrapper"
                   >
                     <i
-                      class="fa fa-file-text"
-                      style="font-size: 3em; cursor: pointer; color: #ff8383"
+                      class="fa fa-file-text matefun-fa-file"
                       aria-hidden="true"
                     ></i>
-                    <p style="cursor: pointer">{{ archivo.nombre }}</p>
+                    <p>{{ archivo.nombre }}</p>
                   </div>
                 </div>
               </div>
@@ -164,16 +155,14 @@
             <div
               *ngFor="let entrega of alumnoSeleccionado.archivos"
               (click)="seleccionarEntrega(entrega)"
-              class="col-sm-3 col-4"
-              style="text-align: center"
+              class="col-sm-3 col-4 matefun-file-wrapper"
             >
               <i
-                [ngStyle]=""
                 class="fa fa-file-text"
-                style="font-size: 3em; cursor: pointer"
+                style="font-size: 3em"
                 aria-hidden="true"
               ></i>
-              <p style="cursor: pointer">{{ entrega.nombre }}</p>
+              <p>{{ entrega.nombre }}</p>
             </div>
             <div
               *ngIf="alumnoSeleccionado.archivos.length == 0"
@@ -227,7 +216,7 @@
           <button
             *ngIf="tipoArchivo == 'entrega'"
             class="btn btn-sm btn-secondary pull-left mr-2"
-            (click)="calificarEntrega()"
+            (click)="mostrarModalCalificarEntrega()"
           >
             Calificar
           </button>
@@ -246,14 +235,32 @@
             {{ archivoSeleccionado?.fechaCreacion | date }}
           </div>
         </div>
-        <codemirror
+        <lt-codemirror
           class="codemirrorGrupos"
           [(ngModel)]="archivoSeleccionado.contenido"
           [config]="configCodeMirror"
           [ngStyle]="{ 'font-size': configCodeMirror.fontSize + 'px' }"
         >
-        </codemirror>
+        </lt-codemirror>
       </div>
     </div>
   </div>
 </div>
+
+<matefun-modal-calificar-entrega
+  cancelLabel="{{ 'i18n.action.cancel' | translate | titleCase }}"
+  confirmLabel="{{ 'i18n.action.qualify' | translate | titleCase }}"
+  [detail]="archivoSeleccionado.evaluacion?.descripcion"
+  detailLabel="{{ 'i18n.object.detail' | translate | titleCase }}:"
+  header="{{ 'i18n.msg.file.qualify' | translate }}"
+  [opened]="modalQualifyDeliveryOpened"
+  [posibleStatuses]="posibleStatusesQualifyDelivery"
+  [score]="archivoSeleccionado.evaluacion?.nota"
+  scoreLabel="{{ 'i18n.object.score' | translate | titleCase }} (0-100):"
+  statusLabel="{{ 'i18n.object.state' | translate | titleCase }}:"
+  (cancelAction)="modalQualifyDeliveryOpened = false"
+  (close)="modalQualifyDelivery = false"
+  (confirmFileQualify)="confirmFileQualify($event)"
+  *ngIf="modalQualifyDelivery"
+>
+</matefun-modal-calificar-entrega>
diff --git a/Frontend Angular 4/src/app/layout/grupos/grupos.component.ts b/Frontend Angular 4/src/app/layout/grupos/grupos.component.ts
index cec5374c..36adbec4 100755
--- a/Frontend Angular 4/src/app/layout/grupos/grupos.component.ts	
+++ b/Frontend Angular 4/src/app/layout/grupos/grupos.component.ts	
@@ -1,14 +1,12 @@
 import { Component } from "@angular/core";
 import { Router } from "@angular/router";
 
-import { Archivo } from "../../shared/objects/archivo";
+import { Archivo, Evaluacion } from "../../shared/objects/archivo";
 import { Grupo } from "../../shared/objects/grupo";
 import { Usuario } from "../../shared/objects/usuario";
 import { AuthenticationService } from "../../shared/services/authentication.service";
 import { HaskellService } from "../../shared/services/haskell.service";
 import { SessionService } from "../../shared/services/session.service";
-import { DialogService } from "ng2-bootstrap-modal";
-import { CalificarEntrega } from "./calificarEntrega.component";
 import { NgbPopoverConfig, NgbPopover } from "@ng-bootstrap/ng-bootstrap";
 import { NotificacionService } from "../../shared/services/notificacion.service";
 import { TranslateService } from "@ngx-translate/core";
@@ -36,19 +34,54 @@ export class GruposComponent {
   configCodeMirror = JSON.parse(sessionStorage.getItem("codeMirrorConfig"));
   translateService: any;
 
+  // - - - - - - - - - - - -  Modal show confirm  - - - - - - - - - - - -
+  /**
+   * Con `true` se renderiza el modal de calificar entrega.
+   */
+  modalQualifyDelivery = false;
+
+  /**
+   * Con `true` se indica que el modal -de calificar entrega- se quiere abrir.
+   * Útil para avisar al modal que anime el dismiss antes de que se elimine del
+   * DOM.
+   */
+  modalQualifyDeliveryOpened = true;
+
+  /**
+   * Determina los estados posibles para calificar un archivo
+   */
+  posibleStatusesQualifyDelivery = [
+    {
+      value: "Corregido",
+      label: "",
+    },
+    {
+      value: "Devuelto",
+      label: "",
+    },
+  ];
+
   constructor(
     private router: Router,
     private authService: AuthenticationService,
     private haskellService: HaskellService,
     private notifService: NotificacionService,
     private sessionService: SessionService,
-    private dialogService: DialogService,
     public translate: TranslateService
   ) {
     this.translateService = translate;
     this.directorioActual = {};
     this.directorioActual.archivos = [];
     this.configCodeMirror.readOnly = true;
+
+    // Se obtienen las traducciones de los estados posibles de calificación
+    this.translateService.get("i18n.msg.file.evaluated").subscribe((res) => {
+      this.posibleStatusesQualifyDelivery[0].label = res;
+    });
+
+    this.translateService.get("i18n.msg.file.returned").subscribe((res) => {
+      this.posibleStatusesQualifyDelivery[1].label = res;
+    });
   }
 
   ngOnInit() {
@@ -145,19 +178,49 @@ export class GruposComponent {
     this.tipoArchivo = "entrega";
   }
 
-  calificarEntrega() {
-    let disposable = this.dialogService
-      .addDialog(CalificarEntrega, {
-        cedula: JSON.parse(sessionStorage.currentUser).cedula + "",
-        archivo: this.archivoSeleccionado,
-        parentContext: this,
-      })
-      .subscribe((isConfirmed) => {
-        if (isConfirmed) {
-          //codeMirrorRef.options.readOnly = false;
-          //componentRef.editDialogFired = true;
+  mostrarModalCalificarEntrega() {
+    // Mostrar el modal
+    this.modalQualifyDelivery = true;
+    this.modalQualifyDeliveryOpened = true;
+  }
+
+  confirmFileQualify(event: CustomEvent<any>) {
+    const { descripcion, estado, nota } = event.detail;
+
+    // Si la nota está fuera de rango, se devuelve un error
+    if (!(nota >= 0 && nota <= 100)) {
+      this.translateService
+        .get("i18n.warning.file.qualifyOutRange")
+        .subscribe((res) => this.notifService.error(res));
+      return;
+    }
+
+    const cedula = JSON.parse(sessionStorage.currentUser).cedula + "";
+
+    const evaluacion = new Evaluacion();
+    evaluacion.cedulaDocente = cedula;
+    evaluacion.descripcion = descripcion;
+    evaluacion.nota = nota;
+
+    this.haskellService
+      .calificarArchivo(this.archivoSeleccionado.id, estado, evaluacion)
+      .subscribe(
+        (evaluacion) => {
+          this.translateService
+            .get("i18n.msg.file.evaluated")
+            .subscribe((res) => this.notifService.success(res));
+          this.archivoSeleccionado.evaluacion = evaluacion;
+
+          // Cerrar el modal en caso de éxito
+          this.modalQualifyDeliveryOpened = false;
+        },
+        (error) => {
+          this.notifService.error(error);
+
+          // Cerrar el modal en caso de falla
+          this.modalQualifyDeliveryOpened = false;
         }
-      });
+      );
   }
 
   esArchivoGrupo() {
diff --git a/Frontend Angular 4/src/app/layout/grupos/grupos.module.ts b/Frontend Angular 4/src/app/layout/grupos/grupos.module.ts
index a06751a5..5816436c 100755
--- a/Frontend Angular 4/src/app/layout/grupos/grupos.module.ts	
+++ b/Frontend Angular 4/src/app/layout/grupos/grupos.module.ts	
@@ -1,14 +1,10 @@
-import { NgModule } from "@angular/core";
+import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from "@angular/core";
 import { FormsModule } from "@angular/forms";
 import { GruposComponent } from "./grupos.component";
 import { CommonModule } from "@angular/common";
 import { GruposRoutingModule } from "./grupos-routing.module";
-import { DialogService } from "ng2-bootstrap-modal";
-import { NotificacionService } from "../../shared/services/notificacion.service";
-import { BootstrapModalModule } from "ng2-bootstrap-modal";
 import { NgbModule } from "@ng-bootstrap/ng-bootstrap";
-import { CodemirrorModule } from "ng2-codemirror";
-import { CalificarEntrega } from "./calificarEntrega.component";
+import { LtCodemirrorModule } from "lt-codemirror";
 import { NotificacionModule } from "../../notificacion/notificacion.module";
 import { I18nModule } from "../../shared/modules/translate/i18n.module";
 import { TitleCaseModule } from "../../shared/modules/titlecase.module";
@@ -18,15 +14,14 @@ import { TitleCaseModule } from "../../shared/modules/titlecase.module";
     CommonModule,
     GruposRoutingModule,
     FormsModule,
-    BootstrapModalModule,
     NgbModule,
-    CodemirrorModule,
+    LtCodemirrorModule,
     NotificacionModule,
     I18nModule,
     TitleCaseModule,
   ],
-  declarations: [GruposComponent, CalificarEntrega],
+  declarations: [GruposComponent],
   exports: [GruposComponent],
-  entryComponents: [CalificarEntrega],
+  schemas: [CUSTOM_ELEMENTS_SCHEMA],
 })
 export class GruposModule {}
diff --git a/Frontend Angular 4/src/app/layout/layout.module.ts b/Frontend Angular 4/src/app/layout/layout.module.ts
index e787ba3e..f331ffe0 100755
--- a/Frontend Angular 4/src/app/layout/layout.module.ts	
+++ b/Frontend Angular 4/src/app/layout/layout.module.ts	
@@ -8,7 +8,7 @@ import { LayoutComponent } from "./layout.component";
 import { HeaderComponent, SidebarComponent } from "../shared";
 import { AuthenticationService } from "../shared/services/authentication.service";
 import { HaskellService } from "../shared/services/haskell.service";
-import { CodemirrorModule } from "ng2-codemirror";
+import { LtCodemirrorModule } from "lt-codemirror";
 import { NotificacionModule } from "../notificacion/notificacion.module";
 import { I18nModule } from "../shared/modules/translate/i18n.module";
 import { TitleCaseModule } from "../shared/modules/titlecase.module";
@@ -20,7 +20,7 @@ import { TitleCaseModule } from "../shared/modules/titlecase.module";
     // NgbModule.forRoot(),
     NgbModule,
     LayoutRoutingModule,
-    CodemirrorModule,
+    LtCodemirrorModule,
     NotificacionModule,
     I18nModule,
     TitleCaseModule,
diff --git a/Frontend Angular 4/src/app/layout/matefun/confirm.component.ts b/Frontend Angular 4/src/app/layout/matefun/confirm.component.ts
deleted file mode 100755
index 2f893f43..00000000
--- a/Frontend Angular 4/src/app/layout/matefun/confirm.component.ts	
+++ /dev/null
@@ -1,44 +0,0 @@
-import { Component } from "@angular/core";
-import { DialogComponent, DialogService } from "ng2-bootstrap-modal";
-export interface ConfirmModel {
-  title: string;
-  message: string;
-}
-@Component({
-  selector: "confirm",
-  template: `<div class="modal-dialog" style="margin-top:100px;">
-    <div class="modal-content">
-      <div class="modal-header">
-        <button type="button" class="close" (click)="close()">&times;</button>
-        <!-- <h4 class="modal-title">{{title || 'Confirm'}}</h4> -->
-      </div>
-      <div class="modal-body">
-        <p>{{ message || "" }}</p>
-      </div>
-      <div class="modal-footer">
-        <button type="button" class="btn btn-primary" (click)="confirm()">
-          {{ "i18n.action.edit" | translate }}
-        </button>
-        <button type="button" class="btn btn-default" (click)="close()">
-          {{ "i18n.action.cancel" | translate }}
-        </button>
-      </div>
-    </div>
-  </div>`,
-})
-export class ConfirmComponent
-  extends DialogComponent<ConfirmModel, boolean>
-  implements ConfirmModel
-{
-  title: string;
-  message: string;
-  constructor(dialogService: DialogService) {
-    super(dialogService);
-  }
-  confirm() {
-    // we set dialog result as true on click on confirm button,
-    // then we can get dialog result from caller code
-    this.result = true;
-    this.close();
-  }
-}
diff --git a/Frontend Angular 4/src/app/layout/matefun/matefun.component.html b/Frontend Angular 4/src/app/layout/matefun/matefun.component.html
index 07e9ba70..30b5ed3f 100755
--- a/Frontend Angular 4/src/app/layout/matefun/matefun.component.html	
+++ b/Frontend Angular 4/src/app/layout/matefun/matefun.component.html	
@@ -318,7 +318,7 @@
                   </ng-template>
                 </form>
               </div>
-              <codemirror
+              <lt-codemirror
                 class="codemirrorPrograma"
                 [(ngModel)]="archivo.contenido"
                 (keyup)="archivoModificado($event)"
@@ -326,7 +326,7 @@
                 [config]="configCodeMirror"
                 [ngStyle]="{ 'font-size': configCodeMirror.fontSize + 'px' }"
               >
-              </codemirror>
+              </lt-codemirror>
             </div>
           </ng-template>
         </ngb-tab>
@@ -345,6 +345,7 @@
             ></graph2D-component>
           </ng-template>
         </ngb-tab>
+
         <ngb-tab
           id="FigurasBtn3D"
           title="{{ 'i18n.object.figures' | translate | titleCase }} 3D"
@@ -409,7 +410,7 @@
             </button>
           </form>
         </div>
-        <codemirror
+        <lt-codemirror
           class="codemirrorPrograma"
           [(ngModel)]="archivoDefinicion.contenido"
           [config]="configCodeMirrorDefinicion"
@@ -417,9 +418,56 @@
             'font-size': configCodeMirrorDefinicion.fontSize + 'px'
           }"
         >
-        </codemirror>
+        </lt-codemirror>
       </div>
     </div>
   </div>
   <span class="version">v{{ version }}</span>
 </div>
+
+<matefun-modal-seleccionar-directorio
+  confirmLabel="{{ 'i18n.action.create' | translate | titleCase }}"
+  [currentDirectory]="archivosTree"
+  fileNameLabel="{{ 'i18n.object.name' | translate | titleCase }}:"
+  header="{{ 'i18n.msg.file.create' | translate }}"
+  [import]="importCreateFile"
+  importLabel="{{ 'i18n.object.file' | translate | titleCase }}:"
+  navigateBackLabel="{{ 'i18n.action.goBack' | translate | titleCase }}"
+  [opened]="modalCreateFileOpened"
+  (close)="modalCreateFile = false"
+  (confirmFileCreation)="confirmFileCreation($event)"
+  (navBack)="navigateBack($event)"
+  (navTo)="archivosTree = $event.detail"
+  *ngIf="modalCreateFile"
+>
+</matefun-modal-seleccionar-directorio>
+
+<matefun-modal
+  [opened]="modalShowConfirmOpened"
+  (close)="modalShowConfirm = false"
+  *ngIf="modalShowConfirm"
+>
+  <span slot="header">Está intentando editar un archivo de solo lectura</span>
+
+  <span slot="body">
+    Está editando un archivo de solo lectura, ¿desea continuar?
+  </span>
+
+  <button
+    slot="primary-action"
+    type="button"
+    class="btn btn-primary"
+    (click)="allowFileEdition()"
+  >
+    {{ "i18n.action.edit" | translate | titleCase }}
+  </button>
+
+  <button
+    slot="primary-action"
+    type="button"
+    class="btn btn-default"
+    (click)="modalShowConfirmOpened = false"
+  >
+    {{ "i18n.action.cancel" | translate | titleCase }}
+  </button>
+</matefun-modal>
diff --git a/Frontend Angular 4/src/app/layout/matefun/matefun.component.ts b/Frontend Angular 4/src/app/layout/matefun/matefun.component.ts
index 1a6073bb..36fdb1b2 100755
--- a/Frontend Angular 4/src/app/layout/matefun/matefun.component.ts	
+++ b/Frontend Angular 4/src/app/layout/matefun/matefun.component.ts	
@@ -1,38 +1,28 @@
 import {
   Component,
-  NgModule,
   ViewChild,
   HostListener,
-  ElementRef,
   ComponentRef,
-  TemplateRef,
   QueryList,
   ViewChildren,
 } from "@angular/core";
-import { CanvasModule } from "../canvas/canvas.module";
-import { CanvasComponent } from "../canvas/canvas.component";
 import { HaskellService } from "../../shared/services/haskell.service";
 import { WebsocketService } from "../../shared/services/websocket.service";
 import { UsuarioService } from "../../shared/services/usuario.service";
 import { SessionService } from "../../shared/services/session.service";
 import { GHCIService } from "../../shared/services/ghci.service";
 import { AuthenticationService } from "../../shared/services/authentication.service";
-import { GHCI_URL } from "../../shared/config";
 import { Archivo } from "../../shared/objects/archivo";
 import { Configuracion } from "../../shared/objects/usuario";
-import { ConfirmComponent } from "./confirm.component";
-import { SeleccionarDirectorioComp } from "./seleccionarDirectorio.component";
-import { DialogService } from "ng2-bootstrap-modal";
-import { CodemirrorComponent } from "ng2-codemirror";
+import { LtCodemirrorComponent } from "lt-codemirror";
 import { NgbPopoverConfig, NgbPopover } from "@ng-bootstrap/ng-bootstrap";
 import { NgbPopoverWindow } from "@ng-bootstrap/ng-bootstrap/popover/popover";
 import { NotificacionService } from "../../shared/services/notificacion.service";
-import { Graph2DModule } from "../plotter/graph2D/graph2D.module";
 import { Graph2DComponent } from "../plotter/graph2D/graph2D.component";
 import { Graph3DComponent } from "../plotter/graph3D/graph3D.component";
 import { TranslateService } from "@ngx-translate/core";
 import { TitleCasePipe } from "../../shared/pipes/titlecase.pipe";
-import { Router, NavigationExtras } from "@angular/router";
+import { Router } from "@angular/router";
 
 // import 'codemirror/mode/haskell/haskell';
 import "codemirror/addon/display/panel";
@@ -55,8 +45,6 @@ import "./codemirror/matefun-mode-EN.js";
 import "./codemirror/addons/functions_definition_EN.js";
 import "./codemirror/addons/functions_definition_ES.js";
 
-import * as npm from "./../../../../package.json";
-
 var codeMirrorRef: any;
 var componentRef: any;
 var focus: any;
@@ -167,14 +155,45 @@ export class MateFunComponent {
   ];
   version: string = "3.1.3"; //npm.version;
 
+  // - - - - - - - - - - - - - Modal create file - - - - - - - - - - - - -
+  /**
+   * Con `true` se renderiza el modal de crear un archivo en un directorio.
+   */
+  modalCreateFile = false;
+
+  /**
+   * Con `true` se indica que el modal -de crear un archivo- se quiere abrir.
+   * Útil para avisar al modal que anime el dismiss antes de que se elimine del
+   * DOM.
+   */
+  modalCreateFileOpened = true;
+
+  /**
+   * Con `true` se renderiza un input para importar el contenido del archivo a
+   * crear en el modal de crear archivo.
+   */
+  importCreateFile = false;
+
+  // - - - - - - - - - - - -  Modal show confirm  - - - - - - - - - - - -
+  /**
+   * Con `true` se renderiza el modal de preguntar para editar un archivo de
+   * solo lectura.
+   */
+  modalShowConfirm = false;
+
+  /**
+   * Con `true` se indica que el modal -de preguntar para editar un archivo de
+   * solo lectura- se quiere abrir. Útil para avisar al
+   * modal que anime el dismiss antes de que se elimine del DOM.
+   */
+  modalShowConfirmOpened = true;
+
   constructor(
     private haskellService: HaskellService,
     private authService: AuthenticationService,
     private ghciService: GHCIService,
-    private elRef: ElementRef,
     private notifService: NotificacionService,
     private sessionService: SessionService,
-    private dialogService: DialogService,
     private usuarioService: UsuarioService,
     public translate: TranslateService,
     private router: Router
@@ -206,7 +225,6 @@ export class MateFunComponent {
       this.argumentoF = config.argumentoF;
     }
     this.code = "my code";
-    let svg: string = "";
 
     for (var key in this.configCodeMirror) {
       this.configCodeMirrorDefinicion[key] = this.configCodeMirror[key];
@@ -214,7 +232,8 @@ export class MateFunComponent {
     this.configCodeMirrorDefinicion["readOnly"] = true;
   }
 
-  @ViewChildren(CodemirrorComponent) codemirror: QueryList<CodemirrorComponent>;
+  @ViewChildren(LtCodemirrorComponent)
+  codemirror: QueryList<LtCodemirrorComponent>;
   // @ViewChild(NgbPopover) popover: NgbPopover;
   @ViewChild("popover", { static: false }) popover: NgbPopover;
 
@@ -234,17 +253,17 @@ export class MateFunComponent {
   }
 
   showConfirm() {
-    let disposable = this.dialogService
-      .addDialog(ConfirmComponent, {
-        title: "Está intentando editar un archivo de solo lectura",
-        message: "Está editando un archivo de solo lectura, desea continuar?",
-      })
-      .subscribe((isConfirmed) => {
-        if (isConfirmed) {
-          codeMirrorRef.options.readOnly = false;
-          componentRef.editDialogFired = true;
-        }
-      });
+    // Mostrar el modal
+    this.modalShowConfirm = true;
+    this.modalShowConfirmOpened = true;
+  }
+
+  allowFileEdition() {
+    codeMirrorRef.options.readOnly = false;
+    componentRef.editDialogFired = true;
+
+    // Cerrar el modal
+    this.modalShowConfirmOpened = false;
   }
 
   /* Panel para la posición del cursor */
@@ -281,7 +300,7 @@ export class MateFunComponent {
 
     this.codemirror.first.instance.on("keyHandled", function (cm, name, evt) {
       if (name.code === "Digit1" && name.ctrlKey && name.shiftKey) {
-        that.seleccionarDirectorio(false);
+        that.seleccionarDirectorio();
       } else if (name.code === "Digit2" && name.ctrlKey && name.shiftKey) {
         that.saveConfig();
       }
@@ -773,26 +792,76 @@ export class MateFunComponent {
     this.consolaVisible = !this.consolaVisible;
   }
 
-  seleccionarDirectorio(toImport: boolean) {
+  seleccionarDirectorio(importFileContent = false) {
     this.archivosTree = this.sessionService.getArchivos(undefined);
 
-    var that = this;
-    let disposable = this.dialogService
-      .addDialog(SeleccionarDirectorioComp, {
-        title: "",
-        import: toImport,
-        message: "",
-        archivos: this.archivosTree,
-        directorioActual: this.archivosTree,
-        nombre: "",
-        parent: this,
-      })
-      .subscribe((isConfirmed) => {
-        if (isConfirmed) {
-          //codeMirrorRef.options.readOnly = false;
-          //componentRef.editDialogFired = true;
-        }
-      });
+    this.importCreateFile = importFileContent;
+
+    // Mostrar el modal
+    this.modalCreateFile = true;
+    this.modalCreateFileOpened = true;
+  }
+
+  confirmFileCreation(event: CustomEvent) {
+    const fileContent = event.detail.fileContent;
+    const nombre = event.detail.nombre;
+    const padreId = event.detail.padreId;
+
+    if (nombre == undefined || nombre == "") {
+      this.notifService.error(
+        this.translateService.get("i18n.warning.file.invalidName").value
+      );
+      return;
+    }
+
+    /** Expresión regular para chequear que el nombre esté empiece con mayúscula */
+    var regex = /^[A-Z]/;
+
+    if (!regex.test(nombre)) {
+      this.notifService.error(
+        this.translateService.get("i18n.warning.file.capitalLetter").value
+      );
+      return;
+    }
+
+    var archivo: Archivo = new Archivo();
+    archivo.cedulaCreador = this.authService.getUser().cedula;
+    archivo.contenido = fileContent;
+    archivo.nombre = nombre;
+    archivo.directorio = false;
+    archivo.padreId = padreId;
+    archivo.editable = true;
+
+    this.haskellService.crearArchivo(archivo).subscribe(
+      (archivo) => {
+        this.archivo = archivo;
+        //this.parent.ghciService.loadFile(archivo.id);
+        this.sessionService.setArchivo(archivo);
+
+        // Cerrar el modal en caso de exito
+        this.modalCreateFileOpened = false;
+      },
+      (error) => {
+        this.notifService.error(error.text());
+
+        // Cerrar el modal en caso de falla
+        this.modalCreateFileOpened = false;
+      }
+    );
+  }
+
+  navigateBack(event: CustomEvent<Archivo>) {
+    const { padreId } = event.detail;
+
+    // No se puede navegar al padre de root
+    if (padreId == -1) {
+      return;
+    }
+
+    const archivosList: Archivo[] = this.sessionService.getArchivosList();
+
+    // Se queda con el archivo identificado por padreId
+    this.archivosTree = archivosList.filter((file) => file.id === padreId)[0];
   }
 
   buildTreeFromList(archivos) {
diff --git a/Frontend Angular 4/src/app/layout/matefun/matefun.module.ts b/Frontend Angular 4/src/app/layout/matefun/matefun.module.ts
index bc415fcb..17c3b6d3 100755
--- a/Frontend Angular 4/src/app/layout/matefun/matefun.module.ts	
+++ b/Frontend Angular 4/src/app/layout/matefun/matefun.module.ts	
@@ -1,13 +1,10 @@
-import { NgModule } from "@angular/core";
+import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from "@angular/core";
 import { FormsModule } from "@angular/forms";
 import { CanvasModule } from "../canvas/canvas.module";
 import { MateFunComponent } from "./matefun.component";
-import { BootstrapModalModule } from "ng2-bootstrap-modal";
-import { ConfirmComponent } from "./confirm.component";
-import { SeleccionarDirectorioComp } from "./seleccionarDirectorio.component";
 import { CommonModule } from "@angular/common";
 import { MateFunRoutingModule } from "./matefun-routing.module";
-import { CodemirrorModule } from "ng2-codemirror";
+import { LtCodemirrorModule } from "lt-codemirror";
 import { NgbModule } from "@ng-bootstrap/ng-bootstrap";
 import { NotificacionModule } from "../../notificacion/notificacion.module";
 import { Graph2DModule } from "../plotter/graph2D/graph2D.module";
@@ -24,14 +21,13 @@ import { TitleCaseModule } from "../../shared/modules/titlecase.module";
     Graph3DModule,
     NotificacionModule,
     MateFunRoutingModule,
-    CodemirrorModule,
+    LtCodemirrorModule,
     NgbModule,
-    BootstrapModalModule,
     I18nModule,
     TitleCaseModule,
   ],
-  entryComponents: [ConfirmComponent, SeleccionarDirectorioComp],
-  declarations: [MateFunComponent, ConfirmComponent, SeleccionarDirectorioComp],
+  declarations: [MateFunComponent],
   exports: [MateFunComponent],
+  schemas: [CUSTOM_ELEMENTS_SCHEMA],
 })
 export class MateFunModule {}
diff --git a/Frontend Angular 4/src/app/layout/matefun/seleccionarDirectorio.component.ts b/Frontend Angular 4/src/app/layout/matefun/seleccionarDirectorio.component.ts
deleted file mode 100755
index aa00cb39..00000000
--- a/Frontend Angular 4/src/app/layout/matefun/seleccionarDirectorio.component.ts	
+++ /dev/null
@@ -1,199 +0,0 @@
-import { Component } from "@angular/core";
-import { DialogComponent, DialogService } from "ng2-bootstrap-modal";
-import { Archivo } from "../../shared/objects/archivo";
-import { TranslateService } from "@ngx-translate/core";
-
-export interface ConfirmModel {
-  title: string;
-  message: string;
-  archivos: any;
-  directorioActual: any;
-  import: boolean;
-  parent: any;
-  nombre: string;
-}
-@Component({
-  selector: "confirm",
-  template: `<div class="modal-dialog" style="margin-top:100px;">
-    <div class="modal-content">
-      <div class="modal-header">
-        <h6 class="modal-title pull-lefth">
-          {{ "i18n.msg.file.create" | translate }}
-        </h6>
-        <button
-          type="button"
-          class="close"
-          (click)="close()"
-          style="margin-rigth:8px;"
-        >
-          &times;
-        </button>
-      </div>
-      <div class="modal-body" style="height:350px;overflow-y: scroll;">
-        <div>
-          <div class="form-group">
-            <label for="file-name" class="form-control-label"
-              >{{ "i18n.object.name" | translate | titleCase }}:</label
-            >
-            <input
-              type="text"
-              class="form-control"
-              id="file-name"
-              [(ngModel)]="nombre"
-            />
-          </div>
-          <div class="list-group">
-            <button
-              *ngFor="
-                let arch of directorioActual.archivos.filter(esDirectorio)
-              "
-              type="button"
-              (click)="navToDir(arch)"
-              style="cursor:pointer"
-              class="list-group-item list-group-item-action"
-            >
-              <i
-                *ngIf="arch.directorio"
-                class="fa fa-folder"
-                style="margin-right:10px; font-size: 3em; cursor: pointer;"
-                aria-hidden="true"
-              ></i>
-              <i
-                *ngIf="!arch.directorio"
-                class="fa fa-file-text"
-                style="margin-right:10px;font-size: 3em; cursor: pointer;"
-                aria-hidden="true"
-              ></i>
-              {{ arch.nombre }}
-            </button>
-          </div>
-          <div *ngIf="import" class="form-group">
-            <br />
-            <label for="file-name" class="form-control-label"
-              >{{ "i18n.object.file" | translate | titleCase }}:</label
-            ><br />
-            <input
-              id="fileid"
-              type="file"
-              (change)="changeListener($event)"
-              #input
-            />
-          </div>
-        </div>
-      </div>
-      <div class="modal-footer">
-        <button
-          [disabled]="this.directorioActual.padreId == -1"
-          type="button"
-          class="btn btn-default"
-          (click)="navBack()"
-        >
-          {{ "i18n.action.goBack" | translate | titleCase }}
-        </button>
-        <button
-          [disabled]="this.nombre == '' || (import && filecontent == '')"
-          type="button"
-          class="btn btn-primary"
-          (click)="confirm()"
-        >
-          {{ "i18n.action.create" | translate | titleCase }}
-        </button>
-      </div>
-    </div>
-  </div>`,
-})
-export class SeleccionarDirectorioComp
-  extends DialogComponent<ConfirmModel, boolean>
-  implements ConfirmModel
-{
-  title: string;
-  message: string;
-  archivos: any;
-  directorioActual: any;
-  parent: any;
-  nombre: string;
-  translateService: any;
-  import: boolean;
-  filecontent: string = "";
-
-  constructor(
-    dialogService: DialogService,
-    public translate: TranslateService
-  ) {
-    super(dialogService);
-    this.translateService = translate;
-  }
-  esDirectorio(archivo) {
-    return archivo.directorio;
-  }
-
-  changeListener($event): void {
-    this.readThis($event.target);
-  }
-
-  readThis(inputValue: any): void {
-    var file: File = inputValue.files[0];
-    var myReader: FileReader = new FileReader();
-    var fileType = inputValue.parentElement.id;
-
-    myReader.onloadend = (e) => {
-      this.filecontent = myReader.result as string;
-    };
-
-    myReader.readAsText(file);
-  }
-
-  confirm() {
-    // we set dialog result as true on click on confirm button,
-    // then we can get dialog result from caller code
-    var regex = /^[A-Z]/;
-    if (this.nombre == undefined || this.nombre == "") {
-      this.parent.notifService.error(
-        this.translateService.get("i18n.warning.file.invalidName").value
-      );
-    } else if (!regex.test(this.nombre)) {
-      this.parent.notifService.error(
-        this.translateService.get("i18n.warning.file.capitalLetter").value
-      );
-    } else {
-      var archivo: Archivo = new Archivo();
-      archivo.cedulaCreador = this.parent.authService.getUser().cedula;
-      archivo.contenido = this.filecontent;
-      archivo.nombre = this.nombre;
-      archivo.directorio = false;
-      archivo.padreId = this.directorioActual.id;
-      archivo.editable = true;
-
-      this.parent.haskellService.crearArchivo(archivo).subscribe(
-        (archivo) => {
-          this.parent.archivo = archivo;
-          //this.parent.ghciService.loadFile(archivo.id);
-          this.parent.sessionService.setArchivo(archivo);
-        },
-        (error) => {
-          this.parent.notifService.error(error.text());
-        }
-      );
-
-      this.result = true;
-      this.close();
-    }
-  }
-
-  navToDir(arch) {
-    if (arch.directorio) {
-      this.directorioActual = arch;
-    }
-  }
-
-  navBack() {
-    if (this.directorioActual.padreId != -1) {
-      var idPadre = this.directorioActual.padreId;
-      var archivosList = this.parent.sessionService.getArchivosList();
-      var nuevoDirectorioActual = archivosList.filter(function (a) {
-        return a.id === idPadre;
-      })[0];
-      this.directorioActual = nuevoDirectorioActual;
-    }
-  }
-}
diff --git a/Frontend Angular 4/src/app/shared/modal/confirm.component.ts b/Frontend Angular 4/src/app/shared/modal/confirm.component.ts
deleted file mode 100755
index 5d8b36c4..00000000
--- a/Frontend Angular 4/src/app/shared/modal/confirm.component.ts	
+++ /dev/null
@@ -1,49 +0,0 @@
-import { Component } from "@angular/core";
-import { DialogComponent, DialogService } from "ng2-bootstrap-modal";
-export interface ConfirmModel {
-  title: string;
-  message: string;
-  confirmText: string;
-  cancelText: string;
-}
-@Component({
-  selector: "confirm",
-  template: `<div class="modal-dialog" style="margin-top:100px;">
-    <div class="modal-content">
-      <div class="modal-header">
-        <h4 class="modal-title">{{ title || "Confirm" }}</h4>
-        <button type="button" class="close" (click)="close()">&times;</button>
-      </div>
-      <div class="modal-body">
-        <p style="white-space: pre;">{{ message || "" }}</p>
-      </div>
-      <div class="modal-footer">
-        <button type="button" class="btn btn-primary" (click)="confirm()">
-          {{ confirmText || "i18n.action.confirm" | translate | titleCase }}
-        </button>
-        <button type="button" class="btn btn-default" (click)="close()">
-          {{ cancelText || "i18n.action.cancel" | translate | titleCase }}
-        </button>
-      </div>
-    </div>
-  </div>`,
-})
-export class ConfirmComponent
-  extends DialogComponent<ConfirmModel, boolean>
-  implements ConfirmModel
-{
-  title: string;
-  message: string;
-  confirmText: string;
-  cancelText: string;
-
-  constructor(dialogService: DialogService) {
-    super(dialogService);
-  }
-  confirm() {
-    // we set dialog result as true on click on confirm button,
-    // then we can get dialog result from caller code
-    this.result = true;
-    this.close();
-  }
-}
diff --git a/Frontend Angular 4/src/app/shared/objects/archivo.ts b/Frontend Angular 4/src/app/shared/objects/archivo.ts
index b47b32d6..2821c248 100755
--- a/Frontend Angular 4/src/app/shared/objects/archivo.ts	
+++ b/Frontend Angular 4/src/app/shared/objects/archivo.ts	
@@ -23,3 +23,12 @@ export class Archivo {
 
   constructor() {}
 }
+
+export class Grupo {
+  anio: number;
+  grado: number;
+  grupo: string;
+  liceoId: number;
+
+  constructor() {}
+}
diff --git a/Frontend Angular 4/src/assets/i18n/en.json b/Frontend Angular 4/src/assets/i18n/en.json
index 577c1505..56fbc955 100755
--- a/Frontend Angular 4/src/assets/i18n/en.json	
+++ b/Frontend Angular 4/src/assets/i18n/en.json	
@@ -1,152 +1,150 @@
 {
-    "i18n" : {
-        "code" : "en",
-        "action" : {
-            "login" : "login",
-            "new" : "new",
-            "load" : "load",
-            "reload" : "reload",
-            "restart" : "restart",
-            "save" : "save",
-            "export" : "export",
-	    "import" : "import",
-            "zoom" : "zoom",
-            "center" : "center",
-            "delete" : "delete",
-            "download": "download",
-            "exit" : "exit",
-            "order": "order",
-            "edit" : "edit",
-            "move" : "move",
-            "share" : "share",
-            "shared" : "shared",
-            "created": "created",
-            "send" : "send",
-            "sent" : "sent",
-            "cancel" : "cancel",
-            "create" : "create",
-            "goBack" : "go back",
-            "close" : "close",
-            "qualify" : "qualify",
-            "confirm" : "confirm"
-        },
-        "object" : {
-            "settings" : "settings",
-            "shortcuts" : "shortcuts",
-            "theme" : "theme",
-            "name" : "name",
-            "descr" : "description",
-            "user" : "user",
-            "password" : "password",
-            "guest" : "guest",
-            "program" : "program",
-            "figure" : "figure",
-            "figures" : "figures",
-            "file" : "file",
-            "files" : "files",
-            "group" : "group",
-            "groups" : "groups",
-            "interpreter" : "interpreter",
-            "axis" : "axis",
-            "axes" : "axes",
-            "grid" : "grid",
-            "tip" : "tip",
-            "normal" : "normal",
-            "quality" : "quality",
-            "folder" : "folder",
-            "here" : "here",
-            "qualification" : "qualification",
-            "date" : "date",
-            "detail" : "detail",
-            "score" : "score",
-            "state" : "state"
-        },
-        "codemirror" : {
-            "command" : {
-                "inLine" : "in line",
-                "column" : "column",
-                "inColumn" : "In column",
-                "line" : "line",
-                "outWarning" : "OUTWarning",
-                "outError" : "OUTError"
-            }
-        },
-        "msg" : {
-            "404" : {
-                "title": "Page Not Found",
-                "descrp": "Sorry, this page does not exist.",
-                "return": "Return"
-            },
-            "codemirror" : {
-                "fontSize" : "Font Size",
-                "functionWarnings": "Show warnings of use of functions",
-                "infixOperatorsWarnings" : "Show warnings of use of infix operators",
-                "cursorPosition" : "Cursor position",
-                "showHints" : "Show autocomplete hints",
-                "functionTyping" : "Show functions typing",
-                "consoleWarnings": "Program contains warnings"
-            },
-            "figure" : {
-                "multiPlot" : "Multi graph",
-                "animationSpeed" : "Animation speed"
-            },
-            "file" : {
-                "fileName" : "File name",
-                "preview" : "Select a file to preview",
-                "myFiles" : "My files",
-                "readOnly": "Read Only",
-                "viewCalification": "View Calification",
-                "modified": "Modified file",
-                "toSend" : "Do you want to send the file {{fileName}}?",
-                "toSendInfo" : "The file can't be edited after being sent.",
-                "delete" : "Are you want to delete the {{fileName}} file?",
-                "seeOriginal" : "See original",
-                "seeMine" : "See mine",
-                "share" : "Share &quot;{{fileName}}&quot; with:",
-                "shared" : "Shared file",
-                "move" : "Where do you want to move the file?",
-                "create" : "Where do you want to create the file?",
-                "qualify" : "Qualify the delivered file",
-                "evaluated" : "Evaluated file",
-                "returned" : "Evaluated file (re-send)"
-
-            },
-            "folder" : {
-                "delete" : "Are you want to delete the {{fileName}} folder?"
-            },
-            "order" : {
-                "kind" : "Kind",
-                "date" : "Date"
-            }
-        },
-        "warning" : {
-            "file" : {
-                "noSelected" : "File not selected",
-                "noPermissionDelete" : "No permissions to delete the file",
-                "noPermissionMove" : "No permissions to move the file",
-                "capitalLetter" : "File name must start with upper case.",
-                "qualifyOutRange" : "Qualification out of range",
-                "invalidName" : "Invalid file name."
-            },
-            "group" : {
-                "select" : "Select a group"
-            }
-        },
-        "shortcuts" : {
-            "runCode" : "Execute the code",
-            "newFile" : "New file",
-            "openMenu" : "Open options menu",
-            "exportFile" : "Export file",
-            "importFile" : "Import file",
-            "restartInterpreter" : "Restart interpreter",
-            "saveFile" : "Save File",
-            "autocomplete" : "Autocomplete",
-            "space" : "Space",
-            "comment" : "Comment/Uncomment",
-            "functionNavigation" : "Jump to the definition",
-    	    "focusProgram" : "Focus on Program",
-	    "focusInterpreter" : "Focus on Interpreter"
-
-        }
+  "i18n": {
+    "code": "en",
+    "action": {
+      "login": "login",
+      "new": "new",
+      "load": "load",
+      "reload": "reload",
+      "restart": "restart",
+      "save": "save",
+      "export": "export",
+      "import": "import",
+      "zoom": "zoom",
+      "center": "center",
+      "delete": "delete",
+      "download": "download",
+      "exit": "exit",
+      "order": "order",
+      "edit": "edit",
+      "move": "move",
+      "share": "share",
+      "shared": "shared",
+      "created": "created",
+      "send": "send",
+      "sent": "sent",
+      "cancel": "cancel",
+      "create": "create",
+      "goBack": "go back",
+      "close": "close",
+      "qualify": "qualify",
+      "confirm": "confirm"
+    },
+    "object": {
+      "settings": "settings",
+      "shortcuts": "shortcuts",
+      "theme": "theme",
+      "name": "name",
+      "descr": "description",
+      "user": "user",
+      "password": "password",
+      "guest": "guest",
+      "program": "program",
+      "figure": "figure",
+      "figures": "figures",
+      "file": "file",
+      "files": "files",
+      "group": "group",
+      "groups": "groups",
+      "interpreter": "interpreter",
+      "axis": "axis",
+      "axes": "axes",
+      "grid": "grid",
+      "tip": "tip",
+      "normal": "normal",
+      "quality": "quality",
+      "folder": "folder",
+      "here": "here",
+      "qualification": "qualification",
+      "date": "date",
+      "detail": "detail",
+      "score": "score",
+      "state": "state"
+    },
+    "codemirror": {
+      "command": {
+        "inLine": "in line",
+        "column": "column",
+        "inColumn": "In column",
+        "line": "line",
+        "outWarning": "OUTWarning",
+        "outError": "OUTError"
+      }
+    },
+    "msg": {
+      "404": {
+        "title": "Page Not Found",
+        "descrp": "Sorry, this page does not exist.",
+        "return": "Return"
+      },
+      "codemirror": {
+        "fontSize": "Font Size",
+        "functionWarnings": "Show warnings of use of functions",
+        "infixOperatorsWarnings": "Show warnings of use of infix operators",
+        "cursorPosition": "Cursor position",
+        "showHints": "Show autocomplete hints",
+        "functionTyping": "Show functions typing",
+        "consoleWarnings": "Program contains warnings"
+      },
+      "figure": {
+        "multiPlot": "Multi graph",
+        "animationSpeed": "Animation speed"
+      },
+      "file": {
+        "fileName": "File name",
+        "preview": "Select a file to preview",
+        "myFiles": "My files",
+        "readOnly": "Read Only",
+        "viewCalification": "View Calification",
+        "modified": "Modified file",
+        "toSend": "Do you want to send the file {{fileName}}?",
+        "toSendInfo": "The file can't be edited after being sent.",
+        "delete": "Are you want to delete the {{fileName}} file?",
+        "seeOriginal": "See original",
+        "seeMine": "See mine",
+        "share": "Share \"{{fileName}}\" with:",
+        "shared": "Shared file",
+        "move": "Where do you want to move the file?",
+        "create": "Where do you want to create the file?",
+        "qualify": "Qualify the delivered file",
+        "evaluated": "Evaluated file",
+        "returned": "Evaluated file (re-send)"
+      },
+      "folder": {
+        "delete": "Are you want to delete the {{fileName}} folder?"
+      },
+      "order": {
+        "kind": "Kind",
+        "date": "Date"
+      }
+    },
+    "warning": {
+      "file": {
+        "noSelected": "File not selected",
+        "noPermissionDelete": "No permissions to delete the file",
+        "noPermissionMove": "No permissions to move the file",
+        "capitalLetter": "File name must start with upper case.",
+        "qualifyOutRange": "Qualification out of range",
+        "invalidName": "Invalid file name."
+      },
+      "group": {
+        "select": "Select a group"
+      }
+    },
+    "shortcuts": {
+      "runCode": "Execute the code",
+      "newFile": "New file",
+      "openMenu": "Open options menu",
+      "exportFile": "Export file",
+      "importFile": "Import file",
+      "restartInterpreter": "Restart interpreter",
+      "saveFile": "Save File",
+      "autocomplete": "Autocomplete",
+      "space": "Space",
+      "comment": "Comment/Uncomment",
+      "functionNavigation": "Jump to the definition",
+      "focusProgram": "Focus on Program",
+      "focusInterpreter": "Focus on Interpreter"
     }
+  }
 }
diff --git a/Frontend Angular 4/src/assets/i18n/es.json b/Frontend Angular 4/src/assets/i18n/es.json
index 8d1fa3f5..13ab990f 100755
--- a/Frontend Angular 4/src/assets/i18n/es.json	
+++ b/Frontend Angular 4/src/assets/i18n/es.json	
@@ -1,150 +1,150 @@
 {
-    "i18n" : {
-        "code" : "es",
-        "action" : {
-            "login" : "iniciar sesión",
-            "new" : "nuevo",
-            "load" : "cargar",
-            "reload" : "recargar",
-            "restart" : "reiniciar",
-            "save" : "guardar",
-            "export" : "exportar",
-	    "import" : "importar",
-            "zoom" : "zoom",
-            "center" : "centrar",
-            "delete" : "borrar",
-            "download": "descargar",
-            "exit" : "salir",
-            "order": "ordenar",
-            "edit": "editar",
-            "move": "mover",
-            "share": "compartir",
-            "shared" : "compartidos",
-            "created": "creado",
-            "send" : "enviar",
-            "sent" : "enviado",
-            "cancel" : "cancelar",
-            "create" : "crear",
-            "goBack" : "atrás",
-            "close" : "cerrar",
-            "qualify" : "calificar",
-            "confirm" : "confirmar"
-        },
-        "object" : {
-            "settings" : "configuración",
-            "shortcuts" : "atajos",
-            "name" : "nombre",
-            "descr" : "descripción",
-            "user" : "usuario",
-            "theme" : "tema",
-            "password" : "contraseña",
-            "guest" : "invitado",
-            "program" : "programa",
-            "figure" : "figura",
-            "figures" : "figuras",
-            "file" : "archivo",
-            "files" : "archivos",
-            "group" : "grupo",
-            "groups" : "grupos",
-            "interpreter" : "intérprete",
-            "axis" : "eje",
-            "axes" : "ejes",
-            "grid" : "grilla",
-            "tip" : "tip",
-            "normal" : "normal",
-            "quality" : "calidad",
-            "folder" : "carpeta",
-            "here" : "aquí",
-            "qualification" : "calificación",
-            "date" : "fecha",
-            "detail" : "detalle",
-            "score" : "puntaje",
-            "state" : "estado"
-        },
-        "codemirror" : {
-            "command" : {
-                "inLine" : "en linea",
-                "column" : "columna",
-                "inColumn" : "En columna",
-                "line" : "linea",
-                "outWarning" : "OUTAdvertencia",
-                "outError" : "OUTError"
-            }
-        },
-        "msg" : {
-            "404" : {
-                "title": "Página no encontrada",
-                "descrp": "Lo sentimos, esta página no existe.",
-                "return": "Volver"
-            },
-            "codemirror" : {
-                "fontSize" : "Tamaño de fuente",
-                "functionWarnings": "Mostrar advertencias de uso de funciones",
-                "infixOperatorsWarnings" : "Mostrar advertencias de uso de operadores infijos",
-                "cursorPosition" : "Posición del cursor",
-                "showHints" : "Mostrar sugerencias de autocompletar",
-                "functionTyping" : "Mostrar tipado de funciones",
-                "consoleWarnings": "El programa contiene advertencias"
-            },
-            "figure" : {
-                "multiPlot" : "Multi gráfica",
-                "animationSpeed" : "Velocidad de animación"
-            },
-            "file" : {
-                "fileName" : "Nombre de archivo",
-                "preview" : "Seleccione un archivo para previsualizarlo",
-                "myFiles" : "Mis archivos",
-                "readOnly": "Sólo lectura",
-                "viewCalification": "Ver Calificación",
-                "modified": "Archivo modificado",
-                "toSend" : "¿Desea enviar el archivo {{fileName}}?",
-                "toSendInfo" : "No se podrá editar luego de enviado.",
-                "delete" : "¿Está seguro que desea eliminar el archivo {{fileName}}?",
-                "seeOriginal" : "Ver original",
-                "seeMine" : "Ver mio",
-                "share" : "Compartir &quot;{{fileName}}&quot; con:",
-                "shared" : "Archivo compartido",
-                "move" : "¿Dónde quieres mover el archivo?",
-                "create" : "¿Dónde quieres crear el archivo?",
-                "qualify" : "Calificar entrega",
-                "evaluated" : "Archivo evaluado",
-                "returned" : "Archivo evaluado (re-entrega)"
-            },
-            "folder" : {
-                "delete" : "¿Está seguro que desea eliminar la carpeta {{fileName}}?"
-            },
-            "order" : {
-                "kind" : "Tipo",
-                "date" : "Fecha"
-            }
-        },
-        "warning" : {
-            "file" : {
-                "noSelected" : "Archivo no seleccionado",
-                "noPermissionDelete" : "Sin permisos para eliminar el archivo",
-                "noPermissionMove" : "Sin permisos para mover el archivo",
-                "capitalLetter" : "Nombre de archivo debe iniciar con mayúscula.",
-                "qualifyOutRange" : "Calificación fuera de rango",
-                "invalidName" : "Nombre de archivo inválido."
-            },
-            "group" : {
-                "select" : "Seleccione un grupo"
-            }
-        },
-        "shortcuts" : {
-            "runCode" : "Ejecutar el código",
-            "newFile" : "Nuevo archivo",
-            "openMenu" : "Abrir menú de opciones",
-            "exportFile" : "Exportar archivo",
-            "importFile" : "Importar archivo",
-            "restartInterpreter" : "Reiniciar intérprete",
-            "saveFile" : "Guardar archivo",
-            "autocomplete" : "Autocompletar",
-            "space" : "Espacio",
-            "comment" : "Comentar/Descomentar",
-            "functionNavigation" : "Saltar a la definición",
-	    "focusProgram" : "Foco en Programa",
-	    "focusInterpreter" : "Foco en Interprete"
-        }
+  "i18n": {
+    "code": "es",
+    "action": {
+      "login": "iniciar sesión",
+      "new": "nuevo",
+      "load": "cargar",
+      "reload": "recargar",
+      "restart": "reiniciar",
+      "save": "guardar",
+      "export": "exportar",
+      "import": "importar",
+      "zoom": "zoom",
+      "center": "centrar",
+      "delete": "borrar",
+      "download": "descargar",
+      "exit": "salir",
+      "order": "ordenar",
+      "edit": "editar",
+      "move": "mover",
+      "share": "compartir",
+      "shared": "compartidos",
+      "created": "creado",
+      "send": "enviar",
+      "sent": "enviado",
+      "cancel": "cancelar",
+      "create": "crear",
+      "goBack": "atrás",
+      "close": "cerrar",
+      "qualify": "calificar",
+      "confirm": "confirmar"
+    },
+    "object": {
+      "settings": "configuración",
+      "shortcuts": "atajos",
+      "name": "nombre",
+      "descr": "descripción",
+      "user": "usuario",
+      "theme": "tema",
+      "password": "contraseña",
+      "guest": "invitado",
+      "program": "programa",
+      "figure": "figura",
+      "figures": "figuras",
+      "file": "archivo",
+      "files": "archivos",
+      "group": "grupo",
+      "groups": "grupos",
+      "interpreter": "intérprete",
+      "axis": "eje",
+      "axes": "ejes",
+      "grid": "grilla",
+      "tip": "tip",
+      "normal": "normal",
+      "quality": "calidad",
+      "folder": "carpeta",
+      "here": "aquí",
+      "qualification": "calificación",
+      "date": "fecha",
+      "detail": "detalle",
+      "score": "puntaje",
+      "state": "estado"
+    },
+    "codemirror": {
+      "command": {
+        "inLine": "en linea",
+        "column": "columna",
+        "inColumn": "En columna",
+        "line": "linea",
+        "outWarning": "OUTAdvertencia",
+        "outError": "OUTError"
+      }
+    },
+    "msg": {
+      "404": {
+        "title": "Página no encontrada",
+        "descrp": "Lo sentimos, esta página no existe.",
+        "return": "Volver"
+      },
+      "codemirror": {
+        "fontSize": "Tamaño de fuente",
+        "functionWarnings": "Mostrar advertencias de uso de funciones",
+        "infixOperatorsWarnings": "Mostrar advertencias de uso de operadores infijos",
+        "cursorPosition": "Posición del cursor",
+        "showHints": "Mostrar sugerencias de autocompletar",
+        "functionTyping": "Mostrar tipado de funciones",
+        "consoleWarnings": "El programa contiene advertencias"
+      },
+      "figure": {
+        "multiPlot": "Multi gráfica",
+        "animationSpeed": "Velocidad de animación"
+      },
+      "file": {
+        "fileName": "Nombre de archivo",
+        "preview": "Seleccione un archivo para previsualizarlo",
+        "myFiles": "Mis archivos",
+        "readOnly": "Sólo lectura",
+        "viewCalification": "Ver Calificación",
+        "modified": "Archivo modificado",
+        "toSend": "¿Desea enviar el archivo {{fileName}}?",
+        "toSendInfo": "No se podrá editar luego de enviado.",
+        "delete": "¿Está seguro que desea eliminar el archivo {{fileName}}?",
+        "seeOriginal": "Ver original",
+        "seeMine": "Ver mio",
+        "share": "Compartir \"{{fileName}}\" con:",
+        "shared": "Archivo compartido",
+        "move": "¿Dónde quieres mover el archivo?",
+        "create": "¿Dónde quieres crear el archivo?",
+        "qualify": "Calificar entrega",
+        "evaluated": "Archivo evaluado",
+        "returned": "Archivo evaluado (re-entrega)"
+      },
+      "folder": {
+        "delete": "¿Está seguro que desea eliminar la carpeta {{fileName}}?"
+      },
+      "order": {
+        "kind": "Tipo",
+        "date": "Fecha"
+      }
+    },
+    "warning": {
+      "file": {
+        "noSelected": "Archivo no seleccionado",
+        "noPermissionDelete": "Sin permisos para eliminar el archivo",
+        "noPermissionMove": "Sin permisos para mover el archivo",
+        "capitalLetter": "Nombre de archivo debe iniciar con mayúscula.",
+        "qualifyOutRange": "Calificación fuera de rango",
+        "invalidName": "Nombre de archivo inválido."
+      },
+      "group": {
+        "select": "Seleccione un grupo"
+      }
+    },
+    "shortcuts": {
+      "runCode": "Ejecutar el código",
+      "newFile": "Nuevo archivo",
+      "openMenu": "Abrir menú de opciones",
+      "exportFile": "Exportar archivo",
+      "importFile": "Importar archivo",
+      "restartInterpreter": "Reiniciar intérprete",
+      "saveFile": "Guardar archivo",
+      "autocomplete": "Autocompletar",
+      "space": "Espacio",
+      "comment": "Comentar/Descomentar",
+      "functionNavigation": "Saltar a la definición",
+      "focusProgram": "Foco en Programa",
+      "focusInterpreter": "Foco en Interprete"
     }
+  }
 }
diff --git a/Frontend Angular 4/src/styles/_responsive.scss b/Frontend Angular 4/src/styles/_responsive.scss
index 89aacd9b..4b615784 100755
--- a/Frontend Angular 4/src/styles/_responsive.scss	
+++ b/Frontend Angular 4/src/styles/_responsive.scss	
@@ -1,82 +1,127 @@
 // @media screen and (max-width: 992px) {
-	.push-right {
-		.sidebar {
-			left: 235px !important;
-		}
-	}
+.push-right {
+  .sidebar {
+    left: 235px !important;
+  }
+}
 // }
 
-
 .CodeMirror {
-	height: 400px !important;
+  height: 400px !important;
 }
 
 #console {
-	height: 400px !important;
+  height: 400px !important;
 }
 
-.contenedor-canvas{
-	height: 400px !important;
+.contenedor-canvas {
+  height: 400px !important;
 }
 
-.listado-archivos{
-	height: 400px !important;
+.listado-archivos {
+  height: 400px !important;
 }
 
-.previewArchivoNoSeleccionado{
-	height: 400px !important;
+.previewArchivoNoSeleccionado {
+  height: 400px !important;
 }
 
 .listado-grupos {
-	height: 400px !important;
+  height: 400px !important;
 }
 
-.previewArchivoNoSeleccionado{
-	height: 400px !important;
+.previewArchivoNoSeleccionado {
+  height: 400px !important;
 }
 
-.listadoEntregasAlumnoGrupos{
-	height: 400px !important;
+.listadoEntregasAlumnoGrupos {
+  height: 400px !important;
 }
 
 @media screen and (min-width: 992px) {
-	.codemirrorArchivo .CodeMirror {
-		height: calc(100vh - 235px) !important;	
-	}
-
-	.codemirrorPrograma .CodeMirror {
-	 	height: calc(100vh - 197px) !important;
-	}
-
-	.codemirrorGrupos .CodeMirror {
-	 	height: calc(100vh - 232px) !important;
-	}
-
-	#console {
-		height: calc(100vh - 79px) !important;
-	}
-
-	.contenedor-canvas{
-		height: calc(100vh - 121px) !important;
-	}
-
-	.listado-archivos{
-		height: calc(100vh - 265px) !important;
-	}
-
-	.previewArchivoNoSeleccionado{
-		height: calc(100vh - 275px) !important;
-	}
-
-	.previewArchivoNoSeleccionadoGrupos{
-		height: calc(100vh - 225px) !important;
-	}
-
-	.listadoEntregasAlumnoGrupos{
-		height: calc(100vh - 225px) !important;
-	}
-
-	.listado-grupos {
-		height: calc(100vh - 270px) !important;
-	}
-}
\ No newline at end of file
+  .codemirrorArchivo .CodeMirror {
+    height: calc(100vh - 235px) !important;
+  }
+
+  .codemirrorPrograma .CodeMirror {
+    height: calc(100vh - 197px) !important;
+  }
+
+  .codemirrorGrupos .CodeMirror {
+    height: calc(100vh - 232px) !important;
+  }
+
+  #console {
+    height: calc(100vh - 79px) !important;
+  }
+
+  .contenedor-canvas {
+    height: calc(100vh - 121px) !important;
+  }
+
+  .listado-archivos {
+    height: calc(100vh - 265px) !important;
+  }
+
+  .previewArchivoNoSeleccionado {
+    height: calc(100vh - 275px) !important;
+  }
+
+  .previewArchivoNoSeleccionadoGrupos {
+    height: calc(100vh - 225px) !important;
+  }
+
+  .listadoEntregasAlumnoGrupos {
+    height: calc(100vh - 225px) !important;
+  }
+
+  .listado-grupos {
+    height: calc(100vh - 270px) !important;
+  }
+}
+
+// - - - - - - - - - - - - - - - -
+//        Archivos y grupos
+// - - - - - - - - - - - - - - - -
+.listado-archivos,
+.listado-grupos,
+.listadoEntregasAlumnoGrupos {
+  align-content: flex-start;
+  text-align: center;
+}
+
+.matefun-file-wrapper,
+.matefun-group-wrapper {
+  cursor: pointer;
+  padding-top: 1rem; // El mismo margin-bottom que pone el p al final del contenedor
+  margin-bottom: 8px;
+  transition-property: background-color, opacity;
+  transition-duration: 0.2s;
+  transition-timing-function: ease-in-out;
+}
+
+.matefun-file-wrapper,
+.matefun-group-wrapper {
+  &:hover {
+    background-color: #eee;
+  }
+}
+
+.matefun-fa-folder,
+.matefun-fa-file,
+.matefun-fa-user {
+  font-size: 3em;
+}
+
+.matefun-fa-folder,
+.matefun-fa-user {
+  color: #f95e5e;
+}
+
+.matefun-fa-file {
+  color: #ff8383;
+}
+
+button {
+  cursor: pointer;
+}
-- 
GitLab