 -
 
- -
-See more screenshots
-[here](http://novnc.com/screenshots.html).
-
-
-### Browser Requirements
-
-noVNC uses many modern web technologies so a formal requirement list is
-not available. However these are the minimum versions we are currently
-aware of:
-
-* Chrome 49, Firefox 44, Safari 10, Opera 36, IE 11, Edge 12
-
-
-### Server Requirements
-
-noVNC follows the standard VNC protocol, but unlike other VNC clients it does
-require WebSockets support. Many servers include support (e.g.
-[x11vnc/libvncserver](http://libvncserver.sourceforge.net/),
-[QEMU](http://www.qemu.org/), and
-[MobileVNC](http://www.smartlab.at/mobilevnc/)), but for the others you need to
-use a WebSockets to TCP socket proxy. noVNC has a sister project
-[websockify](https://github.com/novnc/websockify) that provides a simple such
-proxy.
-
-
-### Quick Start
-
-* Use the launch script to automatically download and start websockify, which
-  includes a mini-webserver and the WebSockets proxy. The `--vnc` option is
-  used to specify the location of a running VNC server:
-
-    `./utils/launch.sh --vnc localhost:5901`
-
-* Point your browser to the cut-and-paste URL that is output by the launch
-  script. Hit the Connect button, enter a password if the VNC server has one
-  configured, and enjoy!
-
-
-### Integration and Deployment
-
-Please see our other documents for how to integrate noVNC in your own software,
-or deploying the noVNC application in production environments:
-
-* [Embedding](docs/EMBEDDING.md) - For the noVNC application
-* [Library](docs/LIBRARY.md) - For the noVNC JavaScript library
-
-
-### Authors/Contributors
-
-* Core team:
-    * [Joel Martin](https://github.com/kanaka)
-    * [Samuel Mannehed](https://github.com/samhed) (Cendio)
-    * [Peter Åstrand](https://github.com/astrand) (Cendio)
-    * [Solly Ross](https://github.com/DirectXMan12) (Red Hat / OpenStack)
-    * [Pierre Ossman](https://github.com/CendioOssman) (Cendio)
-
-* Notable contributions:
-    * UI and Icons : Pierre Ossman, Chris Gordon
-    * Original Logo : Michael Sersen
-    * tight encoding : Michael Tinglof (Mercuri.ca)
-
-* Included libraries:
-    * base64 : Martijn Pieters (Digital Creations 2), Samuel Sieb (sieb.net)
-    * DES : Dave Zimmerman (Widget Workshop), Jef Poskanzer (ACME Labs)
-    * Pako : Vitaly Puzrin (https://github.com/nodeca/pako)
-
-Do you want to be on this list? Check out our
-[contribution guide](https://github.com/novnc/noVNC/wiki/Contributing) and
-start hacking!
diff --git a/public/novnc/app/error-handler.js b/public/novnc/app/error-handler.js
deleted file mode 100644
index e5a6adbe..00000000
--- a/public/novnc/app/error-handler.js
+++ /dev/null
@@ -1,56 +0,0 @@
-// NB: this should *not* be included as a module until we have
-// native support in the browsers, so that our error handler
-// can catch script-loading errors.
-
-
-(function(){
-    "use strict";
-
-    // Fallback for all uncought errors
-    function handleError (event, err) {
-        try {
-            var msg = document.getElementById('noVNC_fallback_errormsg');
-
-            // Only show the initial error
-            if (msg.hasChildNodes()) {
-                return false;
-            }
-
-            var div = document.createElement("div");
-            div.classList.add('noVNC_message');
-            div.appendChild(document.createTextNode(event.message));
-            msg.appendChild(div);
-
-            if (event.filename) {
-                div = document.createElement("div");
-                div.className = 'noVNC_location';
-                var text = event.filename;
-                if (event.lineno !== undefined) {
-                    text += ":" + event.lineno;
-                    if (event.colno !== undefined) {
-                        text += ":" + event.colno;
-                    }
-                }
-                div.appendChild(document.createTextNode(text));
-                msg.appendChild(div);
-            }
-
-            if (err && (err.stack !== undefined)) {
-                div = document.createElement("div");
-                div.className = 'noVNC_stack';
-                div.appendChild(document.createTextNode(err.stack));
-                msg.appendChild(div);
-            }
-
-            document.getElementById('noVNC_fallback_error')
-                .classList.add("noVNC_open");
-        } catch (exc) {
-            document.write("noVNC encountered an error.");
-        }
-        // Don't return true since this would prevent the error
-        // from being printed to the browser console.
-        return false;
-    }
-    window.addEventListener('error', function (evt) { handleError(evt, evt.error); });
-    window.addEventListener('unhandledrejection', function (evt) { handleError(evt.reason, evt.reason); });
-})();
diff --git a/public/novnc/app/images/alt.svg b/public/novnc/app/images/alt.svg
deleted file mode 100644
index e5bb4612..00000000
--- a/public/novnc/app/images/alt.svg
+++ /dev/null
@@ -1,92 +0,0 @@
-
-
-
-
diff --git a/public/novnc/app/images/clipboard.svg b/public/novnc/app/images/clipboard.svg
deleted file mode 100644
index 79af2752..00000000
--- a/public/novnc/app/images/clipboard.svg
+++ /dev/null
@@ -1,106 +0,0 @@
-
-
-
-
diff --git a/public/novnc/app/images/connect.svg b/public/novnc/app/images/connect.svg
deleted file mode 100644
index 56cde414..00000000
--- a/public/novnc/app/images/connect.svg
+++ /dev/null
@@ -1,96 +0,0 @@
-
-
-
-
diff --git a/public/novnc/app/images/ctrl.svg b/public/novnc/app/images/ctrl.svg
deleted file mode 100644
index 856e9395..00000000
--- a/public/novnc/app/images/ctrl.svg
+++ /dev/null
@@ -1,96 +0,0 @@
-
-
-
-
diff --git a/public/novnc/app/images/ctrlaltdel.svg b/public/novnc/app/images/ctrlaltdel.svg
deleted file mode 100644
index d7744ea3..00000000
--- a/public/novnc/app/images/ctrlaltdel.svg
+++ /dev/null
@@ -1,100 +0,0 @@
-
-
-
-
diff --git a/public/novnc/app/images/disconnect.svg b/public/novnc/app/images/disconnect.svg
deleted file mode 100644
index 6be7d187..00000000
--- a/public/novnc/app/images/disconnect.svg
+++ /dev/null
@@ -1,94 +0,0 @@
-
-
-
-
diff --git a/public/novnc/app/images/drag.svg b/public/novnc/app/images/drag.svg
deleted file mode 100644
index 139caf94..00000000
--- a/public/novnc/app/images/drag.svg
+++ /dev/null
@@ -1,76 +0,0 @@
-
-
-
-
diff --git a/public/novnc/app/images/error.svg b/public/novnc/app/images/error.svg
deleted file mode 100644
index 8356d3f1..00000000
--- a/public/novnc/app/images/error.svg
+++ /dev/null
@@ -1,81 +0,0 @@
-
-
-
-
diff --git a/public/novnc/app/images/esc.svg b/public/novnc/app/images/esc.svg
deleted file mode 100644
index 830152b5..00000000
--- a/public/novnc/app/images/esc.svg
+++ /dev/null
@@ -1,92 +0,0 @@
-
-
-
-
diff --git a/public/novnc/app/images/expander.svg b/public/novnc/app/images/expander.svg
deleted file mode 100644
index e1635358..00000000
--- a/public/novnc/app/images/expander.svg
+++ /dev/null
@@ -1,69 +0,0 @@
-
-
-
-
diff --git a/public/novnc/app/images/fullscreen.svg b/public/novnc/app/images/fullscreen.svg
deleted file mode 100644
index 29bd05da..00000000
--- a/public/novnc/app/images/fullscreen.svg
+++ /dev/null
@@ -1,93 +0,0 @@
-
-
-
-
diff --git a/public/novnc/app/images/handle.svg b/public/novnc/app/images/handle.svg
deleted file mode 100644
index 4a7a126f..00000000
--- a/public/novnc/app/images/handle.svg
+++ /dev/null
@@ -1,82 +0,0 @@
-
-
-
-
diff --git a/public/novnc/app/images/handle_bg.svg b/public/novnc/app/images/handle_bg.svg
deleted file mode 100644
index 7579c42c..00000000
--- a/public/novnc/app/images/handle_bg.svg
+++ /dev/null
@@ -1,172 +0,0 @@
-
-
-
-
diff --git a/public/novnc/app/images/icons/Makefile b/public/novnc/app/images/icons/Makefile
deleted file mode 100644
index be564b43..00000000
--- a/public/novnc/app/images/icons/Makefile
+++ /dev/null
@@ -1,42 +0,0 @@
-ICONS := \
-	novnc-16x16.png \
-	novnc-24x24.png \
-	novnc-32x32.png \
-	novnc-48x48.png \
-	novnc-64x64.png
-
-ANDROID_LAUNCHER := \
-	novnc-48x48.png \
-	novnc-72x72.png \
-	novnc-96x96.png \
-	novnc-144x144.png \
-	novnc-192x192.png
-
-IPHONE_LAUNCHER := \
-	novnc-60x60.png \
-	novnc-120x120.png
-
-IPAD_LAUNCHER := \
-	novnc-76x76.png \
-	novnc-152x152.png
-
-ALL_ICONS := $(ICONS) $(ANDROID_LAUNCHER) $(IPHONE_LAUNCHER) $(IPAD_LAUNCHER)
-
-all: $(ALL_ICONS)
-
-novnc-16x16.png: novnc-icon-sm.svg
-	convert -density 90 \
-		-background transparent "$<" "$@"
-novnc-24x24.png: novnc-icon-sm.svg
-	convert -density 135 \
-		-background transparent "$<" "$@"
-novnc-32x32.png: novnc-icon-sm.svg
-	convert -density 180 \
-		-background transparent "$<" "$@"
-
-novnc-%.png: novnc-icon.svg
-	convert -density $$[`echo $* | cut -d x -f 1` * 90 / 48] \
-		-background transparent "$<" "$@"
-
-clean:
-	rm -f *.png
diff --git a/public/novnc/app/images/icons/novnc-120x120.png b/public/novnc/app/images/icons/novnc-120x120.png
deleted file mode 100644
index 40823efb..00000000
Binary files a/public/novnc/app/images/icons/novnc-120x120.png and /dev/null differ
diff --git a/public/novnc/app/images/icons/novnc-144x144.png b/public/novnc/app/images/icons/novnc-144x144.png
deleted file mode 100644
index eee71f11..00000000
Binary files a/public/novnc/app/images/icons/novnc-144x144.png and /dev/null differ
diff --git a/public/novnc/app/images/icons/novnc-152x152.png b/public/novnc/app/images/icons/novnc-152x152.png
deleted file mode 100644
index 0694b2de..00000000
Binary files a/public/novnc/app/images/icons/novnc-152x152.png and /dev/null differ
diff --git a/public/novnc/app/images/icons/novnc-16x16.png b/public/novnc/app/images/icons/novnc-16x16.png
deleted file mode 100644
index 42108f40..00000000
Binary files a/public/novnc/app/images/icons/novnc-16x16.png and /dev/null differ
diff --git a/public/novnc/app/images/icons/novnc-192x192.png b/public/novnc/app/images/icons/novnc-192x192.png
deleted file mode 100644
index ef9201f4..00000000
Binary files a/public/novnc/app/images/icons/novnc-192x192.png and /dev/null differ
diff --git a/public/novnc/app/images/icons/novnc-24x24.png b/public/novnc/app/images/icons/novnc-24x24.png
deleted file mode 100644
index 11061359..00000000
Binary files a/public/novnc/app/images/icons/novnc-24x24.png and /dev/null differ
diff --git a/public/novnc/app/images/icons/novnc-32x32.png b/public/novnc/app/images/icons/novnc-32x32.png
deleted file mode 100644
index ff00dc30..00000000
Binary files a/public/novnc/app/images/icons/novnc-32x32.png and /dev/null differ
diff --git a/public/novnc/app/images/icons/novnc-48x48.png b/public/novnc/app/images/icons/novnc-48x48.png
deleted file mode 100644
index f24cd6cc..00000000
Binary files a/public/novnc/app/images/icons/novnc-48x48.png and /dev/null differ
diff --git a/public/novnc/app/images/icons/novnc-60x60.png b/public/novnc/app/images/icons/novnc-60x60.png
deleted file mode 100644
index 06b0d609..00000000
Binary files a/public/novnc/app/images/icons/novnc-60x60.png and /dev/null differ
diff --git a/public/novnc/app/images/icons/novnc-64x64.png b/public/novnc/app/images/icons/novnc-64x64.png
deleted file mode 100644
index 6d0fb341..00000000
Binary files a/public/novnc/app/images/icons/novnc-64x64.png and /dev/null differ
diff --git a/public/novnc/app/images/icons/novnc-72x72.png b/public/novnc/app/images/icons/novnc-72x72.png
deleted file mode 100644
index 23163a22..00000000
Binary files a/public/novnc/app/images/icons/novnc-72x72.png and /dev/null differ
diff --git a/public/novnc/app/images/icons/novnc-76x76.png b/public/novnc/app/images/icons/novnc-76x76.png
deleted file mode 100644
index aef61c48..00000000
Binary files a/public/novnc/app/images/icons/novnc-76x76.png and /dev/null differ
diff --git a/public/novnc/app/images/icons/novnc-96x96.png b/public/novnc/app/images/icons/novnc-96x96.png
deleted file mode 100644
index 1a77c53f..00000000
Binary files a/public/novnc/app/images/icons/novnc-96x96.png and /dev/null differ
diff --git a/public/novnc/app/images/icons/novnc-icon-sm.svg b/public/novnc/app/images/icons/novnc-icon-sm.svg
deleted file mode 100644
index aa1c6f18..00000000
--- a/public/novnc/app/images/icons/novnc-icon-sm.svg
+++ /dev/null
@@ -1,163 +0,0 @@
-
-
-
-
diff --git a/public/novnc/app/images/icons/novnc-icon.svg b/public/novnc/app/images/icons/novnc-icon.svg
deleted file mode 100644
index 1efff912..00000000
--- a/public/novnc/app/images/icons/novnc-icon.svg
+++ /dev/null
@@ -1,163 +0,0 @@
-
-
-
-
diff --git a/public/novnc/app/images/info.svg b/public/novnc/app/images/info.svg
deleted file mode 100644
index 557b772f..00000000
--- a/public/novnc/app/images/info.svg
+++ /dev/null
@@ -1,81 +0,0 @@
-
-
-
-
diff --git a/public/novnc/app/images/keyboard.svg b/public/novnc/app/images/keyboard.svg
deleted file mode 100644
index 137b350a..00000000
--- a/public/novnc/app/images/keyboard.svg
+++ /dev/null
@@ -1,88 +0,0 @@
-
-
-
-
diff --git a/public/novnc/app/images/mouse_left.svg b/public/novnc/app/images/mouse_left.svg
deleted file mode 100644
index ce4cca41..00000000
--- a/public/novnc/app/images/mouse_left.svg
+++ /dev/null
@@ -1,92 +0,0 @@
-
-
-
-
diff --git a/public/novnc/app/images/mouse_middle.svg b/public/novnc/app/images/mouse_middle.svg
deleted file mode 100644
index 6603425c..00000000
--- a/public/novnc/app/images/mouse_middle.svg
+++ /dev/null
@@ -1,92 +0,0 @@
-
-
-
-
diff --git a/public/novnc/app/images/mouse_none.svg b/public/novnc/app/images/mouse_none.svg
deleted file mode 100644
index 3e0f838a..00000000
--- a/public/novnc/app/images/mouse_none.svg
+++ /dev/null
@@ -1,92 +0,0 @@
-
-
-
-
diff --git a/public/novnc/app/images/mouse_right.svg b/public/novnc/app/images/mouse_right.svg
deleted file mode 100644
index f4bad767..00000000
--- a/public/novnc/app/images/mouse_right.svg
+++ /dev/null
@@ -1,92 +0,0 @@
-
-
-
-
diff --git a/public/novnc/app/images/power.svg b/public/novnc/app/images/power.svg
deleted file mode 100644
index 4925d3e8..00000000
--- a/public/novnc/app/images/power.svg
+++ /dev/null
@@ -1,87 +0,0 @@
-
-
-
-
diff --git a/public/novnc/app/images/settings.svg b/public/novnc/app/images/settings.svg
deleted file mode 100644
index dbb2e80a..00000000
--- a/public/novnc/app/images/settings.svg
+++ /dev/null
@@ -1,76 +0,0 @@
-
-
-
-
diff --git a/public/novnc/app/images/tab.svg b/public/novnc/app/images/tab.svg
deleted file mode 100644
index 1ccb3229..00000000
--- a/public/novnc/app/images/tab.svg
+++ /dev/null
@@ -1,86 +0,0 @@
-
-
-
-
diff --git a/public/novnc/app/images/toggleextrakeys.svg b/public/novnc/app/images/toggleextrakeys.svg
deleted file mode 100644
index b578c0d4..00000000
--- a/public/novnc/app/images/toggleextrakeys.svg
+++ /dev/null
@@ -1,90 +0,0 @@
-
-
-
-
diff --git a/public/novnc/app/images/warning.svg b/public/novnc/app/images/warning.svg
deleted file mode 100644
index 7114f9b1..00000000
--- a/public/novnc/app/images/warning.svg
+++ /dev/null
@@ -1,81 +0,0 @@
-
-
-
-
diff --git a/public/novnc/app/locale/de.json b/public/novnc/app/locale/de.json
deleted file mode 100644
index 62e73360..00000000
--- a/public/novnc/app/locale/de.json
+++ /dev/null
@@ -1,69 +0,0 @@
-{
-    "Connecting...": "Verbinden...",
-    "Disconnecting...": "Verbindung trennen...",
-    "Reconnecting...": "Verbindung wiederherstellen...",
-    "Internal error": "Interner Fehler",
-    "Must set host": "Richten Sie den Server ein",
-    "Connected (encrypted) to ": "Verbunden mit (verschlüsselt) ",
-    "Connected (unencrypted) to ": "Verbunden mit (unverschlüsselt) ",
-    "Something went wrong, connection is closed": "Etwas lief schief, Verbindung wurde getrennt",
-    "Disconnected": "Verbindung zum Server getrennt",
-    "New connection has been rejected with reason: ": "Verbindung wurde aus folgendem Grund abgelehnt: ",
-    "New connection has been rejected": "Verbindung wurde abgelehnt",
-    "Password is required": "Passwort ist erforderlich",
-    "noVNC encountered an error:": "Ein Fehler ist aufgetreten:",
-    "Hide/Show the control bar": "Kontrollleiste verstecken/anzeigen",
-    "Move/Drag Viewport": "Ansichtsfenster verschieben/ziehen",
-    "viewport drag": "Ansichtsfenster ziehen",
-    "Active Mouse Button": "Aktive Maustaste",
-    "No mousebutton": "Keine Maustaste",
-    "Left mousebutton": "Linke Maustaste",
-    "Middle mousebutton": "Mittlere Maustaste",
-    "Right mousebutton": "Rechte Maustaste",
-    "Keyboard": "Tastatur",
-    "Show Keyboard": "Tastatur anzeigen",
-    "Extra keys": "Zusatztasten",
-    "Show Extra Keys": "Zusatztasten anzeigen",
-    "Ctrl": "Strg",
-    "Toggle Ctrl": "Strg umschalten",
-    "Alt": "Alt",
-    "Toggle Alt": "Alt umschalten",
-    "Send Tab": "Tab senden",
-    "Tab": "Tab",
-    "Esc": "Esc",
-    "Send Escape": "Escape senden",
-    "Ctrl+Alt+Del": "Strg+Alt+Entf",
-    "Send Ctrl-Alt-Del": "Strg+Alt+Entf senden",
-    "Shutdown/Reboot": "Herunterfahren/Neustarten",
-    "Shutdown/Reboot...": "Herunterfahren/Neustarten...",
-    "Power": "Energie",
-    "Shutdown": "Herunterfahren",
-    "Reboot": "Neustarten",
-    "Reset": "Zurücksetzen",
-    "Clipboard": "Zwischenablage",
-    "Clear": "Löschen",
-    "Fullscreen": "Vollbild",
-    "Settings": "Einstellungen",
-    "Shared Mode": "Geteilter Modus",
-    "View Only": "Nur betrachten",
-    "Clip to Window": "Auf Fenster begrenzen",
-    "Scaling Mode:": "Skalierungsmodus:",
-    "None": "Keiner",
-    "Local Scaling": "Lokales skalieren",
-    "Remote Resizing": "Serverseitiges skalieren",
-    "Advanced": "Erweitert",
-    "Repeater ID:": "Repeater ID:",
-    "WebSocket": "WebSocket",
-    "Encrypt": "Verschlüsselt",
-    "Host:": "Server:",
-    "Port:": "Port:",
-    "Path:": "Pfad:",
-    "Automatic Reconnect": "Automatisch wiederverbinden",
-    "Reconnect Delay (ms):": "Wiederverbindungsverzögerung (ms):",
-    "Logging:": "Protokollierung:",
-    "Disconnect": "Verbindung trennen",
-    "Connect": "Verbinden",
-    "Password:": "Passwort:",
-    "Cancel": "Abbrechen",
-    "Canvas not supported.": "Canvas nicht unterstützt."
-}
\ No newline at end of file
diff --git a/public/novnc/app/locale/el.json b/public/novnc/app/locale/el.json
deleted file mode 100644
index f801251c..00000000
--- a/public/novnc/app/locale/el.json
+++ /dev/null
@@ -1,69 +0,0 @@
-{
-    "Connecting...": "Συνδέεται...",
-    "Disconnecting...": "Aποσυνδέεται...",
-    "Reconnecting...": "Επανασυνδέεται...",
-    "Internal error": "Εσωτερικό σφάλμα",
-    "Must set host": "Πρέπει να οριστεί ο διακομιστής",
-    "Connected (encrypted) to ": "Συνδέθηκε (κρυπτογραφημένα) με το ",
-    "Connected (unencrypted) to ": "Συνδέθηκε (μη κρυπτογραφημένα) με το ",
-    "Something went wrong, connection is closed": "Κάτι πήγε στραβά, η σύνδεση διακόπηκε",
-    "Disconnected": "Αποσυνδέθηκε",
-    "New connection has been rejected with reason: ": "Η νέα σύνδεση απορρίφθηκε διότι: ",
-    "New connection has been rejected": "Η νέα σύνδεση απορρίφθηκε ",
-    "Password is required": "Απαιτείται ο κωδικός πρόσβασης",
-    "noVNC encountered an error:": "το noVNC αντιμετώπισε ένα σφάλμα:",
-    "Hide/Show the control bar": "Απόκρυψη/Εμφάνιση γραμμής ελέγχου",
-    "Move/Drag Viewport": "Μετακίνηση/Σύρσιμο Θεατού πεδίου",
-    "viewport drag": "σύρσιμο θεατού πεδίου",
-    "Active Mouse Button": "Ενεργό Πλήκτρο Ποντικιού",
-    "No mousebutton": "Χωρίς Πλήκτρο Ποντικιού",
-    "Left mousebutton": "Αριστερό Πλήκτρο Ποντικιού",
-    "Middle mousebutton": "Μεσαίο Πλήκτρο Ποντικιού",
-    "Right mousebutton": "Δεξί Πλήκτρο Ποντικιού",
-    "Keyboard": "Πληκτρολόγιο",
-    "Show Keyboard": "Εμφάνιση Πληκτρολογίου",
-    "Extra keys": "Επιπλέον πλήκτρα",
-    "Show Extra Keys": "Εμφάνιση Επιπλέον Πλήκτρων",
-    "Ctrl": "Ctrl",
-    "Toggle Ctrl": "Εναλλαγή Ctrl",
-    "Alt": "Alt",
-    "Toggle Alt": "Εναλλαγή Alt",
-    "Send Tab": "Αποστολή Tab",
-    "Tab": "Tab",
-    "Esc": "Esc",
-    "Send Escape": "Αποστολή Escape",
-    "Ctrl+Alt+Del": "Ctrl+Alt+Del",
-    "Send Ctrl-Alt-Del": "Αποστολή Ctrl-Alt-Del",
-    "Shutdown/Reboot": "Κλείσιμο/Επανεκκίνηση",
-    "Shutdown/Reboot...": "Κλείσιμο/Επανεκκίνηση...",
-    "Power": "Απενεργοποίηση",
-    "Shutdown": "Κλείσιμο",
-    "Reboot": "Επανεκκίνηση",
-    "Reset": "Επαναφορά",
-    "Clipboard": "Πρόχειρο",
-    "Clear": "Καθάρισμα",
-    "Fullscreen": "Πλήρης Οθόνη",
-    "Settings": "Ρυθμίσεις",
-    "Shared Mode": "Κοινόχρηστη Λειτουργία",
-    "View Only": "Μόνο Θέαση",
-    "Clip to Window": "Αποκοπή στο όριο του Παράθυρου",
-    "Scaling Mode:": "Λειτουργία Κλιμάκωσης:",
-    "None": "Καμία",
-    "Local Scaling": "Τοπική Κλιμάκωση",
-    "Remote Resizing": "Απομακρυσμένη Αλλαγή μεγέθους",
-    "Advanced": "Για προχωρημένους",
-    "Repeater ID:": "Repeater ID:",
-    "WebSocket": "WebSocket",
-    "Encrypt": "Κρυπτογράφηση",
-    "Host:": "Όνομα διακομιστή:",
-    "Port:": "Πόρτα διακομιστή:",
-    "Path:": "Διαδρομή:",
-    "Automatic Reconnect": "Αυτόματη επανασύνδεση",
-    "Reconnect Delay (ms):": "Καθυστέρηση επανασύνδεσης (ms):",
-    "Logging:": "Καταγραφή:",
-    "Disconnect": "Αποσύνδεση",
-    "Connect": "Σύνδεση",
-    "Password:": "Κωδικός Πρόσβασης:",
-    "Cancel": "Ακύρωση",
-    "Canvas not supported.": "Δεν υποστηρίζεται το στοιχείο Canvas"
-}
\ No newline at end of file
diff --git a/public/novnc/app/locale/es.json b/public/novnc/app/locale/es.json
deleted file mode 100644
index 23f23f49..00000000
--- a/public/novnc/app/locale/es.json
+++ /dev/null
@@ -1,68 +0,0 @@
-{
-    "Connecting...": "Conectando...",
-    "Connected (encrypted) to ": "Conectado (con encriptación) a",
-    "Connected (unencrypted) to ": "Conectado (sin encriptación) a",
-    "Disconnecting...": "Desconectando...",
-    "Disconnected": "Desconectado",
-    "Must set host": "Debes configurar el host",
-    "Reconnecting...": "Reconectando...",
-    "Password is required": "Contraseña es obligatoria",
-    "Disconnect timeout": "Tiempo de desconexión agotado",
-    "noVNC encountered an error:": "noVNC ha encontrado un error:",
-    "Hide/Show the control bar": "Ocultar/Mostrar la barra de control",
-    "Move/Drag Viewport": "Mover/Arrastrar la ventana",
-    "viewport drag": "Arrastrar la ventana",
-    "Active Mouse Button": "Botón activo del ratón",
-    "No mousebutton": "Ningún botón del ratón",
-    "Left mousebutton": "Botón izquierdo del ratón",
-    "Middle mousebutton": "Botón central del ratón",
-    "Right mousebutton": "Botón derecho del ratón",
-    "Keyboard": "Teclado",
-    "Show Keyboard": "Mostrar teclado",
-    "Extra keys": "Teclas adicionales",
-    "Show Extra Keys": "Mostrar Teclas Adicionales",
-    "Ctrl": "Ctrl",
-    "Toggle Ctrl": "Pulsar/Soltar Ctrl",
-    "Alt": "Alt",
-    "Toggle Alt": "Pulsar/Soltar Alt",
-    "Send Tab": "Enviar Tabulación",
-    "Tab": "Tabulación",
-    "Esc": "Esc",
-    "Send Escape": "Enviar Escape",
-    "Ctrl+Alt+Del": "Ctrl+Alt+Del",
-    "Send Ctrl-Alt-Del": "Enviar Ctrl+Alt+Del",
-    "Shutdown/Reboot": "Apagar/Reiniciar",
-    "Shutdown/Reboot...": "Apagar/Reiniciar...",
-    "Power": "Encender",
-    "Shutdown": "Apagar",
-    "Reboot": "Reiniciar",
-    "Reset": "Restablecer",
-    "Clipboard": "Portapapeles",
-    "Clear": "Vaciar",
-    "Fullscreen": "Pantalla Completa",
-    "Settings": "Configuraciones",
-    "Shared Mode": "Modo Compartido",
-    "View Only": "Solo visualización",
-    "Clip to Window": "Recortar al tamaño de la ventana",
-    "Scaling Mode:": "Modo de escalado:",
-    "None": "Ninguno",
-    "Local Scaling": "Escalado Local",
-    "Local Downscaling": "Reducción de escala local",
-    "Remote Resizing": "Cambio de tamaño remoto",
-    "Advanced": "Avanzado",
-    "Local Cursor": "Cursor Local",
-    "Repeater ID:": "ID del Repetidor",
-    "WebSocket": "WebSocket",
-    "Encrypt": "",
-    "Host:": "Host",
-    "Port:": "Puesto",
-    "Path:": "Ruta",
-    "Automatic Reconnect": "Reconexión automática",
-    "Reconnect Delay (ms):": "Retraso en la reconexión (ms)",
-    "Logging:": "Logging",
-    "Disconnect": "Desconectar",
-    "Connect": "Conectar",
-    "Password:": "Contraseña",
-    "Cancel": "Cancelar",
-    "Canvas not supported.": "Canvas no está soportado"
-}
\ No newline at end of file
diff --git a/public/novnc/app/locale/nl.json b/public/novnc/app/locale/nl.json
deleted file mode 100644
index 85313d6c..00000000
--- a/public/novnc/app/locale/nl.json
+++ /dev/null
@@ -1,68 +0,0 @@
-{
-    "Connecting...": "Verbinden...",
-    "Connected (encrypted) to ": "Verbonden (versleuteld) met ",
-    "Connected (unencrypted) to ": "Verbonden (onversleuteld) met ",
-    "Disconnecting...": "Verbinding verbreken...",
-    "Disconnected": "Verbinding verbroken",
-    "Must set host": "Host moeten worden ingesteld",
-    "Reconnecting...": "Opnieuw verbinding maken...",
-    "Password is required": "Wachtwoord is vereist",
-    "Disconnect timeout": "Timeout tijdens verbreken van verbinding",
-    "noVNC encountered an error:": "noVNC heeft een fout bemerkt:",
-    "Hide/Show the control bar": "Verberg/Toon de bedieningsbalk",
-    "Move/Drag Viewport": "Verplaats/Versleep Kijkvenster",
-    "viewport drag": "kijkvenster slepen",
-    "Active Mouse Button": "Actieve Muisknop",
-    "No mousebutton": "Geen muisknop",
-    "Left mousebutton": "Linker muisknop",
-    "Middle mousebutton": "Middelste muisknop",
-    "Right mousebutton": "Rechter muisknop",
-    "Keyboard": "Toetsenbord",
-    "Show Keyboard": "Toon Toetsenbord",
-    "Extra keys": "Extra toetsen",
-    "Show Extra Keys": "Toon Extra Toetsen",
-    "Ctrl": "Ctrl",
-    "Toggle Ctrl": "Ctrl aan/uitzetten",
-    "Alt": "Alt",
-    "Toggle Alt": "Alt aan/uitzetten",
-    "Send Tab": "Tab Sturen",
-    "Tab": "Tab",
-    "Esc": "Esc",
-    "Send Escape": "Escape Sturen",
-    "Ctrl+Alt+Del": "Ctrl-Alt-Del",
-    "Send Ctrl-Alt-Del": "Ctrl-Alt-Del Sturen",
-    "Shutdown/Reboot": "Uitschakelen/Herstarten",
-    "Shutdown/Reboot...": "Uitschakelen/Herstarten...",
-    "Power": "Systeem",
-    "Shutdown": "Uitschakelen",
-    "Reboot": "Herstarten",
-    "Reset": "Resetten",
-    "Clipboard": "Klembord",
-    "Clear": "Wissen",
-    "Fullscreen": "Volledig Scherm",
-    "Settings": "Instellingen",
-    "Shared Mode": "Gedeelde Modus",
-    "View Only": "Alleen Kijken",
-    "Clip to Window": "Randen buiten venster afsnijden",
-    "Scaling Mode:": "Schaalmodus:",
-    "None": "Geen",
-    "Local Scaling": "Lokaal Schalen",
-    "Local Downscaling": "Lokaal Neerschalen",
-    "Remote Resizing": "Op Afstand Formaat Wijzigen",
-    "Advanced": "Geavanceerd",
-    "Local Cursor": "Lokale Cursor",
-    "Repeater ID:": "Repeater ID:",
-    "WebSocket": "WebSocket",
-    "Encrypt": "Versleutelen",
-    "Host:": "Host:",
-    "Port:": "Poort:",
-    "Path:": "Pad:",
-    "Automatic Reconnect": "Automatisch Opnieuw Verbinden",
-    "Reconnect Delay (ms):": "Vertraging voor Opnieuw Verbinden (ms):",
-    "Logging:": "Logmeldingen:",
-    "Disconnect": "Verbinding verbreken",
-    "Connect": "Verbinden",
-    "Password:": "Wachtwoord:",
-    "Cancel": "Annuleren",
-    "Canvas not supported.": "Canvas wordt niet ondersteund."
-}
\ No newline at end of file
diff --git a/public/novnc/app/locale/pl.json b/public/novnc/app/locale/pl.json
deleted file mode 100644
index 006ac7a5..00000000
--- a/public/novnc/app/locale/pl.json
+++ /dev/null
@@ -1,69 +0,0 @@
-{
-    "Connecting...": "Łączenie...",
-    "Disconnecting...": "Rozłączanie...",
-    "Reconnecting...": "Łączenie...",
-    "Internal error": "Błąd wewnętrzny",
-    "Must set host": "Host i port są wymagane",
-    "Connected (encrypted) to ": "Połączenie (szyfrowane) z ",
-    "Connected (unencrypted) to ": "Połączenie (nieszyfrowane) z ",
-    "Something went wrong, connection is closed": "Coś poszło źle, połączenie zostało zamknięte",
-    "Disconnected": "Rozłączony",
-    "New connection has been rejected with reason: ": "Nowe połączenie zostało odrzucone z powodu: ",
-    "New connection has been rejected": "Nowe połączenie zostało odrzucone",
-    "Password is required": "Hasło jest wymagane",
-    "noVNC encountered an error:": "noVNC napotkało błąd:",
-    "Hide/Show the control bar": "Pokaż/Ukryj pasek ustawień",
-    "Move/Drag Viewport": "Ruszaj/Przeciągaj Viewport",
-    "viewport drag": "przeciągnij viewport",
-    "Active Mouse Button": "Aktywny Przycisk Myszy",
-    "No mousebutton": "Brak przycisku myszy",
-    "Left mousebutton": "Lewy przycisk myszy",
-    "Middle mousebutton": "Środkowy przycisk myszy",
-    "Right mousebutton": "Prawy przycisk myszy",
-    "Keyboard": "Klawiatura",
-    "Show Keyboard": "Pokaż klawiaturę",
-    "Extra keys": "Przyciski dodatkowe",
-    "Show Extra Keys": "Pokaż przyciski dodatkowe",
-    "Ctrl": "Ctrl",
-    "Toggle Ctrl": "Przełącz Ctrl",
-    "Alt": "Alt",
-    "Toggle Alt": "Przełącz Alt",
-    "Send Tab": "Wyślij Tab",
-    "Tab": "Tab",
-    "Esc": "Esc",
-    "Send Escape": "Wyślij Escape",
-    "Ctrl+Alt+Del": "Ctrl+Alt+Del",
-    "Send Ctrl-Alt-Del": "Wyślij Ctrl-Alt-Del",
-    "Shutdown/Reboot": "Wyłącz/Uruchom ponownie",
-    "Shutdown/Reboot...": "Wyłącz/Uruchom ponownie...",
-    "Power": "Włączony",
-    "Shutdown": "Wyłącz",
-    "Reboot": "Uruchom ponownie",
-    "Reset": "Resetuj",
-    "Clipboard": "Schowek",
-    "Clear": "Wyczyść",
-    "Fullscreen": "Pełny ekran",
-    "Settings": "Ustawienia",
-    "Shared Mode": "Tryb Współdzielenia",
-    "View Only": "Tylko Podgląd",
-    "Clip to Window": "Przytnij do Okna",
-    "Scaling Mode:": "Tryb Skalowania:",
-    "None": "Brak",
-    "Local Scaling": "Skalowanie lokalne",
-    "Remote Resizing": "Skalowanie zdalne",
-    "Advanced": "Zaawansowane",
-    "Repeater ID:": "ID Repeatera:",
-    "WebSocket": "WebSocket",
-    "Encrypt": "Szyfrowanie",
-    "Host:": "Host:",
-    "Port:": "Port:",
-    "Path:": "Ścieżka:",
-    "Automatic Reconnect": "Automatycznie wznawiaj połączenie",
-    "Reconnect Delay (ms):": "Opóźnienie wznawiania (ms):",
-    "Logging:": "Poziom logowania:",
-    "Disconnect": "Rozłącz",
-    "Connect": "Połącz",
-    "Password:": "Hasło:",
-    "Cancel": "Anuluj",
-    "Canvas not supported.": "Element Canvas nie jest wspierany."
-}
\ No newline at end of file
diff --git a/public/novnc/app/locale/sv.json b/public/novnc/app/locale/sv.json
deleted file mode 100644
index cfd8867c..00000000
--- a/public/novnc/app/locale/sv.json
+++ /dev/null
@@ -1,68 +0,0 @@
-{
-    "Connecting...": "Ansluter...",
-    "Connected (encrypted) to ": "Ansluten (krypterat) till ",
-    "Connected (unencrypted) to ": "Ansluten (okrypterat) till ",
-    "Disconnecting...": "Kopplar ner...",
-    "Disconnected": "Frånkopplad",
-    "Must set host": "Du måste specifiera en värd",
-    "Reconnecting...": "Återansluter...",
-    "Password is required": "Lösenord krävs",
-    "Disconnect timeout": "Det tog för lång tid att koppla ner",
-    "noVNC encountered an error:": "noVNC stötte på ett problem:",
-    "Hide/Show the control bar": "Göm/Visa kontrollbaren",
-    "Move/Drag Viewport": "Flytta/Dra Vyn",
-    "viewport drag": "dra vy",
-    "Active Mouse Button": "Aktiv musknapp",
-    "No mousebutton": "Ingen musknapp",
-    "Left mousebutton": "Vänster musknapp",
-    "Middle mousebutton": "Mitten-musknapp",
-    "Right mousebutton": "Höger musknapp",
-    "Keyboard": "Tangentbord",
-    "Show Keyboard": "Visa Tangentbord",
-    "Extra keys": "Extraknappar",
-    "Show Extra Keys": "Visa Extraknappar",
-    "Ctrl": "Ctrl",
-    "Toggle Ctrl": "Växla Ctrl",
-    "Alt": "Alt",
-    "Toggle Alt": "Växla Alt",
-    "Send Tab": "Skicka Tab",
-    "Tab": "Tab",
-    "Esc": "Esc",
-    "Send Escape": "Skicka Escape",
-    "Ctrl+Alt+Del": "Ctrl+Alt+Del",
-    "Send Ctrl-Alt-Del": "Skicka Ctrl-Alt-Del",
-    "Shutdown/Reboot": "Stäng av/Boota om",
-    "Shutdown/Reboot...": "Stäng av/Boota om...",
-    "Power": "Ström",
-    "Shutdown": "Stäng av",
-    "Reboot": "Boota om",
-    "Reset": "Återställ",
-    "Clipboard": "Urklipp",
-    "Clear": "Rensa",
-    "Fullscreen": "Fullskärm",
-    "Settings": "Inställningar",
-    "Shared Mode": "Delat Läge",
-    "View Only": "Endast Visning",
-    "Clip to Window": "Begränsa till Fönster",
-    "Scaling Mode:": "Skalningsläge:",
-    "None": "Ingen",
-    "Local Scaling": "Lokal Skalning",
-    "Local Downscaling": "Lokal Nedskalning",
-    "Remote Resizing": "Ändra Storlek",
-    "Advanced": "Avancerat",
-    "Local Cursor": "Lokal Muspekare",
-    "Repeater ID:": "Repeater-ID:",
-    "WebSocket": "WebSocket",
-    "Encrypt": "Kryptera",
-    "Host:": "Värd:",
-    "Port:": "Port:",
-    "Path:": "Sökväg:",
-    "Automatic Reconnect": "Automatisk Återanslutning",
-    "Reconnect Delay (ms):": "Fördröjning (ms):",
-    "Logging:": "Loggning:",
-    "Disconnect": "Koppla från",
-    "Connect": "Anslut",
-    "Password:": "Lösenord:",
-    "Cancel": "Avbryt",
-    "Canvas not supported.": "Canvas stöds ej"
-}
\ No newline at end of file
diff --git a/public/novnc/app/locale/tr.json b/public/novnc/app/locale/tr.json
deleted file mode 100644
index 451c1b8a..00000000
--- a/public/novnc/app/locale/tr.json
+++ /dev/null
@@ -1,69 +0,0 @@
-{
-    "Connecting...": "Bağlanıyor...",
-    "Disconnecting...": "Bağlantı kesiliyor...",
-    "Reconnecting...": "Yeniden bağlantı kuruluyor...",
-    "Internal error": "İç hata",
-    "Must set host": "Sunucuyu kur",
-    "Connected (encrypted) to ": "Bağlı (şifrelenmiş)",
-    "Connected (unencrypted) to ": "Bağlandı (şifrelenmemiş)",
-    "Something went wrong, connection is closed": "Bir şeyler ters gitti, bağlantı kesildi",
-    "Disconnected": "Bağlantı kesildi",
-    "New connection has been rejected with reason: ": "Bağlantı aşağıdaki nedenlerden dolayı reddedildi: ",
-    "New connection has been rejected": "Bağlantı reddedildi",
-    "Password is required": "Şifre gerekli",
-    "noVNC encountered an error:": "Bir hata oluştu:",
-    "Hide/Show the control bar": "Denetim masasını Gizle/Göster",
-    "Move/Drag Viewport": "Görünümü Taşı/Sürükle",
-    "viewport drag": "Görüntü penceresini sürükle",
-    "Active Mouse Button": "Aktif Fare Düğmesi",
-    "No mousebutton": "Fare düğmesi yok",
-    "Left mousebutton": "Farenin sol düğmesi",
-    "Middle mousebutton": "Farenin orta düğmesi",
-    "Right mousebutton": "Farenin sağ düğmesi",
-    "Keyboard": "Klavye",
-    "Show Keyboard": "Klavye Düzenini Göster",
-    "Extra keys": "Ekstra tuşlar",
-    "Show Extra Keys": "Ekstra tuşları göster",
-    "Ctrl": "Ctrl",
-    "Toggle Ctrl": "Ctrl Değiştir ",
-    "Alt": "Alt",
-    "Toggle Alt": "Alt Değiştir",
-    "Send Tab": "Sekme Gönder",
-    "Tab": "Sekme",
-    "Esc": "Esc",
-    "Send Escape": "Boşluk Gönder",
-    "Ctrl+Alt+Del": "Ctrl + Alt + Del",
-    "Send Ctrl-Alt-Del": "Ctrl-Alt-Del Gönder",
-    "Shutdown/Reboot": "Kapat/Yeniden Başlat",
-    "Shutdown/Reboot...": "Kapat/Yeniden Başlat...",
-    "Power": "Güç",
-    "Shutdown": "Kapat",
-    "Reboot": "Yeniden Başlat",
-    "Reset": "Sıfırla",
-    "Clipboard": "Pano",
-    "Clear": "Temizle",
-    "Fullscreen": "Tam Ekran",
-    "Settings": "Ayarlar",
-    "Shared Mode": "Paylaşım Modu",
-    "View Only": "Sadece Görüntüle",
-    "Clip to Window": "Pencereye Tıkla",
-    "Scaling Mode:": "Ölçekleme Modu:",
-    "None": "Bilinmeyen",
-    "Local Scaling": "Yerel Ölçeklendirme",
-    "Remote Resizing": "Uzaktan Yeniden Boyutlandırma",
-    "Advanced": "Gelişmiş",
-    "Repeater ID:": "Tekralayıcı ID:",
-    "WebSocket": "WebSocket",
-    "Encrypt": "Şifrele",
-    "Host:": "Ana makine:",
-    "Port:": "Port:",
-    "Path:": "Yol:",
-    "Automatic Reconnect": "Otomatik Yeniden Bağlan",
-    "Reconnect Delay (ms):": "Yeniden Bağlanma Süreci (ms):",
-    "Logging:": "Giriş yapılıyor:",
-    "Disconnect": "Bağlantıyı Kes",
-    "Connect": "Bağlan",
-    "Password:": "Parola:",
-    "Cancel": "Vazgeç",
-    "Canvas not supported.": "Tuval desteklenmiyor."
-}
\ No newline at end of file
diff --git a/public/novnc/app/locale/zh.json b/public/novnc/app/locale/zh.json
deleted file mode 100644
index 8ddf813f..00000000
--- a/public/novnc/app/locale/zh.json
+++ /dev/null
@@ -1,69 +0,0 @@
-{
-    "Connecting...": "連線中...",
-    "Disconnecting...": "正在中斷連線...",
-    "Reconnecting...": "重新連線中...",
-    "Internal error": "內部錯誤",
-    "Must set host": "請提供主機資訊",
-    "Connected (encrypted) to ": "已加密連線到",
-    "Connected (unencrypted) to ": "未加密連線到",
-    "Something went wrong, connection is closed": "發生錯誤,連線已關閉",
-    "Failed to connect to server": "無法連線到伺服器",
-    "Disconnected": "連線已中斷",
-    "New connection has been rejected with reason: ": "連線被拒絕,原因:",
-    "New connection has been rejected": "連線被拒絕",
-    "Password is required": "請提供密碼",
-    "noVNC encountered an error:": "noVNC 遇到一個錯誤:",
-    "Hide/Show the control bar": "顯示/隱藏控制列",
-    "Move/Drag Viewport": "拖放顯示範圍",
-    "viewport drag": "顯示範圍拖放",
-    "Active Mouse Button": "啟用滑鼠按鍵",
-    "No mousebutton": "無滑鼠按鍵",
-    "Left mousebutton": "滑鼠左鍵",
-    "Middle mousebutton": "滑鼠中鍵",
-    "Right mousebutton": "滑鼠右鍵",
-    "Keyboard": "鍵盤",
-    "Show Keyboard": "顯示鍵盤",
-    "Extra keys": "額外按鍵",
-    "Show Extra Keys": "顯示額外按鍵",
-    "Ctrl": "Ctrl",
-    "Toggle Ctrl": "切換 Ctrl",
-    "Alt": "Alt",
-    "Toggle Alt": "切換 Alt",
-    "Send Tab": "送出 Tab 鍵",
-    "Tab": "Tab",
-    "Esc": "Esc",
-    "Send Escape": "送出 Escape 鍵",
-    "Ctrl+Alt+Del": "Ctrl-Alt-Del",
-    "Send Ctrl-Alt-Del": "送出 Ctrl-Alt-Del 快捷鍵",
-    "Shutdown/Reboot": "關機/重新啟動",
-    "Shutdown/Reboot...": "關機/重新啟動...",
-    "Power": "電源",
-    "Shutdown": "關機",
-    "Reboot": "重新啟動",
-    "Reset": "重設",
-    "Clipboard": "剪貼簿",
-    "Clear": "清除",
-    "Fullscreen": "全螢幕",
-    "Settings": "設定",
-    "Shared Mode": "分享模式",
-    "View Only": "僅檢視",
-    "Clip to Window": "限制/裁切視窗大小",
-    "Scaling Mode:": "縮放模式:",
-    "None": "無",
-    "Local Scaling": "本機縮放",
-    "Remote Resizing": "遠端調整大小",
-    "Advanced": "進階",
-    "Repeater ID:": "中繼站 ID",
-    "WebSocket": "WebSocket",
-    "Encrypt": "加密",
-    "Host:": "主機:",
-    "Port:": "連接埠:",
-    "Path:": "路徑:",
-    "Automatic Reconnect": "自動重新連線",
-    "Reconnect Delay (ms):": "重新連線間隔 (ms):",
-    "Logging:": "日誌級別:",
-    "Disconnect": "中斷連線",
-    "Connect": "連線",
-    "Password:": "密碼:",
-    "Cancel": "取消"
-}
\ No newline at end of file
diff --git a/public/novnc/app/localization.js b/public/novnc/app/localization.js
deleted file mode 100644
index c43d407a..00000000
--- a/public/novnc/app/localization.js
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * noVNC: HTML5 VNC client
- * Copyright (C) 2012 Joel Martin
- * Licensed under MPL 2.0 (see LICENSE.txt)
- *
- * See README.md for usage and integration instructions.
- */
-
-/*
- * Localization Utilities
- */
-
-export function Localizer() {
-    // Currently configured language
-    this.language = 'en';
-
-    // Current dictionary of translations
-    this.dictionary = undefined;
-}
-
-Localizer.prototype = {
-    // Configure suitable language based on user preferences
-    setup: function (supportedLanguages) {
-        var userLanguages;
-
-        this.language = 'en'; // Default: US English
-
-        /*
-         * Navigator.languages only available in Chrome (32+) and FireFox (32+)
-         * Fall back to navigator.language for other browsers
-         */
-        if (typeof window.navigator.languages == 'object') {
-            userLanguages = window.navigator.languages;
-        } else {
-            userLanguages = [navigator.language || navigator.userLanguage];
-        }
-
-        for (var i = 0;i < userLanguages.length;i++) {
-            var userLang = userLanguages[i];
-            userLang = userLang.toLowerCase();
-            userLang = userLang.replace("_", "-");
-            userLang = userLang.split("-");
-
-            // Built-in default?
-            if ((userLang[0] === 'en') &&
-                ((userLang[1] === undefined) || (userLang[1] === 'us'))) {
-                return;
-            }
-
-            // First pass: perfect match
-            for (var j = 0;j < supportedLanguages.length;j++) {
-                var supLang = supportedLanguages[j];
-                supLang = supLang.toLowerCase();
-                supLang = supLang.replace("_", "-");
-                supLang = supLang.split("-");
-
-                if (userLang[0] !== supLang[0])
-                    continue;
-                if (userLang[1] !== supLang[1])
-                    continue;
-
-                this.language = supportedLanguages[j];
-                return;
-            }
-
-            // Second pass: fallback
-            for (var j = 0;j < supportedLanguages.length;j++) {
-                supLang = supportedLanguages[j];
-                supLang = supLang.toLowerCase();
-                supLang = supLang.replace("_", "-");
-                supLang = supLang.split("-");
-
-                if (userLang[0] !== supLang[0])
-                    continue;
-                if (supLang[1] !== undefined)
-                    continue;
-
-                this.language = supportedLanguages[j];
-                return;
-            }
-        }
-    },
-
-    // Retrieve localised text
-    get: function (id) {
-        if (typeof this.dictionary !== 'undefined' && this.dictionary[id]) {
-            return this.dictionary[id];
-        } else {
-            return id;
-        }
-    },
-
-    // Traverses the DOM and translates relevant fields
-    // See https://html.spec.whatwg.org/multipage/dom.html#attr-translate
-    translateDOM: function () {
-        var self = this;
-        function process(elem, enabled) {
-            function isAnyOf(searchElement, items) {
-                return items.indexOf(searchElement) !== -1;
-            }
-
-            function translateAttribute(elem, attr) {
-                var str = elem.getAttribute(attr);
-                str = self.get(str);
-                elem.setAttribute(attr, str);
-            }
-
-            function translateTextNode(node) {
-                var str = node.data.trim();
-                str = self.get(str);
-                node.data = str;
-            }
-
-            if (elem.hasAttribute("translate")) {
-                if (isAnyOf(elem.getAttribute("translate"), ["", "yes"])) {
-                    enabled = true;
-                } else if (isAnyOf(elem.getAttribute("translate"), ["no"])) {
-                    enabled = false;
-                }
-            }
-
-            if (enabled) {
-                if (elem.hasAttribute("abbr") &&
-                    elem.tagName === "TH") {
-                    translateAttribute(elem, "abbr");
-                }
-                if (elem.hasAttribute("alt") &&
-                    isAnyOf(elem.tagName, ["AREA", "IMG", "INPUT"])) {
-                    translateAttribute(elem, "alt");
-                }
-                if (elem.hasAttribute("download") &&
-                    isAnyOf(elem.tagName, ["A", "AREA"])) {
-                    translateAttribute(elem, "download");
-                }
-                if (elem.hasAttribute("label") &&
-                    isAnyOf(elem.tagName, ["MENUITEM", "MENU", "OPTGROUP",
-                                   "OPTION", "TRACK"])) {
-                    translateAttribute(elem, "label");
-                }
-                // FIXME: Should update "lang"
-                if (elem.hasAttribute("placeholder") &&
-                    isAnyOf(elem.tagName, ["INPUT", "TEXTAREA"])) {
-                    translateAttribute(elem, "placeholder");
-                }
-                if (elem.hasAttribute("title")) {
-                    translateAttribute(elem, "title");
-                }
-                if (elem.hasAttribute("value") &&
-                    elem.tagName === "INPUT" &&
-                    isAnyOf(elem.getAttribute("type"), ["reset", "button", "submit"])) {
-                    translateAttribute(elem, "value");
-                }
-            }
-
-            for (var i = 0;i < elem.childNodes.length;i++) {
-                var node = elem.childNodes[i];
-                if (node.nodeType === node.ELEMENT_NODE) {
-                    process(node, enabled);
-                } else if (node.nodeType === node.TEXT_NODE && enabled) {
-                    translateTextNode(node);
-                }
-            }
-        }
-
-        process(document.body, true);
-    },
-};
-
-export var l10n = new Localizer();
-export default l10n.get.bind(l10n);
diff --git a/public/novnc/app/sounds/CREDITS b/public/novnc/app/sounds/CREDITS
deleted file mode 100644
index ec1fb556..00000000
--- a/public/novnc/app/sounds/CREDITS
+++ /dev/null
@@ -1,4 +0,0 @@
-bell
-        Copyright: Dr. Richard Boulanger et al
-        URL: http://www.archive.org/details/Berklee44v12
-        License: CC-BY Attribution 3.0 Unported
diff --git a/public/novnc/app/sounds/bell.mp3 b/public/novnc/app/sounds/bell.mp3
deleted file mode 100644
index fdbf149a..00000000
Binary files a/public/novnc/app/sounds/bell.mp3 and /dev/null differ
diff --git a/public/novnc/app/sounds/bell.oga b/public/novnc/app/sounds/bell.oga
deleted file mode 100644
index 144d2b36..00000000
Binary files a/public/novnc/app/sounds/bell.oga and /dev/null differ
diff --git a/public/novnc/app/styles/Orbitron700.ttf b/public/novnc/app/styles/Orbitron700.ttf
deleted file mode 100644
index e28729dc..00000000
Binary files a/public/novnc/app/styles/Orbitron700.ttf and /dev/null differ
diff --git a/public/novnc/app/styles/Orbitron700.woff b/public/novnc/app/styles/Orbitron700.woff
deleted file mode 100644
index 61db630c..00000000
Binary files a/public/novnc/app/styles/Orbitron700.woff and /dev/null differ
diff --git a/public/novnc/app/styles/base.css b/public/novnc/app/styles/base.css
deleted file mode 100644
index 344db9b2..00000000
--- a/public/novnc/app/styles/base.css
+++ /dev/null
@@ -1,902 +0,0 @@
-/*
- * noVNC base CSS
- * Copyright (C) 2012 Joel Martin
- * Copyright (C) 2016 Samuel Mannehed for Cendio AB
- * Copyright (C) 2016 Pierre Ossman for Cendio AB
- * noVNC is licensed under the MPL 2.0 (see LICENSE.txt)
- * This file is licensed under the 2-Clause BSD license (see LICENSE.txt).
- */
-
-/*
- * Z index layers:
- *
- * 0: Main screen
- * 10: Control bar
- * 50: Transition blocker
- * 60: Connection popups
- * 100: Status bar
- * ...
- * 1000: Javascript crash
- * ...
- * 10000: Max (used for polyfills)
- */
-
-body {
-  margin:0;
-  padding:0;
-  font-family: Helvetica;
-  /*Background image with light grey curve.*/
-  background-color:#494949;
-  background-repeat:no-repeat;
-  background-position:right bottom;
-  height:100%;
-  touch-action: none;
-}
-
-html {
-  height:100%;
-}
-
-.noVNC_only_touch.noVNC_hidden {
-  display: none;
-}
-
-.noVNC_disabled {
-  color: rgb(128, 128, 128);
-}
-
-/* ----------------------------------------
- * Spinner
- * ----------------------------------------
- */
-
-.noVNC_spinner {
-  position: relative;
-}
-.noVNC_spinner, .noVNC_spinner::before, .noVNC_spinner::after {
-  width: 10px;
-  height: 10px;
-  border-radius: 2px;
-  box-shadow: -60px 10px 0 rgba(255, 255, 255, 0);
-  animation: noVNC_spinner 1.0s linear infinite;
-}
-.noVNC_spinner::before {
-  content: "";
-  position: absolute;
-  left: 0px;
-  top: 0px;
-  animation-delay: -0.1s;
-}
-.noVNC_spinner::after {
-  content: "";
-  position: absolute;
-  top: 0px;
-  left: 0px;
-  animation-delay: 0.1s;
-}
-@keyframes noVNC_spinner {
-  0% { box-shadow: -60px 10px 0 rgba(255, 255, 255, 0); width: 20px; }
-  25% { box-shadow: 20px 10px 0 rgba(255, 255, 255, 1); width: 10px; }
-  50% { box-shadow: 60px 10px 0 rgba(255, 255, 255, 0); width: 10px; }
-}
-
-/* ----------------------------------------
- * Input Elements
- * ----------------------------------------
- */
-
-input[type=input], input[type=password], input[type=number],
-input:not([type]), textarea {
-  /* Disable default rendering */
-  -webkit-appearance: none;
-  -moz-appearance: none;
-  background: none;
-
-  margin: 2px;
-  padding: 2px;
-  border: 1px solid rgb(192, 192, 192);
-  border-radius: 5px;
-  color: black;
-  background: linear-gradient(to top, rgb(255, 255, 255) 80%, rgb(240, 240, 240));
-}
-
-input[type=button], input[type=submit], select {
-  /* Disable default rendering */
-  -webkit-appearance: none;
-  -moz-appearance: none;
-  background: none;
-
-  margin: 2px;
-  padding: 2px;
-  border: 1px solid rgb(192, 192, 192);
-  border-bottom-width: 2px;
-  border-radius: 5px;
-  color: black;
-  background: linear-gradient(to top, rgb(255, 255, 255), rgb(240, 240, 240));
-
-  /* This avoids it jumping around when :active */
-  vertical-align: middle;
-}
-
-input[type=button], input[type=submit] {
-  padding-left: 20px;
-  padding-right: 20px;
-}
-
-option {
-  color: black;
-  background: white;
-}
-
-input[type=input]:focus, input[type=password]:focus,
-input:not([type]):focus, input[type=button]:focus,
-input[type=submit]:focus,
-textarea:focus, select:focus {
-  box-shadow: 0px 0px 3px rgba(74, 144, 217, 0.5);
-  border-color: rgb(74, 144, 217);
-  outline: none;
-}
-
-input[type=button]::-moz-focus-inner,
-input[type=submit]::-moz-focus-inner {
-  border: none;
-}
-
-input[type=input]:disabled, input[type=password]:disabled,
-input:not([type]):disabled, input[type=button]:disabled,
-input[type=submit]:disabled, input[type=number]:disabled,
-textarea:disabled, select:disabled {
-  color: rgb(128, 128, 128);
-  background: rgb(240, 240, 240);
-}
-
-input[type=button]:active, input[type=submit]:active,
-select:active {
-  border-bottom-width: 1px;
-  margin-top: 3px;
-}
-
-:root:not(.noVNC_touch) input[type=button]:hover:not(:disabled),
-:root:not(.noVNC_touch) input[type=submit]:hover:not(:disabled),
-:root:not(.noVNC_touch) select:hover:not(:disabled) {
-  background: linear-gradient(to top, rgb(255, 255, 255), rgb(250, 250, 250));
-}
-
-/* ----------------------------------------
- * WebKit centering hacks
- * ----------------------------------------
- */
-
-.noVNC_center {
-  /*
-   * This is a workaround because webkit misrenders transforms and
-   * uses non-integer coordinates, resulting in blurry content.
-   * Ideally we'd use "top: 50%; transform: translateY(-50%);" on
-   * the objects instead.
-   */
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  position: fixed;
-  top: 0;
-  left: 0;
-  width: 100%;
-  height: 100%;
-  pointer-events: none;
-}
-.noVNC_center > * {
-  pointer-events: auto;
-}
-.noVNC_vcenter {
-  display: flex;
-  flex-direction: column;
-  justify-content: center;
-  position: fixed;
-  top: 0;
-  left: 0;
-  height: 100%;
-  pointer-events: none;
-}
-.noVNC_vcenter > * {
-  pointer-events: auto;
-}
-
-/* ----------------------------------------
- * Layering
- * ----------------------------------------
- */
-
-.noVNC_connect_layer {
-  z-index: 60;
-}
-
-/* ----------------------------------------
- * Fallback error
- * ----------------------------------------
- */
-
-#noVNC_fallback_error {
-  z-index: 1000;
-  visibility: hidden;
-}
-#noVNC_fallback_error.noVNC_open {
-  visibility: visible;
-}
-
-#noVNC_fallback_error > div {
-  max-width: 90%;
-  padding: 15px;
-
-  transition: 0.5s ease-in-out;
-
-  transform: translateY(-50px);
-  opacity: 0;
-
-  text-align: center;
-  font-weight: bold;
-  color: #fff;
-
-  border-radius: 10px;
-  box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5);
-  background: rgba(200,55,55,0.8);
-}
-#noVNC_fallback_error.noVNC_open > div {
-  transform: translateY(0);
-  opacity: 1;
-}
-
-#noVNC_fallback_errormsg {
-  font-weight: normal;
-}
-
-#noVNC_fallback_errormsg .noVNC_message {
-  display: inline-block;
-  text-align: left;
-  font-family: monospace;
-  white-space: pre-wrap;
-}
-
-#noVNC_fallback_error .noVNC_location {
-  font-style: italic;
-  font-size: 0.8em;
-  color: rgba(255, 255, 255, 0.8);
-}
-
-#noVNC_fallback_error .noVNC_stack {
-  max-height: 50vh;
-  padding: 10px;
-  margin: 10px;
-  font-size: 0.8em;
-  text-align: left;
-  font-family: monospace;
-  white-space: pre;
-  border: 1px solid rgba(0, 0, 0, 0.5);
-  background: rgba(0, 0, 0, 0.2);
-  overflow: auto;
-}
-
-/* ----------------------------------------
- * Control Bar
- * ----------------------------------------
- */
-
-#noVNC_control_bar_anchor {
-  /* The anchor is needed to get z-stacking to work */
-  position: fixed;
-  z-index: 10;
-
-  transition: 0.5s ease-in-out;
-
-  /* Edge misrenders animations wihthout this */
-  transform: translateX(0);
-}
-:root.noVNC_connected #noVNC_control_bar_anchor.noVNC_idle {
-  opacity: 0.8;
-}
-#noVNC_control_bar_anchor.noVNC_right {
-  left: auto;
-  right: 0;
-}
-
-#noVNC_control_bar {
-  position: relative;
-  left: -100%;
-
-  transition: 0.5s ease-in-out;
-
-  background-color: rgb(110, 132, 163);
-  border-radius: 0 10px 10px 0;
-
-}
-#noVNC_control_bar.noVNC_open {
-  box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5);
-  left: 0;
-}
-#noVNC_control_bar::before {
-  /* This extra element is to get a proper shadow */
-  content: "";
-  position: absolute;
-  z-index: -1;
-  height: 100%;
-  width: 30px;
-  left: -30px;
-  transition: box-shadow 0.5s ease-in-out;
-}
-#noVNC_control_bar.noVNC_open::before {
-  box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5);
-}
-.noVNC_right #noVNC_control_bar {
-  left: 100%;
-  border-radius: 10px 0 0 10px;
-}
-.noVNC_right #noVNC_control_bar.noVNC_open {
-  left: 0;
-}
-.noVNC_right #noVNC_control_bar::before {
-  visibility: hidden;
-}
-
-#noVNC_control_bar_handle {
-  position: absolute;
-  left: -15px;
-  top: 0;
-  transform: translateY(35px);
-  width: calc(100% + 30px);
-  height: 50px;
-  z-index: -1;
-  cursor: pointer;
-  border-radius: 5px;
-  background-color: rgb(83, 99, 122);
-  background-image: url("../images/handle_bg.svg");
-  background-repeat: no-repeat;
-  background-position: right;
-  box-shadow: 3px 3px 0px rgba(0, 0, 0, 0.5);
-}
-#noVNC_control_bar_handle:after {
-  content: "";
-  transition: transform 0.5s ease-in-out;
-  background: url("../images/handle.svg");
-  position: absolute;
-  top: 22px; /* (50px-6px)/2 */
-  right: 5px;
-  width: 5px;
-  height: 6px;
-}
-#noVNC_control_bar.noVNC_open #noVNC_control_bar_handle:after {
-  transform: translateX(1px) rotate(180deg);
-}
-:root:not(.noVNC_connected) #noVNC_control_bar_handle {
-  display: none;
-}
-.noVNC_right #noVNC_control_bar_handle {
-  background-position: left;
-}
-.noVNC_right #noVNC_control_bar_handle:after {
-  left: 5px;
-  right: 0;
-  transform: translateX(1px) rotate(180deg);
-}
-.noVNC_right #noVNC_control_bar.noVNC_open #noVNC_control_bar_handle:after {
-  transform: none;
-}
-#noVNC_control_bar_handle div {
-  position: absolute;
-  right: -35px;
-  top: 0;
-  width: 50px;
-  height: 50px;
-}
-:root:not(.noVNC_touch) #noVNC_control_bar_handle div {
-  display: none;
-}
-.noVNC_right #noVNC_control_bar_handle div {
-  left: -35px;
-  right: auto;
-}
-
-#noVNC_control_bar .noVNC_scroll {
-  max-height: 100vh; /* Chrome is buggy with 100% */
-  overflow-x: hidden;
-  overflow-y: auto;
-  padding: 0 10px 0 5px;
-}
-.noVNC_right #noVNC_control_bar .noVNC_scroll {
-  padding: 0 5px 0 10px;
-}
-
-/* Control bar hint */
-#noVNC_control_bar_hint {
-  position: fixed;
-  left: calc(100vw - 50px);
-  right: auto;
-  top: 50%;
-  transform: translateY(-50%) scale(0);
-  width: 100px;
-  height: 50%;
-  max-height: 600px;
-
-  visibility: hidden;
-  opacity: 0;
-  transition: 0.2s ease-in-out;
-  background: transparent;
-  box-shadow: 0 0 10px black, inset 0 0 10px 10px rgba(110, 132, 163, 0.8);
-  border-radius: 10px;
-  transition-delay: 0s;
-}
-#noVNC_control_bar_anchor.noVNC_right #noVNC_control_bar_hint{
-  left: auto;
-  right: calc(100vw - 50px);
-}
-#noVNC_control_bar_hint.noVNC_active {
-  visibility: visible;
-  opacity: 1;
-  transition-delay: 0.2s;
-  transform: translateY(-50%) scale(1);
-}
-
-/* General button style */
-.noVNC_button {
-  display: block;
-  padding: 4px 4px;
-  margin: 10px 0;
-  vertical-align: middle;
-  border:1px solid rgba(255, 255, 255, 0.2);
-  border-radius: 6px;
-}
-.noVNC_button.noVNC_selected {
-  border-color: rgba(0, 0, 0, 0.8);
-  background: rgba(0, 0, 0, 0.5);
-}
-.noVNC_button:disabled {
-  opacity: 0.4;
-}
-.noVNC_button:focus {
-  outline: none;
-}
-.noVNC_button:active {
-  padding-top: 5px;
-  padding-bottom: 3px;
-}
-/* Android browsers don't properly update hover state if touch events
- * are intercepted, but focus should be safe to display */
-:root:not(.noVNC_touch) .noVNC_button.noVNC_selected:hover,
-.noVNC_button.noVNC_selected:focus {
-  border-color: rgba(0, 0, 0, 0.4);
-  background: rgba(0, 0, 0, 0.2);
-}
-:root:not(.noVNC_touch) .noVNC_button:hover,
-.noVNC_button:focus {
-  background: rgba(255, 255, 255, 0.2);
-}
-.noVNC_button.noVNC_hidden {
-  display: none;
-}
-
-/* Panels */
-.noVNC_panel {
-  transform: translateX(25px);
-
-  transition: 0.5s ease-in-out;
-
-  max-height: 100vh; /* Chrome is buggy with 100% */
-  overflow-x: hidden;
-  overflow-y: auto;
-
-  visibility: hidden;
-  opacity: 0;
-
-  padding: 15px;
-
-  background: #fff;
-  border-radius: 10px;
-  color: #000;
-  border: 2px solid #E0E0E0;
-  box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5);
-}
-.noVNC_panel.noVNC_open {
-  visibility: visible;
-  opacity: 1;
-  transform: translateX(75px);
-}
-.noVNC_right .noVNC_vcenter {
-  left: auto;
-  right: 0;
-}
-.noVNC_right .noVNC_panel {
-  transform: translateX(-25px);
-}
-.noVNC_right .noVNC_panel.noVNC_open {
-  transform: translateX(-75px);
-}
-
-.noVNC_panel hr {
-  border: none;
-  border-top: 1px solid rgb(192, 192, 192);
-}
-
-.noVNC_panel label {
-  display: block;
-  white-space: nowrap;
-}
-
-.noVNC_panel .noVNC_heading {
-  background-color: rgb(110, 132, 163);
-  border-radius: 5px;
-  padding: 5px;
-  /* Compensate for padding in image */
-  padding-right: 8px;
-  color: white;
-  font-size: 20px;
-  margin-bottom: 10px;
-  white-space: nowrap;
-}
-.noVNC_panel .noVNC_heading img {
-  vertical-align: bottom;
-}
-
-.noVNC_submit {
-  float: right;
-}
-
-/* Expanders */
-.noVNC_expander {
-  cursor: pointer;
-}
-.noVNC_expander::before {
-  content: url("../images/expander.svg");
-  display: inline-block;
-  margin-right: 5px;
-  transition: 0.2s ease-in-out;
-}
-.noVNC_expander.noVNC_open::before {
-  transform: rotateZ(90deg);
-}
-.noVNC_expander ~ * {
-  margin: 5px;
-  margin-left: 10px;
-  padding: 5px;
-  background: rgba(0, 0, 0, 0.05);
-  border-radius: 5px;
-}
-.noVNC_expander:not(.noVNC_open) ~ * {
-  display: none;
-}
-
-/* Control bar content */
-
-#noVNC_control_bar .noVNC_logo {
-  font-size: 13px;
-}
-
-:root:not(.noVNC_connected) #noVNC_view_drag_button {
-  display: none;
-}
-
-/* noVNC Touch Device only buttons */
-:root:not(.noVNC_connected) #noVNC_mobile_buttons {
-  display: none;
-}
-:root:not(.noVNC_touch) #noVNC_mobile_buttons {
-  display: none;
-}
-
-/* Extra manual keys */
-:root:not(.noVNC_connected) #noVNC_extra_keys {
-  display: none;
-}
-
-#noVNC_modifiers {
-  background-color: rgb(92, 92, 92);
-  border: none;
-  padding: 0 10px;
-}
-
-/* Shutdown/Reboot */
-:root:not(.noVNC_connected) #noVNC_power_button {
-  display: none;
-}
-#noVNC_power {
-}
-#noVNC_power_buttons {
-  display: none;
-}
-
-#noVNC_power input[type=button] {
-  width: 100%;
-}
-
-/* Clipboard */
-:root:not(.noVNC_connected) #noVNC_clipboard_button {
-  display: none;
-}
-#noVNC_clipboard {
-  /* Full screen, minus padding and left and right margins */
-  max-width: calc(100vw - 2*15px - 75px - 25px);
-}
-#noVNC_clipboard_text {
-  width: 500px;
-  max-width: 100%;
-}
-
-/* Settings */
-#noVNC_settings {
-}
-#noVNC_settings ul {
-  list-style: none;
-  margin: 0px;
-  padding: 0px;
-}
-#noVNC_setting_port {
-  width: 80px;
-}
-#noVNC_setting_path {
-  width: 100px;
-}
-
-/* Connection Controls */
-:root:not(.noVNC_connected) #noVNC_disconnect_button {
-  display: none;
-}
-
-/* ----------------------------------------
- * Status Dialog
- * ----------------------------------------
- */
-
-#noVNC_status {
-  position: fixed;
-  top: 0;
-  left: 0;
-  width: 100%;
-  z-index: 100;
-  transform: translateY(-100%);
-
-  cursor: pointer;
-
-  transition: 0.5s ease-in-out;
-
-  visibility: hidden;
-  opacity: 0;
-
-  padding: 5px;
-
-  display: flex;
-  flex-direction: row;
-  justify-content: center;
-  align-content: center;
-
-  line-height: 25px;
-  word-wrap: break-word;
-  color: #fff;
-
-  border-bottom: 1px solid rgba(0, 0, 0, 0.9);
-}
-#noVNC_status.noVNC_open {
-  transform: translateY(0);
-  visibility: visible;
-  opacity: 1;
-}
-
-#noVNC_status::before {
-  content: "";
-  display: inline-block;
-  width: 25px;
-  height: 25px;
-  margin-right: 5px;
-}
-
-#noVNC_status.noVNC_status_normal {
-  background: rgba(128,128,128,0.9);
-}
-#noVNC_status.noVNC_status_normal::before {
-  content: url("../images/info.svg") " ";
-}
-#noVNC_status.noVNC_status_error {
-  background: rgba(200,55,55,0.9);
-}
-#noVNC_status.noVNC_status_error::before {
-  content: url("../images/error.svg") " ";
-}
-#noVNC_status.noVNC_status_warn {
-  background: rgba(180,180,30,0.9);
-}
-#noVNC_status.noVNC_status_warn::before {
-  content: url("../images/warning.svg") " ";
-}
-
-/* ----------------------------------------
- * Connect Dialog
- * ----------------------------------------
- */
-
-#noVNC_connect_dlg {
-  transition: 0.5s ease-in-out;
-
-  transform: scale(0, 0);
-  visibility: hidden;
-  opacity: 0;
-}
-#noVNC_connect_dlg.noVNC_open {
-  transform: scale(1, 1);
-  visibility: visible;
-  opacity: 1;
-}
-#noVNC_connect_dlg .noVNC_logo {
-  transition: 0.5s ease-in-out;
-  padding: 10px;
-  margin-bottom: 10px;
-
-  font-size: 80px;
-  text-align: center;
-
-  border-radius: 5px;
-}
-@media (max-width: 440px) {
-  #noVNC_connect_dlg {
-    max-width: calc(100vw - 100px);
-  }
-  #noVNC_connect_dlg .noVNC_logo {
-    font-size: calc(25vw - 30px);
-  }
-}
-#noVNC_connect_button {
-  cursor: pointer;
-
-  padding: 10px;
-
-  color: white;
-  background-color: rgb(110, 132, 163);
-  border-radius: 12px;
-
-  text-align: center;
-  font-size: 20px;
-
-  box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5);
-}
-#noVNC_connect_button div {
-  margin: 2px;
-  padding: 5px 30px;
-  border: 1px solid rgb(83, 99, 122);
-  border-bottom-width: 2px;
-  border-radius: 5px;
-  background: linear-gradient(to top, rgb(110, 132, 163), rgb(99, 119, 147));
-
-  /* This avoids it jumping around when :active */
-  vertical-align: middle;
-}
-#noVNC_connect_button div:active {
-  border-bottom-width: 1px;
-  margin-top: 3px;
-}
-:root:not(.noVNC_touch) #noVNC_connect_button div:hover {
-  background: linear-gradient(to top, rgb(110, 132, 163), rgb(105, 125, 155));
-}
-
-#noVNC_connect_button img {
-  vertical-align: bottom;
-  height: 1.3em;
-}
-
-/* ----------------------------------------
- * Password Dialog
- * ----------------------------------------
- */
-
-#noVNC_password_dlg {
-  position: relative;
-
-  transform: translateY(-50px);
-}
-#noVNC_password_dlg.noVNC_open {
-  transform: translateY(0);
-}
-#noVNC_password_dlg ul {
-  list-style: none;
-  margin: 0px;
-  padding: 0px;
-}
-
-/* ----------------------------------------
- * Main Area
- * ----------------------------------------
- */
-
-/* Transition screen */
-#noVNC_transition {
-  display: none;
-
-  position: fixed;
-  top: 0;
-  left: 0;
-  bottom: 0;
-  right: 0;
-
-  color: white;
-  background: rgba(0, 0, 0, 0.5);
-  z-index: 50;
-
-  /*display: flex;*/
-  align-items: center;
-  justify-content: center;
-  flex-direction: column;
-}
-:root.noVNC_loading #noVNC_transition,
-:root.noVNC_connecting #noVNC_transition,
-:root.noVNC_disconnecting #noVNC_transition,
-:root.noVNC_reconnecting #noVNC_transition {
-  display: flex;
-}
-:root:not(.noVNC_reconnecting) #noVNC_cancel_reconnect_button {
-  display: none;
-}
-#noVNC_transition_text {
-  font-size: 1.5em;
-}
-
-/* Main container */
-#noVNC_container {
-  width: 100%;
-  height: 100%;
-  background-color: #313131;
-  border-bottom-right-radius: 800px 600px;
-  /*border-top-left-radius: 800px 600px;*/
-}
-
-#noVNC_keyboardinput {
-  width: 1px;
-  height: 1px;
-  background-color: #fff;
-  color: #fff;
-  border: 0;
-  position: absolute;
-  left: -40px;
-  z-index: -1;
-  ime-mode: disabled;
-}
-
-/*Default noVNC logo.*/
-/* From: http://fonts.googleapis.com/css?family=Orbitron:700 */
-@font-face {
-  font-family: 'Orbitron';
-  font-style: normal;
-  font-weight: 700;
-  src: local('?'), url('Orbitron700.woff') format('woff'),
-                   url('Orbitron700.ttf') format('truetype');
-}
-
-.noVNC_logo {
-  color:yellow;
-  font-family: 'Orbitron', 'OrbitronTTF', sans-serif;
-  line-height:90%;
-  text-shadow: 0.1em 0.1em 0 black;
-}
-.noVNC_logo span{
-  color:green;
-}
-
-#noVNC_bell {
-  display: none;
-}
-
-/* ----------------------------------------
- * Media sizing
- * ----------------------------------------
- */
-
-@media screen and (max-width: 640px){
-  #noVNC_logo {
-    font-size: 150px;
-  }
-}
-
-@media screen and (min-width: 321px) and (max-width: 480px) {
-  #noVNC_logo {
-    font-size: 110px;
-  }
-}
-
-@media screen and (max-width: 320px) {
-  #noVNC_logo {
-    font-size: 90px;
-  }
-}
diff --git a/public/novnc/app/styles/lite.css b/public/novnc/app/styles/lite.css
deleted file mode 100644
index 13e11c7e..00000000
--- a/public/novnc/app/styles/lite.css
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * noVNC auto CSS
- * Copyright (C) 2012 Joel Martin
- * Copyright (C) 2017 Samuel Mannehed for Cendio AB
- * noVNC is licensed under the MPL 2.0 (see LICENSE.txt)
- * This file is licensed under the 2-Clause BSD license (see LICENSE.txt).
- */
-
-body {
-  margin:0;
-  background-color:#313131;
-  border-bottom-right-radius: 800px 600px;
-  height:100%;
-  display: flex;
-  flex-direction: column;
-}
-
-html {
-  background-color:#494949;
-  height:100%;
-}
-
-#noVNC_status_bar {
-  width: 100%;
-  display:flex;
-  justify-content: space-between;
-}
-
-#noVNC_status {
-  color: #fff;
-  font: bold 12px Helvetica;
-  margin: auto;
-}
-
-.noVNC_status_normal {
-  background: linear-gradient(#b2bdcd 0%,#899cb3 49%,#7e93af 51%,#6e84a3 100%);
-}
-
-.noVNC_status_error {
-  background: linear-gradient(#c83737 0%,#899cb3 49%,#7e93af 51%,#6e84a3 100%);
-}
-
-.noVNC_status_warn {
-  background: linear-gradient(#b4b41e 0%,#899cb3 49%,#7e93af 51%,#6e84a3 100%);
-}
-
-.noNVC_shown {
-  display: inline;
-}
-.noVNC_hidden {
-  display: none;
-}
-
-#noVNC_left_dummy_elem {
-  flex: 1;
-}
-
-#noVNC_buttons {
-  padding: 1px;
-  flex: 1;
-  display: flex;
-  justify-content: flex-end;
-}
diff --git a/public/novnc/app/ui.js b/public/novnc/app/ui.js
deleted file mode 100644
index 2218d241..00000000
--- a/public/novnc/app/ui.js
+++ /dev/null
@@ -1,1669 +0,0 @@
-/*
- * noVNC: HTML5 VNC client
- * Copyright (C) 2012 Joel Martin
- * Copyright (C) 2016 Samuel Mannehed for Cendio AB
- * Copyright (C) 2016 Pierre Ossman for Cendio AB
- * Licensed under MPL 2.0 (see LICENSE.txt)
- *
- * See README.md for usage and integration instructions.
- */
-
-import * as Log from '../core/util/logging.js';
-import _, { l10n } from './localization.js';
-import { isTouchDevice } from '../core/util/browser.js';
-import { setCapture, getPointerEvent } from '../core/util/events.js';
-import KeyTable from "../core/input/keysym.js";
-import keysyms from "../core/input/keysymdef.js";
-import Keyboard from "../core/input/keyboard.js";
-import RFB from "../core/rfb.js";
-import Display from "../core/display.js";
-import * as WebUtil from "./webutil.js";
-
-var UI = {
-
-    connected: false,
-    desktopName: "",
-
-    statusTimeout: null,
-    hideKeyboardTimeout: null,
-    idleControlbarTimeout: null,
-    closeControlbarTimeout: null,
-
-    controlbarGrabbed: false,
-    controlbarDrag: false,
-    controlbarMouseDownClientY: 0,
-    controlbarMouseDownOffsetY: 0,
-
-    isSafari: false,
-    lastKeyboardinput: null,
-    defaultKeyboardinputLen: 100,
-
-    inhibit_reconnect: true,
-    reconnect_callback: null,
-    reconnect_password: null,
-
-    prime: function(callback) {
-        if (document.readyState === "interactive" || document.readyState === "complete") {
-            UI.load(callback);
-        } else {
-            document.addEventListener('DOMContentLoaded', UI.load.bind(UI, callback));
-        }
-    },
-
-    // Setup rfb object, load settings from browser storage, then call
-    // UI.init to setup the UI/menus
-    load: function(callback) {
-        WebUtil.initSettings(UI.start, callback);
-    },
-
-    // Render default UI and initialize settings menu
-    start: function(callback) {
-
-        // Setup global variables first
-        UI.isSafari = (navigator.userAgent.indexOf('Safari') !== -1 &&
-                       navigator.userAgent.indexOf('Chrome') === -1);
-
-        UI.initSettings();
-
-        // Translate the DOM
-        l10n.translateDOM();
-
-        // Adapt the interface for touch screen devices
-        if (isTouchDevice) {
-            document.documentElement.classList.add("noVNC_touch");
-            // Remove the address bar
-            setTimeout(function() { window.scrollTo(0, 1); }, 100);
-        }
-
-        // Restore control bar position
-        if (WebUtil.readSetting('controlbar_pos') === 'right') {
-            UI.toggleControlbarSide();
-        }
-
-        UI.initFullscreen();
-
-        // Setup event handlers
-        UI.addControlbarHandlers();
-        UI.addTouchSpecificHandlers();
-        UI.addExtraKeysHandlers();
-        UI.addMachineHandlers();
-        UI.addConnectionControlHandlers();
-        UI.addClipboardHandlers();
-        UI.addSettingsHandlers();
-        document.getElementById("noVNC_status")
-            .addEventListener('click', UI.hideStatus);
-
-        // Bootstrap fallback input handler
-        UI.keyboardinputReset();
-
-        UI.openControlbar();
-
-        UI.updateVisualState('init');
-
-        document.documentElement.classList.remove("noVNC_loading");
-
-        var autoconnect = WebUtil.getConfigVar('autoconnect', false);
-        if (autoconnect === 'true' || autoconnect == '1') {
-            autoconnect = true;
-            UI.connect();
-        } else {
-            autoconnect = false;
-            // Show the connect panel on first load unless autoconnecting
-            UI.openConnectPanel();
-        }
-
-        if (typeof callback === "function") {
-            callback(UI.rfb);
-        }
-    },
-
-    initFullscreen: function() {
-        // Only show the button if fullscreen is properly supported
-        // * Safari doesn't support alphanumerical input while in fullscreen
-        if (!UI.isSafari &&
-            (document.documentElement.requestFullscreen ||
-             document.documentElement.mozRequestFullScreen ||
-             document.documentElement.webkitRequestFullscreen ||
-             document.body.msRequestFullscreen)) {
-            document.getElementById('noVNC_fullscreen_button')
-                .classList.remove("noVNC_hidden");
-            UI.addFullscreenHandlers();
-        }
-    },
-
-    initSettings: function() {
-        var i;
-
-        // Logging selection dropdown
-        var llevels = ['error', 'warn', 'info', 'debug'];
-        for (i = 0; i < llevels.length; i += 1) {
-            UI.addOption(document.getElementById('noVNC_setting_logging'),llevels[i], llevels[i]);
-        }
-
-        // Settings with immediate effects
-        UI.initSetting('logging', 'warn');
-        UI.updateLogging();
-
-        // if port == 80 (or 443) then it won't be present and should be
-        // set manually
-        var port = window.location.port;
-        if (!port) {
-            if (window.location.protocol.substring(0,5) == 'https') {
-                port = 443;
-            }
-            else if (window.location.protocol.substring(0,4) == 'http') {
-                port = 80;
-            }
-        }
-
-        /* Populate the controls if defaults are provided in the URL */
-        UI.initSetting('host', window.location.hostname);
-        UI.initSetting('port', port);
-        UI.initSetting('encrypt', (window.location.protocol === "https:"));
-        UI.initSetting('view_clip', false);
-        UI.initSetting('resize', 'off');
-        UI.initSetting('shared', true);
-        UI.initSetting('view_only', false);
-        UI.initSetting('path', 'websockify');
-        UI.initSetting('repeaterID', '');
-        UI.initSetting('reconnect', false);
-        UI.initSetting('reconnect_delay', 5000);
-
-        UI.setupSettingLabels();
-    },
-    // Adds a link to the label elements on the corresponding input elements
-    setupSettingLabels: function() {
-        var labels = document.getElementsByTagName('LABEL');
-        for (var i = 0; i < labels.length; i++) {
-            var htmlFor = labels[i].htmlFor;
-            if (htmlFor != '') {
-                var elem = document.getElementById(htmlFor);
-                if (elem) elem.label = labels[i];
-            } else {
-                // If 'for' isn't set, use the first input element child
-                var children = labels[i].children;
-                for (var j = 0; j < children.length; j++) {
-                    if (children[j].form !== undefined) {
-                        children[j].label = labels[i];
-                        break;
-                    }
-                }
-            }
-        }
-    },
-
-/* ------^-------
-*     /INIT
-* ==============
-* EVENT HANDLERS
-* ------v------*/
-
-    addControlbarHandlers: function() {
-        document.getElementById("noVNC_control_bar")
-            .addEventListener('mousemove', UI.activateControlbar);
-        document.getElementById("noVNC_control_bar")
-            .addEventListener('mouseup', UI.activateControlbar);
-        document.getElementById("noVNC_control_bar")
-            .addEventListener('mousedown', UI.activateControlbar);
-        document.getElementById("noVNC_control_bar")
-            .addEventListener('keydown', UI.activateControlbar);
-
-        document.getElementById("noVNC_control_bar")
-            .addEventListener('mousedown', UI.keepControlbar);
-        document.getElementById("noVNC_control_bar")
-            .addEventListener('keydown', UI.keepControlbar);
-
-        document.getElementById("noVNC_view_drag_button")
-            .addEventListener('click', UI.toggleViewDrag);
-
-        document.getElementById("noVNC_control_bar_handle")
-            .addEventListener('mousedown', UI.controlbarHandleMouseDown);
-        document.getElementById("noVNC_control_bar_handle")
-            .addEventListener('mouseup', UI.controlbarHandleMouseUp);
-        document.getElementById("noVNC_control_bar_handle")
-            .addEventListener('mousemove', UI.dragControlbarHandle);
-        // resize events aren't available for elements
-        window.addEventListener('resize', UI.updateControlbarHandle);
-
-        var exps = document.getElementsByClassName("noVNC_expander");
-        for (var i = 0;i < exps.length;i++) {
-            exps[i].addEventListener('click', UI.toggleExpander);
-        }
-    },
-
-    addTouchSpecificHandlers: function() {
-        document.getElementById("noVNC_mouse_button0")
-            .addEventListener('click', function () { UI.setMouseButton(1); });
-        document.getElementById("noVNC_mouse_button1")
-            .addEventListener('click', function () { UI.setMouseButton(2); });
-        document.getElementById("noVNC_mouse_button2")
-            .addEventListener('click', function () { UI.setMouseButton(4); });
-        document.getElementById("noVNC_mouse_button4")
-            .addEventListener('click', function () { UI.setMouseButton(0); });
-        document.getElementById("noVNC_keyboard_button")
-            .addEventListener('click', UI.toggleVirtualKeyboard);
-
-        UI.touchKeyboard = new Keyboard(document.getElementById('noVNC_keyboardinput'));
-        UI.touchKeyboard.onkeyevent = UI.keyEvent;
-        UI.touchKeyboard.grab();
-        document.getElementById("noVNC_keyboardinput")
-            .addEventListener('input', UI.keyInput);
-        document.getElementById("noVNC_keyboardinput")
-            .addEventListener('focus', UI.onfocusVirtualKeyboard);
-        document.getElementById("noVNC_keyboardinput")
-            .addEventListener('blur', UI.onblurVirtualKeyboard);
-        document.getElementById("noVNC_keyboardinput")
-            .addEventListener('submit', function () { return false; });
-
-        document.documentElement
-            .addEventListener('mousedown', UI.keepVirtualKeyboard, true);
-
-        document.getElementById("noVNC_control_bar")
-            .addEventListener('touchstart', UI.activateControlbar);
-        document.getElementById("noVNC_control_bar")
-            .addEventListener('touchmove', UI.activateControlbar);
-        document.getElementById("noVNC_control_bar")
-            .addEventListener('touchend', UI.activateControlbar);
-        document.getElementById("noVNC_control_bar")
-            .addEventListener('input', UI.activateControlbar);
-
-        document.getElementById("noVNC_control_bar")
-            .addEventListener('touchstart', UI.keepControlbar);
-        document.getElementById("noVNC_control_bar")
-            .addEventListener('input', UI.keepControlbar);
-
-        document.getElementById("noVNC_control_bar_handle")
-            .addEventListener('touchstart', UI.controlbarHandleMouseDown);
-        document.getElementById("noVNC_control_bar_handle")
-            .addEventListener('touchend', UI.controlbarHandleMouseUp);
-        document.getElementById("noVNC_control_bar_handle")
-            .addEventListener('touchmove', UI.dragControlbarHandle);
-    },
-
-    addExtraKeysHandlers: function() {
-        document.getElementById("noVNC_toggle_extra_keys_button")
-            .addEventListener('click', UI.toggleExtraKeys);
-        document.getElementById("noVNC_toggle_ctrl_button")
-            .addEventListener('click', UI.toggleCtrl);
-        document.getElementById("noVNC_toggle_alt_button")
-            .addEventListener('click', UI.toggleAlt);
-        document.getElementById("noVNC_send_tab_button")
-            .addEventListener('click', UI.sendTab);
-        document.getElementById("noVNC_send_esc_button")
-            .addEventListener('click', UI.sendEsc);
-        document.getElementById("noVNC_send_ctrl_alt_del_button")
-            .addEventListener('click', UI.sendCtrlAltDel);
-    },
-
-    addMachineHandlers: function() {
-        document.getElementById("noVNC_shutdown_button")
-            .addEventListener('click', function() { UI.rfb.machineShutdown(); });
-        document.getElementById("noVNC_reboot_button")
-            .addEventListener('click', function() { UI.rfb.machineReboot(); });
-        document.getElementById("noVNC_reset_button")
-            .addEventListener('click', function() { UI.rfb.machineReset(); });
-        document.getElementById("noVNC_power_button")
-            .addEventListener('click', UI.togglePowerPanel);
-    },
-
-    addConnectionControlHandlers: function() {
-        document.getElementById("noVNC_disconnect_button")
-            .addEventListener('click', UI.disconnect);
-        document.getElementById("noVNC_connect_button")
-            .addEventListener('click', UI.connect);
-        document.getElementById("noVNC_cancel_reconnect_button")
-            .addEventListener('click', UI.cancelReconnect);
-
-        document.getElementById("noVNC_password_button")
-            .addEventListener('click', UI.setPassword);
-    },
-
-    addClipboardHandlers: function() {
-        document.getElementById("noVNC_clipboard_button")
-            .addEventListener('click', UI.toggleClipboardPanel);
-        document.getElementById("noVNC_clipboard_text")
-            .addEventListener('change', UI.clipboardSend);
-        document.getElementById("noVNC_clipboard_clear_button")
-            .addEventListener('click', UI.clipboardClear);
-    },
-
-    // Add a call to save settings when the element changes,
-    // unless the optional parameter changeFunc is used instead.
-    addSettingChangeHandler: function(name, changeFunc) {
-        var settingElem = document.getElementById("noVNC_setting_" + name);
-        if (changeFunc === undefined) {
-            changeFunc = function () { UI.saveSetting(name); };
-        }
-        settingElem.addEventListener('change', changeFunc);
-    },
-
-    addSettingsHandlers: function() {
-        document.getElementById("noVNC_settings_button")
-            .addEventListener('click', UI.toggleSettingsPanel);
-
-        UI.addSettingChangeHandler('encrypt');
-        UI.addSettingChangeHandler('resize');
-        UI.addSettingChangeHandler('resize', UI.enableDisableViewClip);
-        UI.addSettingChangeHandler('resize', UI.applyResizeMode);
-        UI.addSettingChangeHandler('view_clip');
-        UI.addSettingChangeHandler('view_clip', UI.updateViewClip);
-        UI.addSettingChangeHandler('shared');
-        UI.addSettingChangeHandler('view_only');
-        UI.addSettingChangeHandler('view_only', UI.updateViewOnly);
-        UI.addSettingChangeHandler('host');
-        UI.addSettingChangeHandler('port');
-        UI.addSettingChangeHandler('path');
-        UI.addSettingChangeHandler('repeaterID');
-        UI.addSettingChangeHandler('logging');
-        UI.addSettingChangeHandler('logging', UI.updateLogging);
-        UI.addSettingChangeHandler('reconnect');
-        UI.addSettingChangeHandler('reconnect_delay');
-    },
-
-    addFullscreenHandlers: function() {
-        document.getElementById("noVNC_fullscreen_button")
-            .addEventListener('click', UI.toggleFullscreen);
-
-        window.addEventListener('fullscreenchange', UI.updateFullscreenButton);
-        window.addEventListener('mozfullscreenchange', UI.updateFullscreenButton);
-        window.addEventListener('webkitfullscreenchange', UI.updateFullscreenButton);
-        window.addEventListener('msfullscreenchange', UI.updateFullscreenButton);
-    },
-
-/* ------^-------
- * /EVENT HANDLERS
- * ==============
- *     VISUAL
- * ------v------*/
-
-    // Disable/enable controls depending on connection state
-    updateVisualState: function(state) {
-
-        document.documentElement.classList.remove("noVNC_connecting");
-        document.documentElement.classList.remove("noVNC_connected");
-        document.documentElement.classList.remove("noVNC_disconnecting");
-        document.documentElement.classList.remove("noVNC_reconnecting");
-
-        let transition_elem = document.getElementById("noVNC_transition_text");
-        switch (state) {
-            case 'init':
-                break;
-            case 'connecting':
-                transition_elem.textContent = _("Connecting...");
-                document.documentElement.classList.add("noVNC_connecting");
-                break;
-            case 'connected':
-                document.documentElement.classList.add("noVNC_connected");
-                break;
-            case 'disconnecting':
-                transition_elem.textContent = _("Disconnecting...");
-                document.documentElement.classList.add("noVNC_disconnecting");
-                break;
-            case 'disconnected':
-                break;
-            case 'reconnecting':
-                transition_elem.textContent = _("Reconnecting...");
-                document.documentElement.classList.add("noVNC_reconnecting");
-                break;
-            default:
-                Log.Error("Invalid visual state: " + state);
-                UI.showStatus(_("Internal error"), 'error');
-                return;
-        }
-
-        UI.enableDisableViewClip();
-
-        if (UI.connected) {
-            UI.disableSetting('encrypt');
-            UI.disableSetting('shared');
-            UI.disableSetting('host');
-            UI.disableSetting('port');
-            UI.disableSetting('path');
-            UI.disableSetting('repeaterID');
-            UI.setMouseButton(1);
-
-            // Hide the controlbar after 2 seconds
-            UI.closeControlbarTimeout = setTimeout(UI.closeControlbar, 2000);
-        } else {
-            UI.enableSetting('encrypt');
-            UI.enableSetting('shared');
-            UI.enableSetting('host');
-            UI.enableSetting('port');
-            UI.enableSetting('path');
-            UI.enableSetting('repeaterID');
-            UI.updatePowerButton();
-            UI.keepControlbar();
-        }
-
-        // State change disables viewport dragging.
-        // It is enabled (toggled) by direct click on the button
-        UI.setViewDrag(false);
-
-        // State change also closes the password dialog
-        document.getElementById('noVNC_password_dlg')
-            .classList.remove('noVNC_open');
-    },
-
-    showStatus: function(text, status_type, time) {
-        var statusElem = document.getElementById('noVNC_status');
-
-        clearTimeout(UI.statusTimeout);
-
-        if (typeof status_type === 'undefined') {
-            status_type = 'normal';
-        }
-
-        // Don't overwrite more severe visible statuses and never
-        // errors. Only shows the first error.
-        let visible_status_type = 'none';
-        if (statusElem.classList.contains("noVNC_open")) {
-            if (statusElem.classList.contains("noVNC_status_error")) {
-                visible_status_type = 'error';
-            } else if (statusElem.classList.contains("noVNC_status_warn")) {
-                visible_status_type = 'warn';
-            } else {
-                visible_status_type = 'normal';
-            }
-        }
-        if (visible_status_type === 'error' ||
-            (visible_status_type === 'warn' && status_type === 'normal')) {
-            return;
-        }
-
-        switch (status_type) {
-            case 'error':
-                statusElem.classList.remove("noVNC_status_warn");
-                statusElem.classList.remove("noVNC_status_normal");
-                statusElem.classList.add("noVNC_status_error");
-                break;
-            case 'warning':
-            case 'warn':
-                statusElem.classList.remove("noVNC_status_error");
-                statusElem.classList.remove("noVNC_status_normal");
-                statusElem.classList.add("noVNC_status_warn");
-                break;
-            case 'normal':
-            case 'info':
-            default:
-                statusElem.classList.remove("noVNC_status_error");
-                statusElem.classList.remove("noVNC_status_warn");
-                statusElem.classList.add("noVNC_status_normal");
-                break;
-        }
-
-        statusElem.textContent = text;
-        statusElem.classList.add("noVNC_open");
-
-        // If no time was specified, show the status for 1.5 seconds
-        if (typeof time === 'undefined') {
-            time = 1500;
-        }
-
-        // Error messages do not timeout
-        if (status_type !== 'error') {
-            UI.statusTimeout = window.setTimeout(UI.hideStatus, time);
-        }
-    },
-
-    hideStatus: function() {
-        clearTimeout(UI.statusTimeout);
-        document.getElementById('noVNC_status').classList.remove("noVNC_open");
-    },
-
-    activateControlbar: function(event) {
-        clearTimeout(UI.idleControlbarTimeout);
-        // We manipulate the anchor instead of the actual control
-        // bar in order to avoid creating new a stacking group
-        document.getElementById('noVNC_control_bar_anchor')
-            .classList.remove("noVNC_idle");
-        UI.idleControlbarTimeout = window.setTimeout(UI.idleControlbar, 2000);
-    },
-
-    idleControlbar: function() {
-        document.getElementById('noVNC_control_bar_anchor')
-            .classList.add("noVNC_idle");
-    },
-
-    keepControlbar: function() {
-        clearTimeout(UI.closeControlbarTimeout);
-    },
-
-    openControlbar: function() {
-        document.getElementById('noVNC_control_bar')
-            .classList.add("noVNC_open");
-    },
-
-    closeControlbar: function() {
-        UI.closeAllPanels();
-        document.getElementById('noVNC_control_bar')
-            .classList.remove("noVNC_open");
-    },
-
-    toggleControlbar: function() {
-        if (document.getElementById('noVNC_control_bar')
-            .classList.contains("noVNC_open")) {
-            UI.closeControlbar();
-        } else {
-            UI.openControlbar();
-        }
-    },
-
-    toggleControlbarSide: function () {
-        // Temporarily disable animation to avoid weird movement
-        var bar = document.getElementById('noVNC_control_bar');
-        bar.style.transitionDuration = '0s';
-        bar.addEventListener('transitionend', function () { this.style.transitionDuration = ""; });
-
-        var anchor = document.getElementById('noVNC_control_bar_anchor');
-        if (anchor.classList.contains("noVNC_right")) {
-            WebUtil.writeSetting('controlbar_pos', 'left');
-            anchor.classList.remove("noVNC_right");
-        } else {
-            WebUtil.writeSetting('controlbar_pos', 'right');
-            anchor.classList.add("noVNC_right");
-        }
-
-        // Consider this a movement of the handle
-        UI.controlbarDrag = true;
-    },
-
-    showControlbarHint: function (show) {
-        var hint = document.getElementById('noVNC_control_bar_hint');
-        if (show) {
-            hint.classList.add("noVNC_active");
-        } else {
-            hint.classList.remove("noVNC_active");
-        }
-    },
-
-    dragControlbarHandle: function (e) {
-        if (!UI.controlbarGrabbed) return;
-
-        var ptr = getPointerEvent(e);
-
-        var anchor = document.getElementById('noVNC_control_bar_anchor');
-        if (ptr.clientX < (window.innerWidth * 0.1)) {
-            if (anchor.classList.contains("noVNC_right")) {
-                UI.toggleControlbarSide();
-            }
-        } else if (ptr.clientX > (window.innerWidth * 0.9)) {
-            if (!anchor.classList.contains("noVNC_right")) {
-                UI.toggleControlbarSide();
-            }
-        }
-
-        if (!UI.controlbarDrag) {
-            // The goal is to trigger on a certain physical width, the
-            // devicePixelRatio brings us a bit closer but is not optimal.
-            var dragThreshold = 10 * (window.devicePixelRatio || 1);
-            var dragDistance = Math.abs(ptr.clientY - UI.controlbarMouseDownClientY);
-
-            if (dragDistance < dragThreshold) return;
-
-            UI.controlbarDrag = true;
-        }
-
-        var eventY = ptr.clientY - UI.controlbarMouseDownOffsetY;
-
-        UI.moveControlbarHandle(eventY);
-
-        e.preventDefault();
-        e.stopPropagation();
-        UI.keepControlbar();
-        UI.activateControlbar();
-    },
-
-    // Move the handle but don't allow any position outside the bounds
-    moveControlbarHandle: function (viewportRelativeY) {
-        var handle = document.getElementById("noVNC_control_bar_handle");
-        var handleHeight = handle.getBoundingClientRect().height;
-        var controlbarBounds = document.getElementById("noVNC_control_bar")
-            .getBoundingClientRect();
-        var margin = 10;
-
-        // These heights need to be non-zero for the below logic to work
-        if (handleHeight === 0 || controlbarBounds.height === 0) {
-            return;
-        }
-
-        var newY = viewportRelativeY;
-
-        // Check if the coordinates are outside the control bar
-        if (newY < controlbarBounds.top + margin) {
-            // Force coordinates to be below the top of the control bar
-            newY = controlbarBounds.top + margin;
-
-        } else if (newY > controlbarBounds.top +
-                   controlbarBounds.height - handleHeight - margin) {
-            // Force coordinates to be above the bottom of the control bar
-            newY = controlbarBounds.top +
-                controlbarBounds.height - handleHeight - margin;
-        }
-
-        // Corner case: control bar too small for stable position
-        if (controlbarBounds.height < (handleHeight + margin * 2)) {
-            newY = controlbarBounds.top +
-                (controlbarBounds.height - handleHeight) / 2;
-        }
-
-        // The transform needs coordinates that are relative to the parent
-        var parentRelativeY = newY - controlbarBounds.top;
-        handle.style.transform = "translateY(" + parentRelativeY + "px)";
-    },
-
-    updateControlbarHandle: function () {
-        // Since the control bar is fixed on the viewport and not the page,
-        // the move function expects coordinates relative the the viewport.
-        var handle = document.getElementById("noVNC_control_bar_handle");
-        var handleBounds = handle.getBoundingClientRect();
-        UI.moveControlbarHandle(handleBounds.top);
-    },
-
-    controlbarHandleMouseUp: function(e) {
-        if ((e.type == "mouseup") && (e.button != 0)) return;
-
-        // mouseup and mousedown on the same place toggles the controlbar
-        if (UI.controlbarGrabbed && !UI.controlbarDrag) {
-            UI.toggleControlbar();
-            e.preventDefault();
-            e.stopPropagation();
-            UI.keepControlbar();
-            UI.activateControlbar();
-        }
-        UI.controlbarGrabbed = false;
-        UI.showControlbarHint(false);
-    },
-
-    controlbarHandleMouseDown: function(e) {
-        if ((e.type == "mousedown") && (e.button != 0)) return;
-
-        var ptr = getPointerEvent(e);
-
-        var handle = document.getElementById("noVNC_control_bar_handle");
-        var bounds = handle.getBoundingClientRect();
-
-        // Touch events have implicit capture
-        if (e.type === "mousedown") {
-            setCapture(handle);
-        }
-
-        UI.controlbarGrabbed = true;
-        UI.controlbarDrag = false;
-
-        UI.showControlbarHint(true);
-
-        UI.controlbarMouseDownClientY = ptr.clientY;
-        UI.controlbarMouseDownOffsetY = ptr.clientY - bounds.top;
-        e.preventDefault();
-        e.stopPropagation();
-        UI.keepControlbar();
-        UI.activateControlbar();
-    },
-
-    toggleExpander: function(e) {
-        if (this.classList.contains("noVNC_open")) {
-            this.classList.remove("noVNC_open");
-        } else {
-            this.classList.add("noVNC_open");
-        }
-    },
-
-/* ------^-------
- *    /VISUAL
- * ==============
- *    SETTINGS
- * ------v------*/
-
-    // Initial page load read/initialization of settings
-    initSetting: function(name, defVal) {
-        // Check Query string followed by cookie
-        var val = WebUtil.getConfigVar(name);
-        if (val === null) {
-            val = WebUtil.readSetting(name, defVal);
-        }
-        UI.updateSetting(name, val);
-        return val;
-    },
-
-    // Update cookie and form control setting. If value is not set, then
-    // updates from control to current cookie setting.
-    updateSetting: function(name, value) {
-
-        // Save the cookie for this session
-        if (typeof value !== 'undefined') {
-            WebUtil.writeSetting(name, value);
-        }
-
-        // Update the settings control
-        value = UI.getSetting(name);
-
-        var ctrl = document.getElementById('noVNC_setting_' + name);
-        if (ctrl.type === 'checkbox') {
-            ctrl.checked = value;
-
-        } else if (typeof ctrl.options !== 'undefined') {
-            for (var i = 0; i < ctrl.options.length; i += 1) {
-                if (ctrl.options[i].value === value) {
-                    ctrl.selectedIndex = i;
-                    break;
-                }
-            }
-        } else {
-            /*Weird IE9 error leads to 'null' appearring
-            in textboxes instead of ''.*/
-            if (value === null) {
-                value = "";
-            }
-            ctrl.value = value;
-        }
-    },
-
-    // Save control setting to cookie
-    saveSetting: function(name) {
-        var val, ctrl = document.getElementById('noVNC_setting_' + name);
-        if (ctrl.type === 'checkbox') {
-            val = ctrl.checked;
-        } else if (typeof ctrl.options !== 'undefined') {
-            val = ctrl.options[ctrl.selectedIndex].value;
-        } else {
-            val = ctrl.value;
-        }
-        WebUtil.writeSetting(name, val);
-        //Log.Debug("Setting saved '" + name + "=" + val + "'");
-        return val;
-    },
-
-    // Read form control compatible setting from cookie
-    getSetting: function(name) {
-        var ctrl = document.getElementById('noVNC_setting_' + name);
-        var val = WebUtil.readSetting(name);
-        if (typeof val !== 'undefined' && val !== null && ctrl.type === 'checkbox') {
-            if (val.toString().toLowerCase() in {'0':1, 'no':1, 'false':1}) {
-                val = false;
-            } else {
-                val = true;
-            }
-        }
-        return val;
-    },
-
-    // These helpers compensate for the lack of parent-selectors and
-    // previous-sibling-selectors in CSS which are needed when we want to
-    // disable the labels that belong to disabled input elements.
-    disableSetting: function(name) {
-        var ctrl = document.getElementById('noVNC_setting_' + name);
-        ctrl.disabled = true;
-        ctrl.label.classList.add('noVNC_disabled');
-    },
-
-    enableSetting: function(name) {
-        var ctrl = document.getElementById('noVNC_setting_' + name);
-        ctrl.disabled = false;
-        ctrl.label.classList.remove('noVNC_disabled');
-    },
-
-/* ------^-------
- *   /SETTINGS
- * ==============
- *    PANELS
- * ------v------*/
-
-    closeAllPanels: function() {
-        UI.closeSettingsPanel();
-        UI.closePowerPanel();
-        UI.closeClipboardPanel();
-        UI.closeExtraKeys();
-    },
-
-/* ------^-------
- *   /PANELS
- * ==============
- * SETTINGS (panel)
- * ------v------*/
-
-    openSettingsPanel: function() {
-        UI.closeAllPanels();
-        UI.openControlbar();
-
-        // Refresh UI elements from saved cookies
-        UI.updateSetting('encrypt');
-        UI.updateSetting('view_clip');
-        UI.updateSetting('resize');
-        UI.updateSetting('shared');
-        UI.updateSetting('view_only');
-        UI.updateSetting('path');
-        UI.updateSetting('repeaterID');
-        UI.updateSetting('logging');
-        UI.updateSetting('reconnect');
-        UI.updateSetting('reconnect_delay');
-
-        document.getElementById('noVNC_settings')
-            .classList.add("noVNC_open");
-        document.getElementById('noVNC_settings_button')
-            .classList.add("noVNC_selected");
-    },
-
-    closeSettingsPanel: function() {
-        document.getElementById('noVNC_settings')
-            .classList.remove("noVNC_open");
-        document.getElementById('noVNC_settings_button')
-            .classList.remove("noVNC_selected");
-    },
-
-    toggleSettingsPanel: function() {
-        if (document.getElementById('noVNC_settings')
-            .classList.contains("noVNC_open")) {
-            UI.closeSettingsPanel();
-        } else {
-            UI.openSettingsPanel();
-        }
-    },
-
-/* ------^-------
- *   /SETTINGS
- * ==============
- *     POWER
- * ------v------*/
-
-    openPowerPanel: function() {
-        UI.closeAllPanels();
-        UI.openControlbar();
-
-        document.getElementById('noVNC_power')
-            .classList.add("noVNC_open");
-        document.getElementById('noVNC_power_button')
-            .classList.add("noVNC_selected");
-    },
-
-    closePowerPanel: function() {
-        document.getElementById('noVNC_power')
-            .classList.remove("noVNC_open");
-        document.getElementById('noVNC_power_button')
-            .classList.remove("noVNC_selected");
-    },
-
-    togglePowerPanel: function() {
-        if (document.getElementById('noVNC_power')
-            .classList.contains("noVNC_open")) {
-            UI.closePowerPanel();
-        } else {
-            UI.openPowerPanel();
-        }
-    },
-
-    // Disable/enable power button
-    updatePowerButton: function() {
-        if (UI.connected &&
-            UI.rfb.capabilities.power &&
-            !UI.rfb.viewOnly) {
-            document.getElementById('noVNC_power_button')
-                .classList.remove("noVNC_hidden");
-        } else {
-            document.getElementById('noVNC_power_button')
-                .classList.add("noVNC_hidden");
-            // Close power panel if open
-            UI.closePowerPanel();
-        }
-    },
-
-/* ------^-------
- *    /POWER
- * ==============
- *   CLIPBOARD
- * ------v------*/
-
-    openClipboardPanel: function() {
-        UI.closeAllPanels();
-        UI.openControlbar();
-
-        document.getElementById('noVNC_clipboard')
-            .classList.add("noVNC_open");
-        document.getElementById('noVNC_clipboard_button')
-            .classList.add("noVNC_selected");
-    },
-
-    closeClipboardPanel: function() {
-        document.getElementById('noVNC_clipboard')
-            .classList.remove("noVNC_open");
-        document.getElementById('noVNC_clipboard_button')
-            .classList.remove("noVNC_selected");
-    },
-
-    toggleClipboardPanel: function() {
-        if (document.getElementById('noVNC_clipboard')
-            .classList.contains("noVNC_open")) {
-            UI.closeClipboardPanel();
-        } else {
-            UI.openClipboardPanel();
-        }
-    },
-
-    clipboardReceive: function(e) {
-        Log.Debug(">> UI.clipboardReceive: " + e.detail.text.substr(0,40) + "...");
-        document.getElementById('noVNC_clipboard_text').value = e.detail.text;
-        Log.Debug("<< UI.clipboardReceive");
-    },
-
-    clipboardClear: function() {
-        document.getElementById('noVNC_clipboard_text').value = "";
-        UI.rfb.clipboardPasteFrom("");
-    },
-
-    clipboardSend: function() {
-        var text = document.getElementById('noVNC_clipboard_text').value;
-        Log.Debug(">> UI.clipboardSend: " + text.substr(0,40) + "...");
-        UI.rfb.clipboardPasteFrom(text);
-        Log.Debug("<< UI.clipboardSend");
-    },
-
-/* ------^-------
- *  /CLIPBOARD
- * ==============
- *  CONNECTION
- * ------v------*/
-
-    openConnectPanel: function() {
-        document.getElementById('noVNC_connect_dlg')
-            .classList.add("noVNC_open");
-    },
-
-    closeConnectPanel: function() {
-        document.getElementById('noVNC_connect_dlg')
-            .classList.remove("noVNC_open");
-    },
-
-    connect: function(event, password) {
-
-        // Ignore when rfb already exists
-        if (typeof UI.rfb !== 'undefined') {
-            return;
-        }
-
-        var host = UI.getSetting('host');
-        var port = UI.getSetting('port');
-        var path = UI.getSetting('path');
-
-        if (typeof password === 'undefined') {
-            password = WebUtil.getConfigVar('password');
-            UI.reconnect_password = password;
-        }
-
-        if (password === null) {
-            password = undefined;
-        }
-
-        UI.hideStatus();
-
-        if (!host) {
-            Log.Error("Can't connect when host is: " + host);
-            UI.showStatus(_("Must set host"), 'error');
-            return;
-        }
-
-        UI.closeAllPanels();
-        UI.closeConnectPanel();
-
-        UI.updateVisualState('connecting');
-
-        var url;
-
-        url = UI.getSetting('encrypt') ? 'wss' : 'ws';
-
-        url += '://' + host;
-        if(port) {
-            url += ':' + port;
-        }
-        url += '/' + path;
-
-        UI.rfb = new RFB(document.getElementById('noVNC_container'), url,
-                         { shared: UI.getSetting('shared'),
-                           repeaterID: UI.getSetting('repeaterID'),
-                           credentials: { password: password } });
-        UI.rfb.addEventListener("connect", UI.connectFinished);
-        UI.rfb.addEventListener("disconnect", UI.disconnectFinished);
-        UI.rfb.addEventListener("credentialsrequired", UI.credentials);
-        UI.rfb.addEventListener("securityfailure", UI.securityFailed);
-        UI.rfb.addEventListener("capabilities", function () { UI.updatePowerButton(); });
-        UI.rfb.addEventListener("clipboard", UI.clipboardReceive);
-        UI.rfb.addEventListener("bell", UI.bell);
-        UI.rfb.addEventListener("desktopname", UI.updateDesktopName);
-        UI.rfb.clipViewport = UI.getSetting('view_clip');
-        UI.rfb.scaleViewport = UI.getSetting('resize') === 'scale';
-        UI.rfb.resizeSession = UI.getSetting('resize') === 'remote';
-
-        UI.updateViewOnly(); // requires UI.rfb
-    },
-
-    disconnect: function() {
-        UI.closeAllPanels();
-        UI.rfb.disconnect();
-
-        UI.connected = false;
-
-        // Disable automatic reconnecting
-        UI.inhibit_reconnect = true;
-
-        UI.updateVisualState('disconnecting');
-
-        // Don't display the connection settings until we're actually disconnected
-    },
-
-    reconnect: function() {
-        UI.reconnect_callback = null;
-
-        // if reconnect has been disabled in the meantime, do nothing.
-        if (UI.inhibit_reconnect) {
-            return;
-        }
-
-        UI.connect(null, UI.reconnect_password);
-    },
-
-    cancelReconnect: function() {
-        if (UI.reconnect_callback !== null) {
-            clearTimeout(UI.reconnect_callback);
-            UI.reconnect_callback = null;
-        }
-
-        UI.updateVisualState('disconnected');
-
-        UI.openControlbar();
-        UI.openConnectPanel();
-    },
-
-    connectFinished: function (e) {
-        UI.connected = true;
-        UI.inhibit_reconnect = false;
-
-        let msg;
-        if (UI.getSetting('encrypt')) {
-            msg = _("Connected (encrypted) to ") + UI.desktopName;
-        } else {
-            msg = _("Connected (unencrypted) to ") + UI.desktopName;
-        }
-        UI.showStatus(msg);
-        UI.updateVisualState('connected');
-
-        // Do this last because it can only be used on rendered elements
-        UI.rfb.focus();
-    },
-
-    disconnectFinished: function (e) {
-        let wasConnected = UI.connected;
-
-        // This variable is ideally set when disconnection starts, but
-        // when the disconnection isn't clean or if it is initiated by
-        // the server, we need to do it here as well since
-        // UI.disconnect() won't be used in those cases.
-        UI.connected = false;
-
-        UI.rfb = undefined;
-
-        if (!e.detail.clean) {
-            UI.updateVisualState('disconnected');
-            if (wasConnected) {
-                UI.showStatus(_("Something went wrong, connection is closed"),
-                              'error');
-            } else {
-                UI.showStatus(_("Failed to connect to server"), 'error');
-            }
-        } else if (UI.getSetting('reconnect', false) === true && !UI.inhibit_reconnect) {
-            UI.updateVisualState('reconnecting');
-
-            var delay = parseInt(UI.getSetting('reconnect_delay'));
-            UI.reconnect_callback = setTimeout(UI.reconnect, delay);
-            return;
-        } else {
-            UI.updateVisualState('disconnected');
-            UI.showStatus(_("Disconnected"), 'normal');
-        }
-
-        UI.openControlbar();
-        UI.openConnectPanel();
-    },
-
-    securityFailed: function (e) {
-        let msg = "";
-        // On security failures we might get a string with a reason
-        // directly from the server. Note that we can't control if
-        // this string is translated or not.
-        if ('reason' in e.detail) {
-            msg = _("New connection has been rejected with reason: ") +
-                e.detail.reason;
-        } else {
-            msg = _("New connection has been rejected");
-        }
-        UI.showStatus(msg, 'error');
-    },
-
-/* ------^-------
- *  /CONNECTION
- * ==============
- *   PASSWORD
- * ------v------*/
-
-    credentials: function(e) {
-        // FIXME: handle more types
-        document.getElementById('noVNC_password_dlg')
-            .classList.add('noVNC_open');
-
-        setTimeout(function () {
-                document.getElementById('noVNC_password_input').focus();
-            }, 100);
-
-        Log.Warn("Server asked for a password");
-        UI.showStatus(_("Password is required"), "warning");
-    },
-
-    setPassword: function(e) {
-        // Prevent actually submitting the form
-        e.preventDefault();
-
-        var inputElem = document.getElementById('noVNC_password_input');
-        var password = inputElem.value;
-        // Clear the input after reading the password
-        inputElem.value = "";
-        UI.rfb.sendCredentials({ password: password });
-        UI.reconnect_password = password;
-        document.getElementById('noVNC_password_dlg')
-            .classList.remove('noVNC_open');
-    },
-
-/* ------^-------
- *  /PASSWORD
- * ==============
- *   FULLSCREEN
- * ------v------*/
-
-    toggleFullscreen: function() {
-        if (document.fullscreenElement || // alternative standard method
-            document.mozFullScreenElement || // currently working methods
-            document.webkitFullscreenElement ||
-            document.msFullscreenElement) {
-            if (document.exitFullscreen) {
-                document.exitFullscreen();
-            } else if (document.mozCancelFullScreen) {
-                document.mozCancelFullScreen();
-            } else if (document.webkitExitFullscreen) {
-                document.webkitExitFullscreen();
-            } else if (document.msExitFullscreen) {
-                document.msExitFullscreen();
-            }
-        } else {
-            if (document.documentElement.requestFullscreen) {
-                document.documentElement.requestFullscreen();
-            } else if (document.documentElement.mozRequestFullScreen) {
-                document.documentElement.mozRequestFullScreen();
-            } else if (document.documentElement.webkitRequestFullscreen) {
-                document.documentElement.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT);
-            } else if (document.body.msRequestFullscreen) {
-                document.body.msRequestFullscreen();
-            }
-        }
-        UI.enableDisableViewClip();
-        UI.updateFullscreenButton();
-    },
-
-    updateFullscreenButton: function() {
-        if (document.fullscreenElement || // alternative standard method
-            document.mozFullScreenElement || // currently working methods
-            document.webkitFullscreenElement ||
-            document.msFullscreenElement ) {
-            document.getElementById('noVNC_fullscreen_button')
-                .classList.add("noVNC_selected");
-        } else {
-            document.getElementById('noVNC_fullscreen_button')
-                .classList.remove("noVNC_selected");
-        }
-    },
-
-/* ------^-------
- *  /FULLSCREEN
- * ==============
- *     RESIZE
- * ------v------*/
-
-    // Apply remote resizing or local scaling
-    applyResizeMode: function() {
-        if (!UI.rfb) return;
-
-        UI.rfb.scaleViewport = UI.getSetting('resize') === 'scale';
-        UI.rfb.resizeSession = UI.getSetting('resize') === 'remote';
-    },
-
-/* ------^-------
- *    /RESIZE
- * ==============
- * VIEW CLIPPING
- * ------v------*/
-
-    // Update parameters that depend on the viewport clip setting
-    updateViewClip: function() {
-        if (!UI.rfb) return;
-
-        var cur_clip = UI.rfb.clipViewport;
-        var new_clip = UI.getSetting('view_clip');
-
-        if (isTouchDevice) {
-            // Touch devices usually have shit scrollbars
-            new_clip = true;
-        }
-
-        if (cur_clip !== new_clip) {
-            UI.rfb.clipViewport = new_clip;
-        }
-
-        // Changing the viewport may change the state of
-        // the dragging button
-        UI.updateViewDrag();
-    },
-
-    // Handle special cases where viewport clipping is forced on/off or locked
-    enableDisableViewClip: function() {
-        var resizeSetting = UI.getSetting('resize');
-        // Disable clipping if we are scaling, connected or on touch
-        if (resizeSetting === 'scale' ||
-            isTouchDevice) {
-            UI.disableSetting('view_clip');
-        } else {
-            UI.enableSetting('view_clip');
-        }
-    },
-
-/* ------^-------
- * /VIEW CLIPPING
- * ==============
- *    VIEWDRAG
- * ------v------*/
-
-    toggleViewDrag: function() {
-        if (!UI.rfb) return;
-
-        var drag = UI.rfb.dragViewport;
-        UI.setViewDrag(!drag);
-     },
-
-    // Set the view drag mode which moves the viewport on mouse drags
-    setViewDrag: function(drag) {
-        if (!UI.rfb) return;
-
-        UI.rfb.dragViewport = drag;
-
-        UI.updateViewDrag();
-    },
-
-    updateViewDrag: function() {
-        if (!UI.connected) return;
-
-        var viewDragButton = document.getElementById('noVNC_view_drag_button');
-
-        if (!UI.rfb.clipViewport && UI.rfb.dragViewport) {
-            // We are no longer clipping the viewport. Make sure
-            // viewport drag isn't active when it can't be used.
-            UI.rfb.dragViewport = false;
-        }
-
-        if (UI.rfb.dragViewport) {
-            viewDragButton.classList.add("noVNC_selected");
-        } else {
-            viewDragButton.classList.remove("noVNC_selected");
-        }
-
-        // Different behaviour for touch vs non-touch
-        // The button is disabled instead of hidden on touch devices
-        if (isTouchDevice) {
-            viewDragButton.classList.remove("noVNC_hidden");
-
-            if (UI.rfb.clipViewport) {
-                viewDragButton.disabled = false;
-            } else {
-                viewDragButton.disabled = true;
-            }
-        } else {
-            viewDragButton.disabled = false;
-
-            if (UI.rfb.clipViewport) {
-                viewDragButton.classList.remove("noVNC_hidden");
-            } else {
-                viewDragButton.classList.add("noVNC_hidden");
-            }
-        }
-    },
-
-/* ------^-------
- *   /VIEWDRAG
- * ==============
- *    KEYBOARD
- * ------v------*/
-
-    showVirtualKeyboard: function() {
-        if (!isTouchDevice) return;
-
-        var input = document.getElementById('noVNC_keyboardinput');
-
-        if (document.activeElement == input) return;
-
-        input.focus();
-
-        try {
-            var l = input.value.length;
-            // Move the caret to the end
-            input.setSelectionRange(l, l);
-        } catch (err) {} // setSelectionRange is undefined in Google Chrome
-    },
-
-    hideVirtualKeyboard: function() {
-        if (!isTouchDevice) return;
-
-        var input = document.getElementById('noVNC_keyboardinput');
-
-        if (document.activeElement != input) return;
-
-        input.blur();
-    },
-
-    toggleVirtualKeyboard: function () {
-        if (document.getElementById('noVNC_keyboard_button')
-            .classList.contains("noVNC_selected")) {
-            UI.hideVirtualKeyboard();
-        } else {
-            UI.showVirtualKeyboard();
-        }
-    },
-
-    onfocusVirtualKeyboard: function(event) {
-        document.getElementById('noVNC_keyboard_button')
-            .classList.add("noVNC_selected");
-        if (UI.rfb) {
-            UI.rfb.focusOnClick = false;
-        }
-    },
-
-    onblurVirtualKeyboard: function(event) {
-        document.getElementById('noVNC_keyboard_button')
-            .classList.remove("noVNC_selected");
-        if (UI.rfb) {
-            UI.rfb.focusOnClick = true;
-        }
-    },
-
-    keepVirtualKeyboard: function(event) {
-        var input = document.getElementById('noVNC_keyboardinput');
-
-        // Only prevent focus change if the virtual keyboard is active
-        if (document.activeElement != input) {
-            return;
-        }
-
-        // Only allow focus to move to other elements that need
-        // focus to function properly
-        if (event.target.form !== undefined) {
-            switch (event.target.type) {
-                case 'text':
-                case 'email':
-                case 'search':
-                case 'password':
-                case 'tel':
-                case 'url':
-                case 'textarea':
-                case 'select-one':
-                case 'select-multiple':
-                    return;
-            }
-        }
-
-        event.preventDefault();
-    },
-
-    keyboardinputReset: function() {
-        var kbi = document.getElementById('noVNC_keyboardinput');
-        kbi.value = new Array(UI.defaultKeyboardinputLen).join("_");
-        UI.lastKeyboardinput = kbi.value;
-    },
-
-    keyEvent: function (keysym, code, down) {
-        if (!UI.rfb) return;
-
-        UI.rfb.sendKey(keysym, code, down);
-    },
-
-    // When normal keyboard events are left uncought, use the input events from
-    // the keyboardinput element instead and generate the corresponding key events.
-    // This code is required since some browsers on Android are inconsistent in
-    // sending keyCodes in the normal keyboard events when using on screen keyboards.
-    keyInput: function(event) {
-
-        if (!UI.rfb) return;
-
-        var newValue = event.target.value;
-
-        if (!UI.lastKeyboardinput) {
-            UI.keyboardinputReset();
-        }
-        var oldValue = UI.lastKeyboardinput;
-
-        var newLen;
-        try {
-            // Try to check caret position since whitespace at the end
-            // will not be considered by value.length in some browsers
-            newLen = Math.max(event.target.selectionStart, newValue.length);
-        } catch (err) {
-            // selectionStart is undefined in Google Chrome
-            newLen = newValue.length;
-        }
-        var oldLen = oldValue.length;
-
-        var backspaces;
-        var inputs = newLen - oldLen;
-        if (inputs < 0) {
-            backspaces = -inputs;
-        } else {
-            backspaces = 0;
-        }
-
-        // Compare the old string with the new to account for
-        // text-corrections or other input that modify existing text
-        var i;
-        for (i = 0; i < Math.min(oldLen, newLen); i++) {
-            if (newValue.charAt(i) != oldValue.charAt(i)) {
-                inputs = newLen - i;
-                backspaces = oldLen - i;
-                break;
-            }
-        }
-
-        // Send the key events
-        for (i = 0; i < backspaces; i++) {
-            UI.rfb.sendKey(KeyTable.XK_BackSpace, "Backspace");
-        }
-        for (i = newLen - inputs; i < newLen; i++) {
-            UI.rfb.sendKey(keysyms.lookup(newValue.charCodeAt(i)));
-        }
-
-        // Control the text content length in the keyboardinput element
-        if (newLen > 2 * UI.defaultKeyboardinputLen) {
-            UI.keyboardinputReset();
-        } else if (newLen < 1) {
-            // There always have to be some text in the keyboardinput
-            // element with which backspace can interact.
-            UI.keyboardinputReset();
-            // This sometimes causes the keyboard to disappear for a second
-            // but it is required for the android keyboard to recognize that
-            // text has been added to the field
-            event.target.blur();
-            // This has to be ran outside of the input handler in order to work
-            setTimeout(event.target.focus.bind(event.target), 0);
-        } else {
-            UI.lastKeyboardinput = newValue;
-        }
-    },
-
-/* ------^-------
- *   /KEYBOARD
- * ==============
- *   EXTRA KEYS
- * ------v------*/
-
-    openExtraKeys: function() {
-        UI.closeAllPanels();
-        UI.openControlbar();
-
-        document.getElementById('noVNC_modifiers')
-            .classList.add("noVNC_open");
-        document.getElementById('noVNC_toggle_extra_keys_button')
-            .classList.add("noVNC_selected");
-    },
-
-    closeExtraKeys: function() {
-        document.getElementById('noVNC_modifiers')
-            .classList.remove("noVNC_open");
-        document.getElementById('noVNC_toggle_extra_keys_button')
-            .classList.remove("noVNC_selected");
-    },
-
-    toggleExtraKeys: function() {
-        if(document.getElementById('noVNC_modifiers')
-            .classList.contains("noVNC_open")) {
-            UI.closeExtraKeys();
-        } else  {
-            UI.openExtraKeys();
-        }
-    },
-
-    sendEsc: function() {
-        UI.rfb.sendKey(KeyTable.XK_Escape, "Escape");
-    },
-
-    sendTab: function() {
-        UI.rfb.sendKey(KeyTable.XK_Tab);
-    },
-
-    toggleCtrl: function() {
-        var btn = document.getElementById('noVNC_toggle_ctrl_button');
-        if (btn.classList.contains("noVNC_selected")) {
-            UI.rfb.sendKey(KeyTable.XK_Control_L, "ControlLeft", false);
-            btn.classList.remove("noVNC_selected");
-        } else {
-            UI.rfb.sendKey(KeyTable.XK_Control_L, "ControlLeft", true);
-            btn.classList.add("noVNC_selected");
-        }
-    },
-
-    toggleAlt: function() {
-        var btn = document.getElementById('noVNC_toggle_alt_button');
-        if (btn.classList.contains("noVNC_selected")) {
-            UI.rfb.sendKey(KeyTable.XK_Alt_L, "AltLeft", false);
-            btn.classList.remove("noVNC_selected");
-        } else {
-            UI.rfb.sendKey(KeyTable.XK_Alt_L, "AltLeft", true);
-            btn.classList.add("noVNC_selected");
-        }
-    },
-
-    sendCtrlAltDel: function() {
-        UI.rfb.sendCtrlAltDel();
-    },
-
-/* ------^-------
- *   /EXTRA KEYS
- * ==============
- *     MISC
- * ------v------*/
-
-    setMouseButton: function(num) {
-        var view_only = UI.rfb.viewOnly;
-        if (UI.rfb && !view_only) {
-            UI.rfb.touchButton = num;
-        }
-
-        var blist = [0, 1,2,4];
-        for (var b = 0; b < blist.length; b++) {
-            var button = document.getElementById('noVNC_mouse_button' +
-                                                 blist[b]);
-            if (blist[b] === num && !view_only) {
-                button.classList.remove("noVNC_hidden");
-            } else {
-                button.classList.add("noVNC_hidden");
-            }
-        }
-    },
-
-    updateViewOnly: function() {
-        if (!UI.rfb) return;
-        UI.rfb.viewOnly = UI.getSetting('view_only');
-
-        // Hide input related buttons in view only mode
-        if (UI.rfb.viewOnly) {
-            document.getElementById('noVNC_keyboard_button')
-                .classList.add('noVNC_hidden');
-            document.getElementById('noVNC_toggle_extra_keys_button')
-                .classList.add('noVNC_hidden');
-        } else {
-            document.getElementById('noVNC_keyboard_button')
-                .classList.remove('noVNC_hidden');
-            document.getElementById('noVNC_toggle_extra_keys_button')
-                .classList.remove('noVNC_hidden');
-        }
-        UI.setMouseButton(1); //has it's own logic for hiding/showing
-    },
-
-    updateLogging: function() {
-        WebUtil.init_logging(UI.getSetting('logging'));
-    },
-
-    updateDesktopName: function(e) {
-        UI.desktopName = e.detail.name;
-        // Display the desktop name in the document title
-        document.title = e.detail.name + " - noVNC";
-    },
-
-    bell: function(e) {
-        if (WebUtil.getConfigVar('bell', 'on') === 'on') {
-            var promise = document.getElementById('noVNC_bell').play();
-            // The standards disagree on the return value here
-            if (promise) {
-                promise.catch(function(e) {
-                    if (e.name === "NotAllowedError") {
-                        // Ignore when the browser doesn't let us play audio.
-                        // It is common that the browsers require audio to be
-                        // initiated from a user action.
-                    } else {
-                        Log.Error("Unable to play bell: " + e);
-                    }
-                });
-            }
-        }
-    },
-
-    //Helper to add options to dropdown.
-    addOption: function(selectbox, text, value) {
-        var optn = document.createElement("OPTION");
-        optn.text = text;
-        optn.value = value;
-        selectbox.options.add(optn);
-    },
-
-/* ------^-------
- *    /MISC
- * ==============
- */
-};
-
-// Set up translations
-var LINGUAS = ["de", "el", "es", "nl", "pl", "sv", "tr", "zh"];
-l10n.setup(LINGUAS);
-if (l10n.language !== "en" && l10n.dictionary === undefined) {
-    WebUtil.fetchJSON('app/locale/' + l10n.language + '.json', function (translations) {
-        l10n.dictionary = translations;
-
-        // wait for translations to load before loading the UI
-        UI.prime();
-    }, function (err) {
-        Log.Error("Failed to load translations: " + err);
-        UI.prime();
-    });
-} else {
-    UI.prime();
-}
-
-export default UI;
diff --git a/public/novnc/app/webutil.js b/public/novnc/app/webutil.js
deleted file mode 100644
index 249a1382..00000000
--- a/public/novnc/app/webutil.js
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- * noVNC: HTML5 VNC client
- * Copyright (C) 2012 Joel Martin
- * Copyright (C) 2013 NTT corp.
- * Licensed under MPL 2.0 (see LICENSE.txt)
- *
- * See README.md for usage and integration instructions.
- */
-
-import { init_logging as main_init_logging } from '../core/util/logging.js';
-
-// init log level reading the logging HTTP param
-export function init_logging (level) {
-    "use strict";
-    if (typeof level !== "undefined") {
-        main_init_logging(level);
-    } else {
-        var param = document.location.href.match(/logging=([A-Za-z0-9\._\-]*)/);
-        main_init_logging(param || undefined);
-    }
-};
-
-// Read a query string variable
-export function getQueryVar (name, defVal) {
-    "use strict";
-    var re = new RegExp('.*[?&]' + name + '=([^]*)'),
-        match = document.location.href.match(re);
-    if (typeof defVal === 'undefined') { defVal = null; }
-    if (match) {
-        return decodeURIComponent(match[1]);
-    } else {
-        return defVal;
-    }
-};
-
-// Read a hash fragment variable
-export function getHashVar (name, defVal) {
-    "use strict";
-    var re = new RegExp('.*[]' + name + '=([^&]*)'),
-        match = document.location.hash.match(re);
-    if (typeof defVal === 'undefined') { defVal = null; }
-    if (match) {
-        return decodeURIComponent(match[1]);
-    } else {
-        return defVal;
-    }
-};
-
-// Read a variable from the fragment or the query string
-// Fragment takes precedence
-export function getConfigVar (name, defVal) {
-    "use strict";
-    var val = getHashVar(name);
-    if (val === null) {
-        val = getQueryVar(name, defVal);
-    }
-    return val;
-};
-
-/*
- * Cookie handling. Dervied from: http://www.quirksmode.org/js/cookies.html
- */
-
-// No days means only for this browser session
-export function createCookie (name, value, days) {
-    "use strict";
-    var date, expires;
-    if (days) {
-        date = new Date();
-        date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
-        expires = "; expires=" + date.toGMTString();
-    } else {
-        expires = "";
-    }
-
-    var secure;
-    if (document.location.protocol === "https:") {
-        secure = "; secure";
-    } else {
-        secure = "";
-    }
-    document.cookie = name + "=" + value + expires + "; path=/" + secure;
-};
-
-export function readCookie (name, defaultValue) {
-    "use strict";
-    var nameEQ = name + "=",
-        ca = document.cookie.split(';');
-
-    for (var i = 0; i < ca.length; i += 1) {
-        var c = ca[i];
-        while (c.charAt(0) === ' ') { c = c.substring(1, c.length); }
-        if (c.indexOf(nameEQ) === 0) { return c.substring(nameEQ.length, c.length); }
-    }
-    return (typeof defaultValue !== 'undefined') ? defaultValue : null;
-};
-
-export function eraseCookie (name) {
-    "use strict";
-    createCookie(name, "", -1);
-};
-
-/*
- * Setting handling.
- */
-
-var settings = {};
-
-export function initSettings (callback /*, ...callbackArgs */) {
-    "use strict";
-    var callbackArgs = Array.prototype.slice.call(arguments, 1);
-    if (window.chrome && window.chrome.storage) {
-        window.chrome.storage.sync.get(function (cfg) {
-            settings = cfg;
-            if (callback) {
-                callback.apply(this, callbackArgs);
-            }
-        });
-    } else {
-        // No-op
-        if (callback) {
-            callback.apply(this, callbackArgs);
-        }
-    }
-};
-
-// No days means only for this browser session
-export function writeSetting (name, value) {
-    "use strict";
-    if (window.chrome && window.chrome.storage) {
-        if (settings[name] !== value) {
-            settings[name] = value;
-            window.chrome.storage.sync.set(settings);
-        }
-    } else {
-        localStorage.setItem(name, value);
-    }
-};
-
-export function readSetting (name, defaultValue) {
-    "use strict";
-    var value;
-    if (window.chrome && window.chrome.storage) {
-        value = settings[name];
-    } else {
-        value = localStorage.getItem(name);
-    }
-    if (typeof value === "undefined") {
-        value = null;
-    }
-    if (value === null && typeof defaultValue !== "undefined") {
-        return defaultValue;
-    } else {
-        return value;
-    }
-};
-
-export function eraseSetting (name) {
-    "use strict";
-    if (window.chrome && window.chrome.storage) {
-        window.chrome.storage.sync.remove(name);
-        delete settings[name];
-    } else {
-        localStorage.removeItem(name);
-    }
-};
-
-export function injectParamIfMissing (path, param, value) {
-    // force pretend that we're dealing with a relative path
-    // (assume that we wanted an extra if we pass one in)
-    path = "/" + path;
-
-    var elem = document.createElement('a');
-    elem.href = path;
-
-    var param_eq = encodeURIComponent(param) + "=";
-    var query;
-    if (elem.search) {
-        query = elem.search.slice(1).split('&');
-    } else {
-        query = [];
-    }
-
-    if (!query.some(function (v) { return v.startsWith(param_eq); })) {
-        query.push(param_eq + encodeURIComponent(value));
-        elem.search = "?" + query.join("&");
-    }
-
-    // some browsers (e.g. IE11) may occasionally omit the leading slash
-    // in the elem.pathname string. Handle that case gracefully.
-    if (elem.pathname.charAt(0) == "/") {
-        return elem.pathname.slice(1) + elem.search + elem.hash;
-    } else {
-        return elem.pathname + elem.search + elem.hash;
-    }
-};
-
-// sadly, we can't use the Fetch API until we decide to drop
-// IE11 support or polyfill promises and fetch in IE11.
-// resolve will receive an object on success, while reject
-// will receive either an event or an error on failure.
-export function fetchJSON(path, resolve, reject) {
-    // NB: IE11 doesn't support JSON as a responseType
-    var req = new XMLHttpRequest();
-    req.open('GET', path);
-
-    req.onload = function () {
-        if (req.status === 200) {
-            try {
-                var resObj = JSON.parse(req.responseText);
-            } catch (err) {
-                reject(err);
-                return;
-            }
-            resolve(resObj);
-        } else {
-            reject(new Error("XHR got non-200 status while trying to load '" + path + "': " + req.status));
-        }
-    };
-
-    req.onerror = function (evt) {
-        reject(new Error("XHR encountered an error while trying to load '" + path + "': " + evt.message));
-    };
-
-    req.ontimeout = function (evt) {
-        reject(new Error("XHR timed out while trying to load '" + path + "'"));
-    };
-
-    req.send();
-}
diff --git a/public/novnc/core/base64.js b/public/novnc/core/base64.js
deleted file mode 100644
index 5182c295..00000000
--- a/public/novnc/core/base64.js
+++ /dev/null
@@ -1,110 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-// From: http://hg.mozilla.org/mozilla-central/raw-file/ec10630b1a54/js/src/devtools/jint/sunspider/string-base64.js
-
-import * as Log from './util/logging.js';
-
-export default {
-    /* Convert data (an array of integers) to a Base64 string. */
-    toBase64Table : 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='.split(''),
-    base64Pad     : '=',
-
-    encode: function (data) {
-        "use strict";
-        var result = '';
-        var toBase64Table = this.toBase64Table;
-        var length = data.length;
-        var lengthpad = (length % 3);
-        // Convert every three bytes to 4 ascii characters.
-
-        for (var i = 0; i < (length - 2); i += 3) {
-            result += toBase64Table[data[i] >> 2];
-            result += toBase64Table[((data[i] & 0x03) << 4) + (data[i + 1] >> 4)];
-            result += toBase64Table[((data[i + 1] & 0x0f) << 2) + (data[i + 2] >> 6)];
-            result += toBase64Table[data[i + 2] & 0x3f];
-        }
-
-        // Convert the remaining 1 or 2 bytes, pad out to 4 characters.
-        var j = 0;
-        if (lengthpad === 2) {
-            j = length - lengthpad;
-            result += toBase64Table[data[j] >> 2];
-            result += toBase64Table[((data[j] & 0x03) << 4) + (data[j + 1] >> 4)];
-            result += toBase64Table[(data[j + 1] & 0x0f) << 2];
-            result += toBase64Table[64];
-        } else if (lengthpad === 1) {
-            j = length - lengthpad;
-            result += toBase64Table[data[j] >> 2];
-            result += toBase64Table[(data[j] & 0x03) << 4];
-            result += toBase64Table[64];
-            result += toBase64Table[64];
-        }
-
-        return result;
-    },
-
-    /* Convert Base64 data to a string */
-    toBinaryTable : [
-        -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
-        -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
-        -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63,
-        52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1, 0,-1,-1,
-        -1, 0, 1, 2,  3, 4, 5, 6,  7, 8, 9,10, 11,12,13,14,
-        15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1,
-        -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
-        41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1
-    ],
-
-    decode: function (data, offset) {
-        "use strict";
-        offset = typeof(offset) !== 'undefined' ? offset : 0;
-        var toBinaryTable = this.toBinaryTable;
-        var base64Pad = this.base64Pad;
-        var result, result_length;
-        var leftbits = 0; // number of bits decoded, but yet to be appended
-        var leftdata = 0; // bits decoded, but yet to be appended
-        var data_length = data.indexOf('=') - offset;
-
-        if (data_length < 0) { data_length = data.length - offset; }
-
-        /* Every four characters is 3 resulting numbers */
-        result_length = (data_length >> 2) * 3 + Math.floor((data_length % 4) / 1.5);
-        result = new Array(result_length);
-
-        // Convert one by one.
-        for (var idx = 0, i = offset; i < data.length; i++) {
-            var c = toBinaryTable[data.charCodeAt(i) & 0x7f];
-            var padding = (data.charAt(i) === base64Pad);
-            // Skip illegal characters and whitespace
-            if (c === -1) {
-                Log.Error("Illegal character code " + data.charCodeAt(i) + " at position " + i);
-                continue;
-            }
-
-            // Collect data into leftdata, update bitcount
-            leftdata = (leftdata << 6) | c;
-            leftbits += 6;
-
-            // If we have 8 or more bits, append 8 bits to the result
-            if (leftbits >= 8) {
-                leftbits -= 8;
-                // Append if not padding.
-                if (!padding) {
-                    result[idx++] = (leftdata >> leftbits) & 0xff;
-                }
-                leftdata &= (1 << leftbits) - 1;
-            }
-        }
-
-        // If there are any bits left, the base64 string was corrupted
-        if (leftbits) {
-            err = new Error('Corrupted base64 string');
-            err.name = 'Base64-Error';
-            throw err;
-        }
-
-        return result;
-    }
-}; /* End of Base64 namespace */
diff --git a/public/novnc/core/des.js b/public/novnc/core/des.js
deleted file mode 100644
index 87dc516a..00000000
--- a/public/novnc/core/des.js
+++ /dev/null
@@ -1,271 +0,0 @@
-/*
- * Ported from Flashlight VNC ActionScript implementation:
- *     http://www.wizhelp.com/flashlight-vnc/
- *
- * Full attribution follows:
- *
- * -------------------------------------------------------------------------
- *
- * This DES class has been extracted from package Acme.Crypto for use in VNC.
- * The unnecessary odd parity code has been removed.
- *
- * These changes are:
- *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
-
- * DesCipher - the DES encryption method
- *
- * The meat of this code is by Dave Zimmerman
-
-See more screenshots
-[here](http://novnc.com/screenshots.html).
-
-
-### Browser Requirements
-
-noVNC uses many modern web technologies so a formal requirement list is
-not available. However these are the minimum versions we are currently
-aware of:
-
-* Chrome 49, Firefox 44, Safari 10, Opera 36, IE 11, Edge 12
-
-
-### Server Requirements
-
-noVNC follows the standard VNC protocol, but unlike other VNC clients it does
-require WebSockets support. Many servers include support (e.g.
-[x11vnc/libvncserver](http://libvncserver.sourceforge.net/),
-[QEMU](http://www.qemu.org/), and
-[MobileVNC](http://www.smartlab.at/mobilevnc/)), but for the others you need to
-use a WebSockets to TCP socket proxy. noVNC has a sister project
-[websockify](https://github.com/novnc/websockify) that provides a simple such
-proxy.
-
-
-### Quick Start
-
-* Use the launch script to automatically download and start websockify, which
-  includes a mini-webserver and the WebSockets proxy. The `--vnc` option is
-  used to specify the location of a running VNC server:
-
-    `./utils/launch.sh --vnc localhost:5901`
-
-* Point your browser to the cut-and-paste URL that is output by the launch
-  script. Hit the Connect button, enter a password if the VNC server has one
-  configured, and enjoy!
-
-
-### Integration and Deployment
-
-Please see our other documents for how to integrate noVNC in your own software,
-or deploying the noVNC application in production environments:
-
-* [Embedding](docs/EMBEDDING.md) - For the noVNC application
-* [Library](docs/LIBRARY.md) - For the noVNC JavaScript library
-
-
-### Authors/Contributors
-
-* Core team:
-    * [Joel Martin](https://github.com/kanaka)
-    * [Samuel Mannehed](https://github.com/samhed) (Cendio)
-    * [Peter Åstrand](https://github.com/astrand) (Cendio)
-    * [Solly Ross](https://github.com/DirectXMan12) (Red Hat / OpenStack)
-    * [Pierre Ossman](https://github.com/CendioOssman) (Cendio)
-
-* Notable contributions:
-    * UI and Icons : Pierre Ossman, Chris Gordon
-    * Original Logo : Michael Sersen
-    * tight encoding : Michael Tinglof (Mercuri.ca)
-
-* Included libraries:
-    * base64 : Martijn Pieters (Digital Creations 2), Samuel Sieb (sieb.net)
-    * DES : Dave Zimmerman (Widget Workshop), Jef Poskanzer (ACME Labs)
-    * Pako : Vitaly Puzrin (https://github.com/nodeca/pako)
-
-Do you want to be on this list? Check out our
-[contribution guide](https://github.com/novnc/noVNC/wiki/Contributing) and
-start hacking!
diff --git a/public/novnc/app/error-handler.js b/public/novnc/app/error-handler.js
deleted file mode 100644
index e5a6adbe..00000000
--- a/public/novnc/app/error-handler.js
+++ /dev/null
@@ -1,56 +0,0 @@
-// NB: this should *not* be included as a module until we have
-// native support in the browsers, so that our error handler
-// can catch script-loading errors.
-
-
-(function(){
-    "use strict";
-
-    // Fallback for all uncought errors
-    function handleError (event, err) {
-        try {
-            var msg = document.getElementById('noVNC_fallback_errormsg');
-
-            // Only show the initial error
-            if (msg.hasChildNodes()) {
-                return false;
-            }
-
-            var div = document.createElement("div");
-            div.classList.add('noVNC_message');
-            div.appendChild(document.createTextNode(event.message));
-            msg.appendChild(div);
-
-            if (event.filename) {
-                div = document.createElement("div");
-                div.className = 'noVNC_location';
-                var text = event.filename;
-                if (event.lineno !== undefined) {
-                    text += ":" + event.lineno;
-                    if (event.colno !== undefined) {
-                        text += ":" + event.colno;
-                    }
-                }
-                div.appendChild(document.createTextNode(text));
-                msg.appendChild(div);
-            }
-
-            if (err && (err.stack !== undefined)) {
-                div = document.createElement("div");
-                div.className = 'noVNC_stack';
-                div.appendChild(document.createTextNode(err.stack));
-                msg.appendChild(div);
-            }
-
-            document.getElementById('noVNC_fallback_error')
-                .classList.add("noVNC_open");
-        } catch (exc) {
-            document.write("noVNC encountered an error.");
-        }
-        // Don't return true since this would prevent the error
-        // from being printed to the browser console.
-        return false;
-    }
-    window.addEventListener('error', function (evt) { handleError(evt, evt.error); });
-    window.addEventListener('unhandledrejection', function (evt) { handleError(evt.reason, evt.reason); });
-})();
diff --git a/public/novnc/app/images/alt.svg b/public/novnc/app/images/alt.svg
deleted file mode 100644
index e5bb4612..00000000
--- a/public/novnc/app/images/alt.svg
+++ /dev/null
@@ -1,92 +0,0 @@
-
-
-
-
diff --git a/public/novnc/app/images/clipboard.svg b/public/novnc/app/images/clipboard.svg
deleted file mode 100644
index 79af2752..00000000
--- a/public/novnc/app/images/clipboard.svg
+++ /dev/null
@@ -1,106 +0,0 @@
-
-
-
-
diff --git a/public/novnc/app/images/connect.svg b/public/novnc/app/images/connect.svg
deleted file mode 100644
index 56cde414..00000000
--- a/public/novnc/app/images/connect.svg
+++ /dev/null
@@ -1,96 +0,0 @@
-
-
-
-
diff --git a/public/novnc/app/images/ctrl.svg b/public/novnc/app/images/ctrl.svg
deleted file mode 100644
index 856e9395..00000000
--- a/public/novnc/app/images/ctrl.svg
+++ /dev/null
@@ -1,96 +0,0 @@
-
-
-
-
diff --git a/public/novnc/app/images/ctrlaltdel.svg b/public/novnc/app/images/ctrlaltdel.svg
deleted file mode 100644
index d7744ea3..00000000
--- a/public/novnc/app/images/ctrlaltdel.svg
+++ /dev/null
@@ -1,100 +0,0 @@
-
-
-
-
diff --git a/public/novnc/app/images/disconnect.svg b/public/novnc/app/images/disconnect.svg
deleted file mode 100644
index 6be7d187..00000000
--- a/public/novnc/app/images/disconnect.svg
+++ /dev/null
@@ -1,94 +0,0 @@
-
-
-
-
diff --git a/public/novnc/app/images/drag.svg b/public/novnc/app/images/drag.svg
deleted file mode 100644
index 139caf94..00000000
--- a/public/novnc/app/images/drag.svg
+++ /dev/null
@@ -1,76 +0,0 @@
-
-
-
-
diff --git a/public/novnc/app/images/error.svg b/public/novnc/app/images/error.svg
deleted file mode 100644
index 8356d3f1..00000000
--- a/public/novnc/app/images/error.svg
+++ /dev/null
@@ -1,81 +0,0 @@
-
-
-
-
diff --git a/public/novnc/app/images/esc.svg b/public/novnc/app/images/esc.svg
deleted file mode 100644
index 830152b5..00000000
--- a/public/novnc/app/images/esc.svg
+++ /dev/null
@@ -1,92 +0,0 @@
-
-
-
-
diff --git a/public/novnc/app/images/expander.svg b/public/novnc/app/images/expander.svg
deleted file mode 100644
index e1635358..00000000
--- a/public/novnc/app/images/expander.svg
+++ /dev/null
@@ -1,69 +0,0 @@
-
-
-
-
diff --git a/public/novnc/app/images/fullscreen.svg b/public/novnc/app/images/fullscreen.svg
deleted file mode 100644
index 29bd05da..00000000
--- a/public/novnc/app/images/fullscreen.svg
+++ /dev/null
@@ -1,93 +0,0 @@
-
-
-
-
diff --git a/public/novnc/app/images/handle.svg b/public/novnc/app/images/handle.svg
deleted file mode 100644
index 4a7a126f..00000000
--- a/public/novnc/app/images/handle.svg
+++ /dev/null
@@ -1,82 +0,0 @@
-
-
-
-
diff --git a/public/novnc/app/images/handle_bg.svg b/public/novnc/app/images/handle_bg.svg
deleted file mode 100644
index 7579c42c..00000000
--- a/public/novnc/app/images/handle_bg.svg
+++ /dev/null
@@ -1,172 +0,0 @@
-
-
-
-
diff --git a/public/novnc/app/images/icons/Makefile b/public/novnc/app/images/icons/Makefile
deleted file mode 100644
index be564b43..00000000
--- a/public/novnc/app/images/icons/Makefile
+++ /dev/null
@@ -1,42 +0,0 @@
-ICONS := \
-	novnc-16x16.png \
-	novnc-24x24.png \
-	novnc-32x32.png \
-	novnc-48x48.png \
-	novnc-64x64.png
-
-ANDROID_LAUNCHER := \
-	novnc-48x48.png \
-	novnc-72x72.png \
-	novnc-96x96.png \
-	novnc-144x144.png \
-	novnc-192x192.png
-
-IPHONE_LAUNCHER := \
-	novnc-60x60.png \
-	novnc-120x120.png
-
-IPAD_LAUNCHER := \
-	novnc-76x76.png \
-	novnc-152x152.png
-
-ALL_ICONS := $(ICONS) $(ANDROID_LAUNCHER) $(IPHONE_LAUNCHER) $(IPAD_LAUNCHER)
-
-all: $(ALL_ICONS)
-
-novnc-16x16.png: novnc-icon-sm.svg
-	convert -density 90 \
-		-background transparent "$<" "$@"
-novnc-24x24.png: novnc-icon-sm.svg
-	convert -density 135 \
-		-background transparent "$<" "$@"
-novnc-32x32.png: novnc-icon-sm.svg
-	convert -density 180 \
-		-background transparent "$<" "$@"
-
-novnc-%.png: novnc-icon.svg
-	convert -density $$[`echo $* | cut -d x -f 1` * 90 / 48] \
-		-background transparent "$<" "$@"
-
-clean:
-	rm -f *.png
diff --git a/public/novnc/app/images/icons/novnc-120x120.png b/public/novnc/app/images/icons/novnc-120x120.png
deleted file mode 100644
index 40823efb..00000000
Binary files a/public/novnc/app/images/icons/novnc-120x120.png and /dev/null differ
diff --git a/public/novnc/app/images/icons/novnc-144x144.png b/public/novnc/app/images/icons/novnc-144x144.png
deleted file mode 100644
index eee71f11..00000000
Binary files a/public/novnc/app/images/icons/novnc-144x144.png and /dev/null differ
diff --git a/public/novnc/app/images/icons/novnc-152x152.png b/public/novnc/app/images/icons/novnc-152x152.png
deleted file mode 100644
index 0694b2de..00000000
Binary files a/public/novnc/app/images/icons/novnc-152x152.png and /dev/null differ
diff --git a/public/novnc/app/images/icons/novnc-16x16.png b/public/novnc/app/images/icons/novnc-16x16.png
deleted file mode 100644
index 42108f40..00000000
Binary files a/public/novnc/app/images/icons/novnc-16x16.png and /dev/null differ
diff --git a/public/novnc/app/images/icons/novnc-192x192.png b/public/novnc/app/images/icons/novnc-192x192.png
deleted file mode 100644
index ef9201f4..00000000
Binary files a/public/novnc/app/images/icons/novnc-192x192.png and /dev/null differ
diff --git a/public/novnc/app/images/icons/novnc-24x24.png b/public/novnc/app/images/icons/novnc-24x24.png
deleted file mode 100644
index 11061359..00000000
Binary files a/public/novnc/app/images/icons/novnc-24x24.png and /dev/null differ
diff --git a/public/novnc/app/images/icons/novnc-32x32.png b/public/novnc/app/images/icons/novnc-32x32.png
deleted file mode 100644
index ff00dc30..00000000
Binary files a/public/novnc/app/images/icons/novnc-32x32.png and /dev/null differ
diff --git a/public/novnc/app/images/icons/novnc-48x48.png b/public/novnc/app/images/icons/novnc-48x48.png
deleted file mode 100644
index f24cd6cc..00000000
Binary files a/public/novnc/app/images/icons/novnc-48x48.png and /dev/null differ
diff --git a/public/novnc/app/images/icons/novnc-60x60.png b/public/novnc/app/images/icons/novnc-60x60.png
deleted file mode 100644
index 06b0d609..00000000
Binary files a/public/novnc/app/images/icons/novnc-60x60.png and /dev/null differ
diff --git a/public/novnc/app/images/icons/novnc-64x64.png b/public/novnc/app/images/icons/novnc-64x64.png
deleted file mode 100644
index 6d0fb341..00000000
Binary files a/public/novnc/app/images/icons/novnc-64x64.png and /dev/null differ
diff --git a/public/novnc/app/images/icons/novnc-72x72.png b/public/novnc/app/images/icons/novnc-72x72.png
deleted file mode 100644
index 23163a22..00000000
Binary files a/public/novnc/app/images/icons/novnc-72x72.png and /dev/null differ
diff --git a/public/novnc/app/images/icons/novnc-76x76.png b/public/novnc/app/images/icons/novnc-76x76.png
deleted file mode 100644
index aef61c48..00000000
Binary files a/public/novnc/app/images/icons/novnc-76x76.png and /dev/null differ
diff --git a/public/novnc/app/images/icons/novnc-96x96.png b/public/novnc/app/images/icons/novnc-96x96.png
deleted file mode 100644
index 1a77c53f..00000000
Binary files a/public/novnc/app/images/icons/novnc-96x96.png and /dev/null differ
diff --git a/public/novnc/app/images/icons/novnc-icon-sm.svg b/public/novnc/app/images/icons/novnc-icon-sm.svg
deleted file mode 100644
index aa1c6f18..00000000
--- a/public/novnc/app/images/icons/novnc-icon-sm.svg
+++ /dev/null
@@ -1,163 +0,0 @@
-
-
-
-
diff --git a/public/novnc/app/images/icons/novnc-icon.svg b/public/novnc/app/images/icons/novnc-icon.svg
deleted file mode 100644
index 1efff912..00000000
--- a/public/novnc/app/images/icons/novnc-icon.svg
+++ /dev/null
@@ -1,163 +0,0 @@
-
-
-
-
diff --git a/public/novnc/app/images/info.svg b/public/novnc/app/images/info.svg
deleted file mode 100644
index 557b772f..00000000
--- a/public/novnc/app/images/info.svg
+++ /dev/null
@@ -1,81 +0,0 @@
-
-
-
-
diff --git a/public/novnc/app/images/keyboard.svg b/public/novnc/app/images/keyboard.svg
deleted file mode 100644
index 137b350a..00000000
--- a/public/novnc/app/images/keyboard.svg
+++ /dev/null
@@ -1,88 +0,0 @@
-
-
-
-
diff --git a/public/novnc/app/images/mouse_left.svg b/public/novnc/app/images/mouse_left.svg
deleted file mode 100644
index ce4cca41..00000000
--- a/public/novnc/app/images/mouse_left.svg
+++ /dev/null
@@ -1,92 +0,0 @@
-
-
-
-
diff --git a/public/novnc/app/images/mouse_middle.svg b/public/novnc/app/images/mouse_middle.svg
deleted file mode 100644
index 6603425c..00000000
--- a/public/novnc/app/images/mouse_middle.svg
+++ /dev/null
@@ -1,92 +0,0 @@
-
-
-
-
diff --git a/public/novnc/app/images/mouse_none.svg b/public/novnc/app/images/mouse_none.svg
deleted file mode 100644
index 3e0f838a..00000000
--- a/public/novnc/app/images/mouse_none.svg
+++ /dev/null
@@ -1,92 +0,0 @@
-
-
-
-
diff --git a/public/novnc/app/images/mouse_right.svg b/public/novnc/app/images/mouse_right.svg
deleted file mode 100644
index f4bad767..00000000
--- a/public/novnc/app/images/mouse_right.svg
+++ /dev/null
@@ -1,92 +0,0 @@
-
-
-
-
diff --git a/public/novnc/app/images/power.svg b/public/novnc/app/images/power.svg
deleted file mode 100644
index 4925d3e8..00000000
--- a/public/novnc/app/images/power.svg
+++ /dev/null
@@ -1,87 +0,0 @@
-
-
-
-
diff --git a/public/novnc/app/images/settings.svg b/public/novnc/app/images/settings.svg
deleted file mode 100644
index dbb2e80a..00000000
--- a/public/novnc/app/images/settings.svg
+++ /dev/null
@@ -1,76 +0,0 @@
-
-
-
-
diff --git a/public/novnc/app/images/tab.svg b/public/novnc/app/images/tab.svg
deleted file mode 100644
index 1ccb3229..00000000
--- a/public/novnc/app/images/tab.svg
+++ /dev/null
@@ -1,86 +0,0 @@
-
-
-
-
diff --git a/public/novnc/app/images/toggleextrakeys.svg b/public/novnc/app/images/toggleextrakeys.svg
deleted file mode 100644
index b578c0d4..00000000
--- a/public/novnc/app/images/toggleextrakeys.svg
+++ /dev/null
@@ -1,90 +0,0 @@
-
-
-
-
diff --git a/public/novnc/app/images/warning.svg b/public/novnc/app/images/warning.svg
deleted file mode 100644
index 7114f9b1..00000000
--- a/public/novnc/app/images/warning.svg
+++ /dev/null
@@ -1,81 +0,0 @@
-
-
-
-
diff --git a/public/novnc/app/locale/de.json b/public/novnc/app/locale/de.json
deleted file mode 100644
index 62e73360..00000000
--- a/public/novnc/app/locale/de.json
+++ /dev/null
@@ -1,69 +0,0 @@
-{
-    "Connecting...": "Verbinden...",
-    "Disconnecting...": "Verbindung trennen...",
-    "Reconnecting...": "Verbindung wiederherstellen...",
-    "Internal error": "Interner Fehler",
-    "Must set host": "Richten Sie den Server ein",
-    "Connected (encrypted) to ": "Verbunden mit (verschlüsselt) ",
-    "Connected (unencrypted) to ": "Verbunden mit (unverschlüsselt) ",
-    "Something went wrong, connection is closed": "Etwas lief schief, Verbindung wurde getrennt",
-    "Disconnected": "Verbindung zum Server getrennt",
-    "New connection has been rejected with reason: ": "Verbindung wurde aus folgendem Grund abgelehnt: ",
-    "New connection has been rejected": "Verbindung wurde abgelehnt",
-    "Password is required": "Passwort ist erforderlich",
-    "noVNC encountered an error:": "Ein Fehler ist aufgetreten:",
-    "Hide/Show the control bar": "Kontrollleiste verstecken/anzeigen",
-    "Move/Drag Viewport": "Ansichtsfenster verschieben/ziehen",
-    "viewport drag": "Ansichtsfenster ziehen",
-    "Active Mouse Button": "Aktive Maustaste",
-    "No mousebutton": "Keine Maustaste",
-    "Left mousebutton": "Linke Maustaste",
-    "Middle mousebutton": "Mittlere Maustaste",
-    "Right mousebutton": "Rechte Maustaste",
-    "Keyboard": "Tastatur",
-    "Show Keyboard": "Tastatur anzeigen",
-    "Extra keys": "Zusatztasten",
-    "Show Extra Keys": "Zusatztasten anzeigen",
-    "Ctrl": "Strg",
-    "Toggle Ctrl": "Strg umschalten",
-    "Alt": "Alt",
-    "Toggle Alt": "Alt umschalten",
-    "Send Tab": "Tab senden",
-    "Tab": "Tab",
-    "Esc": "Esc",
-    "Send Escape": "Escape senden",
-    "Ctrl+Alt+Del": "Strg+Alt+Entf",
-    "Send Ctrl-Alt-Del": "Strg+Alt+Entf senden",
-    "Shutdown/Reboot": "Herunterfahren/Neustarten",
-    "Shutdown/Reboot...": "Herunterfahren/Neustarten...",
-    "Power": "Energie",
-    "Shutdown": "Herunterfahren",
-    "Reboot": "Neustarten",
-    "Reset": "Zurücksetzen",
-    "Clipboard": "Zwischenablage",
-    "Clear": "Löschen",
-    "Fullscreen": "Vollbild",
-    "Settings": "Einstellungen",
-    "Shared Mode": "Geteilter Modus",
-    "View Only": "Nur betrachten",
-    "Clip to Window": "Auf Fenster begrenzen",
-    "Scaling Mode:": "Skalierungsmodus:",
-    "None": "Keiner",
-    "Local Scaling": "Lokales skalieren",
-    "Remote Resizing": "Serverseitiges skalieren",
-    "Advanced": "Erweitert",
-    "Repeater ID:": "Repeater ID:",
-    "WebSocket": "WebSocket",
-    "Encrypt": "Verschlüsselt",
-    "Host:": "Server:",
-    "Port:": "Port:",
-    "Path:": "Pfad:",
-    "Automatic Reconnect": "Automatisch wiederverbinden",
-    "Reconnect Delay (ms):": "Wiederverbindungsverzögerung (ms):",
-    "Logging:": "Protokollierung:",
-    "Disconnect": "Verbindung trennen",
-    "Connect": "Verbinden",
-    "Password:": "Passwort:",
-    "Cancel": "Abbrechen",
-    "Canvas not supported.": "Canvas nicht unterstützt."
-}
\ No newline at end of file
diff --git a/public/novnc/app/locale/el.json b/public/novnc/app/locale/el.json
deleted file mode 100644
index f801251c..00000000
--- a/public/novnc/app/locale/el.json
+++ /dev/null
@@ -1,69 +0,0 @@
-{
-    "Connecting...": "Συνδέεται...",
-    "Disconnecting...": "Aποσυνδέεται...",
-    "Reconnecting...": "Επανασυνδέεται...",
-    "Internal error": "Εσωτερικό σφάλμα",
-    "Must set host": "Πρέπει να οριστεί ο διακομιστής",
-    "Connected (encrypted) to ": "Συνδέθηκε (κρυπτογραφημένα) με το ",
-    "Connected (unencrypted) to ": "Συνδέθηκε (μη κρυπτογραφημένα) με το ",
-    "Something went wrong, connection is closed": "Κάτι πήγε στραβά, η σύνδεση διακόπηκε",
-    "Disconnected": "Αποσυνδέθηκε",
-    "New connection has been rejected with reason: ": "Η νέα σύνδεση απορρίφθηκε διότι: ",
-    "New connection has been rejected": "Η νέα σύνδεση απορρίφθηκε ",
-    "Password is required": "Απαιτείται ο κωδικός πρόσβασης",
-    "noVNC encountered an error:": "το noVNC αντιμετώπισε ένα σφάλμα:",
-    "Hide/Show the control bar": "Απόκρυψη/Εμφάνιση γραμμής ελέγχου",
-    "Move/Drag Viewport": "Μετακίνηση/Σύρσιμο Θεατού πεδίου",
-    "viewport drag": "σύρσιμο θεατού πεδίου",
-    "Active Mouse Button": "Ενεργό Πλήκτρο Ποντικιού",
-    "No mousebutton": "Χωρίς Πλήκτρο Ποντικιού",
-    "Left mousebutton": "Αριστερό Πλήκτρο Ποντικιού",
-    "Middle mousebutton": "Μεσαίο Πλήκτρο Ποντικιού",
-    "Right mousebutton": "Δεξί Πλήκτρο Ποντικιού",
-    "Keyboard": "Πληκτρολόγιο",
-    "Show Keyboard": "Εμφάνιση Πληκτρολογίου",
-    "Extra keys": "Επιπλέον πλήκτρα",
-    "Show Extra Keys": "Εμφάνιση Επιπλέον Πλήκτρων",
-    "Ctrl": "Ctrl",
-    "Toggle Ctrl": "Εναλλαγή Ctrl",
-    "Alt": "Alt",
-    "Toggle Alt": "Εναλλαγή Alt",
-    "Send Tab": "Αποστολή Tab",
-    "Tab": "Tab",
-    "Esc": "Esc",
-    "Send Escape": "Αποστολή Escape",
-    "Ctrl+Alt+Del": "Ctrl+Alt+Del",
-    "Send Ctrl-Alt-Del": "Αποστολή Ctrl-Alt-Del",
-    "Shutdown/Reboot": "Κλείσιμο/Επανεκκίνηση",
-    "Shutdown/Reboot...": "Κλείσιμο/Επανεκκίνηση...",
-    "Power": "Απενεργοποίηση",
-    "Shutdown": "Κλείσιμο",
-    "Reboot": "Επανεκκίνηση",
-    "Reset": "Επαναφορά",
-    "Clipboard": "Πρόχειρο",
-    "Clear": "Καθάρισμα",
-    "Fullscreen": "Πλήρης Οθόνη",
-    "Settings": "Ρυθμίσεις",
-    "Shared Mode": "Κοινόχρηστη Λειτουργία",
-    "View Only": "Μόνο Θέαση",
-    "Clip to Window": "Αποκοπή στο όριο του Παράθυρου",
-    "Scaling Mode:": "Λειτουργία Κλιμάκωσης:",
-    "None": "Καμία",
-    "Local Scaling": "Τοπική Κλιμάκωση",
-    "Remote Resizing": "Απομακρυσμένη Αλλαγή μεγέθους",
-    "Advanced": "Για προχωρημένους",
-    "Repeater ID:": "Repeater ID:",
-    "WebSocket": "WebSocket",
-    "Encrypt": "Κρυπτογράφηση",
-    "Host:": "Όνομα διακομιστή:",
-    "Port:": "Πόρτα διακομιστή:",
-    "Path:": "Διαδρομή:",
-    "Automatic Reconnect": "Αυτόματη επανασύνδεση",
-    "Reconnect Delay (ms):": "Καθυστέρηση επανασύνδεσης (ms):",
-    "Logging:": "Καταγραφή:",
-    "Disconnect": "Αποσύνδεση",
-    "Connect": "Σύνδεση",
-    "Password:": "Κωδικός Πρόσβασης:",
-    "Cancel": "Ακύρωση",
-    "Canvas not supported.": "Δεν υποστηρίζεται το στοιχείο Canvas"
-}
\ No newline at end of file
diff --git a/public/novnc/app/locale/es.json b/public/novnc/app/locale/es.json
deleted file mode 100644
index 23f23f49..00000000
--- a/public/novnc/app/locale/es.json
+++ /dev/null
@@ -1,68 +0,0 @@
-{
-    "Connecting...": "Conectando...",
-    "Connected (encrypted) to ": "Conectado (con encriptación) a",
-    "Connected (unencrypted) to ": "Conectado (sin encriptación) a",
-    "Disconnecting...": "Desconectando...",
-    "Disconnected": "Desconectado",
-    "Must set host": "Debes configurar el host",
-    "Reconnecting...": "Reconectando...",
-    "Password is required": "Contraseña es obligatoria",
-    "Disconnect timeout": "Tiempo de desconexión agotado",
-    "noVNC encountered an error:": "noVNC ha encontrado un error:",
-    "Hide/Show the control bar": "Ocultar/Mostrar la barra de control",
-    "Move/Drag Viewport": "Mover/Arrastrar la ventana",
-    "viewport drag": "Arrastrar la ventana",
-    "Active Mouse Button": "Botón activo del ratón",
-    "No mousebutton": "Ningún botón del ratón",
-    "Left mousebutton": "Botón izquierdo del ratón",
-    "Middle mousebutton": "Botón central del ratón",
-    "Right mousebutton": "Botón derecho del ratón",
-    "Keyboard": "Teclado",
-    "Show Keyboard": "Mostrar teclado",
-    "Extra keys": "Teclas adicionales",
-    "Show Extra Keys": "Mostrar Teclas Adicionales",
-    "Ctrl": "Ctrl",
-    "Toggle Ctrl": "Pulsar/Soltar Ctrl",
-    "Alt": "Alt",
-    "Toggle Alt": "Pulsar/Soltar Alt",
-    "Send Tab": "Enviar Tabulación",
-    "Tab": "Tabulación",
-    "Esc": "Esc",
-    "Send Escape": "Enviar Escape",
-    "Ctrl+Alt+Del": "Ctrl+Alt+Del",
-    "Send Ctrl-Alt-Del": "Enviar Ctrl+Alt+Del",
-    "Shutdown/Reboot": "Apagar/Reiniciar",
-    "Shutdown/Reboot...": "Apagar/Reiniciar...",
-    "Power": "Encender",
-    "Shutdown": "Apagar",
-    "Reboot": "Reiniciar",
-    "Reset": "Restablecer",
-    "Clipboard": "Portapapeles",
-    "Clear": "Vaciar",
-    "Fullscreen": "Pantalla Completa",
-    "Settings": "Configuraciones",
-    "Shared Mode": "Modo Compartido",
-    "View Only": "Solo visualización",
-    "Clip to Window": "Recortar al tamaño de la ventana",
-    "Scaling Mode:": "Modo de escalado:",
-    "None": "Ninguno",
-    "Local Scaling": "Escalado Local",
-    "Local Downscaling": "Reducción de escala local",
-    "Remote Resizing": "Cambio de tamaño remoto",
-    "Advanced": "Avanzado",
-    "Local Cursor": "Cursor Local",
-    "Repeater ID:": "ID del Repetidor",
-    "WebSocket": "WebSocket",
-    "Encrypt": "",
-    "Host:": "Host",
-    "Port:": "Puesto",
-    "Path:": "Ruta",
-    "Automatic Reconnect": "Reconexión automática",
-    "Reconnect Delay (ms):": "Retraso en la reconexión (ms)",
-    "Logging:": "Logging",
-    "Disconnect": "Desconectar",
-    "Connect": "Conectar",
-    "Password:": "Contraseña",
-    "Cancel": "Cancelar",
-    "Canvas not supported.": "Canvas no está soportado"
-}
\ No newline at end of file
diff --git a/public/novnc/app/locale/nl.json b/public/novnc/app/locale/nl.json
deleted file mode 100644
index 85313d6c..00000000
--- a/public/novnc/app/locale/nl.json
+++ /dev/null
@@ -1,68 +0,0 @@
-{
-    "Connecting...": "Verbinden...",
-    "Connected (encrypted) to ": "Verbonden (versleuteld) met ",
-    "Connected (unencrypted) to ": "Verbonden (onversleuteld) met ",
-    "Disconnecting...": "Verbinding verbreken...",
-    "Disconnected": "Verbinding verbroken",
-    "Must set host": "Host moeten worden ingesteld",
-    "Reconnecting...": "Opnieuw verbinding maken...",
-    "Password is required": "Wachtwoord is vereist",
-    "Disconnect timeout": "Timeout tijdens verbreken van verbinding",
-    "noVNC encountered an error:": "noVNC heeft een fout bemerkt:",
-    "Hide/Show the control bar": "Verberg/Toon de bedieningsbalk",
-    "Move/Drag Viewport": "Verplaats/Versleep Kijkvenster",
-    "viewport drag": "kijkvenster slepen",
-    "Active Mouse Button": "Actieve Muisknop",
-    "No mousebutton": "Geen muisknop",
-    "Left mousebutton": "Linker muisknop",
-    "Middle mousebutton": "Middelste muisknop",
-    "Right mousebutton": "Rechter muisknop",
-    "Keyboard": "Toetsenbord",
-    "Show Keyboard": "Toon Toetsenbord",
-    "Extra keys": "Extra toetsen",
-    "Show Extra Keys": "Toon Extra Toetsen",
-    "Ctrl": "Ctrl",
-    "Toggle Ctrl": "Ctrl aan/uitzetten",
-    "Alt": "Alt",
-    "Toggle Alt": "Alt aan/uitzetten",
-    "Send Tab": "Tab Sturen",
-    "Tab": "Tab",
-    "Esc": "Esc",
-    "Send Escape": "Escape Sturen",
-    "Ctrl+Alt+Del": "Ctrl-Alt-Del",
-    "Send Ctrl-Alt-Del": "Ctrl-Alt-Del Sturen",
-    "Shutdown/Reboot": "Uitschakelen/Herstarten",
-    "Shutdown/Reboot...": "Uitschakelen/Herstarten...",
-    "Power": "Systeem",
-    "Shutdown": "Uitschakelen",
-    "Reboot": "Herstarten",
-    "Reset": "Resetten",
-    "Clipboard": "Klembord",
-    "Clear": "Wissen",
-    "Fullscreen": "Volledig Scherm",
-    "Settings": "Instellingen",
-    "Shared Mode": "Gedeelde Modus",
-    "View Only": "Alleen Kijken",
-    "Clip to Window": "Randen buiten venster afsnijden",
-    "Scaling Mode:": "Schaalmodus:",
-    "None": "Geen",
-    "Local Scaling": "Lokaal Schalen",
-    "Local Downscaling": "Lokaal Neerschalen",
-    "Remote Resizing": "Op Afstand Formaat Wijzigen",
-    "Advanced": "Geavanceerd",
-    "Local Cursor": "Lokale Cursor",
-    "Repeater ID:": "Repeater ID:",
-    "WebSocket": "WebSocket",
-    "Encrypt": "Versleutelen",
-    "Host:": "Host:",
-    "Port:": "Poort:",
-    "Path:": "Pad:",
-    "Automatic Reconnect": "Automatisch Opnieuw Verbinden",
-    "Reconnect Delay (ms):": "Vertraging voor Opnieuw Verbinden (ms):",
-    "Logging:": "Logmeldingen:",
-    "Disconnect": "Verbinding verbreken",
-    "Connect": "Verbinden",
-    "Password:": "Wachtwoord:",
-    "Cancel": "Annuleren",
-    "Canvas not supported.": "Canvas wordt niet ondersteund."
-}
\ No newline at end of file
diff --git a/public/novnc/app/locale/pl.json b/public/novnc/app/locale/pl.json
deleted file mode 100644
index 006ac7a5..00000000
--- a/public/novnc/app/locale/pl.json
+++ /dev/null
@@ -1,69 +0,0 @@
-{
-    "Connecting...": "Łączenie...",
-    "Disconnecting...": "Rozłączanie...",
-    "Reconnecting...": "Łączenie...",
-    "Internal error": "Błąd wewnętrzny",
-    "Must set host": "Host i port są wymagane",
-    "Connected (encrypted) to ": "Połączenie (szyfrowane) z ",
-    "Connected (unencrypted) to ": "Połączenie (nieszyfrowane) z ",
-    "Something went wrong, connection is closed": "Coś poszło źle, połączenie zostało zamknięte",
-    "Disconnected": "Rozłączony",
-    "New connection has been rejected with reason: ": "Nowe połączenie zostało odrzucone z powodu: ",
-    "New connection has been rejected": "Nowe połączenie zostało odrzucone",
-    "Password is required": "Hasło jest wymagane",
-    "noVNC encountered an error:": "noVNC napotkało błąd:",
-    "Hide/Show the control bar": "Pokaż/Ukryj pasek ustawień",
-    "Move/Drag Viewport": "Ruszaj/Przeciągaj Viewport",
-    "viewport drag": "przeciągnij viewport",
-    "Active Mouse Button": "Aktywny Przycisk Myszy",
-    "No mousebutton": "Brak przycisku myszy",
-    "Left mousebutton": "Lewy przycisk myszy",
-    "Middle mousebutton": "Środkowy przycisk myszy",
-    "Right mousebutton": "Prawy przycisk myszy",
-    "Keyboard": "Klawiatura",
-    "Show Keyboard": "Pokaż klawiaturę",
-    "Extra keys": "Przyciski dodatkowe",
-    "Show Extra Keys": "Pokaż przyciski dodatkowe",
-    "Ctrl": "Ctrl",
-    "Toggle Ctrl": "Przełącz Ctrl",
-    "Alt": "Alt",
-    "Toggle Alt": "Przełącz Alt",
-    "Send Tab": "Wyślij Tab",
-    "Tab": "Tab",
-    "Esc": "Esc",
-    "Send Escape": "Wyślij Escape",
-    "Ctrl+Alt+Del": "Ctrl+Alt+Del",
-    "Send Ctrl-Alt-Del": "Wyślij Ctrl-Alt-Del",
-    "Shutdown/Reboot": "Wyłącz/Uruchom ponownie",
-    "Shutdown/Reboot...": "Wyłącz/Uruchom ponownie...",
-    "Power": "Włączony",
-    "Shutdown": "Wyłącz",
-    "Reboot": "Uruchom ponownie",
-    "Reset": "Resetuj",
-    "Clipboard": "Schowek",
-    "Clear": "Wyczyść",
-    "Fullscreen": "Pełny ekran",
-    "Settings": "Ustawienia",
-    "Shared Mode": "Tryb Współdzielenia",
-    "View Only": "Tylko Podgląd",
-    "Clip to Window": "Przytnij do Okna",
-    "Scaling Mode:": "Tryb Skalowania:",
-    "None": "Brak",
-    "Local Scaling": "Skalowanie lokalne",
-    "Remote Resizing": "Skalowanie zdalne",
-    "Advanced": "Zaawansowane",
-    "Repeater ID:": "ID Repeatera:",
-    "WebSocket": "WebSocket",
-    "Encrypt": "Szyfrowanie",
-    "Host:": "Host:",
-    "Port:": "Port:",
-    "Path:": "Ścieżka:",
-    "Automatic Reconnect": "Automatycznie wznawiaj połączenie",
-    "Reconnect Delay (ms):": "Opóźnienie wznawiania (ms):",
-    "Logging:": "Poziom logowania:",
-    "Disconnect": "Rozłącz",
-    "Connect": "Połącz",
-    "Password:": "Hasło:",
-    "Cancel": "Anuluj",
-    "Canvas not supported.": "Element Canvas nie jest wspierany."
-}
\ No newline at end of file
diff --git a/public/novnc/app/locale/sv.json b/public/novnc/app/locale/sv.json
deleted file mode 100644
index cfd8867c..00000000
--- a/public/novnc/app/locale/sv.json
+++ /dev/null
@@ -1,68 +0,0 @@
-{
-    "Connecting...": "Ansluter...",
-    "Connected (encrypted) to ": "Ansluten (krypterat) till ",
-    "Connected (unencrypted) to ": "Ansluten (okrypterat) till ",
-    "Disconnecting...": "Kopplar ner...",
-    "Disconnected": "Frånkopplad",
-    "Must set host": "Du måste specifiera en värd",
-    "Reconnecting...": "Återansluter...",
-    "Password is required": "Lösenord krävs",
-    "Disconnect timeout": "Det tog för lång tid att koppla ner",
-    "noVNC encountered an error:": "noVNC stötte på ett problem:",
-    "Hide/Show the control bar": "Göm/Visa kontrollbaren",
-    "Move/Drag Viewport": "Flytta/Dra Vyn",
-    "viewport drag": "dra vy",
-    "Active Mouse Button": "Aktiv musknapp",
-    "No mousebutton": "Ingen musknapp",
-    "Left mousebutton": "Vänster musknapp",
-    "Middle mousebutton": "Mitten-musknapp",
-    "Right mousebutton": "Höger musknapp",
-    "Keyboard": "Tangentbord",
-    "Show Keyboard": "Visa Tangentbord",
-    "Extra keys": "Extraknappar",
-    "Show Extra Keys": "Visa Extraknappar",
-    "Ctrl": "Ctrl",
-    "Toggle Ctrl": "Växla Ctrl",
-    "Alt": "Alt",
-    "Toggle Alt": "Växla Alt",
-    "Send Tab": "Skicka Tab",
-    "Tab": "Tab",
-    "Esc": "Esc",
-    "Send Escape": "Skicka Escape",
-    "Ctrl+Alt+Del": "Ctrl+Alt+Del",
-    "Send Ctrl-Alt-Del": "Skicka Ctrl-Alt-Del",
-    "Shutdown/Reboot": "Stäng av/Boota om",
-    "Shutdown/Reboot...": "Stäng av/Boota om...",
-    "Power": "Ström",
-    "Shutdown": "Stäng av",
-    "Reboot": "Boota om",
-    "Reset": "Återställ",
-    "Clipboard": "Urklipp",
-    "Clear": "Rensa",
-    "Fullscreen": "Fullskärm",
-    "Settings": "Inställningar",
-    "Shared Mode": "Delat Läge",
-    "View Only": "Endast Visning",
-    "Clip to Window": "Begränsa till Fönster",
-    "Scaling Mode:": "Skalningsläge:",
-    "None": "Ingen",
-    "Local Scaling": "Lokal Skalning",
-    "Local Downscaling": "Lokal Nedskalning",
-    "Remote Resizing": "Ändra Storlek",
-    "Advanced": "Avancerat",
-    "Local Cursor": "Lokal Muspekare",
-    "Repeater ID:": "Repeater-ID:",
-    "WebSocket": "WebSocket",
-    "Encrypt": "Kryptera",
-    "Host:": "Värd:",
-    "Port:": "Port:",
-    "Path:": "Sökväg:",
-    "Automatic Reconnect": "Automatisk Återanslutning",
-    "Reconnect Delay (ms):": "Fördröjning (ms):",
-    "Logging:": "Loggning:",
-    "Disconnect": "Koppla från",
-    "Connect": "Anslut",
-    "Password:": "Lösenord:",
-    "Cancel": "Avbryt",
-    "Canvas not supported.": "Canvas stöds ej"
-}
\ No newline at end of file
diff --git a/public/novnc/app/locale/tr.json b/public/novnc/app/locale/tr.json
deleted file mode 100644
index 451c1b8a..00000000
--- a/public/novnc/app/locale/tr.json
+++ /dev/null
@@ -1,69 +0,0 @@
-{
-    "Connecting...": "Bağlanıyor...",
-    "Disconnecting...": "Bağlantı kesiliyor...",
-    "Reconnecting...": "Yeniden bağlantı kuruluyor...",
-    "Internal error": "İç hata",
-    "Must set host": "Sunucuyu kur",
-    "Connected (encrypted) to ": "Bağlı (şifrelenmiş)",
-    "Connected (unencrypted) to ": "Bağlandı (şifrelenmemiş)",
-    "Something went wrong, connection is closed": "Bir şeyler ters gitti, bağlantı kesildi",
-    "Disconnected": "Bağlantı kesildi",
-    "New connection has been rejected with reason: ": "Bağlantı aşağıdaki nedenlerden dolayı reddedildi: ",
-    "New connection has been rejected": "Bağlantı reddedildi",
-    "Password is required": "Şifre gerekli",
-    "noVNC encountered an error:": "Bir hata oluştu:",
-    "Hide/Show the control bar": "Denetim masasını Gizle/Göster",
-    "Move/Drag Viewport": "Görünümü Taşı/Sürükle",
-    "viewport drag": "Görüntü penceresini sürükle",
-    "Active Mouse Button": "Aktif Fare Düğmesi",
-    "No mousebutton": "Fare düğmesi yok",
-    "Left mousebutton": "Farenin sol düğmesi",
-    "Middle mousebutton": "Farenin orta düğmesi",
-    "Right mousebutton": "Farenin sağ düğmesi",
-    "Keyboard": "Klavye",
-    "Show Keyboard": "Klavye Düzenini Göster",
-    "Extra keys": "Ekstra tuşlar",
-    "Show Extra Keys": "Ekstra tuşları göster",
-    "Ctrl": "Ctrl",
-    "Toggle Ctrl": "Ctrl Değiştir ",
-    "Alt": "Alt",
-    "Toggle Alt": "Alt Değiştir",
-    "Send Tab": "Sekme Gönder",
-    "Tab": "Sekme",
-    "Esc": "Esc",
-    "Send Escape": "Boşluk Gönder",
-    "Ctrl+Alt+Del": "Ctrl + Alt + Del",
-    "Send Ctrl-Alt-Del": "Ctrl-Alt-Del Gönder",
-    "Shutdown/Reboot": "Kapat/Yeniden Başlat",
-    "Shutdown/Reboot...": "Kapat/Yeniden Başlat...",
-    "Power": "Güç",
-    "Shutdown": "Kapat",
-    "Reboot": "Yeniden Başlat",
-    "Reset": "Sıfırla",
-    "Clipboard": "Pano",
-    "Clear": "Temizle",
-    "Fullscreen": "Tam Ekran",
-    "Settings": "Ayarlar",
-    "Shared Mode": "Paylaşım Modu",
-    "View Only": "Sadece Görüntüle",
-    "Clip to Window": "Pencereye Tıkla",
-    "Scaling Mode:": "Ölçekleme Modu:",
-    "None": "Bilinmeyen",
-    "Local Scaling": "Yerel Ölçeklendirme",
-    "Remote Resizing": "Uzaktan Yeniden Boyutlandırma",
-    "Advanced": "Gelişmiş",
-    "Repeater ID:": "Tekralayıcı ID:",
-    "WebSocket": "WebSocket",
-    "Encrypt": "Şifrele",
-    "Host:": "Ana makine:",
-    "Port:": "Port:",
-    "Path:": "Yol:",
-    "Automatic Reconnect": "Otomatik Yeniden Bağlan",
-    "Reconnect Delay (ms):": "Yeniden Bağlanma Süreci (ms):",
-    "Logging:": "Giriş yapılıyor:",
-    "Disconnect": "Bağlantıyı Kes",
-    "Connect": "Bağlan",
-    "Password:": "Parola:",
-    "Cancel": "Vazgeç",
-    "Canvas not supported.": "Tuval desteklenmiyor."
-}
\ No newline at end of file
diff --git a/public/novnc/app/locale/zh.json b/public/novnc/app/locale/zh.json
deleted file mode 100644
index 8ddf813f..00000000
--- a/public/novnc/app/locale/zh.json
+++ /dev/null
@@ -1,69 +0,0 @@
-{
-    "Connecting...": "連線中...",
-    "Disconnecting...": "正在中斷連線...",
-    "Reconnecting...": "重新連線中...",
-    "Internal error": "內部錯誤",
-    "Must set host": "請提供主機資訊",
-    "Connected (encrypted) to ": "已加密連線到",
-    "Connected (unencrypted) to ": "未加密連線到",
-    "Something went wrong, connection is closed": "發生錯誤,連線已關閉",
-    "Failed to connect to server": "無法連線到伺服器",
-    "Disconnected": "連線已中斷",
-    "New connection has been rejected with reason: ": "連線被拒絕,原因:",
-    "New connection has been rejected": "連線被拒絕",
-    "Password is required": "請提供密碼",
-    "noVNC encountered an error:": "noVNC 遇到一個錯誤:",
-    "Hide/Show the control bar": "顯示/隱藏控制列",
-    "Move/Drag Viewport": "拖放顯示範圍",
-    "viewport drag": "顯示範圍拖放",
-    "Active Mouse Button": "啟用滑鼠按鍵",
-    "No mousebutton": "無滑鼠按鍵",
-    "Left mousebutton": "滑鼠左鍵",
-    "Middle mousebutton": "滑鼠中鍵",
-    "Right mousebutton": "滑鼠右鍵",
-    "Keyboard": "鍵盤",
-    "Show Keyboard": "顯示鍵盤",
-    "Extra keys": "額外按鍵",
-    "Show Extra Keys": "顯示額外按鍵",
-    "Ctrl": "Ctrl",
-    "Toggle Ctrl": "切換 Ctrl",
-    "Alt": "Alt",
-    "Toggle Alt": "切換 Alt",
-    "Send Tab": "送出 Tab 鍵",
-    "Tab": "Tab",
-    "Esc": "Esc",
-    "Send Escape": "送出 Escape 鍵",
-    "Ctrl+Alt+Del": "Ctrl-Alt-Del",
-    "Send Ctrl-Alt-Del": "送出 Ctrl-Alt-Del 快捷鍵",
-    "Shutdown/Reboot": "關機/重新啟動",
-    "Shutdown/Reboot...": "關機/重新啟動...",
-    "Power": "電源",
-    "Shutdown": "關機",
-    "Reboot": "重新啟動",
-    "Reset": "重設",
-    "Clipboard": "剪貼簿",
-    "Clear": "清除",
-    "Fullscreen": "全螢幕",
-    "Settings": "設定",
-    "Shared Mode": "分享模式",
-    "View Only": "僅檢視",
-    "Clip to Window": "限制/裁切視窗大小",
-    "Scaling Mode:": "縮放模式:",
-    "None": "無",
-    "Local Scaling": "本機縮放",
-    "Remote Resizing": "遠端調整大小",
-    "Advanced": "進階",
-    "Repeater ID:": "中繼站 ID",
-    "WebSocket": "WebSocket",
-    "Encrypt": "加密",
-    "Host:": "主機:",
-    "Port:": "連接埠:",
-    "Path:": "路徑:",
-    "Automatic Reconnect": "自動重新連線",
-    "Reconnect Delay (ms):": "重新連線間隔 (ms):",
-    "Logging:": "日誌級別:",
-    "Disconnect": "中斷連線",
-    "Connect": "連線",
-    "Password:": "密碼:",
-    "Cancel": "取消"
-}
\ No newline at end of file
diff --git a/public/novnc/app/localization.js b/public/novnc/app/localization.js
deleted file mode 100644
index c43d407a..00000000
--- a/public/novnc/app/localization.js
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * noVNC: HTML5 VNC client
- * Copyright (C) 2012 Joel Martin
- * Licensed under MPL 2.0 (see LICENSE.txt)
- *
- * See README.md for usage and integration instructions.
- */
-
-/*
- * Localization Utilities
- */
-
-export function Localizer() {
-    // Currently configured language
-    this.language = 'en';
-
-    // Current dictionary of translations
-    this.dictionary = undefined;
-}
-
-Localizer.prototype = {
-    // Configure suitable language based on user preferences
-    setup: function (supportedLanguages) {
-        var userLanguages;
-
-        this.language = 'en'; // Default: US English
-
-        /*
-         * Navigator.languages only available in Chrome (32+) and FireFox (32+)
-         * Fall back to navigator.language for other browsers
-         */
-        if (typeof window.navigator.languages == 'object') {
-            userLanguages = window.navigator.languages;
-        } else {
-            userLanguages = [navigator.language || navigator.userLanguage];
-        }
-
-        for (var i = 0;i < userLanguages.length;i++) {
-            var userLang = userLanguages[i];
-            userLang = userLang.toLowerCase();
-            userLang = userLang.replace("_", "-");
-            userLang = userLang.split("-");
-
-            // Built-in default?
-            if ((userLang[0] === 'en') &&
-                ((userLang[1] === undefined) || (userLang[1] === 'us'))) {
-                return;
-            }
-
-            // First pass: perfect match
-            for (var j = 0;j < supportedLanguages.length;j++) {
-                var supLang = supportedLanguages[j];
-                supLang = supLang.toLowerCase();
-                supLang = supLang.replace("_", "-");
-                supLang = supLang.split("-");
-
-                if (userLang[0] !== supLang[0])
-                    continue;
-                if (userLang[1] !== supLang[1])
-                    continue;
-
-                this.language = supportedLanguages[j];
-                return;
-            }
-
-            // Second pass: fallback
-            for (var j = 0;j < supportedLanguages.length;j++) {
-                supLang = supportedLanguages[j];
-                supLang = supLang.toLowerCase();
-                supLang = supLang.replace("_", "-");
-                supLang = supLang.split("-");
-
-                if (userLang[0] !== supLang[0])
-                    continue;
-                if (supLang[1] !== undefined)
-                    continue;
-
-                this.language = supportedLanguages[j];
-                return;
-            }
-        }
-    },
-
-    // Retrieve localised text
-    get: function (id) {
-        if (typeof this.dictionary !== 'undefined' && this.dictionary[id]) {
-            return this.dictionary[id];
-        } else {
-            return id;
-        }
-    },
-
-    // Traverses the DOM and translates relevant fields
-    // See https://html.spec.whatwg.org/multipage/dom.html#attr-translate
-    translateDOM: function () {
-        var self = this;
-        function process(elem, enabled) {
-            function isAnyOf(searchElement, items) {
-                return items.indexOf(searchElement) !== -1;
-            }
-
-            function translateAttribute(elem, attr) {
-                var str = elem.getAttribute(attr);
-                str = self.get(str);
-                elem.setAttribute(attr, str);
-            }
-
-            function translateTextNode(node) {
-                var str = node.data.trim();
-                str = self.get(str);
-                node.data = str;
-            }
-
-            if (elem.hasAttribute("translate")) {
-                if (isAnyOf(elem.getAttribute("translate"), ["", "yes"])) {
-                    enabled = true;
-                } else if (isAnyOf(elem.getAttribute("translate"), ["no"])) {
-                    enabled = false;
-                }
-            }
-
-            if (enabled) {
-                if (elem.hasAttribute("abbr") &&
-                    elem.tagName === "TH") {
-                    translateAttribute(elem, "abbr");
-                }
-                if (elem.hasAttribute("alt") &&
-                    isAnyOf(elem.tagName, ["AREA", "IMG", "INPUT"])) {
-                    translateAttribute(elem, "alt");
-                }
-                if (elem.hasAttribute("download") &&
-                    isAnyOf(elem.tagName, ["A", "AREA"])) {
-                    translateAttribute(elem, "download");
-                }
-                if (elem.hasAttribute("label") &&
-                    isAnyOf(elem.tagName, ["MENUITEM", "MENU", "OPTGROUP",
-                                   "OPTION", "TRACK"])) {
-                    translateAttribute(elem, "label");
-                }
-                // FIXME: Should update "lang"
-                if (elem.hasAttribute("placeholder") &&
-                    isAnyOf(elem.tagName, ["INPUT", "TEXTAREA"])) {
-                    translateAttribute(elem, "placeholder");
-                }
-                if (elem.hasAttribute("title")) {
-                    translateAttribute(elem, "title");
-                }
-                if (elem.hasAttribute("value") &&
-                    elem.tagName === "INPUT" &&
-                    isAnyOf(elem.getAttribute("type"), ["reset", "button", "submit"])) {
-                    translateAttribute(elem, "value");
-                }
-            }
-
-            for (var i = 0;i < elem.childNodes.length;i++) {
-                var node = elem.childNodes[i];
-                if (node.nodeType === node.ELEMENT_NODE) {
-                    process(node, enabled);
-                } else if (node.nodeType === node.TEXT_NODE && enabled) {
-                    translateTextNode(node);
-                }
-            }
-        }
-
-        process(document.body, true);
-    },
-};
-
-export var l10n = new Localizer();
-export default l10n.get.bind(l10n);
diff --git a/public/novnc/app/sounds/CREDITS b/public/novnc/app/sounds/CREDITS
deleted file mode 100644
index ec1fb556..00000000
--- a/public/novnc/app/sounds/CREDITS
+++ /dev/null
@@ -1,4 +0,0 @@
-bell
-        Copyright: Dr. Richard Boulanger et al
-        URL: http://www.archive.org/details/Berklee44v12
-        License: CC-BY Attribution 3.0 Unported
diff --git a/public/novnc/app/sounds/bell.mp3 b/public/novnc/app/sounds/bell.mp3
deleted file mode 100644
index fdbf149a..00000000
Binary files a/public/novnc/app/sounds/bell.mp3 and /dev/null differ
diff --git a/public/novnc/app/sounds/bell.oga b/public/novnc/app/sounds/bell.oga
deleted file mode 100644
index 144d2b36..00000000
Binary files a/public/novnc/app/sounds/bell.oga and /dev/null differ
diff --git a/public/novnc/app/styles/Orbitron700.ttf b/public/novnc/app/styles/Orbitron700.ttf
deleted file mode 100644
index e28729dc..00000000
Binary files a/public/novnc/app/styles/Orbitron700.ttf and /dev/null differ
diff --git a/public/novnc/app/styles/Orbitron700.woff b/public/novnc/app/styles/Orbitron700.woff
deleted file mode 100644
index 61db630c..00000000
Binary files a/public/novnc/app/styles/Orbitron700.woff and /dev/null differ
diff --git a/public/novnc/app/styles/base.css b/public/novnc/app/styles/base.css
deleted file mode 100644
index 344db9b2..00000000
--- a/public/novnc/app/styles/base.css
+++ /dev/null
@@ -1,902 +0,0 @@
-/*
- * noVNC base CSS
- * Copyright (C) 2012 Joel Martin
- * Copyright (C) 2016 Samuel Mannehed for Cendio AB
- * Copyright (C) 2016 Pierre Ossman for Cendio AB
- * noVNC is licensed under the MPL 2.0 (see LICENSE.txt)
- * This file is licensed under the 2-Clause BSD license (see LICENSE.txt).
- */
-
-/*
- * Z index layers:
- *
- * 0: Main screen
- * 10: Control bar
- * 50: Transition blocker
- * 60: Connection popups
- * 100: Status bar
- * ...
- * 1000: Javascript crash
- * ...
- * 10000: Max (used for polyfills)
- */
-
-body {
-  margin:0;
-  padding:0;
-  font-family: Helvetica;
-  /*Background image with light grey curve.*/
-  background-color:#494949;
-  background-repeat:no-repeat;
-  background-position:right bottom;
-  height:100%;
-  touch-action: none;
-}
-
-html {
-  height:100%;
-}
-
-.noVNC_only_touch.noVNC_hidden {
-  display: none;
-}
-
-.noVNC_disabled {
-  color: rgb(128, 128, 128);
-}
-
-/* ----------------------------------------
- * Spinner
- * ----------------------------------------
- */
-
-.noVNC_spinner {
-  position: relative;
-}
-.noVNC_spinner, .noVNC_spinner::before, .noVNC_spinner::after {
-  width: 10px;
-  height: 10px;
-  border-radius: 2px;
-  box-shadow: -60px 10px 0 rgba(255, 255, 255, 0);
-  animation: noVNC_spinner 1.0s linear infinite;
-}
-.noVNC_spinner::before {
-  content: "";
-  position: absolute;
-  left: 0px;
-  top: 0px;
-  animation-delay: -0.1s;
-}
-.noVNC_spinner::after {
-  content: "";
-  position: absolute;
-  top: 0px;
-  left: 0px;
-  animation-delay: 0.1s;
-}
-@keyframes noVNC_spinner {
-  0% { box-shadow: -60px 10px 0 rgba(255, 255, 255, 0); width: 20px; }
-  25% { box-shadow: 20px 10px 0 rgba(255, 255, 255, 1); width: 10px; }
-  50% { box-shadow: 60px 10px 0 rgba(255, 255, 255, 0); width: 10px; }
-}
-
-/* ----------------------------------------
- * Input Elements
- * ----------------------------------------
- */
-
-input[type=input], input[type=password], input[type=number],
-input:not([type]), textarea {
-  /* Disable default rendering */
-  -webkit-appearance: none;
-  -moz-appearance: none;
-  background: none;
-
-  margin: 2px;
-  padding: 2px;
-  border: 1px solid rgb(192, 192, 192);
-  border-radius: 5px;
-  color: black;
-  background: linear-gradient(to top, rgb(255, 255, 255) 80%, rgb(240, 240, 240));
-}
-
-input[type=button], input[type=submit], select {
-  /* Disable default rendering */
-  -webkit-appearance: none;
-  -moz-appearance: none;
-  background: none;
-
-  margin: 2px;
-  padding: 2px;
-  border: 1px solid rgb(192, 192, 192);
-  border-bottom-width: 2px;
-  border-radius: 5px;
-  color: black;
-  background: linear-gradient(to top, rgb(255, 255, 255), rgb(240, 240, 240));
-
-  /* This avoids it jumping around when :active */
-  vertical-align: middle;
-}
-
-input[type=button], input[type=submit] {
-  padding-left: 20px;
-  padding-right: 20px;
-}
-
-option {
-  color: black;
-  background: white;
-}
-
-input[type=input]:focus, input[type=password]:focus,
-input:not([type]):focus, input[type=button]:focus,
-input[type=submit]:focus,
-textarea:focus, select:focus {
-  box-shadow: 0px 0px 3px rgba(74, 144, 217, 0.5);
-  border-color: rgb(74, 144, 217);
-  outline: none;
-}
-
-input[type=button]::-moz-focus-inner,
-input[type=submit]::-moz-focus-inner {
-  border: none;
-}
-
-input[type=input]:disabled, input[type=password]:disabled,
-input:not([type]):disabled, input[type=button]:disabled,
-input[type=submit]:disabled, input[type=number]:disabled,
-textarea:disabled, select:disabled {
-  color: rgb(128, 128, 128);
-  background: rgb(240, 240, 240);
-}
-
-input[type=button]:active, input[type=submit]:active,
-select:active {
-  border-bottom-width: 1px;
-  margin-top: 3px;
-}
-
-:root:not(.noVNC_touch) input[type=button]:hover:not(:disabled),
-:root:not(.noVNC_touch) input[type=submit]:hover:not(:disabled),
-:root:not(.noVNC_touch) select:hover:not(:disabled) {
-  background: linear-gradient(to top, rgb(255, 255, 255), rgb(250, 250, 250));
-}
-
-/* ----------------------------------------
- * WebKit centering hacks
- * ----------------------------------------
- */
-
-.noVNC_center {
-  /*
-   * This is a workaround because webkit misrenders transforms and
-   * uses non-integer coordinates, resulting in blurry content.
-   * Ideally we'd use "top: 50%; transform: translateY(-50%);" on
-   * the objects instead.
-   */
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  position: fixed;
-  top: 0;
-  left: 0;
-  width: 100%;
-  height: 100%;
-  pointer-events: none;
-}
-.noVNC_center > * {
-  pointer-events: auto;
-}
-.noVNC_vcenter {
-  display: flex;
-  flex-direction: column;
-  justify-content: center;
-  position: fixed;
-  top: 0;
-  left: 0;
-  height: 100%;
-  pointer-events: none;
-}
-.noVNC_vcenter > * {
-  pointer-events: auto;
-}
-
-/* ----------------------------------------
- * Layering
- * ----------------------------------------
- */
-
-.noVNC_connect_layer {
-  z-index: 60;
-}
-
-/* ----------------------------------------
- * Fallback error
- * ----------------------------------------
- */
-
-#noVNC_fallback_error {
-  z-index: 1000;
-  visibility: hidden;
-}
-#noVNC_fallback_error.noVNC_open {
-  visibility: visible;
-}
-
-#noVNC_fallback_error > div {
-  max-width: 90%;
-  padding: 15px;
-
-  transition: 0.5s ease-in-out;
-
-  transform: translateY(-50px);
-  opacity: 0;
-
-  text-align: center;
-  font-weight: bold;
-  color: #fff;
-
-  border-radius: 10px;
-  box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5);
-  background: rgba(200,55,55,0.8);
-}
-#noVNC_fallback_error.noVNC_open > div {
-  transform: translateY(0);
-  opacity: 1;
-}
-
-#noVNC_fallback_errormsg {
-  font-weight: normal;
-}
-
-#noVNC_fallback_errormsg .noVNC_message {
-  display: inline-block;
-  text-align: left;
-  font-family: monospace;
-  white-space: pre-wrap;
-}
-
-#noVNC_fallback_error .noVNC_location {
-  font-style: italic;
-  font-size: 0.8em;
-  color: rgba(255, 255, 255, 0.8);
-}
-
-#noVNC_fallback_error .noVNC_stack {
-  max-height: 50vh;
-  padding: 10px;
-  margin: 10px;
-  font-size: 0.8em;
-  text-align: left;
-  font-family: monospace;
-  white-space: pre;
-  border: 1px solid rgba(0, 0, 0, 0.5);
-  background: rgba(0, 0, 0, 0.2);
-  overflow: auto;
-}
-
-/* ----------------------------------------
- * Control Bar
- * ----------------------------------------
- */
-
-#noVNC_control_bar_anchor {
-  /* The anchor is needed to get z-stacking to work */
-  position: fixed;
-  z-index: 10;
-
-  transition: 0.5s ease-in-out;
-
-  /* Edge misrenders animations wihthout this */
-  transform: translateX(0);
-}
-:root.noVNC_connected #noVNC_control_bar_anchor.noVNC_idle {
-  opacity: 0.8;
-}
-#noVNC_control_bar_anchor.noVNC_right {
-  left: auto;
-  right: 0;
-}
-
-#noVNC_control_bar {
-  position: relative;
-  left: -100%;
-
-  transition: 0.5s ease-in-out;
-
-  background-color: rgb(110, 132, 163);
-  border-radius: 0 10px 10px 0;
-
-}
-#noVNC_control_bar.noVNC_open {
-  box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5);
-  left: 0;
-}
-#noVNC_control_bar::before {
-  /* This extra element is to get a proper shadow */
-  content: "";
-  position: absolute;
-  z-index: -1;
-  height: 100%;
-  width: 30px;
-  left: -30px;
-  transition: box-shadow 0.5s ease-in-out;
-}
-#noVNC_control_bar.noVNC_open::before {
-  box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5);
-}
-.noVNC_right #noVNC_control_bar {
-  left: 100%;
-  border-radius: 10px 0 0 10px;
-}
-.noVNC_right #noVNC_control_bar.noVNC_open {
-  left: 0;
-}
-.noVNC_right #noVNC_control_bar::before {
-  visibility: hidden;
-}
-
-#noVNC_control_bar_handle {
-  position: absolute;
-  left: -15px;
-  top: 0;
-  transform: translateY(35px);
-  width: calc(100% + 30px);
-  height: 50px;
-  z-index: -1;
-  cursor: pointer;
-  border-radius: 5px;
-  background-color: rgb(83, 99, 122);
-  background-image: url("../images/handle_bg.svg");
-  background-repeat: no-repeat;
-  background-position: right;
-  box-shadow: 3px 3px 0px rgba(0, 0, 0, 0.5);
-}
-#noVNC_control_bar_handle:after {
-  content: "";
-  transition: transform 0.5s ease-in-out;
-  background: url("../images/handle.svg");
-  position: absolute;
-  top: 22px; /* (50px-6px)/2 */
-  right: 5px;
-  width: 5px;
-  height: 6px;
-}
-#noVNC_control_bar.noVNC_open #noVNC_control_bar_handle:after {
-  transform: translateX(1px) rotate(180deg);
-}
-:root:not(.noVNC_connected) #noVNC_control_bar_handle {
-  display: none;
-}
-.noVNC_right #noVNC_control_bar_handle {
-  background-position: left;
-}
-.noVNC_right #noVNC_control_bar_handle:after {
-  left: 5px;
-  right: 0;
-  transform: translateX(1px) rotate(180deg);
-}
-.noVNC_right #noVNC_control_bar.noVNC_open #noVNC_control_bar_handle:after {
-  transform: none;
-}
-#noVNC_control_bar_handle div {
-  position: absolute;
-  right: -35px;
-  top: 0;
-  width: 50px;
-  height: 50px;
-}
-:root:not(.noVNC_touch) #noVNC_control_bar_handle div {
-  display: none;
-}
-.noVNC_right #noVNC_control_bar_handle div {
-  left: -35px;
-  right: auto;
-}
-
-#noVNC_control_bar .noVNC_scroll {
-  max-height: 100vh; /* Chrome is buggy with 100% */
-  overflow-x: hidden;
-  overflow-y: auto;
-  padding: 0 10px 0 5px;
-}
-.noVNC_right #noVNC_control_bar .noVNC_scroll {
-  padding: 0 5px 0 10px;
-}
-
-/* Control bar hint */
-#noVNC_control_bar_hint {
-  position: fixed;
-  left: calc(100vw - 50px);
-  right: auto;
-  top: 50%;
-  transform: translateY(-50%) scale(0);
-  width: 100px;
-  height: 50%;
-  max-height: 600px;
-
-  visibility: hidden;
-  opacity: 0;
-  transition: 0.2s ease-in-out;
-  background: transparent;
-  box-shadow: 0 0 10px black, inset 0 0 10px 10px rgba(110, 132, 163, 0.8);
-  border-radius: 10px;
-  transition-delay: 0s;
-}
-#noVNC_control_bar_anchor.noVNC_right #noVNC_control_bar_hint{
-  left: auto;
-  right: calc(100vw - 50px);
-}
-#noVNC_control_bar_hint.noVNC_active {
-  visibility: visible;
-  opacity: 1;
-  transition-delay: 0.2s;
-  transform: translateY(-50%) scale(1);
-}
-
-/* General button style */
-.noVNC_button {
-  display: block;
-  padding: 4px 4px;
-  margin: 10px 0;
-  vertical-align: middle;
-  border:1px solid rgba(255, 255, 255, 0.2);
-  border-radius: 6px;
-}
-.noVNC_button.noVNC_selected {
-  border-color: rgba(0, 0, 0, 0.8);
-  background: rgba(0, 0, 0, 0.5);
-}
-.noVNC_button:disabled {
-  opacity: 0.4;
-}
-.noVNC_button:focus {
-  outline: none;
-}
-.noVNC_button:active {
-  padding-top: 5px;
-  padding-bottom: 3px;
-}
-/* Android browsers don't properly update hover state if touch events
- * are intercepted, but focus should be safe to display */
-:root:not(.noVNC_touch) .noVNC_button.noVNC_selected:hover,
-.noVNC_button.noVNC_selected:focus {
-  border-color: rgba(0, 0, 0, 0.4);
-  background: rgba(0, 0, 0, 0.2);
-}
-:root:not(.noVNC_touch) .noVNC_button:hover,
-.noVNC_button:focus {
-  background: rgba(255, 255, 255, 0.2);
-}
-.noVNC_button.noVNC_hidden {
-  display: none;
-}
-
-/* Panels */
-.noVNC_panel {
-  transform: translateX(25px);
-
-  transition: 0.5s ease-in-out;
-
-  max-height: 100vh; /* Chrome is buggy with 100% */
-  overflow-x: hidden;
-  overflow-y: auto;
-
-  visibility: hidden;
-  opacity: 0;
-
-  padding: 15px;
-
-  background: #fff;
-  border-radius: 10px;
-  color: #000;
-  border: 2px solid #E0E0E0;
-  box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5);
-}
-.noVNC_panel.noVNC_open {
-  visibility: visible;
-  opacity: 1;
-  transform: translateX(75px);
-}
-.noVNC_right .noVNC_vcenter {
-  left: auto;
-  right: 0;
-}
-.noVNC_right .noVNC_panel {
-  transform: translateX(-25px);
-}
-.noVNC_right .noVNC_panel.noVNC_open {
-  transform: translateX(-75px);
-}
-
-.noVNC_panel hr {
-  border: none;
-  border-top: 1px solid rgb(192, 192, 192);
-}
-
-.noVNC_panel label {
-  display: block;
-  white-space: nowrap;
-}
-
-.noVNC_panel .noVNC_heading {
-  background-color: rgb(110, 132, 163);
-  border-radius: 5px;
-  padding: 5px;
-  /* Compensate for padding in image */
-  padding-right: 8px;
-  color: white;
-  font-size: 20px;
-  margin-bottom: 10px;
-  white-space: nowrap;
-}
-.noVNC_panel .noVNC_heading img {
-  vertical-align: bottom;
-}
-
-.noVNC_submit {
-  float: right;
-}
-
-/* Expanders */
-.noVNC_expander {
-  cursor: pointer;
-}
-.noVNC_expander::before {
-  content: url("../images/expander.svg");
-  display: inline-block;
-  margin-right: 5px;
-  transition: 0.2s ease-in-out;
-}
-.noVNC_expander.noVNC_open::before {
-  transform: rotateZ(90deg);
-}
-.noVNC_expander ~ * {
-  margin: 5px;
-  margin-left: 10px;
-  padding: 5px;
-  background: rgba(0, 0, 0, 0.05);
-  border-radius: 5px;
-}
-.noVNC_expander:not(.noVNC_open) ~ * {
-  display: none;
-}
-
-/* Control bar content */
-
-#noVNC_control_bar .noVNC_logo {
-  font-size: 13px;
-}
-
-:root:not(.noVNC_connected) #noVNC_view_drag_button {
-  display: none;
-}
-
-/* noVNC Touch Device only buttons */
-:root:not(.noVNC_connected) #noVNC_mobile_buttons {
-  display: none;
-}
-:root:not(.noVNC_touch) #noVNC_mobile_buttons {
-  display: none;
-}
-
-/* Extra manual keys */
-:root:not(.noVNC_connected) #noVNC_extra_keys {
-  display: none;
-}
-
-#noVNC_modifiers {
-  background-color: rgb(92, 92, 92);
-  border: none;
-  padding: 0 10px;
-}
-
-/* Shutdown/Reboot */
-:root:not(.noVNC_connected) #noVNC_power_button {
-  display: none;
-}
-#noVNC_power {
-}
-#noVNC_power_buttons {
-  display: none;
-}
-
-#noVNC_power input[type=button] {
-  width: 100%;
-}
-
-/* Clipboard */
-:root:not(.noVNC_connected) #noVNC_clipboard_button {
-  display: none;
-}
-#noVNC_clipboard {
-  /* Full screen, minus padding and left and right margins */
-  max-width: calc(100vw - 2*15px - 75px - 25px);
-}
-#noVNC_clipboard_text {
-  width: 500px;
-  max-width: 100%;
-}
-
-/* Settings */
-#noVNC_settings {
-}
-#noVNC_settings ul {
-  list-style: none;
-  margin: 0px;
-  padding: 0px;
-}
-#noVNC_setting_port {
-  width: 80px;
-}
-#noVNC_setting_path {
-  width: 100px;
-}
-
-/* Connection Controls */
-:root:not(.noVNC_connected) #noVNC_disconnect_button {
-  display: none;
-}
-
-/* ----------------------------------------
- * Status Dialog
- * ----------------------------------------
- */
-
-#noVNC_status {
-  position: fixed;
-  top: 0;
-  left: 0;
-  width: 100%;
-  z-index: 100;
-  transform: translateY(-100%);
-
-  cursor: pointer;
-
-  transition: 0.5s ease-in-out;
-
-  visibility: hidden;
-  opacity: 0;
-
-  padding: 5px;
-
-  display: flex;
-  flex-direction: row;
-  justify-content: center;
-  align-content: center;
-
-  line-height: 25px;
-  word-wrap: break-word;
-  color: #fff;
-
-  border-bottom: 1px solid rgba(0, 0, 0, 0.9);
-}
-#noVNC_status.noVNC_open {
-  transform: translateY(0);
-  visibility: visible;
-  opacity: 1;
-}
-
-#noVNC_status::before {
-  content: "";
-  display: inline-block;
-  width: 25px;
-  height: 25px;
-  margin-right: 5px;
-}
-
-#noVNC_status.noVNC_status_normal {
-  background: rgba(128,128,128,0.9);
-}
-#noVNC_status.noVNC_status_normal::before {
-  content: url("../images/info.svg") " ";
-}
-#noVNC_status.noVNC_status_error {
-  background: rgba(200,55,55,0.9);
-}
-#noVNC_status.noVNC_status_error::before {
-  content: url("../images/error.svg") " ";
-}
-#noVNC_status.noVNC_status_warn {
-  background: rgba(180,180,30,0.9);
-}
-#noVNC_status.noVNC_status_warn::before {
-  content: url("../images/warning.svg") " ";
-}
-
-/* ----------------------------------------
- * Connect Dialog
- * ----------------------------------------
- */
-
-#noVNC_connect_dlg {
-  transition: 0.5s ease-in-out;
-
-  transform: scale(0, 0);
-  visibility: hidden;
-  opacity: 0;
-}
-#noVNC_connect_dlg.noVNC_open {
-  transform: scale(1, 1);
-  visibility: visible;
-  opacity: 1;
-}
-#noVNC_connect_dlg .noVNC_logo {
-  transition: 0.5s ease-in-out;
-  padding: 10px;
-  margin-bottom: 10px;
-
-  font-size: 80px;
-  text-align: center;
-
-  border-radius: 5px;
-}
-@media (max-width: 440px) {
-  #noVNC_connect_dlg {
-    max-width: calc(100vw - 100px);
-  }
-  #noVNC_connect_dlg .noVNC_logo {
-    font-size: calc(25vw - 30px);
-  }
-}
-#noVNC_connect_button {
-  cursor: pointer;
-
-  padding: 10px;
-
-  color: white;
-  background-color: rgb(110, 132, 163);
-  border-radius: 12px;
-
-  text-align: center;
-  font-size: 20px;
-
-  box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5);
-}
-#noVNC_connect_button div {
-  margin: 2px;
-  padding: 5px 30px;
-  border: 1px solid rgb(83, 99, 122);
-  border-bottom-width: 2px;
-  border-radius: 5px;
-  background: linear-gradient(to top, rgb(110, 132, 163), rgb(99, 119, 147));
-
-  /* This avoids it jumping around when :active */
-  vertical-align: middle;
-}
-#noVNC_connect_button div:active {
-  border-bottom-width: 1px;
-  margin-top: 3px;
-}
-:root:not(.noVNC_touch) #noVNC_connect_button div:hover {
-  background: linear-gradient(to top, rgb(110, 132, 163), rgb(105, 125, 155));
-}
-
-#noVNC_connect_button img {
-  vertical-align: bottom;
-  height: 1.3em;
-}
-
-/* ----------------------------------------
- * Password Dialog
- * ----------------------------------------
- */
-
-#noVNC_password_dlg {
-  position: relative;
-
-  transform: translateY(-50px);
-}
-#noVNC_password_dlg.noVNC_open {
-  transform: translateY(0);
-}
-#noVNC_password_dlg ul {
-  list-style: none;
-  margin: 0px;
-  padding: 0px;
-}
-
-/* ----------------------------------------
- * Main Area
- * ----------------------------------------
- */
-
-/* Transition screen */
-#noVNC_transition {
-  display: none;
-
-  position: fixed;
-  top: 0;
-  left: 0;
-  bottom: 0;
-  right: 0;
-
-  color: white;
-  background: rgba(0, 0, 0, 0.5);
-  z-index: 50;
-
-  /*display: flex;*/
-  align-items: center;
-  justify-content: center;
-  flex-direction: column;
-}
-:root.noVNC_loading #noVNC_transition,
-:root.noVNC_connecting #noVNC_transition,
-:root.noVNC_disconnecting #noVNC_transition,
-:root.noVNC_reconnecting #noVNC_transition {
-  display: flex;
-}
-:root:not(.noVNC_reconnecting) #noVNC_cancel_reconnect_button {
-  display: none;
-}
-#noVNC_transition_text {
-  font-size: 1.5em;
-}
-
-/* Main container */
-#noVNC_container {
-  width: 100%;
-  height: 100%;
-  background-color: #313131;
-  border-bottom-right-radius: 800px 600px;
-  /*border-top-left-radius: 800px 600px;*/
-}
-
-#noVNC_keyboardinput {
-  width: 1px;
-  height: 1px;
-  background-color: #fff;
-  color: #fff;
-  border: 0;
-  position: absolute;
-  left: -40px;
-  z-index: -1;
-  ime-mode: disabled;
-}
-
-/*Default noVNC logo.*/
-/* From: http://fonts.googleapis.com/css?family=Orbitron:700 */
-@font-face {
-  font-family: 'Orbitron';
-  font-style: normal;
-  font-weight: 700;
-  src: local('?'), url('Orbitron700.woff') format('woff'),
-                   url('Orbitron700.ttf') format('truetype');
-}
-
-.noVNC_logo {
-  color:yellow;
-  font-family: 'Orbitron', 'OrbitronTTF', sans-serif;
-  line-height:90%;
-  text-shadow: 0.1em 0.1em 0 black;
-}
-.noVNC_logo span{
-  color:green;
-}
-
-#noVNC_bell {
-  display: none;
-}
-
-/* ----------------------------------------
- * Media sizing
- * ----------------------------------------
- */
-
-@media screen and (max-width: 640px){
-  #noVNC_logo {
-    font-size: 150px;
-  }
-}
-
-@media screen and (min-width: 321px) and (max-width: 480px) {
-  #noVNC_logo {
-    font-size: 110px;
-  }
-}
-
-@media screen and (max-width: 320px) {
-  #noVNC_logo {
-    font-size: 90px;
-  }
-}
diff --git a/public/novnc/app/styles/lite.css b/public/novnc/app/styles/lite.css
deleted file mode 100644
index 13e11c7e..00000000
--- a/public/novnc/app/styles/lite.css
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * noVNC auto CSS
- * Copyright (C) 2012 Joel Martin
- * Copyright (C) 2017 Samuel Mannehed for Cendio AB
- * noVNC is licensed under the MPL 2.0 (see LICENSE.txt)
- * This file is licensed under the 2-Clause BSD license (see LICENSE.txt).
- */
-
-body {
-  margin:0;
-  background-color:#313131;
-  border-bottom-right-radius: 800px 600px;
-  height:100%;
-  display: flex;
-  flex-direction: column;
-}
-
-html {
-  background-color:#494949;
-  height:100%;
-}
-
-#noVNC_status_bar {
-  width: 100%;
-  display:flex;
-  justify-content: space-between;
-}
-
-#noVNC_status {
-  color: #fff;
-  font: bold 12px Helvetica;
-  margin: auto;
-}
-
-.noVNC_status_normal {
-  background: linear-gradient(#b2bdcd 0%,#899cb3 49%,#7e93af 51%,#6e84a3 100%);
-}
-
-.noVNC_status_error {
-  background: linear-gradient(#c83737 0%,#899cb3 49%,#7e93af 51%,#6e84a3 100%);
-}
-
-.noVNC_status_warn {
-  background: linear-gradient(#b4b41e 0%,#899cb3 49%,#7e93af 51%,#6e84a3 100%);
-}
-
-.noNVC_shown {
-  display: inline;
-}
-.noVNC_hidden {
-  display: none;
-}
-
-#noVNC_left_dummy_elem {
-  flex: 1;
-}
-
-#noVNC_buttons {
-  padding: 1px;
-  flex: 1;
-  display: flex;
-  justify-content: flex-end;
-}
diff --git a/public/novnc/app/ui.js b/public/novnc/app/ui.js
deleted file mode 100644
index 2218d241..00000000
--- a/public/novnc/app/ui.js
+++ /dev/null
@@ -1,1669 +0,0 @@
-/*
- * noVNC: HTML5 VNC client
- * Copyright (C) 2012 Joel Martin
- * Copyright (C) 2016 Samuel Mannehed for Cendio AB
- * Copyright (C) 2016 Pierre Ossman for Cendio AB
- * Licensed under MPL 2.0 (see LICENSE.txt)
- *
- * See README.md for usage and integration instructions.
- */
-
-import * as Log from '../core/util/logging.js';
-import _, { l10n } from './localization.js';
-import { isTouchDevice } from '../core/util/browser.js';
-import { setCapture, getPointerEvent } from '../core/util/events.js';
-import KeyTable from "../core/input/keysym.js";
-import keysyms from "../core/input/keysymdef.js";
-import Keyboard from "../core/input/keyboard.js";
-import RFB from "../core/rfb.js";
-import Display from "../core/display.js";
-import * as WebUtil from "./webutil.js";
-
-var UI = {
-
-    connected: false,
-    desktopName: "",
-
-    statusTimeout: null,
-    hideKeyboardTimeout: null,
-    idleControlbarTimeout: null,
-    closeControlbarTimeout: null,
-
-    controlbarGrabbed: false,
-    controlbarDrag: false,
-    controlbarMouseDownClientY: 0,
-    controlbarMouseDownOffsetY: 0,
-
-    isSafari: false,
-    lastKeyboardinput: null,
-    defaultKeyboardinputLen: 100,
-
-    inhibit_reconnect: true,
-    reconnect_callback: null,
-    reconnect_password: null,
-
-    prime: function(callback) {
-        if (document.readyState === "interactive" || document.readyState === "complete") {
-            UI.load(callback);
-        } else {
-            document.addEventListener('DOMContentLoaded', UI.load.bind(UI, callback));
-        }
-    },
-
-    // Setup rfb object, load settings from browser storage, then call
-    // UI.init to setup the UI/menus
-    load: function(callback) {
-        WebUtil.initSettings(UI.start, callback);
-    },
-
-    // Render default UI and initialize settings menu
-    start: function(callback) {
-
-        // Setup global variables first
-        UI.isSafari = (navigator.userAgent.indexOf('Safari') !== -1 &&
-                       navigator.userAgent.indexOf('Chrome') === -1);
-
-        UI.initSettings();
-
-        // Translate the DOM
-        l10n.translateDOM();
-
-        // Adapt the interface for touch screen devices
-        if (isTouchDevice) {
-            document.documentElement.classList.add("noVNC_touch");
-            // Remove the address bar
-            setTimeout(function() { window.scrollTo(0, 1); }, 100);
-        }
-
-        // Restore control bar position
-        if (WebUtil.readSetting('controlbar_pos') === 'right') {
-            UI.toggleControlbarSide();
-        }
-
-        UI.initFullscreen();
-
-        // Setup event handlers
-        UI.addControlbarHandlers();
-        UI.addTouchSpecificHandlers();
-        UI.addExtraKeysHandlers();
-        UI.addMachineHandlers();
-        UI.addConnectionControlHandlers();
-        UI.addClipboardHandlers();
-        UI.addSettingsHandlers();
-        document.getElementById("noVNC_status")
-            .addEventListener('click', UI.hideStatus);
-
-        // Bootstrap fallback input handler
-        UI.keyboardinputReset();
-
-        UI.openControlbar();
-
-        UI.updateVisualState('init');
-
-        document.documentElement.classList.remove("noVNC_loading");
-
-        var autoconnect = WebUtil.getConfigVar('autoconnect', false);
-        if (autoconnect === 'true' || autoconnect == '1') {
-            autoconnect = true;
-            UI.connect();
-        } else {
-            autoconnect = false;
-            // Show the connect panel on first load unless autoconnecting
-            UI.openConnectPanel();
-        }
-
-        if (typeof callback === "function") {
-            callback(UI.rfb);
-        }
-    },
-
-    initFullscreen: function() {
-        // Only show the button if fullscreen is properly supported
-        // * Safari doesn't support alphanumerical input while in fullscreen
-        if (!UI.isSafari &&
-            (document.documentElement.requestFullscreen ||
-             document.documentElement.mozRequestFullScreen ||
-             document.documentElement.webkitRequestFullscreen ||
-             document.body.msRequestFullscreen)) {
-            document.getElementById('noVNC_fullscreen_button')
-                .classList.remove("noVNC_hidden");
-            UI.addFullscreenHandlers();
-        }
-    },
-
-    initSettings: function() {
-        var i;
-
-        // Logging selection dropdown
-        var llevels = ['error', 'warn', 'info', 'debug'];
-        for (i = 0; i < llevels.length; i += 1) {
-            UI.addOption(document.getElementById('noVNC_setting_logging'),llevels[i], llevels[i]);
-        }
-
-        // Settings with immediate effects
-        UI.initSetting('logging', 'warn');
-        UI.updateLogging();
-
-        // if port == 80 (or 443) then it won't be present and should be
-        // set manually
-        var port = window.location.port;
-        if (!port) {
-            if (window.location.protocol.substring(0,5) == 'https') {
-                port = 443;
-            }
-            else if (window.location.protocol.substring(0,4) == 'http') {
-                port = 80;
-            }
-        }
-
-        /* Populate the controls if defaults are provided in the URL */
-        UI.initSetting('host', window.location.hostname);
-        UI.initSetting('port', port);
-        UI.initSetting('encrypt', (window.location.protocol === "https:"));
-        UI.initSetting('view_clip', false);
-        UI.initSetting('resize', 'off');
-        UI.initSetting('shared', true);
-        UI.initSetting('view_only', false);
-        UI.initSetting('path', 'websockify');
-        UI.initSetting('repeaterID', '');
-        UI.initSetting('reconnect', false);
-        UI.initSetting('reconnect_delay', 5000);
-
-        UI.setupSettingLabels();
-    },
-    // Adds a link to the label elements on the corresponding input elements
-    setupSettingLabels: function() {
-        var labels = document.getElementsByTagName('LABEL');
-        for (var i = 0; i < labels.length; i++) {
-            var htmlFor = labels[i].htmlFor;
-            if (htmlFor != '') {
-                var elem = document.getElementById(htmlFor);
-                if (elem) elem.label = labels[i];
-            } else {
-                // If 'for' isn't set, use the first input element child
-                var children = labels[i].children;
-                for (var j = 0; j < children.length; j++) {
-                    if (children[j].form !== undefined) {
-                        children[j].label = labels[i];
-                        break;
-                    }
-                }
-            }
-        }
-    },
-
-/* ------^-------
-*     /INIT
-* ==============
-* EVENT HANDLERS
-* ------v------*/
-
-    addControlbarHandlers: function() {
-        document.getElementById("noVNC_control_bar")
-            .addEventListener('mousemove', UI.activateControlbar);
-        document.getElementById("noVNC_control_bar")
-            .addEventListener('mouseup', UI.activateControlbar);
-        document.getElementById("noVNC_control_bar")
-            .addEventListener('mousedown', UI.activateControlbar);
-        document.getElementById("noVNC_control_bar")
-            .addEventListener('keydown', UI.activateControlbar);
-
-        document.getElementById("noVNC_control_bar")
-            .addEventListener('mousedown', UI.keepControlbar);
-        document.getElementById("noVNC_control_bar")
-            .addEventListener('keydown', UI.keepControlbar);
-
-        document.getElementById("noVNC_view_drag_button")
-            .addEventListener('click', UI.toggleViewDrag);
-
-        document.getElementById("noVNC_control_bar_handle")
-            .addEventListener('mousedown', UI.controlbarHandleMouseDown);
-        document.getElementById("noVNC_control_bar_handle")
-            .addEventListener('mouseup', UI.controlbarHandleMouseUp);
-        document.getElementById("noVNC_control_bar_handle")
-            .addEventListener('mousemove', UI.dragControlbarHandle);
-        // resize events aren't available for elements
-        window.addEventListener('resize', UI.updateControlbarHandle);
-
-        var exps = document.getElementsByClassName("noVNC_expander");
-        for (var i = 0;i < exps.length;i++) {
-            exps[i].addEventListener('click', UI.toggleExpander);
-        }
-    },
-
-    addTouchSpecificHandlers: function() {
-        document.getElementById("noVNC_mouse_button0")
-            .addEventListener('click', function () { UI.setMouseButton(1); });
-        document.getElementById("noVNC_mouse_button1")
-            .addEventListener('click', function () { UI.setMouseButton(2); });
-        document.getElementById("noVNC_mouse_button2")
-            .addEventListener('click', function () { UI.setMouseButton(4); });
-        document.getElementById("noVNC_mouse_button4")
-            .addEventListener('click', function () { UI.setMouseButton(0); });
-        document.getElementById("noVNC_keyboard_button")
-            .addEventListener('click', UI.toggleVirtualKeyboard);
-
-        UI.touchKeyboard = new Keyboard(document.getElementById('noVNC_keyboardinput'));
-        UI.touchKeyboard.onkeyevent = UI.keyEvent;
-        UI.touchKeyboard.grab();
-        document.getElementById("noVNC_keyboardinput")
-            .addEventListener('input', UI.keyInput);
-        document.getElementById("noVNC_keyboardinput")
-            .addEventListener('focus', UI.onfocusVirtualKeyboard);
-        document.getElementById("noVNC_keyboardinput")
-            .addEventListener('blur', UI.onblurVirtualKeyboard);
-        document.getElementById("noVNC_keyboardinput")
-            .addEventListener('submit', function () { return false; });
-
-        document.documentElement
-            .addEventListener('mousedown', UI.keepVirtualKeyboard, true);
-
-        document.getElementById("noVNC_control_bar")
-            .addEventListener('touchstart', UI.activateControlbar);
-        document.getElementById("noVNC_control_bar")
-            .addEventListener('touchmove', UI.activateControlbar);
-        document.getElementById("noVNC_control_bar")
-            .addEventListener('touchend', UI.activateControlbar);
-        document.getElementById("noVNC_control_bar")
-            .addEventListener('input', UI.activateControlbar);
-
-        document.getElementById("noVNC_control_bar")
-            .addEventListener('touchstart', UI.keepControlbar);
-        document.getElementById("noVNC_control_bar")
-            .addEventListener('input', UI.keepControlbar);
-
-        document.getElementById("noVNC_control_bar_handle")
-            .addEventListener('touchstart', UI.controlbarHandleMouseDown);
-        document.getElementById("noVNC_control_bar_handle")
-            .addEventListener('touchend', UI.controlbarHandleMouseUp);
-        document.getElementById("noVNC_control_bar_handle")
-            .addEventListener('touchmove', UI.dragControlbarHandle);
-    },
-
-    addExtraKeysHandlers: function() {
-        document.getElementById("noVNC_toggle_extra_keys_button")
-            .addEventListener('click', UI.toggleExtraKeys);
-        document.getElementById("noVNC_toggle_ctrl_button")
-            .addEventListener('click', UI.toggleCtrl);
-        document.getElementById("noVNC_toggle_alt_button")
-            .addEventListener('click', UI.toggleAlt);
-        document.getElementById("noVNC_send_tab_button")
-            .addEventListener('click', UI.sendTab);
-        document.getElementById("noVNC_send_esc_button")
-            .addEventListener('click', UI.sendEsc);
-        document.getElementById("noVNC_send_ctrl_alt_del_button")
-            .addEventListener('click', UI.sendCtrlAltDel);
-    },
-
-    addMachineHandlers: function() {
-        document.getElementById("noVNC_shutdown_button")
-            .addEventListener('click', function() { UI.rfb.machineShutdown(); });
-        document.getElementById("noVNC_reboot_button")
-            .addEventListener('click', function() { UI.rfb.machineReboot(); });
-        document.getElementById("noVNC_reset_button")
-            .addEventListener('click', function() { UI.rfb.machineReset(); });
-        document.getElementById("noVNC_power_button")
-            .addEventListener('click', UI.togglePowerPanel);
-    },
-
-    addConnectionControlHandlers: function() {
-        document.getElementById("noVNC_disconnect_button")
-            .addEventListener('click', UI.disconnect);
-        document.getElementById("noVNC_connect_button")
-            .addEventListener('click', UI.connect);
-        document.getElementById("noVNC_cancel_reconnect_button")
-            .addEventListener('click', UI.cancelReconnect);
-
-        document.getElementById("noVNC_password_button")
-            .addEventListener('click', UI.setPassword);
-    },
-
-    addClipboardHandlers: function() {
-        document.getElementById("noVNC_clipboard_button")
-            .addEventListener('click', UI.toggleClipboardPanel);
-        document.getElementById("noVNC_clipboard_text")
-            .addEventListener('change', UI.clipboardSend);
-        document.getElementById("noVNC_clipboard_clear_button")
-            .addEventListener('click', UI.clipboardClear);
-    },
-
-    // Add a call to save settings when the element changes,
-    // unless the optional parameter changeFunc is used instead.
-    addSettingChangeHandler: function(name, changeFunc) {
-        var settingElem = document.getElementById("noVNC_setting_" + name);
-        if (changeFunc === undefined) {
-            changeFunc = function () { UI.saveSetting(name); };
-        }
-        settingElem.addEventListener('change', changeFunc);
-    },
-
-    addSettingsHandlers: function() {
-        document.getElementById("noVNC_settings_button")
-            .addEventListener('click', UI.toggleSettingsPanel);
-
-        UI.addSettingChangeHandler('encrypt');
-        UI.addSettingChangeHandler('resize');
-        UI.addSettingChangeHandler('resize', UI.enableDisableViewClip);
-        UI.addSettingChangeHandler('resize', UI.applyResizeMode);
-        UI.addSettingChangeHandler('view_clip');
-        UI.addSettingChangeHandler('view_clip', UI.updateViewClip);
-        UI.addSettingChangeHandler('shared');
-        UI.addSettingChangeHandler('view_only');
-        UI.addSettingChangeHandler('view_only', UI.updateViewOnly);
-        UI.addSettingChangeHandler('host');
-        UI.addSettingChangeHandler('port');
-        UI.addSettingChangeHandler('path');
-        UI.addSettingChangeHandler('repeaterID');
-        UI.addSettingChangeHandler('logging');
-        UI.addSettingChangeHandler('logging', UI.updateLogging);
-        UI.addSettingChangeHandler('reconnect');
-        UI.addSettingChangeHandler('reconnect_delay');
-    },
-
-    addFullscreenHandlers: function() {
-        document.getElementById("noVNC_fullscreen_button")
-            .addEventListener('click', UI.toggleFullscreen);
-
-        window.addEventListener('fullscreenchange', UI.updateFullscreenButton);
-        window.addEventListener('mozfullscreenchange', UI.updateFullscreenButton);
-        window.addEventListener('webkitfullscreenchange', UI.updateFullscreenButton);
-        window.addEventListener('msfullscreenchange', UI.updateFullscreenButton);
-    },
-
-/* ------^-------
- * /EVENT HANDLERS
- * ==============
- *     VISUAL
- * ------v------*/
-
-    // Disable/enable controls depending on connection state
-    updateVisualState: function(state) {
-
-        document.documentElement.classList.remove("noVNC_connecting");
-        document.documentElement.classList.remove("noVNC_connected");
-        document.documentElement.classList.remove("noVNC_disconnecting");
-        document.documentElement.classList.remove("noVNC_reconnecting");
-
-        let transition_elem = document.getElementById("noVNC_transition_text");
-        switch (state) {
-            case 'init':
-                break;
-            case 'connecting':
-                transition_elem.textContent = _("Connecting...");
-                document.documentElement.classList.add("noVNC_connecting");
-                break;
-            case 'connected':
-                document.documentElement.classList.add("noVNC_connected");
-                break;
-            case 'disconnecting':
-                transition_elem.textContent = _("Disconnecting...");
-                document.documentElement.classList.add("noVNC_disconnecting");
-                break;
-            case 'disconnected':
-                break;
-            case 'reconnecting':
-                transition_elem.textContent = _("Reconnecting...");
-                document.documentElement.classList.add("noVNC_reconnecting");
-                break;
-            default:
-                Log.Error("Invalid visual state: " + state);
-                UI.showStatus(_("Internal error"), 'error');
-                return;
-        }
-
-        UI.enableDisableViewClip();
-
-        if (UI.connected) {
-            UI.disableSetting('encrypt');
-            UI.disableSetting('shared');
-            UI.disableSetting('host');
-            UI.disableSetting('port');
-            UI.disableSetting('path');
-            UI.disableSetting('repeaterID');
-            UI.setMouseButton(1);
-
-            // Hide the controlbar after 2 seconds
-            UI.closeControlbarTimeout = setTimeout(UI.closeControlbar, 2000);
-        } else {
-            UI.enableSetting('encrypt');
-            UI.enableSetting('shared');
-            UI.enableSetting('host');
-            UI.enableSetting('port');
-            UI.enableSetting('path');
-            UI.enableSetting('repeaterID');
-            UI.updatePowerButton();
-            UI.keepControlbar();
-        }
-
-        // State change disables viewport dragging.
-        // It is enabled (toggled) by direct click on the button
-        UI.setViewDrag(false);
-
-        // State change also closes the password dialog
-        document.getElementById('noVNC_password_dlg')
-            .classList.remove('noVNC_open');
-    },
-
-    showStatus: function(text, status_type, time) {
-        var statusElem = document.getElementById('noVNC_status');
-
-        clearTimeout(UI.statusTimeout);
-
-        if (typeof status_type === 'undefined') {
-            status_type = 'normal';
-        }
-
-        // Don't overwrite more severe visible statuses and never
-        // errors. Only shows the first error.
-        let visible_status_type = 'none';
-        if (statusElem.classList.contains("noVNC_open")) {
-            if (statusElem.classList.contains("noVNC_status_error")) {
-                visible_status_type = 'error';
-            } else if (statusElem.classList.contains("noVNC_status_warn")) {
-                visible_status_type = 'warn';
-            } else {
-                visible_status_type = 'normal';
-            }
-        }
-        if (visible_status_type === 'error' ||
-            (visible_status_type === 'warn' && status_type === 'normal')) {
-            return;
-        }
-
-        switch (status_type) {
-            case 'error':
-                statusElem.classList.remove("noVNC_status_warn");
-                statusElem.classList.remove("noVNC_status_normal");
-                statusElem.classList.add("noVNC_status_error");
-                break;
-            case 'warning':
-            case 'warn':
-                statusElem.classList.remove("noVNC_status_error");
-                statusElem.classList.remove("noVNC_status_normal");
-                statusElem.classList.add("noVNC_status_warn");
-                break;
-            case 'normal':
-            case 'info':
-            default:
-                statusElem.classList.remove("noVNC_status_error");
-                statusElem.classList.remove("noVNC_status_warn");
-                statusElem.classList.add("noVNC_status_normal");
-                break;
-        }
-
-        statusElem.textContent = text;
-        statusElem.classList.add("noVNC_open");
-
-        // If no time was specified, show the status for 1.5 seconds
-        if (typeof time === 'undefined') {
-            time = 1500;
-        }
-
-        // Error messages do not timeout
-        if (status_type !== 'error') {
-            UI.statusTimeout = window.setTimeout(UI.hideStatus, time);
-        }
-    },
-
-    hideStatus: function() {
-        clearTimeout(UI.statusTimeout);
-        document.getElementById('noVNC_status').classList.remove("noVNC_open");
-    },
-
-    activateControlbar: function(event) {
-        clearTimeout(UI.idleControlbarTimeout);
-        // We manipulate the anchor instead of the actual control
-        // bar in order to avoid creating new a stacking group
-        document.getElementById('noVNC_control_bar_anchor')
-            .classList.remove("noVNC_idle");
-        UI.idleControlbarTimeout = window.setTimeout(UI.idleControlbar, 2000);
-    },
-
-    idleControlbar: function() {
-        document.getElementById('noVNC_control_bar_anchor')
-            .classList.add("noVNC_idle");
-    },
-
-    keepControlbar: function() {
-        clearTimeout(UI.closeControlbarTimeout);
-    },
-
-    openControlbar: function() {
-        document.getElementById('noVNC_control_bar')
-            .classList.add("noVNC_open");
-    },
-
-    closeControlbar: function() {
-        UI.closeAllPanels();
-        document.getElementById('noVNC_control_bar')
-            .classList.remove("noVNC_open");
-    },
-
-    toggleControlbar: function() {
-        if (document.getElementById('noVNC_control_bar')
-            .classList.contains("noVNC_open")) {
-            UI.closeControlbar();
-        } else {
-            UI.openControlbar();
-        }
-    },
-
-    toggleControlbarSide: function () {
-        // Temporarily disable animation to avoid weird movement
-        var bar = document.getElementById('noVNC_control_bar');
-        bar.style.transitionDuration = '0s';
-        bar.addEventListener('transitionend', function () { this.style.transitionDuration = ""; });
-
-        var anchor = document.getElementById('noVNC_control_bar_anchor');
-        if (anchor.classList.contains("noVNC_right")) {
-            WebUtil.writeSetting('controlbar_pos', 'left');
-            anchor.classList.remove("noVNC_right");
-        } else {
-            WebUtil.writeSetting('controlbar_pos', 'right');
-            anchor.classList.add("noVNC_right");
-        }
-
-        // Consider this a movement of the handle
-        UI.controlbarDrag = true;
-    },
-
-    showControlbarHint: function (show) {
-        var hint = document.getElementById('noVNC_control_bar_hint');
-        if (show) {
-            hint.classList.add("noVNC_active");
-        } else {
-            hint.classList.remove("noVNC_active");
-        }
-    },
-
-    dragControlbarHandle: function (e) {
-        if (!UI.controlbarGrabbed) return;
-
-        var ptr = getPointerEvent(e);
-
-        var anchor = document.getElementById('noVNC_control_bar_anchor');
-        if (ptr.clientX < (window.innerWidth * 0.1)) {
-            if (anchor.classList.contains("noVNC_right")) {
-                UI.toggleControlbarSide();
-            }
-        } else if (ptr.clientX > (window.innerWidth * 0.9)) {
-            if (!anchor.classList.contains("noVNC_right")) {
-                UI.toggleControlbarSide();
-            }
-        }
-
-        if (!UI.controlbarDrag) {
-            // The goal is to trigger on a certain physical width, the
-            // devicePixelRatio brings us a bit closer but is not optimal.
-            var dragThreshold = 10 * (window.devicePixelRatio || 1);
-            var dragDistance = Math.abs(ptr.clientY - UI.controlbarMouseDownClientY);
-
-            if (dragDistance < dragThreshold) return;
-
-            UI.controlbarDrag = true;
-        }
-
-        var eventY = ptr.clientY - UI.controlbarMouseDownOffsetY;
-
-        UI.moveControlbarHandle(eventY);
-
-        e.preventDefault();
-        e.stopPropagation();
-        UI.keepControlbar();
-        UI.activateControlbar();
-    },
-
-    // Move the handle but don't allow any position outside the bounds
-    moveControlbarHandle: function (viewportRelativeY) {
-        var handle = document.getElementById("noVNC_control_bar_handle");
-        var handleHeight = handle.getBoundingClientRect().height;
-        var controlbarBounds = document.getElementById("noVNC_control_bar")
-            .getBoundingClientRect();
-        var margin = 10;
-
-        // These heights need to be non-zero for the below logic to work
-        if (handleHeight === 0 || controlbarBounds.height === 0) {
-            return;
-        }
-
-        var newY = viewportRelativeY;
-
-        // Check if the coordinates are outside the control bar
-        if (newY < controlbarBounds.top + margin) {
-            // Force coordinates to be below the top of the control bar
-            newY = controlbarBounds.top + margin;
-
-        } else if (newY > controlbarBounds.top +
-                   controlbarBounds.height - handleHeight - margin) {
-            // Force coordinates to be above the bottom of the control bar
-            newY = controlbarBounds.top +
-                controlbarBounds.height - handleHeight - margin;
-        }
-
-        // Corner case: control bar too small for stable position
-        if (controlbarBounds.height < (handleHeight + margin * 2)) {
-            newY = controlbarBounds.top +
-                (controlbarBounds.height - handleHeight) / 2;
-        }
-
-        // The transform needs coordinates that are relative to the parent
-        var parentRelativeY = newY - controlbarBounds.top;
-        handle.style.transform = "translateY(" + parentRelativeY + "px)";
-    },
-
-    updateControlbarHandle: function () {
-        // Since the control bar is fixed on the viewport and not the page,
-        // the move function expects coordinates relative the the viewport.
-        var handle = document.getElementById("noVNC_control_bar_handle");
-        var handleBounds = handle.getBoundingClientRect();
-        UI.moveControlbarHandle(handleBounds.top);
-    },
-
-    controlbarHandleMouseUp: function(e) {
-        if ((e.type == "mouseup") && (e.button != 0)) return;
-
-        // mouseup and mousedown on the same place toggles the controlbar
-        if (UI.controlbarGrabbed && !UI.controlbarDrag) {
-            UI.toggleControlbar();
-            e.preventDefault();
-            e.stopPropagation();
-            UI.keepControlbar();
-            UI.activateControlbar();
-        }
-        UI.controlbarGrabbed = false;
-        UI.showControlbarHint(false);
-    },
-
-    controlbarHandleMouseDown: function(e) {
-        if ((e.type == "mousedown") && (e.button != 0)) return;
-
-        var ptr = getPointerEvent(e);
-
-        var handle = document.getElementById("noVNC_control_bar_handle");
-        var bounds = handle.getBoundingClientRect();
-
-        // Touch events have implicit capture
-        if (e.type === "mousedown") {
-            setCapture(handle);
-        }
-
-        UI.controlbarGrabbed = true;
-        UI.controlbarDrag = false;
-
-        UI.showControlbarHint(true);
-
-        UI.controlbarMouseDownClientY = ptr.clientY;
-        UI.controlbarMouseDownOffsetY = ptr.clientY - bounds.top;
-        e.preventDefault();
-        e.stopPropagation();
-        UI.keepControlbar();
-        UI.activateControlbar();
-    },
-
-    toggleExpander: function(e) {
-        if (this.classList.contains("noVNC_open")) {
-            this.classList.remove("noVNC_open");
-        } else {
-            this.classList.add("noVNC_open");
-        }
-    },
-
-/* ------^-------
- *    /VISUAL
- * ==============
- *    SETTINGS
- * ------v------*/
-
-    // Initial page load read/initialization of settings
-    initSetting: function(name, defVal) {
-        // Check Query string followed by cookie
-        var val = WebUtil.getConfigVar(name);
-        if (val === null) {
-            val = WebUtil.readSetting(name, defVal);
-        }
-        UI.updateSetting(name, val);
-        return val;
-    },
-
-    // Update cookie and form control setting. If value is not set, then
-    // updates from control to current cookie setting.
-    updateSetting: function(name, value) {
-
-        // Save the cookie for this session
-        if (typeof value !== 'undefined') {
-            WebUtil.writeSetting(name, value);
-        }
-
-        // Update the settings control
-        value = UI.getSetting(name);
-
-        var ctrl = document.getElementById('noVNC_setting_' + name);
-        if (ctrl.type === 'checkbox') {
-            ctrl.checked = value;
-
-        } else if (typeof ctrl.options !== 'undefined') {
-            for (var i = 0; i < ctrl.options.length; i += 1) {
-                if (ctrl.options[i].value === value) {
-                    ctrl.selectedIndex = i;
-                    break;
-                }
-            }
-        } else {
-            /*Weird IE9 error leads to 'null' appearring
-            in textboxes instead of ''.*/
-            if (value === null) {
-                value = "";
-            }
-            ctrl.value = value;
-        }
-    },
-
-    // Save control setting to cookie
-    saveSetting: function(name) {
-        var val, ctrl = document.getElementById('noVNC_setting_' + name);
-        if (ctrl.type === 'checkbox') {
-            val = ctrl.checked;
-        } else if (typeof ctrl.options !== 'undefined') {
-            val = ctrl.options[ctrl.selectedIndex].value;
-        } else {
-            val = ctrl.value;
-        }
-        WebUtil.writeSetting(name, val);
-        //Log.Debug("Setting saved '" + name + "=" + val + "'");
-        return val;
-    },
-
-    // Read form control compatible setting from cookie
-    getSetting: function(name) {
-        var ctrl = document.getElementById('noVNC_setting_' + name);
-        var val = WebUtil.readSetting(name);
-        if (typeof val !== 'undefined' && val !== null && ctrl.type === 'checkbox') {
-            if (val.toString().toLowerCase() in {'0':1, 'no':1, 'false':1}) {
-                val = false;
-            } else {
-                val = true;
-            }
-        }
-        return val;
-    },
-
-    // These helpers compensate for the lack of parent-selectors and
-    // previous-sibling-selectors in CSS which are needed when we want to
-    // disable the labels that belong to disabled input elements.
-    disableSetting: function(name) {
-        var ctrl = document.getElementById('noVNC_setting_' + name);
-        ctrl.disabled = true;
-        ctrl.label.classList.add('noVNC_disabled');
-    },
-
-    enableSetting: function(name) {
-        var ctrl = document.getElementById('noVNC_setting_' + name);
-        ctrl.disabled = false;
-        ctrl.label.classList.remove('noVNC_disabled');
-    },
-
-/* ------^-------
- *   /SETTINGS
- * ==============
- *    PANELS
- * ------v------*/
-
-    closeAllPanels: function() {
-        UI.closeSettingsPanel();
-        UI.closePowerPanel();
-        UI.closeClipboardPanel();
-        UI.closeExtraKeys();
-    },
-
-/* ------^-------
- *   /PANELS
- * ==============
- * SETTINGS (panel)
- * ------v------*/
-
-    openSettingsPanel: function() {
-        UI.closeAllPanels();
-        UI.openControlbar();
-
-        // Refresh UI elements from saved cookies
-        UI.updateSetting('encrypt');
-        UI.updateSetting('view_clip');
-        UI.updateSetting('resize');
-        UI.updateSetting('shared');
-        UI.updateSetting('view_only');
-        UI.updateSetting('path');
-        UI.updateSetting('repeaterID');
-        UI.updateSetting('logging');
-        UI.updateSetting('reconnect');
-        UI.updateSetting('reconnect_delay');
-
-        document.getElementById('noVNC_settings')
-            .classList.add("noVNC_open");
-        document.getElementById('noVNC_settings_button')
-            .classList.add("noVNC_selected");
-    },
-
-    closeSettingsPanel: function() {
-        document.getElementById('noVNC_settings')
-            .classList.remove("noVNC_open");
-        document.getElementById('noVNC_settings_button')
-            .classList.remove("noVNC_selected");
-    },
-
-    toggleSettingsPanel: function() {
-        if (document.getElementById('noVNC_settings')
-            .classList.contains("noVNC_open")) {
-            UI.closeSettingsPanel();
-        } else {
-            UI.openSettingsPanel();
-        }
-    },
-
-/* ------^-------
- *   /SETTINGS
- * ==============
- *     POWER
- * ------v------*/
-
-    openPowerPanel: function() {
-        UI.closeAllPanels();
-        UI.openControlbar();
-
-        document.getElementById('noVNC_power')
-            .classList.add("noVNC_open");
-        document.getElementById('noVNC_power_button')
-            .classList.add("noVNC_selected");
-    },
-
-    closePowerPanel: function() {
-        document.getElementById('noVNC_power')
-            .classList.remove("noVNC_open");
-        document.getElementById('noVNC_power_button')
-            .classList.remove("noVNC_selected");
-    },
-
-    togglePowerPanel: function() {
-        if (document.getElementById('noVNC_power')
-            .classList.contains("noVNC_open")) {
-            UI.closePowerPanel();
-        } else {
-            UI.openPowerPanel();
-        }
-    },
-
-    // Disable/enable power button
-    updatePowerButton: function() {
-        if (UI.connected &&
-            UI.rfb.capabilities.power &&
-            !UI.rfb.viewOnly) {
-            document.getElementById('noVNC_power_button')
-                .classList.remove("noVNC_hidden");
-        } else {
-            document.getElementById('noVNC_power_button')
-                .classList.add("noVNC_hidden");
-            // Close power panel if open
-            UI.closePowerPanel();
-        }
-    },
-
-/* ------^-------
- *    /POWER
- * ==============
- *   CLIPBOARD
- * ------v------*/
-
-    openClipboardPanel: function() {
-        UI.closeAllPanels();
-        UI.openControlbar();
-
-        document.getElementById('noVNC_clipboard')
-            .classList.add("noVNC_open");
-        document.getElementById('noVNC_clipboard_button')
-            .classList.add("noVNC_selected");
-    },
-
-    closeClipboardPanel: function() {
-        document.getElementById('noVNC_clipboard')
-            .classList.remove("noVNC_open");
-        document.getElementById('noVNC_clipboard_button')
-            .classList.remove("noVNC_selected");
-    },
-
-    toggleClipboardPanel: function() {
-        if (document.getElementById('noVNC_clipboard')
-            .classList.contains("noVNC_open")) {
-            UI.closeClipboardPanel();
-        } else {
-            UI.openClipboardPanel();
-        }
-    },
-
-    clipboardReceive: function(e) {
-        Log.Debug(">> UI.clipboardReceive: " + e.detail.text.substr(0,40) + "...");
-        document.getElementById('noVNC_clipboard_text').value = e.detail.text;
-        Log.Debug("<< UI.clipboardReceive");
-    },
-
-    clipboardClear: function() {
-        document.getElementById('noVNC_clipboard_text').value = "";
-        UI.rfb.clipboardPasteFrom("");
-    },
-
-    clipboardSend: function() {
-        var text = document.getElementById('noVNC_clipboard_text').value;
-        Log.Debug(">> UI.clipboardSend: " + text.substr(0,40) + "...");
-        UI.rfb.clipboardPasteFrom(text);
-        Log.Debug("<< UI.clipboardSend");
-    },
-
-/* ------^-------
- *  /CLIPBOARD
- * ==============
- *  CONNECTION
- * ------v------*/
-
-    openConnectPanel: function() {
-        document.getElementById('noVNC_connect_dlg')
-            .classList.add("noVNC_open");
-    },
-
-    closeConnectPanel: function() {
-        document.getElementById('noVNC_connect_dlg')
-            .classList.remove("noVNC_open");
-    },
-
-    connect: function(event, password) {
-
-        // Ignore when rfb already exists
-        if (typeof UI.rfb !== 'undefined') {
-            return;
-        }
-
-        var host = UI.getSetting('host');
-        var port = UI.getSetting('port');
-        var path = UI.getSetting('path');
-
-        if (typeof password === 'undefined') {
-            password = WebUtil.getConfigVar('password');
-            UI.reconnect_password = password;
-        }
-
-        if (password === null) {
-            password = undefined;
-        }
-
-        UI.hideStatus();
-
-        if (!host) {
-            Log.Error("Can't connect when host is: " + host);
-            UI.showStatus(_("Must set host"), 'error');
-            return;
-        }
-
-        UI.closeAllPanels();
-        UI.closeConnectPanel();
-
-        UI.updateVisualState('connecting');
-
-        var url;
-
-        url = UI.getSetting('encrypt') ? 'wss' : 'ws';
-
-        url += '://' + host;
-        if(port) {
-            url += ':' + port;
-        }
-        url += '/' + path;
-
-        UI.rfb = new RFB(document.getElementById('noVNC_container'), url,
-                         { shared: UI.getSetting('shared'),
-                           repeaterID: UI.getSetting('repeaterID'),
-                           credentials: { password: password } });
-        UI.rfb.addEventListener("connect", UI.connectFinished);
-        UI.rfb.addEventListener("disconnect", UI.disconnectFinished);
-        UI.rfb.addEventListener("credentialsrequired", UI.credentials);
-        UI.rfb.addEventListener("securityfailure", UI.securityFailed);
-        UI.rfb.addEventListener("capabilities", function () { UI.updatePowerButton(); });
-        UI.rfb.addEventListener("clipboard", UI.clipboardReceive);
-        UI.rfb.addEventListener("bell", UI.bell);
-        UI.rfb.addEventListener("desktopname", UI.updateDesktopName);
-        UI.rfb.clipViewport = UI.getSetting('view_clip');
-        UI.rfb.scaleViewport = UI.getSetting('resize') === 'scale';
-        UI.rfb.resizeSession = UI.getSetting('resize') === 'remote';
-
-        UI.updateViewOnly(); // requires UI.rfb
-    },
-
-    disconnect: function() {
-        UI.closeAllPanels();
-        UI.rfb.disconnect();
-
-        UI.connected = false;
-
-        // Disable automatic reconnecting
-        UI.inhibit_reconnect = true;
-
-        UI.updateVisualState('disconnecting');
-
-        // Don't display the connection settings until we're actually disconnected
-    },
-
-    reconnect: function() {
-        UI.reconnect_callback = null;
-
-        // if reconnect has been disabled in the meantime, do nothing.
-        if (UI.inhibit_reconnect) {
-            return;
-        }
-
-        UI.connect(null, UI.reconnect_password);
-    },
-
-    cancelReconnect: function() {
-        if (UI.reconnect_callback !== null) {
-            clearTimeout(UI.reconnect_callback);
-            UI.reconnect_callback = null;
-        }
-
-        UI.updateVisualState('disconnected');
-
-        UI.openControlbar();
-        UI.openConnectPanel();
-    },
-
-    connectFinished: function (e) {
-        UI.connected = true;
-        UI.inhibit_reconnect = false;
-
-        let msg;
-        if (UI.getSetting('encrypt')) {
-            msg = _("Connected (encrypted) to ") + UI.desktopName;
-        } else {
-            msg = _("Connected (unencrypted) to ") + UI.desktopName;
-        }
-        UI.showStatus(msg);
-        UI.updateVisualState('connected');
-
-        // Do this last because it can only be used on rendered elements
-        UI.rfb.focus();
-    },
-
-    disconnectFinished: function (e) {
-        let wasConnected = UI.connected;
-
-        // This variable is ideally set when disconnection starts, but
-        // when the disconnection isn't clean or if it is initiated by
-        // the server, we need to do it here as well since
-        // UI.disconnect() won't be used in those cases.
-        UI.connected = false;
-
-        UI.rfb = undefined;
-
-        if (!e.detail.clean) {
-            UI.updateVisualState('disconnected');
-            if (wasConnected) {
-                UI.showStatus(_("Something went wrong, connection is closed"),
-                              'error');
-            } else {
-                UI.showStatus(_("Failed to connect to server"), 'error');
-            }
-        } else if (UI.getSetting('reconnect', false) === true && !UI.inhibit_reconnect) {
-            UI.updateVisualState('reconnecting');
-
-            var delay = parseInt(UI.getSetting('reconnect_delay'));
-            UI.reconnect_callback = setTimeout(UI.reconnect, delay);
-            return;
-        } else {
-            UI.updateVisualState('disconnected');
-            UI.showStatus(_("Disconnected"), 'normal');
-        }
-
-        UI.openControlbar();
-        UI.openConnectPanel();
-    },
-
-    securityFailed: function (e) {
-        let msg = "";
-        // On security failures we might get a string with a reason
-        // directly from the server. Note that we can't control if
-        // this string is translated or not.
-        if ('reason' in e.detail) {
-            msg = _("New connection has been rejected with reason: ") +
-                e.detail.reason;
-        } else {
-            msg = _("New connection has been rejected");
-        }
-        UI.showStatus(msg, 'error');
-    },
-
-/* ------^-------
- *  /CONNECTION
- * ==============
- *   PASSWORD
- * ------v------*/
-
-    credentials: function(e) {
-        // FIXME: handle more types
-        document.getElementById('noVNC_password_dlg')
-            .classList.add('noVNC_open');
-
-        setTimeout(function () {
-                document.getElementById('noVNC_password_input').focus();
-            }, 100);
-
-        Log.Warn("Server asked for a password");
-        UI.showStatus(_("Password is required"), "warning");
-    },
-
-    setPassword: function(e) {
-        // Prevent actually submitting the form
-        e.preventDefault();
-
-        var inputElem = document.getElementById('noVNC_password_input');
-        var password = inputElem.value;
-        // Clear the input after reading the password
-        inputElem.value = "";
-        UI.rfb.sendCredentials({ password: password });
-        UI.reconnect_password = password;
-        document.getElementById('noVNC_password_dlg')
-            .classList.remove('noVNC_open');
-    },
-
-/* ------^-------
- *  /PASSWORD
- * ==============
- *   FULLSCREEN
- * ------v------*/
-
-    toggleFullscreen: function() {
-        if (document.fullscreenElement || // alternative standard method
-            document.mozFullScreenElement || // currently working methods
-            document.webkitFullscreenElement ||
-            document.msFullscreenElement) {
-            if (document.exitFullscreen) {
-                document.exitFullscreen();
-            } else if (document.mozCancelFullScreen) {
-                document.mozCancelFullScreen();
-            } else if (document.webkitExitFullscreen) {
-                document.webkitExitFullscreen();
-            } else if (document.msExitFullscreen) {
-                document.msExitFullscreen();
-            }
-        } else {
-            if (document.documentElement.requestFullscreen) {
-                document.documentElement.requestFullscreen();
-            } else if (document.documentElement.mozRequestFullScreen) {
-                document.documentElement.mozRequestFullScreen();
-            } else if (document.documentElement.webkitRequestFullscreen) {
-                document.documentElement.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT);
-            } else if (document.body.msRequestFullscreen) {
-                document.body.msRequestFullscreen();
-            }
-        }
-        UI.enableDisableViewClip();
-        UI.updateFullscreenButton();
-    },
-
-    updateFullscreenButton: function() {
-        if (document.fullscreenElement || // alternative standard method
-            document.mozFullScreenElement || // currently working methods
-            document.webkitFullscreenElement ||
-            document.msFullscreenElement ) {
-            document.getElementById('noVNC_fullscreen_button')
-                .classList.add("noVNC_selected");
-        } else {
-            document.getElementById('noVNC_fullscreen_button')
-                .classList.remove("noVNC_selected");
-        }
-    },
-
-/* ------^-------
- *  /FULLSCREEN
- * ==============
- *     RESIZE
- * ------v------*/
-
-    // Apply remote resizing or local scaling
-    applyResizeMode: function() {
-        if (!UI.rfb) return;
-
-        UI.rfb.scaleViewport = UI.getSetting('resize') === 'scale';
-        UI.rfb.resizeSession = UI.getSetting('resize') === 'remote';
-    },
-
-/* ------^-------
- *    /RESIZE
- * ==============
- * VIEW CLIPPING
- * ------v------*/
-
-    // Update parameters that depend on the viewport clip setting
-    updateViewClip: function() {
-        if (!UI.rfb) return;
-
-        var cur_clip = UI.rfb.clipViewport;
-        var new_clip = UI.getSetting('view_clip');
-
-        if (isTouchDevice) {
-            // Touch devices usually have shit scrollbars
-            new_clip = true;
-        }
-
-        if (cur_clip !== new_clip) {
-            UI.rfb.clipViewport = new_clip;
-        }
-
-        // Changing the viewport may change the state of
-        // the dragging button
-        UI.updateViewDrag();
-    },
-
-    // Handle special cases where viewport clipping is forced on/off or locked
-    enableDisableViewClip: function() {
-        var resizeSetting = UI.getSetting('resize');
-        // Disable clipping if we are scaling, connected or on touch
-        if (resizeSetting === 'scale' ||
-            isTouchDevice) {
-            UI.disableSetting('view_clip');
-        } else {
-            UI.enableSetting('view_clip');
-        }
-    },
-
-/* ------^-------
- * /VIEW CLIPPING
- * ==============
- *    VIEWDRAG
- * ------v------*/
-
-    toggleViewDrag: function() {
-        if (!UI.rfb) return;
-
-        var drag = UI.rfb.dragViewport;
-        UI.setViewDrag(!drag);
-     },
-
-    // Set the view drag mode which moves the viewport on mouse drags
-    setViewDrag: function(drag) {
-        if (!UI.rfb) return;
-
-        UI.rfb.dragViewport = drag;
-
-        UI.updateViewDrag();
-    },
-
-    updateViewDrag: function() {
-        if (!UI.connected) return;
-
-        var viewDragButton = document.getElementById('noVNC_view_drag_button');
-
-        if (!UI.rfb.clipViewport && UI.rfb.dragViewport) {
-            // We are no longer clipping the viewport. Make sure
-            // viewport drag isn't active when it can't be used.
-            UI.rfb.dragViewport = false;
-        }
-
-        if (UI.rfb.dragViewport) {
-            viewDragButton.classList.add("noVNC_selected");
-        } else {
-            viewDragButton.classList.remove("noVNC_selected");
-        }
-
-        // Different behaviour for touch vs non-touch
-        // The button is disabled instead of hidden on touch devices
-        if (isTouchDevice) {
-            viewDragButton.classList.remove("noVNC_hidden");
-
-            if (UI.rfb.clipViewport) {
-                viewDragButton.disabled = false;
-            } else {
-                viewDragButton.disabled = true;
-            }
-        } else {
-            viewDragButton.disabled = false;
-
-            if (UI.rfb.clipViewport) {
-                viewDragButton.classList.remove("noVNC_hidden");
-            } else {
-                viewDragButton.classList.add("noVNC_hidden");
-            }
-        }
-    },
-
-/* ------^-------
- *   /VIEWDRAG
- * ==============
- *    KEYBOARD
- * ------v------*/
-
-    showVirtualKeyboard: function() {
-        if (!isTouchDevice) return;
-
-        var input = document.getElementById('noVNC_keyboardinput');
-
-        if (document.activeElement == input) return;
-
-        input.focus();
-
-        try {
-            var l = input.value.length;
-            // Move the caret to the end
-            input.setSelectionRange(l, l);
-        } catch (err) {} // setSelectionRange is undefined in Google Chrome
-    },
-
-    hideVirtualKeyboard: function() {
-        if (!isTouchDevice) return;
-
-        var input = document.getElementById('noVNC_keyboardinput');
-
-        if (document.activeElement != input) return;
-
-        input.blur();
-    },
-
-    toggleVirtualKeyboard: function () {
-        if (document.getElementById('noVNC_keyboard_button')
-            .classList.contains("noVNC_selected")) {
-            UI.hideVirtualKeyboard();
-        } else {
-            UI.showVirtualKeyboard();
-        }
-    },
-
-    onfocusVirtualKeyboard: function(event) {
-        document.getElementById('noVNC_keyboard_button')
-            .classList.add("noVNC_selected");
-        if (UI.rfb) {
-            UI.rfb.focusOnClick = false;
-        }
-    },
-
-    onblurVirtualKeyboard: function(event) {
-        document.getElementById('noVNC_keyboard_button')
-            .classList.remove("noVNC_selected");
-        if (UI.rfb) {
-            UI.rfb.focusOnClick = true;
-        }
-    },
-
-    keepVirtualKeyboard: function(event) {
-        var input = document.getElementById('noVNC_keyboardinput');
-
-        // Only prevent focus change if the virtual keyboard is active
-        if (document.activeElement != input) {
-            return;
-        }
-
-        // Only allow focus to move to other elements that need
-        // focus to function properly
-        if (event.target.form !== undefined) {
-            switch (event.target.type) {
-                case 'text':
-                case 'email':
-                case 'search':
-                case 'password':
-                case 'tel':
-                case 'url':
-                case 'textarea':
-                case 'select-one':
-                case 'select-multiple':
-                    return;
-            }
-        }
-
-        event.preventDefault();
-    },
-
-    keyboardinputReset: function() {
-        var kbi = document.getElementById('noVNC_keyboardinput');
-        kbi.value = new Array(UI.defaultKeyboardinputLen).join("_");
-        UI.lastKeyboardinput = kbi.value;
-    },
-
-    keyEvent: function (keysym, code, down) {
-        if (!UI.rfb) return;
-
-        UI.rfb.sendKey(keysym, code, down);
-    },
-
-    // When normal keyboard events are left uncought, use the input events from
-    // the keyboardinput element instead and generate the corresponding key events.
-    // This code is required since some browsers on Android are inconsistent in
-    // sending keyCodes in the normal keyboard events when using on screen keyboards.
-    keyInput: function(event) {
-
-        if (!UI.rfb) return;
-
-        var newValue = event.target.value;
-
-        if (!UI.lastKeyboardinput) {
-            UI.keyboardinputReset();
-        }
-        var oldValue = UI.lastKeyboardinput;
-
-        var newLen;
-        try {
-            // Try to check caret position since whitespace at the end
-            // will not be considered by value.length in some browsers
-            newLen = Math.max(event.target.selectionStart, newValue.length);
-        } catch (err) {
-            // selectionStart is undefined in Google Chrome
-            newLen = newValue.length;
-        }
-        var oldLen = oldValue.length;
-
-        var backspaces;
-        var inputs = newLen - oldLen;
-        if (inputs < 0) {
-            backspaces = -inputs;
-        } else {
-            backspaces = 0;
-        }
-
-        // Compare the old string with the new to account for
-        // text-corrections or other input that modify existing text
-        var i;
-        for (i = 0; i < Math.min(oldLen, newLen); i++) {
-            if (newValue.charAt(i) != oldValue.charAt(i)) {
-                inputs = newLen - i;
-                backspaces = oldLen - i;
-                break;
-            }
-        }
-
-        // Send the key events
-        for (i = 0; i < backspaces; i++) {
-            UI.rfb.sendKey(KeyTable.XK_BackSpace, "Backspace");
-        }
-        for (i = newLen - inputs; i < newLen; i++) {
-            UI.rfb.sendKey(keysyms.lookup(newValue.charCodeAt(i)));
-        }
-
-        // Control the text content length in the keyboardinput element
-        if (newLen > 2 * UI.defaultKeyboardinputLen) {
-            UI.keyboardinputReset();
-        } else if (newLen < 1) {
-            // There always have to be some text in the keyboardinput
-            // element with which backspace can interact.
-            UI.keyboardinputReset();
-            // This sometimes causes the keyboard to disappear for a second
-            // but it is required for the android keyboard to recognize that
-            // text has been added to the field
-            event.target.blur();
-            // This has to be ran outside of the input handler in order to work
-            setTimeout(event.target.focus.bind(event.target), 0);
-        } else {
-            UI.lastKeyboardinput = newValue;
-        }
-    },
-
-/* ------^-------
- *   /KEYBOARD
- * ==============
- *   EXTRA KEYS
- * ------v------*/
-
-    openExtraKeys: function() {
-        UI.closeAllPanels();
-        UI.openControlbar();
-
-        document.getElementById('noVNC_modifiers')
-            .classList.add("noVNC_open");
-        document.getElementById('noVNC_toggle_extra_keys_button')
-            .classList.add("noVNC_selected");
-    },
-
-    closeExtraKeys: function() {
-        document.getElementById('noVNC_modifiers')
-            .classList.remove("noVNC_open");
-        document.getElementById('noVNC_toggle_extra_keys_button')
-            .classList.remove("noVNC_selected");
-    },
-
-    toggleExtraKeys: function() {
-        if(document.getElementById('noVNC_modifiers')
-            .classList.contains("noVNC_open")) {
-            UI.closeExtraKeys();
-        } else  {
-            UI.openExtraKeys();
-        }
-    },
-
-    sendEsc: function() {
-        UI.rfb.sendKey(KeyTable.XK_Escape, "Escape");
-    },
-
-    sendTab: function() {
-        UI.rfb.sendKey(KeyTable.XK_Tab);
-    },
-
-    toggleCtrl: function() {
-        var btn = document.getElementById('noVNC_toggle_ctrl_button');
-        if (btn.classList.contains("noVNC_selected")) {
-            UI.rfb.sendKey(KeyTable.XK_Control_L, "ControlLeft", false);
-            btn.classList.remove("noVNC_selected");
-        } else {
-            UI.rfb.sendKey(KeyTable.XK_Control_L, "ControlLeft", true);
-            btn.classList.add("noVNC_selected");
-        }
-    },
-
-    toggleAlt: function() {
-        var btn = document.getElementById('noVNC_toggle_alt_button');
-        if (btn.classList.contains("noVNC_selected")) {
-            UI.rfb.sendKey(KeyTable.XK_Alt_L, "AltLeft", false);
-            btn.classList.remove("noVNC_selected");
-        } else {
-            UI.rfb.sendKey(KeyTable.XK_Alt_L, "AltLeft", true);
-            btn.classList.add("noVNC_selected");
-        }
-    },
-
-    sendCtrlAltDel: function() {
-        UI.rfb.sendCtrlAltDel();
-    },
-
-/* ------^-------
- *   /EXTRA KEYS
- * ==============
- *     MISC
- * ------v------*/
-
-    setMouseButton: function(num) {
-        var view_only = UI.rfb.viewOnly;
-        if (UI.rfb && !view_only) {
-            UI.rfb.touchButton = num;
-        }
-
-        var blist = [0, 1,2,4];
-        for (var b = 0; b < blist.length; b++) {
-            var button = document.getElementById('noVNC_mouse_button' +
-                                                 blist[b]);
-            if (blist[b] === num && !view_only) {
-                button.classList.remove("noVNC_hidden");
-            } else {
-                button.classList.add("noVNC_hidden");
-            }
-        }
-    },
-
-    updateViewOnly: function() {
-        if (!UI.rfb) return;
-        UI.rfb.viewOnly = UI.getSetting('view_only');
-
-        // Hide input related buttons in view only mode
-        if (UI.rfb.viewOnly) {
-            document.getElementById('noVNC_keyboard_button')
-                .classList.add('noVNC_hidden');
-            document.getElementById('noVNC_toggle_extra_keys_button')
-                .classList.add('noVNC_hidden');
-        } else {
-            document.getElementById('noVNC_keyboard_button')
-                .classList.remove('noVNC_hidden');
-            document.getElementById('noVNC_toggle_extra_keys_button')
-                .classList.remove('noVNC_hidden');
-        }
-        UI.setMouseButton(1); //has it's own logic for hiding/showing
-    },
-
-    updateLogging: function() {
-        WebUtil.init_logging(UI.getSetting('logging'));
-    },
-
-    updateDesktopName: function(e) {
-        UI.desktopName = e.detail.name;
-        // Display the desktop name in the document title
-        document.title = e.detail.name + " - noVNC";
-    },
-
-    bell: function(e) {
-        if (WebUtil.getConfigVar('bell', 'on') === 'on') {
-            var promise = document.getElementById('noVNC_bell').play();
-            // The standards disagree on the return value here
-            if (promise) {
-                promise.catch(function(e) {
-                    if (e.name === "NotAllowedError") {
-                        // Ignore when the browser doesn't let us play audio.
-                        // It is common that the browsers require audio to be
-                        // initiated from a user action.
-                    } else {
-                        Log.Error("Unable to play bell: " + e);
-                    }
-                });
-            }
-        }
-    },
-
-    //Helper to add options to dropdown.
-    addOption: function(selectbox, text, value) {
-        var optn = document.createElement("OPTION");
-        optn.text = text;
-        optn.value = value;
-        selectbox.options.add(optn);
-    },
-
-/* ------^-------
- *    /MISC
- * ==============
- */
-};
-
-// Set up translations
-var LINGUAS = ["de", "el", "es", "nl", "pl", "sv", "tr", "zh"];
-l10n.setup(LINGUAS);
-if (l10n.language !== "en" && l10n.dictionary === undefined) {
-    WebUtil.fetchJSON('app/locale/' + l10n.language + '.json', function (translations) {
-        l10n.dictionary = translations;
-
-        // wait for translations to load before loading the UI
-        UI.prime();
-    }, function (err) {
-        Log.Error("Failed to load translations: " + err);
-        UI.prime();
-    });
-} else {
-    UI.prime();
-}
-
-export default UI;
diff --git a/public/novnc/app/webutil.js b/public/novnc/app/webutil.js
deleted file mode 100644
index 249a1382..00000000
--- a/public/novnc/app/webutil.js
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- * noVNC: HTML5 VNC client
- * Copyright (C) 2012 Joel Martin
- * Copyright (C) 2013 NTT corp.
- * Licensed under MPL 2.0 (see LICENSE.txt)
- *
- * See README.md for usage and integration instructions.
- */
-
-import { init_logging as main_init_logging } from '../core/util/logging.js';
-
-// init log level reading the logging HTTP param
-export function init_logging (level) {
-    "use strict";
-    if (typeof level !== "undefined") {
-        main_init_logging(level);
-    } else {
-        var param = document.location.href.match(/logging=([A-Za-z0-9\._\-]*)/);
-        main_init_logging(param || undefined);
-    }
-};
-
-// Read a query string variable
-export function getQueryVar (name, defVal) {
-    "use strict";
-    var re = new RegExp('.*[?&]' + name + '=([^]*)'),
-        match = document.location.href.match(re);
-    if (typeof defVal === 'undefined') { defVal = null; }
-    if (match) {
-        return decodeURIComponent(match[1]);
-    } else {
-        return defVal;
-    }
-};
-
-// Read a hash fragment variable
-export function getHashVar (name, defVal) {
-    "use strict";
-    var re = new RegExp('.*[]' + name + '=([^&]*)'),
-        match = document.location.hash.match(re);
-    if (typeof defVal === 'undefined') { defVal = null; }
-    if (match) {
-        return decodeURIComponent(match[1]);
-    } else {
-        return defVal;
-    }
-};
-
-// Read a variable from the fragment or the query string
-// Fragment takes precedence
-export function getConfigVar (name, defVal) {
-    "use strict";
-    var val = getHashVar(name);
-    if (val === null) {
-        val = getQueryVar(name, defVal);
-    }
-    return val;
-};
-
-/*
- * Cookie handling. Dervied from: http://www.quirksmode.org/js/cookies.html
- */
-
-// No days means only for this browser session
-export function createCookie (name, value, days) {
-    "use strict";
-    var date, expires;
-    if (days) {
-        date = new Date();
-        date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
-        expires = "; expires=" + date.toGMTString();
-    } else {
-        expires = "";
-    }
-
-    var secure;
-    if (document.location.protocol === "https:") {
-        secure = "; secure";
-    } else {
-        secure = "";
-    }
-    document.cookie = name + "=" + value + expires + "; path=/" + secure;
-};
-
-export function readCookie (name, defaultValue) {
-    "use strict";
-    var nameEQ = name + "=",
-        ca = document.cookie.split(';');
-
-    for (var i = 0; i < ca.length; i += 1) {
-        var c = ca[i];
-        while (c.charAt(0) === ' ') { c = c.substring(1, c.length); }
-        if (c.indexOf(nameEQ) === 0) { return c.substring(nameEQ.length, c.length); }
-    }
-    return (typeof defaultValue !== 'undefined') ? defaultValue : null;
-};
-
-export function eraseCookie (name) {
-    "use strict";
-    createCookie(name, "", -1);
-};
-
-/*
- * Setting handling.
- */
-
-var settings = {};
-
-export function initSettings (callback /*, ...callbackArgs */) {
-    "use strict";
-    var callbackArgs = Array.prototype.slice.call(arguments, 1);
-    if (window.chrome && window.chrome.storage) {
-        window.chrome.storage.sync.get(function (cfg) {
-            settings = cfg;
-            if (callback) {
-                callback.apply(this, callbackArgs);
-            }
-        });
-    } else {
-        // No-op
-        if (callback) {
-            callback.apply(this, callbackArgs);
-        }
-    }
-};
-
-// No days means only for this browser session
-export function writeSetting (name, value) {
-    "use strict";
-    if (window.chrome && window.chrome.storage) {
-        if (settings[name] !== value) {
-            settings[name] = value;
-            window.chrome.storage.sync.set(settings);
-        }
-    } else {
-        localStorage.setItem(name, value);
-    }
-};
-
-export function readSetting (name, defaultValue) {
-    "use strict";
-    var value;
-    if (window.chrome && window.chrome.storage) {
-        value = settings[name];
-    } else {
-        value = localStorage.getItem(name);
-    }
-    if (typeof value === "undefined") {
-        value = null;
-    }
-    if (value === null && typeof defaultValue !== "undefined") {
-        return defaultValue;
-    } else {
-        return value;
-    }
-};
-
-export function eraseSetting (name) {
-    "use strict";
-    if (window.chrome && window.chrome.storage) {
-        window.chrome.storage.sync.remove(name);
-        delete settings[name];
-    } else {
-        localStorage.removeItem(name);
-    }
-};
-
-export function injectParamIfMissing (path, param, value) {
-    // force pretend that we're dealing with a relative path
-    // (assume that we wanted an extra if we pass one in)
-    path = "/" + path;
-
-    var elem = document.createElement('a');
-    elem.href = path;
-
-    var param_eq = encodeURIComponent(param) + "=";
-    var query;
-    if (elem.search) {
-        query = elem.search.slice(1).split('&');
-    } else {
-        query = [];
-    }
-
-    if (!query.some(function (v) { return v.startsWith(param_eq); })) {
-        query.push(param_eq + encodeURIComponent(value));
-        elem.search = "?" + query.join("&");
-    }
-
-    // some browsers (e.g. IE11) may occasionally omit the leading slash
-    // in the elem.pathname string. Handle that case gracefully.
-    if (elem.pathname.charAt(0) == "/") {
-        return elem.pathname.slice(1) + elem.search + elem.hash;
-    } else {
-        return elem.pathname + elem.search + elem.hash;
-    }
-};
-
-// sadly, we can't use the Fetch API until we decide to drop
-// IE11 support or polyfill promises and fetch in IE11.
-// resolve will receive an object on success, while reject
-// will receive either an event or an error on failure.
-export function fetchJSON(path, resolve, reject) {
-    // NB: IE11 doesn't support JSON as a responseType
-    var req = new XMLHttpRequest();
-    req.open('GET', path);
-
-    req.onload = function () {
-        if (req.status === 200) {
-            try {
-                var resObj = JSON.parse(req.responseText);
-            } catch (err) {
-                reject(err);
-                return;
-            }
-            resolve(resObj);
-        } else {
-            reject(new Error("XHR got non-200 status while trying to load '" + path + "': " + req.status));
-        }
-    };
-
-    req.onerror = function (evt) {
-        reject(new Error("XHR encountered an error while trying to load '" + path + "': " + evt.message));
-    };
-
-    req.ontimeout = function (evt) {
-        reject(new Error("XHR timed out while trying to load '" + path + "'"));
-    };
-
-    req.send();
-}
diff --git a/public/novnc/core/base64.js b/public/novnc/core/base64.js
deleted file mode 100644
index 5182c295..00000000
--- a/public/novnc/core/base64.js
+++ /dev/null
@@ -1,110 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-// From: http://hg.mozilla.org/mozilla-central/raw-file/ec10630b1a54/js/src/devtools/jint/sunspider/string-base64.js
-
-import * as Log from './util/logging.js';
-
-export default {
-    /* Convert data (an array of integers) to a Base64 string. */
-    toBase64Table : 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='.split(''),
-    base64Pad     : '=',
-
-    encode: function (data) {
-        "use strict";
-        var result = '';
-        var toBase64Table = this.toBase64Table;
-        var length = data.length;
-        var lengthpad = (length % 3);
-        // Convert every three bytes to 4 ascii characters.
-
-        for (var i = 0; i < (length - 2); i += 3) {
-            result += toBase64Table[data[i] >> 2];
-            result += toBase64Table[((data[i] & 0x03) << 4) + (data[i + 1] >> 4)];
-            result += toBase64Table[((data[i + 1] & 0x0f) << 2) + (data[i + 2] >> 6)];
-            result += toBase64Table[data[i + 2] & 0x3f];
-        }
-
-        // Convert the remaining 1 or 2 bytes, pad out to 4 characters.
-        var j = 0;
-        if (lengthpad === 2) {
-            j = length - lengthpad;
-            result += toBase64Table[data[j] >> 2];
-            result += toBase64Table[((data[j] & 0x03) << 4) + (data[j + 1] >> 4)];
-            result += toBase64Table[(data[j + 1] & 0x0f) << 2];
-            result += toBase64Table[64];
-        } else if (lengthpad === 1) {
-            j = length - lengthpad;
-            result += toBase64Table[data[j] >> 2];
-            result += toBase64Table[(data[j] & 0x03) << 4];
-            result += toBase64Table[64];
-            result += toBase64Table[64];
-        }
-
-        return result;
-    },
-
-    /* Convert Base64 data to a string */
-    toBinaryTable : [
-        -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
-        -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
-        -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63,
-        52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1, 0,-1,-1,
-        -1, 0, 1, 2,  3, 4, 5, 6,  7, 8, 9,10, 11,12,13,14,
-        15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1,
-        -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
-        41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1
-    ],
-
-    decode: function (data, offset) {
-        "use strict";
-        offset = typeof(offset) !== 'undefined' ? offset : 0;
-        var toBinaryTable = this.toBinaryTable;
-        var base64Pad = this.base64Pad;
-        var result, result_length;
-        var leftbits = 0; // number of bits decoded, but yet to be appended
-        var leftdata = 0; // bits decoded, but yet to be appended
-        var data_length = data.indexOf('=') - offset;
-
-        if (data_length < 0) { data_length = data.length - offset; }
-
-        /* Every four characters is 3 resulting numbers */
-        result_length = (data_length >> 2) * 3 + Math.floor((data_length % 4) / 1.5);
-        result = new Array(result_length);
-
-        // Convert one by one.
-        for (var idx = 0, i = offset; i < data.length; i++) {
-            var c = toBinaryTable[data.charCodeAt(i) & 0x7f];
-            var padding = (data.charAt(i) === base64Pad);
-            // Skip illegal characters and whitespace
-            if (c === -1) {
-                Log.Error("Illegal character code " + data.charCodeAt(i) + " at position " + i);
-                continue;
-            }
-
-            // Collect data into leftdata, update bitcount
-            leftdata = (leftdata << 6) | c;
-            leftbits += 6;
-
-            // If we have 8 or more bits, append 8 bits to the result
-            if (leftbits >= 8) {
-                leftbits -= 8;
-                // Append if not padding.
-                if (!padding) {
-                    result[idx++] = (leftdata >> leftbits) & 0xff;
-                }
-                leftdata &= (1 << leftbits) - 1;
-            }
-        }
-
-        // If there are any bits left, the base64 string was corrupted
-        if (leftbits) {
-            err = new Error('Corrupted base64 string');
-            err.name = 'Base64-Error';
-            throw err;
-        }
-
-        return result;
-    }
-}; /* End of Base64 namespace */
diff --git a/public/novnc/core/des.js b/public/novnc/core/des.js
deleted file mode 100644
index 87dc516a..00000000
--- a/public/novnc/core/des.js
+++ /dev/null
@@ -1,271 +0,0 @@
-/*
- * Ported from Flashlight VNC ActionScript implementation:
- *     http://www.wizhelp.com/flashlight-vnc/
- *
- * Full attribution follows:
- *
- * -------------------------------------------------------------------------
- *
- * This DES class has been extracted from package Acme.Crypto for use in VNC.
- * The unnecessary odd parity code has been removed.
- *
- * These changes are:
- *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
-
- * DesCipher - the DES encryption method
- *
- * The meat of this code is by Dave Zimmerman