diff --git a/about.html b/about.html
index 101fdd6..17e32b9 100644
--- a/about.html
+++ b/about.html
@@ -5,8 +5,8 @@
 	<meta http-equiv="X-UA-Compatible" content="IE=edge">
 	<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, maximum-scale=1">
 	<title>About ESPTerm :: ESPTerm</title>
-	<link href="/css/app.69e5b77.css" rel="stylesheet">
-	<script src="/js/app.69e5b77.js"></script>
+	<link href="/css/app.4a032ee-en.css" rel="stylesheet">
+	<script src="/js/app.4a032ee-en.js"></script>
 	<script>
 		var _root = location.host;
 		var _demo = 1;
@@ -52,12 +52,12 @@
 	<table>
 		<tr>
 			<th>ESPTerm</th>
-			<td>v2.1.0, built 2017-10-02 at&nbsp;3:24 CEST</td>
+			<td>v2.1.0, built 2017-10-04 at&nbsp;0:54 CEST</td>
 		</tr>
 		<tr>
 			<th>Git hash</th>
-			<td>back-end: <a href="https://github.com/espterm/espterm-firmware/commit/a72e2be">a72e2be</a>,
-				front-end: <a href="https://github.com/espterm/espterm-front-end/commit/69e5b77">69e5b77</td>
+			<td>back-end: <a href="https://github.com/espterm/espterm-firmware/commit/7b8c936">7b8c936</a>,
+				front-end: <a href="https://github.com/espterm/espterm-front-end/commit/4a032ee">4a032ee</td>
 		</tr>
 		<tr>
 			<th>libesphttpd</th>
diff --git a/cfg_network.html b/cfg_network.html
index 1b832bc..2a2456f 100644
--- a/cfg_network.html
+++ b/cfg_network.html
@@ -5,8 +5,8 @@
 	<meta http-equiv="X-UA-Compatible" content="IE=edge">
 	<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, maximum-scale=1">
 	<title>Network Settings :: ESPTerm</title>
-	<link href="/css/app.69e5b77.css" rel="stylesheet">
-	<script src="/js/app.69e5b77.js"></script>
+	<link href="/css/app.4a032ee-en.css" rel="stylesheet">
+	<script src="/js/app.4a032ee-en.js"></script>
 	<script>
 		var _root = location.host;
 		var _demo = 1;
diff --git a/cfg_system.html b/cfg_system.html
index 5d66427..8809782 100644
--- a/cfg_system.html
+++ b/cfg_system.html
@@ -5,8 +5,8 @@
 	<meta http-equiv="X-UA-Compatible" content="IE=edge">
 	<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, maximum-scale=1">
 	<title>System Settings :: ESPTerm</title>
-	<link href="/css/app.69e5b77.css" rel="stylesheet">
-	<script src="/js/app.69e5b77.js"></script>
+	<link href="/css/app.4a032ee-en.css" rel="stylesheet">
+	<script src="/js/app.4a032ee-en.js"></script>
 	<script>
 		var _root = location.host;
 		var _demo = 1;
diff --git a/cfg_term.html b/cfg_term.html
index 313c177..073972d 100644
--- a/cfg_term.html
+++ b/cfg_term.html
@@ -5,8 +5,8 @@
 	<meta http-equiv="X-UA-Compatible" content="IE=edge">
 	<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, maximum-scale=1">
 	<title>Terminal Settings :: ESPTerm</title>
-	<link href="/css/app.69e5b77.css" rel="stylesheet">
-	<script src="/js/app.69e5b77.js"></script>
+	<link href="/css/app.4a032ee-en.css" rel="stylesheet">
+	<script src="/js/app.4a032ee-en.js"></script>
 	<script>
 		var _root = location.host;
 		var _demo = 1;
diff --git a/cfg_wifi.html b/cfg_wifi.html
index 394ffe2..8ab23d6 100644
--- a/cfg_wifi.html
+++ b/cfg_wifi.html
@@ -5,8 +5,8 @@
 	<meta http-equiv="X-UA-Compatible" content="IE=edge">
 	<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, maximum-scale=1">
 	<title>WiFi Settings :: ESPTerm</title>
-	<link href="/css/app.69e5b77.css" rel="stylesheet">
-	<script src="/js/app.69e5b77.js"></script>
+	<link href="/css/app.4a032ee-en.css" rel="stylesheet">
+	<script src="/js/app.4a032ee-en.js"></script>
 	<script>
 		var _root = location.host;
 		var _demo = 1;
diff --git a/cfg_wifi_conn.html b/cfg_wifi_conn.html
index c5bf05a..a48fa7c 100644
--- a/cfg_wifi_conn.html
+++ b/cfg_wifi_conn.html
@@ -5,8 +5,8 @@
 	<meta http-equiv="X-UA-Compatible" content="IE=edge">
 	<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, maximum-scale=1">
 	<title>Connecting to Network :: ESPTerm</title>
-	<link href="/css/app.69e5b77.css" rel="stylesheet">
-	<script src="/js/app.69e5b77.js"></script>
+	<link href="/css/app.4a032ee-en.css" rel="stylesheet">
+	<script src="/js/app.4a032ee-en.js"></script>
 	<script>
 		var _root = location.host;
 		var _demo = 1;
diff --git a/css/app.4a032ee-en.css b/css/app.4a032ee-en.css
new file mode 100644
index 0000000..595b0cf
--- /dev/null
+++ b/css/app.4a032ee-en.css
@@ -0,0 +1,2272 @@
+@charset "UTF-8";
+/* normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */
+/**
+ * 1. Set default font family to sans-serif.
+ * 2. Prevent iOS and IE text size adjust after device orientation change,
+ *    without disabling user zoom.
+ */
+*, *:before, *:after {
+  box-sizing: border-box;
+}
+
+html {
+  font-family: sans-serif;
+  /* 1 */
+  -ms-text-size-adjust: 100%;
+  /* 2 */
+  -webkit-text-size-adjust: 100%;
+  /* 2 */
+}
+
+/**
+ * Remove default margin.
+ */
+body {
+  margin: 0;
+}
+
+/* HTML5 display definitions
+   ========================================================================== */
+/**
+ * Correct `block` display not defined for any HTML5 element in IE 8/9.
+ * Correct `block` display not defined for `details` or `summary` in IE 10/11
+ * and Firefox.
+ * Correct `block` display not defined for `main` in IE 11.
+ */
+figure,
+nav {
+  display: block;
+}
+
+/**
+ * 1. Correct `inline-block` display not defined in IE 8/9.
+ * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
+ */
+canvas,
+progress {
+  display: inline-block;
+  /* 1 */
+  vertical-align: baseline;
+  /* 2 */
+}
+
+/**
+ * Prevent modern browsers from displaying `audio` without controls.
+ * Remove excess height in iOS 5 devices.
+ */
+/**
+ * Address `[hidden]` styling not present in IE 8/9/10.
+ * Hide the `template` element in IE 8/9/10/11, Safari, and Firefox < 22.
+ */
+[hidden] {
+  display: none;
+}
+
+/* Links
+   ========================================================================== */
+/**
+ * Remove the gray background color from active links in IE 10.
+ */
+a {
+  background-color: transparent;
+}
+
+/**
+ * Improve readability of focused elements when they are also in an
+ * active/hover state.
+ */
+a:active,
+a:hover {
+  outline: 0;
+}
+
+/* Text-level semantics
+   ========================================================================== */
+/**
+ * Address styling not present in IE 8/9/10/11, Safari, and Chrome.
+ */
+/**
+ * Address style set to `bolder` in Firefox 4+, Safari, and Chrome.
+ */
+b {
+  font-weight: bold;
+}
+
+/**
+ * Address styling not present in Safari and Chrome.
+ */
+/**
+ * Address variable `h1` font-size and margin within `section` and `article`
+ * contexts in Firefox 4+, Safari, and Chrome.
+ */
+h1 {
+  font-size: 2em;
+  margin: 0.67em 0;
+}
+
+h2 {
+  font-size: 2em;
+  margin: 0.67em 0;
+}
+
+/**
+ * Address styling not present in IE 8/9.
+ */
+/**
+ * Address inconsistent and variable font size in all browsers.
+ */
+small {
+  font-size: 80%;
+}
+
+/**
+ * Prevent `sub` and `sup` affecting `line-height` in all browsers.
+ */
+sub,
+sup {
+  font-size: 75%;
+  line-height: 0;
+  position: relative;
+  vertical-align: baseline;
+}
+
+sup {
+  top: -0.5em;
+}
+
+sub {
+  bottom: -0.25em;
+}
+
+/* Embedded content
+   ========================================================================== */
+/**
+ * Remove border when inside `a` element in IE 8/9/10.
+ */
+img {
+  border: 0;
+}
+
+/**
+ * Correct overflow not hidden in IE 9/10/11.
+ */
+svg:not(:root) {
+  overflow: hidden;
+}
+
+/* Grouping content
+   ========================================================================== */
+/**
+ * Address margin not present in IE 8/9 and Safari.
+ */
+/**
+ * Address differences between Firefox and other browsers.
+ */
+hr {
+  box-sizing: content-box;
+  height: 0;
+}
+
+/**
+ * Contain overflow in all browsers.
+ */
+pre {
+  overflow: auto;
+}
+
+/**
+ * Address odd `em`-unit font size rendering in all browsers.
+ */
+code,
+pre {
+  font-family: "DejaVu Sans Mono", "Inconsolata", monospace;
+  font-size: 1em;
+}
+
+/* Forms
+   ========================================================================== */
+/**
+ * Known limitation: by default, Chrome and Safari on OS X allow very limited
+ * styling of `select`, unless a `border` property is set.
+ */
+/**
+ * 1. Correct color not being inherited.
+ *    Known issue: affects color of disabled elements.
+ * 2. Correct font properties not being inherited.
+ * 3. Address margins set differently in Firefox 4+, Safari, and Chrome.
+ */
+button,
+input,
+select,
+textarea {
+  color: inherit;
+  /* 1 */
+  font: inherit;
+  /* 2 */
+  margin: 0;
+  /* 3 */
+}
+
+/**
+ * Address `overflow` set to `hidden` in IE 8/9/10/11.
+ */
+button {
+  overflow: visible;
+}
+
+/**
+ * Address inconsistent `text-transform` inheritance for `button` and `select`.
+ * All other form control elements do not inherit `text-transform` values.
+ * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.
+ * Correct `select` style inheritance in Firefox.
+ */
+button,
+select {
+  text-transform: none;
+}
+
+/**
+ * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
+ *    and `video` controls.
+ * 2. Correct inability to style clickable `input` types in iOS.
+ * 3. Improve usability and consistency of cursor style between image-type
+ *    `input` and others.
+ */
+button,
+input[type="reset"],
+input[type="submit"] {
+  -webkit-appearance: button;
+  /* 2 */
+  cursor: pointer;
+  /* 3 */
+}
+
+/**
+ * Re-set default cursor for disabled elements.
+ */
+button[disabled],
+html input[disabled] {
+  cursor: default;
+}
+
+/**
+ * Remove inner padding and border in Firefox 4+.
+ */
+button::-moz-focus-inner,
+input::-moz-focus-inner {
+  border: 0;
+  padding: 0;
+}
+
+/**
+ * Address Firefox 4+ setting `line-height` on `input` using `!important` in
+ * the UA stylesheet.
+ */
+input {
+  line-height: normal;
+}
+
+/**
+ * It's recommended that you don't attempt to style these elements.
+ * Firefox's implementation doesn't respect box-sizing, padding, or width.
+ *
+ * 1. Address box sizing set to `content-box` in IE 8/9/10.
+ * 2. Remove excess padding in IE 8/9/10.
+ */
+input[type="checkbox"],
+input[type="radio"] {
+  box-sizing: border-box;
+  /* 1 */
+  padding: 0;
+  /* 2 */
+}
+
+/**
+ * Fix the cursor style for Chrome's increment/decrement buttons. For certain
+ * `font-size` values of the `input`, it causes the cursor style of the
+ * decrement button to change from `default` to `text`.
+ */
+/**
+ * 1. Address `appearance` set to `searchfield` in Safari and Chrome.
+ * 2. Address `box-sizing` set to `border-box` in Safari and Chrome.
+ */
+/**
+ * Remove inner padding and search cancel button in Safari and Chrome on OS X.
+ * Safari (but not Chrome) clips the cancel button when the search input has
+ * padding (and `textfield` appearance).
+ */
+/**
+ * Define consistent border, margin, and padding.
+ */
+/**
+ * 1. Correct `color` not being inherited in IE 8/9/10/11.
+ * 2. Remove padding so people aren't caught out if they zero out fieldsets.
+ */
+legend {
+  border: 0;
+  /* 1 */
+  padding: 0;
+  /* 2 */
+}
+
+/**
+ * Remove default vertical scrollbar in IE 8/9/10/11.
+ */
+textarea {
+  overflow: auto;
+}
+
+/**
+ * Don't inherit the `font-weight` (applied by a rule above).
+ * NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
+ */
+/* Tables
+   ========================================================================== */
+/**
+ * Remove most spacing between table cells.
+ */
+table {
+  border-collapse: collapse;
+  border-spacing: 0;
+}
+
+td,
+th {
+  padding: 0;
+}
+
+/* Fontello data, processed by the unpack script. */
+@font-face {
+  font-family: 'fontello';
+  src: url("data:application/octet-stream;base64,d09GRgABAAAAAB1IAA8AAAAALzgAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABHU1VCAAABWAAAADsAAABUIIslek9TLzIAAAGUAAAAQwAAAFZ5SGGeY21hcAAAAdgAAADcAAACmkrYBwZjdnQgAAACtAAAABQAAAAgBzn/aGZwZ20AAALIAAAFkAAAC3CKkZBZZ2FzcAAACFgAAAAIAAAACAAAABBnbHlmAAAIYAAAEYIAABpAwgwZhmhlYWQAABnkAAAAMgAAADYPKXCxaGhlYQAAGhgAAAAgAAAAJAfeBCBobXR4AAAaOAAAADIAAABMRb//8WxvY2EAABpsAAAAKAAAACg4wD2+bWF4cAAAGpQAAAAgAAAAIAGDDbpuYW1lAAAatAAAAXcAAALNzJ0dH3Bvc3QAABwsAAAAnQAAANQsTQapcHJlcAAAHMwAAAB6AAAAhuVBK7x4nGNgZGBg4GIwYLBjYHJx8wlh4MtJLMljkGJgYYAAkDwymzEnMz2RgQPGA8qxgGkOIGaDiAIAJjsFSAB4nGNgZF7DOIGBlYGBqYppDwMDQw+EZnzAYMjIBBRlYGVmwAoC0lxTGByUNf7/Z275P4chirmFIQUozAiSAwAEsAy2AHic5ZI7bgJBEETf7M/mD9bKAamlGQdOfBauQMwJCLgGdyAyuW9jaUWEZHAKNd1ENjdwr962plaanq0aoAZK8SYqCB8Ecu2kBtNL+qZXbLR+ZiqleXmNdVzHbWrTIi3TqiuOh8sF/ui4fqeC9vr9zE0vNKHSyRoeeKSn+QOG+tDc3ed/1dDe3W31lB13clqxduQgce3kdOPWyQmn1snJp4Ujp0lLR56TVo7ct1E2rqcenHwjusJRNsrY0enC98gA9dO7AWP1TwMm6l8Gukvh9GPAjHDeG/qvK2X7Og94nGNgQAMSEMjc8n8OCAMAFYwEpXicrVZpd9NGFB15SZyELCULLWphxMRpsEYmbMGACUGyYyBdnK2VoIsUO+m+8Ynf4F/zZNpz6Dd+Wu8bLySQtOdwmpOjd+fN1czbZRJaktgL65GUmy/F1NYmjew8CemGTctRfCg7eyFlisnfBVEQrZbatx2HREQiULWusEQQ+x5ZmmR86FFGy7akV03KLT3pLlvjQb1V334aOsqxO6GkZjN0aD2yJVUYVaJIpj1S0qZlqPorSSu8v8LMV81QwohOImm8GcbQSN4bZ7TKaDW24yiKbLLcKFIkmuFBFHmU1RLn5IoJDMoHzZDyyqcR5cP8iKzYo5xWsEu20/y+L3mndzk/sV9vUbbkQB/Ijuzg7HQlX4RbW2HctJPtKFQRdtd3QmzZ7FT/Zo/ymkYDtysyvdCMYKl8hRArP6HM/iFZLZxP+ZJHo1qykRNB62VO7Es+gdbjiClxzRhZ0N3RCRHU/ZIzDPaYPh788d4plgsTAngcy3pHJZwIEylhczRJ2jByYCVliyqp9a6YOOV1WsRbwn7t2tGXzmjjUHdiPFsPHVs5UcnxaFKnmUyd2knNoykNopR0JnjMrwMoP6JJXm1jNYmVR9M4ZsaERCICLdxLU0EsO7GkKQTNoxm9uRumuXYtWqTJA/Xco/f05la4udNT2g70s0Z/VqdiOtgL0+lp5C/xadrlIkXp+ukZfkziQdYCMpEtNsOUgwdv/Q7Sy9eWHIXXBtju7fMrqH3WRPCkAfsb0B5P1SkJTIWYVYhWQGKta1mWydWsFqnI1HdDmla+rNMEinIcF8e+jHH9XzMzlpgSvt+J07MjLj1z7UsI0xx8m3U9mtepxXIBcWZ5TqdZlu/rNMfyA53mWZ7X6QhLW6ejLD/UaYHlRzodY3lBC5p038GQizDkAg6QMISlA0NYXoIhLBUMYbkIQ1gWYQjLJRjC8mMYwnIZhrC8rGXV1FNJ49qZWAZsQmBijh65zEXlaiq5VEK7aFRqQ54SbpVUFM+qf2WgXjzyhjmwFkiXyJpfMc6Vj0bl+NYVLW8aO1fAsepvH472OfFS1ouFPwX/1dZUJb1izcOTq/Abhp5sJ6o2qXh0TZfPVT26/l9UVFgL9BtIhVgoyrJscGcihI86nYZqoJVDzGzMPLTrdcuan8P9NzFCFlD9+DcUGgvcg05ZSVnt4KzV19uy3DuDcjgTLEkxN/P6VvgiI7PSfpFZyp6PfB5wBYxKZdhqA60VvNknMQ+Z3iTPBHFbUTZI2tjOBIkNHPOAefOdBCZh6qoN5E7hhg34BWFuwXknXKJ6oyyH7kXs8yik/Fun4kT2qGiMwLPZG2Gv70LKb3EMJDT5pX4MVBWhqRg1FdA0Um6oBl/G2bptQsYO9CMqdsOyrOLDxxb3lZJtGYR8pIjVo6Of1l6iTqrcfmYUl++dvgXBIDUxf3vfdHGQyrtayTJHbQNTtxqVU9eaQ+NVh+rmUfW94+wTOWuabronHnpf06rbwcVcLLD2bQ7SUiYX1PVhhQ2iy8WlUOplNEnvuAcYFhjQ71CKjf+r+th8nitVhdFxJN9O1LfR52AM/A/Yf0f1A9D3Y+hyDS7P95oTn2704WyZrqIX66foNzBrrblZugbc0HQD4iFHrY64yg18pwZxeqS5HOkh4GPdFeIBwCaAxeAT3bWM5lMAo/mMOT7A58xh0GQOgy3mMNhmzhrADnMY7DKHwR5zGHzBnHWAL5nDIGQOg4g5DJ4wJwB4yhwGXzGHwdfMYfANc+4DfMscBjFzGCTMYbCv6dYwzC1e0F2gtkFVoANTT1jcw+JQU2XI/o4Xhv29Qcz+wSCm/qjp9pD6Ey8M9WeDmPqLQUz9VdOdIfU3Xhjq7wYx9Q+DmPpMvxjLZQa/jHyXCgeUXWw+5++J9w/bxUC5AAEAAf//AA94nMVYe4yc1XW/5z6/13zz+uab8e7M7O7M7sx6dz1rz87D7Nrrwa9d7LG7Xq/NrgX2llccjL3UNVglcoqMFUFAOIkUQikxdrBLhQolBJqYJqh/AIkSVYU2Mk5ppBanqkkrpFaOiqg97rnfLAZKH1H/aOdxv/s493znnnvuOb9zSZjghy+nzxObJEmeDJMxMkG2kz1kHzlMHiDHyVPkafId8kjjoUmgDCZIlnSKbOfujmQibAvhe67FORN8fkk0ZHKWijgGp8Dob8YVhZikJA1kvgvSmUx6Gh/pzCzJpDPNkydf/ONnnzn59Mmnv3XqqSefePzrXzv+yENfeuD+I/cdPvRbB/btvf2WPTfN7Zye2rJpYv3142MrRxY/5W6RGawnvEHIrYbKGJQ/WS9+og4JL9+j6yM95b7/gib5a/QnP83zf6Kp6nY82hOFqCdRgEI1WqmhCP45s2rib9I8YuJvst2iq8xW1jThXbP1+2bNxN/iwDlDt4yJxVb78XabpPVu+3n8owdyHMfKxOU97GJ/1+U9mYGBDDuVHfggmPWldtme+rPPdD3+mXq7hETQtfh7LSAyW9vhUsvRf/0OuJQdGEDzAUKuXman2EHSRaoNKxa20CAIhYnNL6SnZhsOAKHkbkKpQ2/obFjYoAvYR+6YeznjJZlIDoIXhnjCc2EYlESdVerxoi776rVyFwifnQr/eLmTcP7tQ8d3YPlP3C5IfdHudo5Aqpt2OuHXW+85dgTUsWMqZnEDkq+HnYTobyWTrX4RyHeBzbHVZAUZb4wNABN9GcoZnSCcAeOwn2jTpvuIIIwLNo8SEjqDApNZrJDm0moyn+yVogMFdanKFYqFyhqo+cksjJTHWYnmpEr6Em2gUKxWal0wjv1ZyubWHzy5c/75VVw0ZZQvvXfd6N6pAVpq3rVwW/+WaDz5YdiDoejkqiembzxxaC18RZd0+gbp8i0CZHW01Lzz0J3NUn/flsgy3/0wFY9NXje+/tAJ1LnENZ3mw+wLxCAx0knuI39C/pk82fi9939GuXvnzVQYb37/bkbEq3908p7p5oZ8xgTynRMNRmF0GZX06/dTm6mJf3iHuhuOgr3eAsMUpiH2E0kVlWo/cQk3XT5PTIOYM0SEgIAgqBoJdEZvqWKg5gmzbTZDGLNnic3s5t9f+OEbz/7hw1/ef9dtt+yaq5QHB+Ke58VjYa27SiEnPb9cE5WCC0ldY7orC+WaSngyDFL5Sd9TLuSGsY5frdFqsVBEowjsYRzqhWEoAR61Gm5AXW9EXSu7Cxv4xbPnd4GfRLNJ+gkv4NgFWcCDi+x8XeY171zRBdVmiSyQG07GBrIcKePsJDIPGGh5op+cWygGc3/NqXBp5t4Z/MFzQyuHYGB0CBaf5w1+o3TiXZw76yOikfCl4qG90grFk2t5SE5x0WuE1A5hGGKnstt0lpSNeEoqpgkBKa8XIbGNp6JGSO6QEu7YLq00XQ8ikbEdWw0xWM8yltq+XVkZVokAHzCi0XSS03U0bWL3IvWAEVDz/5YYvjKm1zFzITNE+7vw7NM5LMYGBv78cyiLG0929kmHR9fysi1XdYYMFMgpc745LIQx5KT8EBhqr7hGKSJIaRmrOgJKe4Wm5DKbCHXGHWq0/mKraYTdNS6l/Z19AHYF+inFdtgwt5pmJKRHsmYFjbA/CUU9FIqYdATH2rOKesipFNuTTJxkXJtkAxSvTTIC30UIO0N/TBIk0+gIo5VjjKNAF3AIFnDwDi/ptX2U0oYDwdFHgwsKn52JtLojQ5HWL8PhJj5PwwEsmxE66eNAOAx+0IycgYVIpBkm7OoV9EV70BeFSZ2sJ5ONDUtBMBMoOkn0R5ShY9pPmKBM7COKUK7oPPql9uED3OcZlFDOEgmymcgOxv1CIW+I9GBftVLA4yIz4Pl4DGrxSgnyOSVRxpEynpEy2qTEo4WxKhjXB2icJdHn5koUh/GQXLKMfYYVFMfHb1rx4IQZ2sSlKbJ9Kwf8zvwqCIZSsbSV9Zy3D75x8UcH5H3fv/TKF499NM2C310xUzocsutcFTqzsUSHE17b5+FALGdHZEe6f/qe1w4deu2Xulj0yxfZOEmTnkY2GuiegtY70+EBSDIRshFApLnwBgXqvlhi6F/r6FuTKHvZ11sCl1y7dTpsDeQ6Hj2Smxwvxb2hxsb8kUfvb52xMhZMha1abarvC1+G1EAu4fX2d8Ajv7q/9W0reP+/0MfZvcQjy16G4PWbX+jFkGVrw7gb2w5gxDKvmcLcS8kkFf6gSX3tXAJrqLcNwaOPtt6GpZZ1s522W7fYNpywstbNFv2b1vnW20HVgqfwCSds+2YrS3RkIVf/kU2zKiKv5WR5Y9lAbyejLIygCYLYxBcIthf+gzkmrhtNCbFkEJ2aLAQBczgwSvSFgQPUwRTdaOA866gu9IBBGPXhOT9tbzsrIrwh5dkpG0OK68OZj6te1tp2VrpyjYS7sE3Nba8I0cAOpEj7PnxeiVeCmhuMTp3FUbF4huhP6fdIL8k2OnNLIorr8I8h9aNI76U9j4vUYF+gtk8L3T5ObRED0elP20fpdPvo4DPycTscPn06/C1fV86cCX+WMFzSBIFuL7BdeM5SqNsVjVJ/1xI8WjGHsbZyKSoXDxtqGNjHyh31kh31QLmLSlT5IKaPwzUlXoMpH2u9jq4fzoizU5YX1jEd1Tz1inBlQ8BLXjfqSeq6eGVbMO5DXcmz2/AQASoy7FEHCbTO37nWaODkRQoNz3EtT+I5OYaxPoWxvk42NyZjFjqKMlDeCegrJojCJSiyH4mp4HQ3ugxQAjBAM2OWGIYzqUEDug0ZkjdU89V4sjfeEzERTIueaLDGPNpKodiTk9pD1HvQg4wUBYJY1aNHdYFIFvt9lWjH1Ofg0nt+Fs49aqnWYeWgd4CHlHX8mWcg2+1feQ/BUestLLp9usfvBsf4RcTPwB3Z5MVTvcoCR/bqOa2vPvN+66GAbK47Qd8Pat9Vxi/CtUVfqXGbAz+Af6WHN79gTs1ev4r8gPwp+R4mJo+RBxEIMVzZcaIxJiN/Tf4KdTBHtpG1ZJyMkG6yhFjajcIJeBweg0fgYbgP7oHb4VZg5O/I3xIHOSjYDlugH+cb6FcvwTvwFvwE/gxehZUwgn2g+8lE5+YXLHz/usW3P4i6RutHaQBniv8DGRSmZo9hTUPajZ3/f4qYmwt2olHFE6QYRbCoJFNyH5EGk8Y+YgAzYB+6zwMIOvHAzeCDsFm0S0ZYs63GxihHHE4Fu51QJajCYCdFm4do8xAf8xCizUPsxLWLTZ3/yzfPzV2/RHsrOA/n4Cx8F26EneSH5HXyMnmJfJs8T36H3Is6QmyN2gD8W/g6TO0wOH4UJwGBY3kcqohEa8mCBqFrQBaqnqoUZLXEtU/QzsEbAC8nc6pWLORrheJIiRZLuhsdCOJdpbGuhroyhxWEkcWC0v9yQY1DXjMt+hre1sr+iF8plgMCmdTE+IIiskWuxYJuZzXaVPgq6asSFP1iPqexcr2SLEpV1qwQkxY0gFUoAU6VKku9uq9wGk4sFqQ/ovl0oUB12cUwskrNr4pUfr1WLNGqRtcyS0dQ7nKWdzG/HOQ+fj2n3UAiC8laFblgoVdfqCXLNVwuLsuTiXxNu3fsVznlsgKKoNtFLReGqgquw68hJxTYr2cpaqdW11nVOCDsr5ZQBQHOL5aRIofSINT3dVn3a4VxSNRreS2jVnC5igphCMXRLdcwKupfGHBlCdRXCXctDIVaQeu9JhMuJEpQR8F9nWQkPYmh8dAbBz9CNBCnBsYuzqKJODoqakhMdSTnlpAcDERqjHH8IAKjmDRxiZRgOCDSmFJSJHCBKhNJAK0OFPppEWLMc+PcwNwJqDApxE3JqZAWMzgaP5MmchMm5p4MvTe4yg7zCEOumMsa+oGMGYasmGCOg6+nzpJOJoWIC2bzkI0vktzgJt9W5oJKwSBloQyCaznxlQDUUirGlcnxhdTFNnUppzRsMGTNBHAEJ8hBOIoyg5nKlxKTjwj3kA8yZy5myZYwohbFDwYcbFHmMIraQPnwINr4Hmp4zMAJet1C3wEBA55iJkMBWIi6Wh0cRyTKgHriXBlCORwbmFSKQBCH0xhOp8I1KbUMVJWUSpiO9fnfnkIwFsL5Ce02tKKFg2ceP6Alt3CHKKoaiVAQboeBmhaw1YtYE4vWz8FAbkjMhI1kyALjjwr0ChSTEol65aA3Fx9Yp4ZWq74fwL1WzFCW4kIKR5sGLs0xUSkCl8CilLmG7mcmbiuT4HILWQpclsWVUmAKQxmoJKZ1ieZgMebqYYHgHsNmmDLtzFxUAJf4RSGW/QbXu85l2EIZBEd9eDYF2UEhiRbHhMdYBHXMDWFwsFMh4eCquWO43AXL9hS6T1Q57kWMWZybQlJmBQqmESOm7RflsDAd0FuJ+o6IsPbF1MZFY5OnXNMVJqBVoqpR6XhMBA2jjQQXJcwQmBoaqEiXWpbADm6bQpsG7gGumeOBQBVIwOXhRL3vWLRCiR16zZKGQZ8DVDW1mMQu1K4rqabR9qT5iLQRNV3ToTyiAvxzgZ2iv0KPvARj2S6Nf+amt04gfUhHOzphgjLUAjGosaBF1LCOMA09BVkgAo15BmOIhj9CNnfM5DOb67nYYDpuIf7pQ9deYuM0C+JaLVkp6NwJHSm6U+VlWV3f89Q95XKVK/F29o9/zPgx7U9qh6QzfrjdzZV6UcXd5WwMbv1EY3br9cmd/fPFHam1TeitTW8q7S5tml6Z+2LO3zRz587y4ORNW5uj8XwznF69a/X0ru2bRm8ay4SbP/dL/bS33F/J8YGh1Kca63Y7Ujq7162YHPLRR3X0N792aMPgeM7DDbVSuZW9Gw4dm1tWblw3NOzFSgNwXWPFsrlFXWpMxUgPWUE2kG2NrYMD+RyeIZgI6R036EZiKTQti89jvMe4yuYxJgIigt24ycQ0ybR+EnOWmMRsNlavrCYLI9H4WDQasfX1bE+1R4xEK8FVjb7ZyQcQMh8dqbbvQhVbTFYDqDlSronFy9Li4mWpDizn4Dl93TjpiG+iNWSTrVcRbE5OdifgLYST5zDfDDCnLm/LJq/E2lBTJGvhJyP+4LlzcMnoUE9KBy763d3+xSu14AnZF3Wu+qKea135UHfR9/3ulPtNBJw6jbn6wdWL7J/YKOakeXL45ay2U8wKbUQsSxFsqAUTvQjIBaFtODA2Rm/V0ItNa8AxhxWypbPR/5/TBob5KdK5RjSTyeQz+Wg8motH/Zqlk/ksxisXtEowjq2BEaWDcI++4CoiKu8biY5E2Y9iMZnmvf7lN/1enrYGTtzy7IsG74ehfoO/+Owty1uXW5f/4NUPrKHYE15Hh/fE8tRdR40DB4yj5y5dAnI1yCuw0HcRFuLDUTJNHm48OAG2MYxmkMAAglk48IloiNqGNGy5P2JSxfWNxP6wdsHaF+zXKMlwLG0pGIPkvE5A0IPOBzhL31WQWRfZkObYWE8PZsVkbHpsurl5w7rGmp7RntHKyLLBYp/dbXd3LInHwq4UxAIrhvl+H5oD5l2+8mQdI3gOY3dwMzxOfX2/hp0aUuVclm93g47ni/1Uti/rKvVabzcPuumYPQUbhyZh+hEYmJzc6PvWjBg6evTYoJh5VMrm0R3D8xtXdlNzRm568/xf3iCxV916vnXuNiXNGZB7oRuGIPc5MVOetmMpmo7Y099Ip9OuO2MpObicVpZKZc08LkZXQirXm8JesWmabm0K7P2GmJ2lN+0UmnTvwYN7NaW2tatXL/BhzOvCZFjn/8EtULeOTBM68b+bLPrbedwnMYsezCE3VBHGFLzgLjraztdU1PNHdL4WJGseqmHxMKH2dN5WXzxU7KJlXH4gSL3YEeVsrPS13opFMNFtvYs5ayzWerO3BpU+dqSvArvgrYCwNawQGZy/cgr7vBJiOMz9jdxQotZL9/RVKuTfARBwvMoAAHicY2BkYGAA4kTBOMl4fpuvDNzML4AiDFdvTguD0f9//J/DEs/cAuRyMDCBRAFTrQ07AAB4nGNgZGBgbvk/h4GBpez/j/+/WOIZgCIoQBgArDwHBXicY37BwMCiz8DAvACII6HsFyD2/78gmukURJxZEErD5BbA+P9/sJSB9P3/DwAx8xHmAAAAAAAAASIBcgHcA4ADuAQ+BH4EvgUiBWwF0gZOClIK+AuIC/4Mvg0gAAEAAAATAfgADwAAAAAAAgBAAFAAcwAAAK0LcAAAAAB4nHWQ3WrCMBiG38yfbQrb2GCny9FQxuoPDEEQBIeebCcyPB211rZSG0mj4G3sHnYxu4ldy17bOIayljTP9+TLl68BcI1vCOTPE0fOAmeMcj7BKXqWC/TPlovkF8slVPFmuUz/brmCBwSWq7jBByuI4jmjBT4tC1yJS8snuBB3lgv0j5aL5J7lEm7Fq+UyvWe5golILVdxL74GarXVURAaWRvUZbvZ6sjpViqqKHFj6a5NqHQq+3KuEuPHsXI8tdzz2A/Wsav34X6e+DqNVCJbTnOvRn7ia9f4s131dBO0jZnLuVZLObQZcqXVwveMExqz6jYaf8/DAAorbKER8apCGEjUaOuc22iihQ5pygzJzDwrQgIXMY2LNXeE2UrKuM8xZ5TQ+syIyQ48fpdHfkwKuD9mFX20ehhPSLszosxL9uWwu8OsESnJMt3Mzn57T7HhaW1aw127LnXWlcTwoIbkfezWFjQevZPdiqHtosH3n//7AeZuhFEAeJxtylsOgjAQRuH+yB284jZc1AADNJQOaUuIrl4TffR7PDkqUl+l+q9BhANiJEiRIUeBEhVqHHHCGRdccUODu8pnfrZCrk+olS1kjn0Qx0UndtDj5jiSOZ7YrGkvlgLHLXVz/bn0ix9+IWPSjmzHpvq1YTMmWckHziyHXdycjjpMW5ut7Lz2Ie9lt0aoj3c96DywW7Qlo9QbVzAzAwAAAHicY/DewXAiKGIjI2Nf5AbGnRwMHAzJBRsZWJ02MTAyaIEYm7mYGDkgLD4GMIvNaRfTAaA0J5DN7rSLwQHCZmZw2ajC2BEYscGhI2Ijc4rLRjUQbxdHAwMji0NHckgESEkkEGzmYWLk0drB+L91A0vvRiYGFwAMdiP0AAA=") format("woff");
+}
+
+[class^="icn-"]::before, [class*=" icn-"]::before {
+  font-family: "fontello";
+  font-style: normal;
+  font-weight: normal;
+  speak: none;
+  display: inline-block;
+  text-decoration: inherit;
+  width: 1em;
+  margin-right: .2em;
+  text-align: center;
+  /* opacity: .8; */
+  /* For safety - reset parent styles, that can break glyph codes*/
+  font-variant: normal;
+  text-transform: none;
+  /* fix buttons height, for twitter bootstrap */
+  line-height: 1em;
+  /* Animation center compensation - margins should be symmetric */
+  /* remove if not needed */
+  margin-left: .2em;
+  /* you can be more comfortable with increased icons size */
+  /* font-size: 120%; */
+  /* Font smoothing. That was taken from TWBS */
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  /* Uncomment for 3D effect */
+  /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
+}
+
+/* Fontello icon codes */
+/* Fontello classes */
+.icn-keyboard::before {
+  content: '\2328';
+}
+
+.icn-about::before {
+  content: '\2605';
+}
+
+.icn-restore::before {
+  content: '\267c';
+}
+
+.icn-configure::before {
+  content: '\2699';
+}
+
+.icn-ok::before {
+  content: '\2714';
+}
+
+.icn-help::before {
+  content: '\2753';
+}
+
+.icn-donate::before {
+  content: '\2764';
+}
+
+.icn-back::before {
+  content: '\276e';
+}
+
+.icn-resize-small::before {
+  content: '\e800';
+}
+
+.icn-cancel::before {
+  content: '\e801';
+}
+
+.icn-resize-full::before {
+  content: '\e802';
+}
+
+.icn-paste::before {
+  content: '\f0ea';
+}
+
+.icn-network::before {
+  content: '🌍';
+}
+
+.icn-github::before {
+  content: '🐱';
+}
+
+.icn-persist::before {
+  content: '💾';
+}
+
+.icn-download::before {
+  content: '📥';
+}
+
+.icn-wifi::before {
+  content: '📶';
+}
+
+.icn-terminal::before {
+  content: '🖳';
+}
+
+html {
+  box-sizing: border-box;
+}
+
+*, *::after, *::before {
+  box-sizing: inherit;
+}
+
+html {
+  font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", Helvetica, Roboto, Arial, sans-serif;
+  color: #D0D0D0;
+}
+
+html, body {
+  background: #131315;
+  border: 0 none;
+  margin: 0;
+  padding: 0;
+  text-decoration: none;
+  width: 100%;
+  height: 100%;
+  overflow: hidden;
+}
+
+a, a:visited, a:link {
+  cursor: pointer;
+  color: #5abfff;
+  text-decoration: none;
+}
+
+a:hover {
+  color: #5abfff;
+  text-decoration: underline;
+}
+
+.hidden {
+  display: none !important;
+}
+
+.invisible {
+  visibility: hidden !important;
+}
+
+[onclick] {
+  cursor: pointer;
+}
+
+ul > * {
+  padding-top: .3em;
+  padding-bottom: .3em;
+}
+
+ul {
+  margin-top: 0;
+  margin-bottom: 0;
+}
+
+/* Main outer container */
+#outer {
+  display: flex;
+  position: absolute;
+  width: 100%;
+  height: 100%;
+  left: 0;
+  right: 0;
+  top: 0;
+  bottom: 0;
+  overflow: hidden;
+  flex-direction: row;
+}
+
+@media screen and (max-width: 544px) {
+  #outer {
+    display: block;
+    overflow-y: scroll;
+  }
+}
+
+#menu {
+  flex: 0 0 15rem;
+  background: #3983CD;
+}
+
+#menu > * {
+  display: block;
+  text-decoration: none;
+  padding: 0.61805rem 1rem;
+  white-space: nowrap;
+  word-wrap: normal;
+  -webkit-user-select: none;
+  -moz-user-select: none;
+  -ms-user-select: none;
+  user-select: none;
+}
+
+#menu #brand {
+  cursor: pointer;
+  color: white;
+  background: #2b6aa8;
+  font-size: 120%;
+  text-align: center;
+  position: relative;
+  transition: none;
+  font-weight: bold;
+  margin-bottom: 1rem;
+}
+
+@media screen and (max-width: 544px) {
+  #menu #brand {
+    background: #3983CD;
+    cursor: pointer;
+    margin-bottom: 0.38198rem;
+  }
+  #menu #brand::after {
+    position: absolute;
+    color: rgba(0, 0, 0, 0.4);
+    right: 1rem;
+    content: '▸';
+    top: 50%;
+    font-size: 120%;
+    font-weight: bold;
+    transform: translate(0, -50%) rotate(90deg);
+  }
+}
+
+#menu.expanded #brand {
+  background: #2b6aa8;
+}
+
+@media screen and (max-width: 544px) {
+  #menu.expanded #brand:after {
+    transform: translate(-25%, -50%) rotate(-90deg);
+  }
+}
+
+#menu a {
+  font-size: 130%;
+  color: white;
+  transition: background-color 0.2s;
+  text-shadow: 0 0 5px rgba(0, 0, 0, 0.4);
+}
+
+#menu a:hover, #menu a.selected {
+  background: #5badff;
+  text-shadow: 0 0 5px rgba(0, 0, 0, 0.6);
+}
+
+#menu a.selected {
+  position: relative;
+  box-shadow: 0 0 5px rgba(0, 0, 0, 0.5);
+}
+
+#menu a:focus {
+  outline-color: #ff0099;
+}
+
+#menu a::before {
+  vertical-align: -2px;
+  margin-left: 0;
+  margin-right: 15px;
+}
+
+@media screen and (max-width: 544px) {
+  #menu a {
+    display: none;
+  }
+  #menu a::before {
+    margin-left: 10px;
+  }
+}
+
+#menu.expanded a {
+  display: block;
+}
+
+@media screen and (min-width: 545px) and (max-width: 1000px) {
+  #menu {
+    flex-basis: 10rem;
+  }
+  #menu #brand {
+    font-size: 95%;
+    margin-bottom: 0.61805rem;
+  }
+  #menu a {
+    font-size: 105%;
+  }
+  #menu > * {
+    padding: 0.38198rem 0.61805rem;
+  }
+}
+
+#content {
+  flex-grow: 1;
+  position: relative;
+  padding: 1rem;
+  overflow-y: auto;
+}
+
+@media screen and (max-width: 544px) {
+  #content {
+    padding: 0.61805rem;
+  }
+}
+
+#content > * {
+  margin-left: auto;
+  margin-right: auto;
+}
+
+#content h1 {
+  text-align: center;
+  font-size: 2.2807em;
+  margin-top: 0;
+  margin-bottom: 1rem;
+}
+
+#content h2 {
+  font-size: 1.42383em;
+  margin-bottom: 0.61805rem;
+}
+
+@media screen and (max-width: 544px) {
+  #content h1 {
+    font-size: 1.80203em;
+    margin-bottom: 0.61805rem;
+  }
+  #content h2 {
+    font-size: 1.26562em;
+    margin-bottom: 0.61805rem;
+  }
+}
+
+#content td, #content th {
+  padding: 0.38198rem;
+}
+
+#content tbody th {
+  text-align: right;
+  width: 220px;
+  color: white;
+}
+
+#content {
+  opacity: 0;
+  transition: opacity 0.15s ease-in;
+}
+
+#content.load {
+  opacity: 1;
+}
+
+#loader {
+  position: absolute;
+  right: 1.618rem;
+  top: 1.618rem;
+  transition: opacity .2s;
+  opacity: 0;
+}
+
+@media screen and (max-width: 544px) {
+  #loader {
+    top: 1rem;
+    right: 1rem;
+  }
+}
+
+#loader.show {
+  opacity: 1;
+}
+
+.botpad {
+  display: block;
+  height: 5em;
+}
+
+.Box {
+  display: block;
+  max-width: 900px;
+  margin-top: 1rem;
+  padding: 0.61805rem 1rem;
+  border-radius: 3px;
+  background-color: rgba(255, 255, 255, 0.07);
+  box-shadow: 0 0 4px black;
+  border: 1px solid #4f4f4f;
+}
+
+.Box::after {
+  content: '';
+  display: block;
+  clear: both;
+}
+
+@media screen and (max-width: 544px) {
+  .Box {
+    margin-top: 0.61805rem;
+  }
+}
+
+.Box h1, .Box h2 {
+  overflow: hidden;
+}
+
+h1 + .Box {
+  margin-top: 0;
+}
+
+.Box h2 {
+  margin-top: 0;
+  margin-bottom: 0 !important;
+}
+
+.Box p:last-child {
+  margin-bottom: 0.5em;
+}
+
+.Box.wide {
+  width: initial;
+  max-width: initial;
+}
+
+.Box.medium {
+  max-width: 1200px;
+}
+
+.Box.str {
+  position: relative;
+}
+
+.Box.str .Row.buttons {
+  position: absolute;
+}
+
+@media screen and (max-width: 544px) {
+  .Box.str .Row.buttons {
+    right: 1rem;
+    top: 1.8em;
+    margin: 1rem auto;
+  }
+}
+
+@media screen and (min-width: 545px) {
+  .Box.str .Row.buttons {
+    right: 0;
+    top: 0;
+    margin-top: 0.61805rem;
+  }
+}
+
+.Box.str.mobopen .Row.buttons {
+  top: 0;
+  margin-top: 0.61805rem;
+}
+
+.Box .Row.explain {
+  display: block;
+  max-width: 600px;
+  margin-left: 0;
+  line-height: 1.2;
+}
+
+@media screen and (max-width: 544px) {
+  .Box .Row.explain {
+    margin-top: 60px;
+  }
+}
+
+.Box .Row.explain.nomargintop {
+  margin-top: 12px !important;
+}
+
+.Box.mobopen .Row.explain {
+  margin-top: 12px;
+}
+
+@media screen and (max-width: 544px) {
+  .Box.mobopen .Row.explain {
+    margin-top: 18px;
+  }
+}
+
+.Box.fold h2 {
+  position: relative;
+  cursor: pointer;
+  padding: 2px 1.3rem 2px 5px;
+  margin: 0 -5px 0 -5px;
+}
+
+.Box.fold h2::after {
+  position: absolute;
+  right: 4px;
+  content: '▸';
+  top: 50%;
+  font-size: 120%;
+  font-weight: bold;
+  transform: translate(0, -50%) rotate(90deg);
+}
+
+.Box.fold.expanded h2::after {
+  transform: translate(-25%, -50%) rotate(-90deg);
+  margin-bottom: 1rem;
+}
+
+.Box.fold .Row {
+  display: none;
+}
+
+.Box.fold.expanded .Row {
+  display: flex;
+}
+
+.Box.fold.expanded .Row.explain {
+  display: block;
+}
+
+.Box.fold.expanded .Row.v {
+  display: block;
+}
+
+@media screen and (min-width: 545px) {
+  .Box.fold.d-expanded .Row {
+    display: flex;
+  }
+  .Box.fold.d-expanded .Row.explain {
+    display: block;
+  }
+  .Box.fold.d-expanded .Row.v {
+    display: block;
+  }
+}
+
+@media screen and (max-width: 544px) {
+  .Box.fold h2, .Box.mobcol h2 {
+    padding: 2px 1.3rem 2px 5px;
+    margin: 0 -5px 0 -5px;
+  }
+  .Box.fold.expanded h2::after, .Box.mobcol.expanded h2::after {
+    margin-bottom: 1rem;
+  }
+  .Box.mobcol h2 {
+    position: relative;
+    cursor: pointer;
+    padding: 2px 1.3rem 2px 5px;
+    margin: 0 -5px 0 -5px;
+  }
+  .Box.mobcol h2::after {
+    position: absolute;
+    right: 4px;
+    content: '▸';
+    top: 50%;
+    font-size: 120%;
+    font-weight: bold;
+    transform: translate(0, -50%) rotate(90deg);
+  }
+  .Box.mobcol.expanded h2::after {
+    transform: translate(-25%, -50%) rotate(-90deg);
+    margin-bottom: 1rem;
+  }
+  .Box.mobcol .Row {
+    display: none;
+  }
+  .Box.mobcol.expanded .Row {
+    display: flex;
+  }
+  .Box.mobcol.expanded .Row.explain {
+    display: block;
+  }
+  .Box.mobcol.expanded .Row.v {
+    display: block;
+  }
+}
+
+@media screen and (max-width: 544px) and (min-width: 545px) {
+  .Box.mobcol.d-expanded .Row {
+    display: flex;
+  }
+  .Box.mobcol.d-expanded .Row.explain {
+    display: block;
+  }
+  .Box.mobcol.d-expanded .Row.v {
+    display: block;
+  }
+}
+
+@media screen and (max-width: 544px) {
+  .Box.mobcol #ap-box {
+    display: none;
+  }
+  .Box.mobcol.expanded #ap-box {
+    display: block;
+  }
+}
+
+.Modal {
+  z-index: 100;
+  position: fixed;
+  width: 100%;
+  height: 100%;
+  left: 0;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  transition: opacity .5s;
+  background: rgba(0, 0, 0, 0.65);
+  opacity: 0;
+}
+
+.Modal.visible {
+  opacity: 1;
+}
+
+.Modal.hidden {
+  display: none;
+}
+
+.Modal.light {
+  background: rgba(0, 0, 0, 0.25);
+}
+
+@media screen and (max-width: 544px) {
+  .Modal {
+    flex-direction: column;
+    justify-content: flex-start;
+    overflow-y: auto;
+  }
+  .Modal .Dialog {
+    margin-top: 0.61805rem !important;
+    flex-basis: unset;
+    flex-shrink: 0;
+  }
+}
+
+.Dialog {
+  margin: 0.61805rem;
+  padding: 1rem;
+  overflow: hidden;
+  flex-basis: 35rem;
+  background: #242426;
+  border-left: 6px solid #2972ba;
+  border-right: 6px solid #2972ba;
+  box-shadow: 0 0 6px 0 black;
+  border-radius: 6px;
+}
+
+.Dialog h1, .Dialog h2 {
+  margin-top: 0;
+}
+
+.Dialog p:last-child {
+  margin-bottom: 0;
+}
+
+.NotifyMsg {
+  position: fixed;
+  top: 1.618rem;
+  right: 2.61792rem;
+  padding: 0.61805rem 1rem;
+  -webkit-font-smoothing: subpixel-antialiased;
+  -webkit-transform: translateZ(0) scale(1, 1);
+  background: #3887d0;
+  color: white;
+  text-shadow: 0 0 2px black;
+  box-shadow: 0 0 6px 0 rgba(0, 0, 0, 0.6);
+  border-radius: 5px;
+  max-width: 600px;
+  transition: opacity .5s;
+  opacity: 0;
+}
+
+.NotifyMsg.error {
+  background: #d03e42;
+}
+
+@media screen and (max-width: 544px) {
+  .NotifyMsg {
+    width: calc(100% - 1rem);
+  }
+}
+
+.NotifyMsg.visible {
+  opacity: 1;
+}
+
+.NotifyMsg.hidden {
+  display: none;
+}
+
+button, input[type=submit], .button {
+  text-align: center;
+  cursor: pointer;
+  display: inline-block;
+  border-radius: 2px;
+  padding: 0 0.6em;
+  border: 0 none;
+  line-height: 1.8em;
+  font-size: 1.1em;
+  margin-bottom: 3px;
+  min-width: 5em;
+  -webkit-user-select: none;
+  -moz-user-select: none;
+  -ms-user-select: none;
+  user-select: none;
+  text-shadow: 1.5px 1.5px 2px rgba(0, 0, 0, 0.4);
+  background-color: #3983cd;
+  box-shadow: 0 3px 0 #265f98;
+  text-decoration: none !important;
+}
+
+button:active, input[type=submit]:active, .button:active {
+  position: relative;
+  top: 2px;
+}
+
+button.narrow, input[type=submit].narrow, .button.narrow {
+  min-width: initial;
+}
+
+button::before, input[type=submit]::before, .button::before {
+  vertical-align: -1px;
+  margin-left: 0;
+}
+
+button, button:link, button:visited, input[type=submit], input[type=submit]:link, input[type=submit]:visited, .button, .button:link, .button:visited {
+  color: #FEFEFE;
+}
+
+button:hover, button:active, button.active, button.selected, input[type=submit]:hover, input[type=submit]:active, input[type=submit].active, input[type=submit].selected, .button:hover, .button:active, .button.active, .button.selected {
+  background-color: #2076C6;
+  color: #FEFEFE;
+}
+
+button:hover, button.selected, button.active, input[type=submit]:hover, input[type=submit].selected, input[type=submit].active, .button:hover, .button.selected, .button.active {
+  box-shadow: 0 3px 0 #154c80;
+}
+
+button:active, input[type=submit]:active, .button:active {
+  box-shadow: 0 1px 0 #154c80;
+}
+
+button:focus, input[type=submit]:focus, .button:focus {
+  outline-color: #ff0099;
+}
+
+button, input[type=submit], .button {
+  text-align: center;
+  cursor: pointer;
+  display: inline-block;
+  border-radius: 2px;
+  padding: 0 0.6em;
+  border: 0 none;
+  line-height: 1.8em;
+  font-size: 1.1em;
+  margin-bottom: 3px;
+  min-width: 5em;
+  -webkit-user-select: none;
+  -moz-user-select: none;
+  -ms-user-select: none;
+  user-select: none;
+  text-shadow: 1.5px 1.5px 2px rgba(0, 0, 0, 0.4);
+  background-color: #3983cd;
+  box-shadow: 0 3px 0 #265f98;
+  text-decoration: none !important;
+}
+
+button:active, input[type=submit]:active, .button:active {
+  position: relative;
+  top: 2px;
+}
+
+button.narrow, input[type=submit].narrow, .button.narrow {
+  min-width: initial;
+}
+
+button::before, input[type=submit]::before, .button::before {
+  vertical-align: -1px;
+  margin-left: 0;
+}
+
+button, button:link, button:visited, input[type=submit], input[type=submit]:link, input[type=submit]:visited, .button, .button:link, .button:visited {
+  color: #FEFEFE;
+}
+
+button:hover, button:active, button.active, button.selected, input[type=submit]:hover, input[type=submit]:active, input[type=submit].active, input[type=submit].selected, .button:hover, .button:active, .button.active, .button.selected {
+  background-color: #2076C6;
+  color: #FEFEFE;
+}
+
+button:hover, button.selected, button.active, input[type=submit]:hover, input[type=submit].selected, input[type=submit].active, .button:hover, .button.selected, .button.active {
+  box-shadow: 0 3px 0 #154c80;
+}
+
+button:active, input[type=submit]:active, .button:active {
+  box-shadow: 0 1px 0 #154c80;
+}
+
+button:focus, input[type=submit]:focus, .button:focus {
+  outline-color: #ff0099;
+}
+
+input[type="number"], input[type="password"], input[type="text"], textarea, select, label.select-wrap {
+  width: 250px;
+  margin-right: 3px;
+}
+
+input[type="number"], input.short, select.short {
+  width: 123.5px;
+}
+
+input.tiny, select.tiny {
+  width: 90px;
+}
+
+input[type="number"], input[type="password"], input[type="text"], textarea, select {
+  border: 0 none;
+  border-bottom: 2px solid #2972ba;
+  background-color: #3c3c3c;
+  color: white;
+  padding: 4px 6px;
+  line-height: 1em;
+  font-weight: normal;
+}
+
+input[type="number"]:focus, input[type="number"]:hover, input[type="password"]:focus, input[type="password"]:hover, input[type="text"]:focus, input[type="text"]:hover, textarea:focus, textarea:hover, select:focus, select:hover {
+  border-bottom-color: #2ea1f9;
+}
+
+.Row.checkbox {
+  line-height: 27px;
+}
+
+.Row.checkbox .box {
+  overflow: hidden;
+  width: 27px;
+  height: 27px;
+  border: 1px solid #808080;
+  border-radius: 3px;
+  background: #3c3c3c;
+  display: inline-block;
+  position: relative;
+  cursor: pointer;
+  color: #2ea1f9;
+}
+
+.Row.checkbox .box::before {
+  font-family: "fontello";
+  position: absolute;
+  left: 0;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  line-height: 25px;
+  text-align: center;
+  font-size: 20px;
+  vertical-align: middle;
+  display: none;
+}
+
+.Row.checkbox .box::before {
+  content: "✔";
+}
+
+.Row.checkbox .box.checked::before {
+  display: block;
+}
+
+.Row.range .display {
+  margin-left: 1ex;
+}
+
+.Row.range label .display {
+  font-weight: normal;
+}
+
+#psk-modal form > *, #wificonfbox form > * {
+  margin-right: 0.38198rem;
+}
+
+#psk-modal form > *:last-child, #wificonfbox form > *:last-child {
+  margin-right: 0;
+}
+
+form {
+  border: 0 none;
+  margin: 0;
+  padding: 0;
+  text-decoration: none;
+}
+
+.Box.errors .list {
+  color: crimson;
+  font-weight: bold;
+}
+
+.Box.errors .lead {
+  color: white;
+}
+
+.Box.message {
+  font-weight: bold;
+  color: #0fca50;
+  transition: opacity linear 1s;
+  opacity: 1;
+}
+
+.Box.message.hiding {
+  opacity: 0;
+}
+
+.Row {
+  vertical-align: middle;
+  margin: 12px auto;
+  text-align: left;
+  line-height: 1.35em;
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  flex-wrap: wrap;
+}
+
+.Row .SubRow {
+  display: flex;
+  flex-direction: row;
+}
+
+@media screen and (max-width: 544px) {
+  .Row .SubRow {
+    flex-direction: column;
+    margin: 6px auto;
+    width: 100%;
+  }
+}
+
+.Row:first-child {
+  margin-top: 0;
+}
+
+.Row:last-child {
+  margin-bottom: 0;
+}
+
+.Row.v {
+  display: block;
+}
+
+.Row .aside {
+  float: right;
+  margin-left: 5px;
+  margin-bottom: 5px;
+}
+
+@media screen and (max-width: 544px) {
+  .Row .aside {
+    margin: 0;
+    float: none;
+  }
+}
+
+.Row .spacer {
+  width: 220px;
+}
+
+@media screen and (max-width: 544px) {
+  .Row .spacer {
+    display: none;
+  }
+}
+
+.Row.buttons, .Row.buttons2 {
+  margin: 16px auto;
+}
+
+.Row.buttons input, .Row.buttons .button, .Row.buttons2 input, .Row.buttons2 .button {
+  margin-right: 0.61805rem;
+}
+
+.Row.buttons2 {
+  display: block;
+}
+
+.Row.centered {
+  justify-content: center;
+}
+
+.Row.message {
+  font-size: 1em;
+  text-shadow: 1px 1px 3px black;
+  text-align: center;
+}
+
+.Row.message.error {
+  color: crimson;
+}
+
+.Row.message.ok {
+  color: #0fe851;
+}
+
+.Row.separator {
+  padding-top: 14px;
+  border-top: 2px solid rgba(255, 255, 255, 0.1);
+}
+
+.Row textarea {
+  display: inline-block;
+  vertical-align: top;
+  min-height: 10rem;
+  flex-grow: 1;
+  resize: vertical;
+}
+
+.Row label {
+  font-weight: bold;
+  color: white;
+  display: inline-block;
+  width: 220px;
+  text-align: right;
+  text-shadow: 1px 1px 3px black;
+  padding: 8px;
+  align-self: flex-start;
+  -webkit-user-select: none;
+  -moz-user-select: none;
+  -ms-user-select: none;
+  user-select: none;
+  white-space: nowrap;
+  word-wrap: normal;
+}
+
+.Row label.error {
+  color: crimson;
+}
+
+.Row input[type="range"] {
+  width: 200px;
+}
+
+@media screen and (max-width: 544px) {
+  .Row {
+    flex-direction: column;
+    margin: 6px auto;
+  }
+  .Row.buttons, .Row.centered, .Row.checkbox {
+    flex-direction: row;
+  }
+  .Row.buttons {
+    justify-content: center;
+  }
+  .Row.buttons :last-child {
+    margin-right: 0;
+  }
+  .Row label {
+    padding-left: 0;
+    text-align: left;
+    width: auto;
+  }
+  .Row .checkbox-wrap {
+    order: 1;
+    text-align: left;
+    padding-bottom: 0;
+    border-radius: .4px;
+    width: auto;
+  }
+  .Row .checkbox-wrap + label {
+    width: auto;
+  }
+  .Row input[type="number"], .Row input[type="password"], .Row input[type="text"], .Row textarea, .Row input[type="range"], .Row textarea, .Row select {
+    width: 100%;
+  }
+}
+
+form span.required {
+  color: red;
+}
+
+.RadioGroup {
+  display: inline-block;
+  line-height: 1.5em;
+  vertical-align: middle;
+}
+
+.RadioGroup label {
+  width: auto;
+  text-align: left;
+  cursor: pointer;
+  font-weight: normal;
+}
+
+.RadioGroup input[type="radio"] {
+  vertical-align: middle;
+  margin: 0 0 0 5px;
+}
+
+#ap-list {
+  column-count: 3;
+  column-gap: 0;
+  margin: 0 -0.23608rem;
+}
+
+@media screen and (min-width: 545px) and (max-width: 1000px) {
+  #ap-list {
+    column-count: 2;
+  }
+}
+
+@media screen and (max-width: 544px) {
+  #ap-list {
+    column-count: 1;
+  }
+}
+
+#ap-loader, #ap-noscan, #ap-scan {
+  background: rgba(255, 255, 255, 0.1);
+  border-radius: 5px;
+  padding: 0.38198rem;
+  margin-bottom: 0.38198rem;
+  margin-top: 0.38198rem;
+  font-size: 110%;
+}
+
+#ap-noscan {
+  font-weight: bold;
+}
+
+#ap-box {
+  padding-top: 0.38198rem;
+}
+
+#ap-box label {
+  display: block;
+  color: white;
+  font-weight: bold;
+  margin-bottom: 0.23608rem;
+}
+
+#psk-modal form {
+  display: flex;
+  align-items: center;
+  margin: 0.38198rem;
+}
+
+#psk-modal form input[type=password] {
+  min-width: 5rem;
+}
+
+.AP .inner, .AP-preview .wrap {
+  cursor: pointer;
+  -webkit-user-select: none;
+  -moz-user-select: none;
+  -ms-user-select: none;
+  user-select: none;
+  position: relative;
+  border-radius: 3px;
+  color: #222;
+  background: #afafaf;
+  transition: background-color 0.5s;
+  display: flex;
+}
+
+.AP .inner:active, .AP-preview .wrap:active {
+  left: 0;
+  top: 1px;
+}
+
+.AP .inner:hover, .AP-preview .wrap:hover {
+  background: white;
+}
+
+.AP .inner .rssi, .AP-preview .wrap .rssi {
+  min-width: 2.5rem;
+  flex: 0 0 15%;
+  text-align: right;
+}
+
+.AP .inner .rssi:after, .AP-preview .wrap .rssi:after {
+  padding-left: 0.09018rem;
+  content: '%';
+  font-size: 0.88889em;
+}
+
+.AP .inner .essid, .AP-preview .wrap .essid {
+  flex: 1 1 70%;
+  min-width: 0;
+  text-overflow: ellipsis;
+  overflow: hidden;
+  font-weight: bold;
+}
+
+.AP .inner .auth, .AP-preview .wrap .auth {
+  flex: 0 0 15%;
+}
+
+.AP {
+  break-inside: avoid-column;
+  max-width: 500px;
+  padding: 0.23608rem;
+}
+
+.AP.selected .inner {
+  background: #42a6f9 !important;
+  cursor: default;
+  top: 0 !important;
+}
+
+.AP .inner > * {
+  padding: 0.61805rem;
+  white-space: nowrap;
+  word-wrap: normal;
+}
+
+.AP-preview-nil {
+  padding: 8px;
+  border-radius: 5px;
+  border: 1px dashed #ddd;
+  width: 250px;
+  height: 94px;
+}
+
+.AP-preview .wrap {
+  flex-direction: row;
+  background: #ddd !important;
+  cursor: default;
+  top: 0 !important;
+  overflow: hidden;
+}
+
+.AP-preview .wrap .inner {
+  display: flex;
+  flex-direction: column;
+}
+
+.AP-preview .wrap .inner > * {
+  padding: 0.61805rem;
+  white-space: nowrap;
+  word-wrap: normal;
+}
+
+.AP-preview .wrap .forget {
+  align-self: stretch;
+  line-height: 100%;
+  padding: 0.61805rem;
+  border-left: 1px solid  #bbb;
+  display: flex;
+  align-items: center;
+  font-size: 28px;
+}
+
+.AP-preview .wrap .forget, .AP-preview .wrap .forget:hover {
+  color: black;
+  text-decoration: none;
+}
+
+.AP-preview .wrap .forget:hover {
+  background: #dc4a6a;
+  color: white;
+  border-left: 1px solid  #666;
+  border-bottom-right-radius: 3px;
+  border-top-right-radius: 3px;
+}
+
+.AP-preview .wrap .forget:active {
+  position: relative;
+  padding-top: calc(0.61805rem + 1px);
+}
+
+.AP-preview .wrap .essid, .AP-preview .wrap .passwd, .AP-preview .wrap .nopasswd {
+  padding-bottom: 0;
+}
+
+.AP-preview .wrap .x-passwd {
+  font-family: monospace;
+}
+
+body.term #content {
+  padding-left: 0;
+  padding-right: 0;
+  transition: opacity 0.25s ease-in;
+}
+
+body.term #content h1 {
+  font-size: 1.80203em;
+}
+
+@media screen and (max-width: 544px) {
+  body.term #content h1 {
+    font-size: 1.42383em;
+  }
+}
+
+#screen {
+  white-space: nowrap;
+  background: #111213;
+  display: inline-block;
+  border: 2px solid #3983CD;
+  position: relative;
+  line-height: 0;
+  cursor: default;
+  -webkit-user-select: none;
+  -moz-user-select: none;
+  -ms-user-select: none;
+  user-select: none;
+}
+
+#screen canvas.selectable {
+  cursor: text;
+}
+
+#screen .screen-margin {
+  position: absolute;
+  background: rgba(17, 18, 19, 0.2);
+  -webkit-backdrop-filter: blur(10px);
+  backdrop-filter: blur(10px);
+  pointer-events: none;
+}
+
+#screen .screen-margin.top {
+  top: 0;
+  left: 0;
+  right: 0;
+  height: 6px;
+}
+
+#screen .screen-margin.left, #screen .screen-margin.right {
+  top: 6px;
+  left: 0;
+  bottom: 0;
+  width: 6px;
+}
+
+#screen .screen-margin.right {
+  left: auto;
+  right: 0;
+}
+
+#screen .screen-margin.bottom {
+  left: 6px;
+  right: 6px;
+  bottom: 0;
+  height: 6px;
+}
+
+#screen #softkb-input {
+  position: absolute;
+  top: 6px;
+  left: 6px;
+  width: 1em;
+  height: 1em;
+  background: none;
+  border: none;
+  resize: none;
+  overflow: hidden;
+  opacity: 0;
+  outline: 0 none !important;
+  caret-color: transparent;
+  color: transparent;
+  pointer-events: none;
+  font-size: 1px;
+}
+
+#screen #touch-select-menu {
+  display: none;
+  position: absolute;
+  top: 6px;
+  left: 6px;
+}
+
+#screen #touch-select-menu.open {
+  display: block;
+}
+
+#screen .debug-canvas {
+  position: absolute;
+  top: 6px;
+  left: 6px;
+  pointer-events: none;
+}
+
+#screen .debug-toolbar {
+  line-height: 1.5;
+  text-align: left;
+  padding: 6px;
+  font-family: "DejaVu Sans Mono", "Liberation Mono", "Inconsolata", "Menlo", monospace;
+  font-size: 12px;
+  white-space: normal;
+}
+
+#action-buttons {
+  margin-top: 10px;
+  white-space: nowrap;
+}
+
+#action-buttons button {
+  margin: 0 3px;
+  padding: 8px 5px;
+  min-width: 62px;
+  cursor: pointer;
+  font-weight: bold;
+}
+
+#action-buttons button:focus {
+  outline: 0 none !important;
+}
+
+#action-buttons button.inactive {
+  opacity: 0.2;
+}
+
+#load-failed {
+  color: red;
+  font-size: 18px;
+  font-weight: bold;
+  margin: 10px 5px 14px 5px;
+}
+
+#term-nav {
+  padding-top: 1.5em;
+  text-align: center;
+}
+
+#term-nav a {
+  text-decoration: none;
+  padding: 5px 5px;
+  border-radius: 2px;
+  position: relative;
+}
+
+#term-nav a, #term-nav a:visited, #term-nav a:link {
+  color: #336085;
+}
+
+#term-nav a:hover {
+  color: #5abfff;
+  background: #1b273c;
+}
+
+#term-nav a:active {
+  top: 1px;
+}
+
+#term-nav a i::before {
+  display: inline;
+}
+
+#term-nav a span {
+  margin-left: .2em;
+}
+
+@media screen and (max-width: 544px) {
+  #term-nav a {
+    font-size: 130%;
+    padding: 6px;
+  }
+  #term-nav a span {
+    display: none;
+  }
+}
+
+#term-nav .icn-keyboard {
+  text-decoration: none;
+  font-size: 130%;
+  vertical-align: middle;
+}
+
+#term-wrap {
+  text-align: center;
+}
+
+#fu_modal {
+  align-items: flex-start;
+}
+
+#fu_form {
+  padding: 1rem;
+  margin-top: 100px;
+  z-index: 1000;
+}
+
+#fu_form label {
+  width: 12em;
+  display: inline-block;
+}
+
+#fu_form input[type="number"], #fu_form select {
+  width: 10em;
+}
+
+#fu_form textarea {
+  width: 100%;
+  min-height: 8em;
+  margin-top: 0.61805rem;
+  resize: vertical;
+}
+
+#fu_form .fu-buttons {
+  text-align: center;
+  padding: 0.38198rem;
+  margin-top: 0.38198rem;
+  border-radius: 3px;
+}
+
+#fu_form .fu-prog-box {
+  display: none;
+}
+
+#fu_form.busy {
+  background: rgba(36, 36, 38, 0.3);
+  border-left-color: rgba(41, 114, 186, 0.3);
+  border-right-color: rgba(41, 114, 186, 0.3);
+}
+
+#fu_form.busy .fu-content {
+  pointer-events: none;
+  opacity: .3;
+}
+
+#fu_form.busy .fu-buttons {
+  text-align: left;
+  background: #242426;
+  border: 1px solid #2972ba;
+}
+
+#fu_form.busy .fu-prog-box {
+  display: inline-block;
+}
+
+#keyboard-shortcut-bar {
+  border-radius: 4px;
+  width: calc(100vw - 20px);
+  background: #d1d5db;
+  padding: 5px 10px;
+  overflow-x: auto;
+  margin: 6px;
+}
+
+#keyboard-shortcut-bar:not(.open) {
+  display: none;
+}
+
+#keyboard-shortcut-bar .shortcut-button {
+  background: #fff;
+  color: #000;
+  padding: 10px 20px;
+  box-shadow: 0 1px 0 rgba(0, 0, 0, 0.3);
+  text-shadow: none;
+  border-radius: 4px;
+  margin: 0 10px 0 0;
+  font-family: -apple-system, sans-serif;
+  min-width: 2em;
+}
+
+#keyboard-shortcut-bar .shortcut-button.modifier:not(.enabled) {
+  background: #9ea6b1;
+  color: #000;
+}
+
+body.pseudo-fullscreen #screen .screen-margin,
+body.pseudo-fullscreen #keyboard-shortcut-bar {
+  display: none;
+}
+
+body.pseudo-fullscreen #outer {
+  position: static;
+}
+
+body.pseudo-fullscreen #screen {
+  position: fixed;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  border: none;
+}
+
+body.pseudo-fullscreen #screen canvas {
+  position: fixed;
+  top: 0;
+  left: 0;
+  z-index: 99;
+}
+
+body.pseudo-fullscreen #term-nav {
+  position: fixed;
+  width: 100%;
+  bottom: 0;
+  z-index: 98;
+  height: 24px;
+  padding: 0;
+}
+
+.bold {
+  font-weight: bold !important;
+}
+
+.faint span {
+  opacity: 0.6;
+}
+
+.italic {
+  font-style: italic;
+}
+
+.under {
+  text-decoration: underline;
+}
+
+.strike {
+  text-decoration: line-through;
+}
+
+.underline.strike {
+  text-decoration: underline line-through;
+}
+
+.blink-hide .blink {
+  color: transparent;
+}
+
+.color-example {
+  font-family: monospace;
+  font-size: 14pt;
+  padding: 4px 6px;
+}
+
+.preset {
+  cursor: pointer;
+  font-family: monospace;
+  font-size: 14pt;
+}
+
+.Row.color-preview label {
+  align-self: center;
+}
+
+@media screen and (max-width: 544px) {
+  .Row.color-preview {
+    font-size: 12pt;
+    align-items: flex-start;
+  }
+  .Row.color-preview label {
+    align-self: flex-start;
+  }
+}
+
+.Row.color-preview .colorprev {
+  font-family: monospace;
+  font-size: 14pt;
+  display: block;
+  margin: 0;
+  cursor: pointer;
+}
+
+#color-example {
+  display: inline-block;
+  padding: 5px;
+}
+
+.theme-nav-btn {
+  width: 2em;
+  height: 2em;
+  display: flex;
+  align-items: center;
+  justify-content: space-around;
+  background: #4c4c4c;
+  color: #eaeaea;
+  margin: 5px;
+  border-radius: 5px;
+  -webkit-user-select: none;
+  -moz-user-select: none;
+  -ms-user-select: none;
+  user-select: none;
+  cursor: pointer;
+  position: relative;
+}
+
+.theme-nav-btn:active {
+  top: 1px;
+}
+
+.page-about .Box {
+  padding-left: 1rem;
+  padding-right: 1rem;
+}
+
+.page-about .Box a {
+  font-weight: bold;
+}
+
+.page-about #logo {
+  float: right;
+  height: 130px;
+}
+
+.page-about #logo2 {
+  max-width: 100%;
+  margin: 1rem;
+}
+
+.page-about td {
+  white-space: normal;
+}
+
+.page-help code {
+  background: #2da2b9;
+  color: black;
+  border-radius: 1px;
+  padding: 0 2px;
+  word-wrap: break-word;
+}
+
+.colorprev {
+  margin-top: 0.38198rem;
+  margin-bottom: 0.38198rem;
+}
+
+.colorprev span {
+  display: inline-block;
+  width: 2em;
+  padding: 2px 0;
+  text-align: center;
+}
+
+.Row table, .Row table td, .Row table th {
+  border: 1px solid #666;
+}
+
+.Row table th, .Row table td {
+  white-space: normal;
+}
+
+.Row table th {
+  background-color: rgba(255, 255, 255, 0.1);
+}
+
+.ansiref.w100 {
+  width: 100%;
+}
+
+.ansiref.w100 td:nth-child(1) {
+  width: 8em;
+}
+
+.nomen {
+  width: 100%;
+}
+
+.nomen code {
+  white-space: nowrap;
+}
+
+.nomen td:last-child {
+  min-width: 15em;
+}
+
+.tscroll {
+  overflow-x: auto;
+}
+
+.charset {
+  line-height: 1;
+}
+
+.charset div {
+  display: inline-block;
+  width: 2.7em;
+  border: 1px solid #666;
+  height: 3em;
+  margin: 1px;
+  position: relative;
+}
+
+.charset div span {
+  display: block;
+  position: absolute;
+}
+
+.charset div span:nth-child(1) {
+  left: .2em;
+  top: .2em;
+  height: 1em;
+  font-size: 85%;
+  color: #999;
+}
+
+.charset div span:nth-child(2) {
+  right: .2em;
+  top: .2em;
+  height: 1em;
+  font-size: 85%;
+  color: #999;
+}
+
+.charset div span:nth-child(3) {
+  width: 100%;
+  font-size: 105%;
+  text-align: center;
+  bottom: .4em;
+  font-family: "DejaVu Sans Mono", "Liberation Mono", "Inconsolata", "Menlo", monospace;
+}
+
+.charset div.none {
+  opacity: .4;
+}
+
+.smallpad {
+  display: block;
+  padding-bottom: 5px;
+}
+
+@media screen and (min-width: 545px) {
+  .mq-phone {
+    display: none !important;
+  }
+}
+
+@media screen and (max-width: 544px) {
+  .mq-tablet-min, .mq-no-phone {
+    display: none !important;
+  }
+}
+
+@media screen and (min-width: 1001px) {
+  .mq-tablet-max {
+    display: none !important;
+  }
+}
+
+@media screen and (max-width: 1000px) {
+  .mq-normal-min {
+    display: none !important;
+  }
+}
+
+@media print {
+  .Row.buttons, nav {
+    display: none !important;
+  }
+  .Row.buttons .button {
+    display: none !important;
+  }
+  h1, h2, h3 {
+    break-after: avoid-page !important;
+    page-break-after: avoid !important;
+    font-family: sans-serif;
+  }
+  html, body {
+    background: white;
+    color: black;
+    font-family: serif;
+    line-height: 1.3em;
+  }
+  label, p {
+    color: black !important;
+    text-shadow: none !important;
+  }
+  .Box {
+    box-shadow: none;
+  }
+  input, select, button {
+    background: white !important;
+    color: black !important;
+    border: 1px solid black !important;
+  }
+  a {
+    color: #004eff !important;
+  }
+  a[href^="http://"]::after,
+  a[href^="https://"]::after {
+    content: attr(href);
+    padding-left: .8ex;
+    text-decoration: underline !important;
+  }
+  p a {
+    word-wrap: break-word;
+  }
+  .Row.checkbox .box {
+    border-color: black;
+    border-radius: 3px;
+    background: white;
+    color: black;
+  }
+  .button {
+    background: white;
+    border: 1px solid black;
+    text-shadow: none !important;
+    color: black;
+    box-shadow: none;
+    text-decoration: underline !important;
+  }
+  [class^="icn-"]::before, [class*=" icn-"]::before {
+    display: none;
+  }
+  .Box .Row {
+    display: block !important;
+  }
+  .Box.fold h2::after {
+    display: none;
+  }
+  #outer {
+    display: block;
+    overflow: auto;
+    width: unset;
+    height: unset;
+    position: static;
+  }
+  html, body {
+    overflow: auto !important;
+    width: unset;
+    height: unset;
+  }
+  .Box {
+    padding: 0;
+    border: 0 none;
+  }
+  .charset div span:nth-child(1),
+  .charset div span:nth-child(2) {
+    color: #666;
+  }
+  .page-help code {
+    background: rgba(0, 215, 255, 0.31);
+  }
+  [noprint] {
+    display: none !important;
+  }
+  #content tbody th {
+    color: black !important;
+  }
+}
diff --git a/help.html b/help.html
index e4e9e8b..ce4c3ec 100644
--- a/help.html
+++ b/help.html
@@ -5,8 +5,8 @@
 	<meta http-equiv="X-UA-Compatible" content="IE=edge">
 	<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, maximum-scale=1">
 	<title>Quick Reference :: ESPTerm</title>
-	<link href="/css/app.69e5b77.css" rel="stylesheet">
-	<script src="/js/app.69e5b77.js"></script>
+	<link href="/css/app.4a032ee-en.css" rel="stylesheet">
+	<script src="/js/app.4a032ee-en.js"></script>
 	<script>
 		var _root = location.host;
 		var _demo = 1;
@@ -208,6 +208,7 @@
 			Here are some examples of control key codes:
 		</p>
 
+		<div class="tscroll">
 		<table>
 			<thead><tr><th>Key</th><th>Code</th><th>Key</th><th>Code</th></tr></thead>
 			<tr>
@@ -295,6 +296,7 @@
 				<td>ASCII 1-26</td>
 			</tr>
 		</table>
+		</div>
 
 		<h3>Action buttons</h3>
 
@@ -952,7 +954,10 @@
 
 		<p>
 			This command sends a POST request to <code>http://<i>&lt;DestIP&gt;</i>/api/v1/msg</code>.
-			The IP address may be appended by a port, if needed (eg. :8080).
+			The IP address may be appended by a port, if needed (eg. :8080). In addition to POST,
+			a GET request can also be used. In that case, any GET arguments (<code>/api/v1/msg?<i>arguments</i></code>)
+			will be used instead of the request body. This is intended for external access
+			when sending POST requests is not convenient.
 		</p>
 
 		<p>
@@ -985,6 +990,8 @@
 					<li><code>H</code> - get response headers
 					<li><code>B</code> - get response body
 					<li><code>X</code> - ignore the response, return nothing
+					<li><code>N=<i>nonce</i></code> - a custom string that will be added in the options field of the response message.
+						Use this to keep track of which request a response belongs to.
 					<li><code>T=<i>ms</i></code> - request timeout (default 5000&nbsp;ms), in milliseconds
 					<li><code>L=<i>bytes</i></code> - limit response length (default 0 = don't limit). Applies to the head, body, or both combined, depending on the <code>H</code> and <code>B</code> flags
 					<li><code>l=<i>bytes</i></code> - limit the response buffer size (default 5000&nbsp;B).
@@ -1003,7 +1010,7 @@
 		<ul>
 			<li><code><i>status</i></code> - a HTTP status code, eg. 200 is OK, 404 Not found.
 			<li><code><i>options</i></code> - similar to those in the request, here describing the response data.
-				This field can contain comma-separated <code>B</code>, <code>H</code> and <code>L=<i>bytes</i></code>.
+				This field can contain comma-separated <code>B</code>, <code>H</code> and <code>L=<i>bytes</i></code> and <code>N=<i>nonce</i></code>.
 			<li><code><i>response</i></code> - the response, as requested. If both headers and body are received,
 				they will be separated by an empty line (i.e. <code>\r\n\r\n</code>). Response can be up to several
 				kilobytes long, depending on the <code>L=</code> and <code>l=</code> options.
diff --git a/img/adapter.jpg.orig b/img/adapter.jpg.orig
new file mode 100644
index 0000000..ab6cfd3
Binary files /dev/null and b/img/adapter.jpg.orig differ
diff --git a/img/vt100.jpg.orig b/img/vt100.jpg.orig
new file mode 100644
index 0000000..909461a
Binary files /dev/null and b/img/vt100.jpg.orig differ
diff --git a/js/app.4a032ee-en.js b/js/app.4a032ee-en.js
new file mode 100644
index 0000000..d68b192
--- /dev/null
+++ b/js/app.4a032ee-en.js
@@ -0,0 +1,4 @@
+!function(e){function t(i){if(n[i])return n[i].exports;var r=n[i]={i:i,l:!1,exports:{}};return e[i].call(r.exports,r,r.exports,t),r.l=!0,r.exports}var n={};t.m=e,t.c=n,t.d=function(e,n,i){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:i})},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="",t(t.s=9)}([function(e,t,n){"use strict";t.mk=function(e){return document.createElement(e)},t.qs=function(e){return document.querySelector(e)},t.qsa=function(e){return document.querySelectorAll(e)},t.cr=function(e){return function(t){10!==t.which&&13!==t.which&&32!==t.which||e()}},t.parse2B=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0;return e.charCodeAt(t++)-1+127*(e.charCodeAt(t)-1)},t.parse3B=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0;return e.charCodeAt(t)-1+127*(e.charCodeAt(t+1)-1)+127*(e.charCodeAt(t+2)-1)*127},t.encode2B=function(e){var t=void 0,n=void 0;return t=e%127,e=(e-t)/127,t+=1,n=e+1,String.fromCharCode(t)+String.fromCharCode(n)},t.encode3B=function(e){var t=void 0,n=void 0,i=void 0;return t=e%127,e=(e-t)/127,t+=1,n=e%127,e=(e-n)/127,n+=1,i=e+1,String.fromCharCode(t)+String.fromCharCode(n)+String.fromCharCode(i)}},function(e,t,n){"use strict";var i="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e};/*!chibi 3.0.7, Copyright 2012-2016 Kyle Barrow, released under MIT license */
+!function(){function t(){var e;for(m=!0,e=0;e<v.length;e+=1)v[e]();v=[]}function n(){var e;for(g=!0,m||t(),e=0;e<p.length;e+=1)p[e]();p=[]}function r(e,t){var n;for(n=t.length-1;n>=0;n-=1)e(t[n])}function o(e){return e.replace(/-\w/g,function(e){return e.charAt(1).toUpperCase()})}function s(e,t){return e.currentStyle?e.currentStyle[o(t)]:y.getComputedStyle?y.getComputedStyle(e,null).getPropertyValue(t):null}function a(e,t){return encodeURIComponent(e).replace(/%20/g,"+")+"="+encodeURIComponent(t).replace(/%20/g,"+")}function l(e,t,n){try{e.style[o(t)]=n}catch(e){}}function c(e){e.style.display="","none"===s(e,"display")&&(e.style.display="block")}function h(e){var t,n,i,o="";if(e.constructor===Object){for(t in e)if(e.hasOwnProperty(t))if(e[t].constructor===Array)for(n=0;n<e[t].length;n+=1)o+="&"+a(t,e[t][n]);else o+="&"+a(t,e[t])}else r(function(e){if("FORM"===e.nodeName)for(n=0;n<e.elements.length;n+=1)if(t=e.elements[n],!t.disabled)switch(t.type){case"button":case"image":case"file":case"submit":case"reset":break;case"select-one":t.length>0&&(o+="&"+a(t.name,t.value));break;case"select-multiple":for(i=0;i<t.length;i+=1)t[i].selected&&(o+="&"+a(t.name,t[i].value));break;case"checkbox":case"radio":t.checked&&(o+="&"+a(t.name,t.value));break;default:o+="&"+a(t.name,t.value)}},e);return o.length>0?o.substring(1):""}function u(e,t,n){var i,o,s=!1;return e&&(i=e.split(/\s+/),r(function(e){for(o=0;o<i.length;o+=1){var n=i[o];if("remove"===t)e.classList.remove(n);else if("add"===t)e.classList.add(n);else if("toggle"===t)e.classList.toggle(n);else if("has"===t&&e.classList.contains(n)){s=!0;break}}},n)),s}function d(e,t,n){var i,o;e&&r(function(n){for(i=w.createElement("div"),i.innerHTML=e;null!==(o=i.lastChild);)try{"before"===t?n.parentNode.insertBefore(o,n):"after"===t?n.parentNode.insertBefore(o,n.nextSibling):"append"===t?n.appendChild(o):"prepend"===t&&n.insertBefore(o,n.firstChild)}catch(e){break}},n)}function f(e){var t,n,a,h=[],v=!1;if(e)if(e.nodeType&&1===e.nodeType)h=[e];else if("object"===(void 0===e?"undefined":i(e)))v="number"!=typeof e.length,h=e;else if("string"==typeof e)for(n=w.querySelectorAll(e),a=0;a<n.length;a+=1)h[a]=n[a];return t=v?{}:h,t.each=function(e){return"function"==typeof e&&r(function(t){return e.apply(t,arguments)},h),t},t.first=function(){return f(h.shift())},t.last=function(){return f(h.pop())},t.odd=function(){var e,t=[];for(e=0;e<h.length;e+=2)t.push(h[e]);return f(t)},t.even=function(){var e,t=[];for(e=1;e<h.length;e+=2)t.push(h[e]);return f(t)},t.hide=function(){return r(function(e){e.style.display="none"},h),t},t.show=function(){return r(function(e){c(e)},h),t},t.toggle=function(e){return void 0!==e?e?t.show():t.hide():r(function(e){"none"===s(e,"display")?c(e):e.style.display="none"},h),t},t.remove=function(){return r(function(e){try{e.parentNode.removeChild(e)}catch(e){}},h),f()},t.css=function(e,n){if(e){if(n||""===n)return r(function(t){l(t,e,n)},h),t;if(h[0]){if(h[0].style[o(e)])return h[0].style[o(e)];if(s(h[0],e))return s(h[0],e)}}},t.getClass=function(){if(h[0]&&h[0].className.length>0)return h[0].className.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,"").replace(/\s+/," ")},t.setClass=function(e){return(e||""===e)&&r(function(t){t.className=e},h),t},t.addClass=function(e){return u(e,"add",h),t},t.removeClass=function(e){return u(e,"remove",h),t},t.toggleClass=function(e,n){return u(e,void 0===n?"toggle":+n?"add":"remove",h),t},t.hasClass=function(e){return u(e,"has",h)},t.html=function(e){return e||""===e?(r(function(t){t.innerHTML=e},h),t):h[0]?h[0].innerHTML:void 0},t.htmlBefore=function(e){return d(e,"before",h),t},t.htmlAfter=function(e){return d(e,"after",h),t},t.htmlAppend=function(e){return d(e,"append",h),t},t.htmlPrepend=function(e){return d(e,"prepend",h),t},t.attr=function(e,n){if(e){if(e=e.toLowerCase(),void 0!==n)return r(function(t){"style"===e?t.style.cssText=n:"class"===e?t.className=n:t.setAttribute(e,n)},h),t;if(h[0])if("style"===e){if(h[0].style.cssText)return h[0].style.cssText}else if("class"===e){if(h[0].className)return h[0].className}else if(h[0].getAttribute(e))return h[0].getAttribute(e)}},t.data=function(e,n){if(e)return t.attr("data-"+e,n)},t.val=function(e){var n,i,o;if(void 0!==e)return r(function(t){switch(t.nodeName){case"SELECT":for("string"!=typeof e&&"number"!=typeof e||(e=[e]),i=0;i<t.length;i+=1)for(o=0;o<e.length;o+=1)if(t[i].selected="",t[i].value===""+e[o]){t[i].selected="selected";break}break;case"INPUT":case"TEXTAREA":case"BUTTON":t.value=e}},h),t;if(h[0])switch(h[0].nodeName){case"SELECT":for(n=[],i=0;i<h[0].length;i+=1)h[0][i].selected&&n.push(h[0][i].value);return n.length>1?n:n[0];case"INPUT":case"TEXTAREA":case"BUTTON":return h[0].value}},t.checked=function(e){return"boolean"==typeof e?(r(function(t){"INPUT"!==t.nodeName||"checkbox"!==t.type&&"radio"!==t.type||(t.checked=e)},h),t):!h[0]||"INPUT"!==h[0].nodeName||"checkbox"!==h[0].type&&"radio"!==h[0].type?void 0:!!h[0].checked},t.on=function(n,i){return e!==y&&e!==w||(h=[e]),r(function(e){w.addEventListener?e.addEventListener(n,i,!1):w.attachEvent&&(e[n+i]=function(){return i.apply(e,arguments)},e.attachEvent("on"+n,e[n+i]))},h),t},t.off=function(n,i){return e!==y&&e!==w||(h=[e]),r(function(e){w.addEventListener?e.removeEventListener(n,i,!1):w.attachEvent&&(e.detachEvent("on"+n,e[n+i]),e[n+i]=null)},h),t},t}var v=[],p=[],m=!1,g=!1,w=document,y=window;w.addEventListener?(w.addEventListener("DOMContentLoaded",t,!1),y.addEventListener("load",n,!1)):w.attachEvent?(w.attachEvent("onreadystatechange",t),y.attachEvent("onload",n)):y.onload=n,f.ajax=function(e){var t=Object.assign({method:"GET",nocache:!0,timeout:5e3,loader:!0,callback:null},e);t.method=t.method.toUpperCase();var n=t.loader?f._loader:function(){},i=t.url,r=t.method,o=null;t.data&&(o=h(t.data)),o&&"GET"===r&&(i+=-1===i.indexOf("?")?"?"+o:"&"+o,o=null);var s=new XMLHttpRequest;if(t.nocache){var a=(+new Date).toString(36);i+=(-1===i.indexOf("?")?"?":"&")+"_="+a}n(!0),s.open(r,i,!0),s.timeout=t.timeout;var l=setTimeout(function(){console.error("XHR timed out."),s.abort(),n(!1)},t.timeout+10);return s.onreadystatechange=function(){4===s.readyState&&(n(!1),t.callback&&t.callback(s.responseText,s.status),clearTimeout(l))},s.setRequestHeader("X-Requested-With","XMLHttpRequest"),"POST"===r&&s.setRequestHeader("Content-Type","application/x-www-form-urlencoded"),s.send(o),s},f._loader=function(){},f.get=function(e,t,n){return n=n||{},n.url=e,n.callback=t,n.method="GET",f.ajax(n)},f.post=function(e,t,n){return n=n||{},n.url=e,n.callback=t,n.method="POST",f.ajax(n)},f.ready=function(e){if(e){if(m)return e(),f;v.push(e)}},f.loaded=function(e){if(e){if(g)return e(),f;p.push(e)}};var b={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;","/":"&#x2F;","`":"&#x60;","=":"&#x3D;"};f.htmlEscape=function(e){return String(e).replace(/[&<>"'`=\/]/g,function(e){return b[e]})},e.exports=f}()},function(e,t,n){"use strict";var i=n(1),r={},o=null;r.show=function(e,t){var n=i(e);n.removeClass("hidden visible"),setTimeout(function(){n.addClass("visible")},1),o=t},r.hide=function(e){var t=i(e);t.removeClass("visible"),setTimeout(function(){t.addClass("hidden"),o&&o()},500)},r.init=function(){i(".Modal").on("click",function(){i(this).hasClass("no-close")||r.hide(this)}),i(".Dialog").on("click",function(e){e.stopImmediatePropagation()}),i(window).on("keydown",function(e){27===e.which&&r.hide(".Modal")})},e.exports=r},function(e,t,n){"use strict";var i=n(1),r=n(2),o={},s=void 0,a=void 0,l=void 0,c=!1,h=function(){clearTimeout(a),clearTimeout(l)};o.show=function(e,t,n){s.toggleClass("error",!0===n),s.html(e),r.show(s),h(),(!t||t<=0)&&(t=2500),a=setTimeout(o.hide,t),c=!1,setTimeout(function(){c=!0},500)},o.hide=function(){var e=i("#notif");e.removeClass("visible"),l=setTimeout(function(){e.addClass("hidden")},250)},o.init=function(){s=i("#notif"),i(document).on("click",function(){c&&o.hide(this)}),s.on("click",function(e){return e.stopImmediatePropagation(),!1}),s.on("mouseenter",function(){h(),s.removeClass("hidden").addClass("visible")})},e.exports=o},function(e,t){function n(){this._events=this._events||{},this._maxListeners=this._maxListeners||void 0}function i(e){return"function"==typeof e}function r(e){return"number"==typeof e}function o(e){return"object"==typeof e&&null!==e}function s(e){return void 0===e}e.exports=n,n.EventEmitter=n,n.prototype._events=void 0,n.prototype._maxListeners=void 0,n.defaultMaxListeners=10,n.prototype.setMaxListeners=function(e){if(!r(e)||e<0||isNaN(e))throw TypeError("n must be a positive number");return this._maxListeners=e,this},n.prototype.emit=function(e){var t,n,r,a,l,c;if(this._events||(this._events={}),"error"===e&&(!this._events.error||o(this._events.error)&&!this._events.error.length)){if((t=arguments[1])instanceof Error)throw t;var h=new Error('Uncaught, unspecified "error" event. ('+t+")");throw h.context=t,h}if(n=this._events[e],s(n))return!1;if(i(n))switch(arguments.length){case 1:n.call(this);break;case 2:n.call(this,arguments[1]);break;case 3:n.call(this,arguments[1],arguments[2]);break;default:a=Array.prototype.slice.call(arguments,1),n.apply(this,a)}else if(o(n))for(a=Array.prototype.slice.call(arguments,1),c=n.slice(),r=c.length,l=0;l<r;l++)c[l].apply(this,a);return!0},n.prototype.addListener=function(e,t){var r;if(!i(t))throw TypeError("listener must be a function");return this._events||(this._events={}),this._events.newListener&&this.emit("newListener",e,i(t.listener)?t.listener:t),this._events[e]?o(this._events[e])?this._events[e].push(t):this._events[e]=[this._events[e],t]:this._events[e]=t,o(this._events[e])&&!this._events[e].warned&&(r=s(this._maxListeners)?n.defaultMaxListeners:this._maxListeners)&&r>0&&this._events[e].length>r&&(this._events[e].warned=!0,console.error("(node) warning: possible EventEmitter memory leak detected. %d listeners added. Use emitter.setMaxListeners() to increase limit.",this._events[e].length),"function"==typeof console.trace&&console.trace()),this},n.prototype.on=n.prototype.addListener,n.prototype.once=function(e,t){function n(){this.removeListener(e,n),r||(r=!0,t.apply(this,arguments))}if(!i(t))throw TypeError("listener must be a function");var r=!1;return n.listener=t,this.on(e,n),this},n.prototype.removeListener=function(e,t){var n,r,s,a;if(!i(t))throw TypeError("listener must be a function");if(!this._events||!this._events[e])return this;if(n=this._events[e],s=n.length,r=-1,n===t||i(n.listener)&&n.listener===t)delete this._events[e],this._events.removeListener&&this.emit("removeListener",e,t);else if(o(n)){for(a=s;a-- >0;)if(n[a]===t||n[a].listener&&n[a].listener===t){r=a;break}if(r<0)return this;1===n.length?(n.length=0,delete this._events[e]):n.splice(r,1),this._events.removeListener&&this.emit("removeListener",e,t)}return this},n.prototype.removeAllListeners=function(e){var t,n;if(!this._events)return this;if(!this._events.removeListener)return 0===arguments.length?this._events={}:this._events[e]&&delete this._events[e],this;if(0===arguments.length){for(t in this._events)"removeListener"!==t&&this.removeAllListeners(t);return this.removeAllListeners("removeListener"),this._events={},this}if(n=this._events[e],i(n))this.removeListener(e,n);else if(n)for(;n.length;)this.removeListener(e,n[n.length-1]);return delete this._events[e],this},n.prototype.listeners=function(e){return this._events&&this._events[e]?i(this._events[e])?[this._events[e]]:this._events[e].slice():[]},n.prototype.listenerCount=function(e){if(this._events){var t=this._events[e];if(i(t))return 1;if(t)return t.length}return 0},n.listenerCount=function(e,t){return e.listenerCount(t)}},function(e,t,n){"use strict";var i=n(1),r=n(7),o=r.rgb255ToHex,s=t.themes=[["#111213","#CC0000","#4E9A06","#C4A000","#3465A4","#75507B","#06989A","#D3D7CF","#555753","#EF2929","#8AE234","#FCE94F","#729FCF","#AD7FA8","#34E2E2","#EEEEEC"],["#000000","#aa0000","#00aa00","#aa5500","#0000aa","#aa00aa","#00aaaa","#aaaaaa","#555555","#ff5555","#55ff55","#ffff55","#5555ff","#ff55ff","#55ffff","#ffffff"],["#000000","#cd0000","#00cd00","#cdcd00","#0000ee","#cd00cd","#00cdcd","#e5e5e5","#7f7f7f","#ff0000","#00ff00","#ffff00","#5c5cff","#ff00ff","#00ffff","#ffffff"],["#000000","#cd0000","#00cd00","#cdcd00","#0000cd","#cd00cd","#00cdcd","#faebd7","#404040","#ff0000","#00ff00","#ffff00","#0000ff","#ff00ff","#00ffff","#ffffff"],["#2e3436","#cc0000","#4e9a06","#c4a000","#3465a4","#75507b","#06989a","#d3d7cf","#555753","#ef2929","#8ae234","#fce94f","#729fcf","#ad7fa8","#34e2e2","#eeeeec"],["#073642","#dc322f","#859900","#b58900","#268bd2","#d33682","#2aa198","#eee8d5","#002b36","#cb4b16","#586e75","#657b83","#839496","#6c71c4","#93a1a1","#fdf6e3"],["#000000","#69001A","#117800","#769100","#1A00A6","#8019AB","#289E76","#A4A4A4","#484848","#C54E76","#6DD441","#D2ED46","#765BFF","#DC75FF","#84FAD2","#FFFFFF"],["#000000","#aa0000","#00aa00","#aaaa00","#0000aa","#aa00aa","#00aaaa","#aaaaaa","#000000","#ff0000","#00FF00","#ffff00","#0000ff","#ff00ff","#00ffff","#ffffff"],["#000000","#722640","#0E5940","#808080","#40337F","#E434FE","#1B9AFE","#BFB3FF","#404C00","#E46501","#1BCB01","#BFCC80","#808080","#F1A6BF","#8DD9BF","#ffffff"],["#000000","#8D3E37","#55A049","#AAB95D","#40318D","#80348B","#72C1C8","#D59F74","#8B5429","#B86962","#94E089","#FFFFB2","#8071CC","#AA5FB6","#87D6DD","#ffffff"],["#eee8d5","#dc322f","#859900","#b58900","#268bd2","#d33682","#2aa198","#073642","#fdf6e3","#cb4b16","#93a1a1","#839496","#657b83","#6c71c4","#586e75","#002b36"],["#073642","#dc322f","#859900","#b58900","#268bd2","#d33682","#2aa198","#fdf6e3","#002b36","#cb4b16","#657b83","#839496","#93a1a1","#6c71c4","#eee8d5","#fdf6e3"]];t.fgbgThemes=[["#AAAAAA","#000000","Lnx","Linux"],["#FFFFFF","#000000","W+K","White on Black"],["#00FF00","#000000","Lim","Lime"],["#E53C00","#000000","Nix","Nixie"],["#EFF0F1","#31363B","Brz","Breeze"],["#FFFFFF","#300A24","Amb","Ambiance"],["#839496","#002B36","SoD","Solarized Dark"],["#93a1a1","#002b36","SoH","Solarized Dark (High Contrast)"],["#657B83","#FDF6E3","SoL","Solarized Light"],["#000000","#FFD75F","Wsp","Wasp"],["#000000","#FFFFDD","K+Y","Black on Yellow"],["#000000","#FFFFFF","K+W","Black on White"]];var a=null;t.buildColorTable=function(){if(null!==a)return a;a=new Array(16).fill("#000000");for(var e=0;e<6;e++)for(var t=0;t<6;t++)for(var n=0;n<6;n++){var i=40*e+(e?55:0),r=40*t+(t?55:0),s=40*n+(n?55:0);a.push(o(i,r,s))}for(var l=0;l<24;l++){var c=10*l+8;a.push(o(c,c,c))}return a},t.SELECTION_FG="#333",t.SELECTION_BG="#b2d7fe",t.themePreview=function(e){i("[data-fg]").forEach(function(n){var i=n.dataset.fg;/^\d+$/.test(i)&&(i=t.toHex(i,e)),n.style.color=i}),i("[data-bg]").forEach(function(n){var i=n.dataset.bg;/^\d+$/.test(i)&&(i=t.toHex(i,e)),n.style.backgroundColor=i})},t.toHex=function(e,n){return/^\d+$/.test(e)&&(e=+e,e=e<16?s[n][e]:t.buildColorTable()[e]),e}},function(e,t,n){"use strict";function i(e){if(Array.isArray(e)){for(var t=0,n=Array(e.length);t<e.length;t++)n[t]=e[t];return n}return Array.from(e)}function r(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function o(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}function s(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var a=function e(t,n,i){null===t&&(t=Function.prototype);var r=Object.getOwnPropertyDescriptor(t,n);if(void 0===r){var o=Object.getPrototypeOf(t);return null===o?void 0:e(o,n,i)}if("value"in r)return r.value;var s=r.get;if(void 0!==s)return s.call(i)},l=function(){function e(e,t){for(var n=0;n<t.length;n++){var i=t[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(e,i.key,i)}}return function(t,n,i){return n&&e(t.prototype,n),i&&e(t,i),t}}(),c=n(4),h=n(0),u=h.parse2B,d=n(5),f=d.themes,v=function(e){return String.fromCodePoint(e+(e>=55296?2049:1))},p=function(){function e(t){s(this,e),this.reset(),this.handler=t,this.joinChunks=!0}return l(e,[{key:"reset",value:function(){this.currentSequence=0,this.sequence=""}},{key:"parseSequence",value:function(e){if("["===e[0]){var t=e[e.length-1],n=e.substring(1,e.length-1),i=n?n.split(";").map(function(e){return+e.replace(/\D/g,"")}):[],r=i.length?i[0]:1;if("H"===t)this.handler("set-cursor",(0|i[0])-1,(0|i[1])-1);else if(t>="A"&&t<="D")this.handler("move-cursor-"+(t<="B"?"y":"x"),("B"===t||"C"===t?1:-1)*r);else if("E"===t||"F"===t)this.handler("move-cursor-line",("E"===t?1:-1)*r);else if("G"===t)this.handler("set-cursor-x",r-1);else if("J"===t){var o=i.length?i[0]:2;2===o&&this.handler("clear")}else if("P"===t)this.handler("delete",r);else if("@"===t)this.handler("insert-blanks",r);else if("q"===t)this.handler("set-cursor-style",r);else if("m"===t){if(!i.length)return void this.handler("reset-style");for(var s=void 0;s=i.shift();)if(0===s)this.handler("reset-style");else if(1===s)this.handler("add-attrs",4);else if(2===s)this.handler("add-attrs",512);else if(3===s)this.handler("add-attrs",64);else if(4===s)this.handler("add-attrs",8);else if(5===s||6===s)this.handler("add-attrs",32);else if(7===s)this.handler("add-attrs",16);else if(9===s)this.handler("add-attrs",128);else if(20===s)this.handler("add-attrs",1024);else if(s>=30&&s<=37)this.handler("set-color-fg",s%10);else if(s>=40&&s<=47)this.handler("set-color-bg",s%10);else if(39===s)this.handler("reset-color-fg");else if(49===s)this.handler("reset-color-bg");else if(s>=90&&s<=98)this.handler("set-color-fg",s%10+8);else if(s>=100&&s<=108)this.handler("set-color-bg",s%10+8);else if(38===s||48===s){var a=i.shift();if(2===a){var l=i.shift(),c=i.shift(),h=i.shift(),u=256+(l<<16|c<<8|h);38===s&&this.handler("set-color-fg",u),48===s&&this.handler("set-color-bg",u)}else if(5===a){var d=255&(0|i.shift());38===s&&this.handler("set-color-fg",d),48===s&&this.handler("set-color-bg",d)}}}else"h"!==t&&"l"!==t||"?25"===n&&("h"===t?this.handler("show-cursor"):"l"===t&&this.handler("hide-cursor"))}}},{key:"write",value:function(e){var t=!0,n=!1,i=void 0;try{for(var r,o=e.toString()[Symbol.iterator]();!(t=(r=o.next()).done);t=!0){var s=r.value,a=s.codePointAt(0);27===a?this.currentSequence=1:1===this.currentSequence&&"["===s?(this.currentSequence=2,this.sequence+="["):this.currentSequence&&s.match(/[\x40-\x7e]/)?(this.parseSequence(this.sequence+s),this.currentSequence=0,this.sequence=""):this.currentSequence>1?this.sequence+=s:1===this.currentSequence?(this.currentSequence=0,this.handler("write",s)):a<3?this.handler("_null"):3===a?this.handler("sigint"):a<=6?this.handler("_null"):7===a?this.handler("bell"):8===a?this.handler("back"):9===a?this.handler("tab"):10===a?this.handler("new-line"):13===a?this.handler("return"):21===a?this.handler("delete-line"):23===a?this.handler("delete-word"):this.handler("write",s)}}catch(e){n=!0,i=e}finally{try{!t&&o.return&&o.return()}finally{if(n)throw i}}this.joinChunks||this.reset()}}]),e}(),m=[0,0,0],g=function(e){return 16+36*Math.floor(2.5*Math.sin(e)+2.5)+6*Math.floor(2.5*Math.sin(e+2/3*Math.PI)+2.5)+Math.floor(2.5*Math.sin(e+4/3*Math.PI)+2.5)},w=function(){function e(t){var n=this;s(this,e),this.width=80,this.height=25,this.termScreen=t,this.parser=new p(function(){return n.handleParsed.apply(n,arguments)}),this.buttonLabels=[],this.reset(),this._lastLoad=Date.now(),this.loadTimer(),window.showPage()}return l(e,[{key:"reset",value:function(){this.style=m.slice(),this.cursor={x:0,y:0,style:1,visible:!0},this.trackMouse=!1,this.theme=0,this.rainbow=this.superRainbow=!1,this.parser.reset(),this.clear()}},{key:"clear",value:function(){this.screen=[];for(var e=0;e<this.width*this.height;e++)this.screen.push([" ",this.style.slice()])}},{key:"scroll",value:function(){this.screen.splice(0,this.width);for(var e=0;e<this.width;e++)this.screen.push([" ",m.slice()]);this.cursor.y--}},{key:"newLine",value:function(){++this.cursor.y>=this.height&&this.scroll()}},{key:"writeChar",value:function(e){this.screen[this.cursor.y*this.width+this.cursor.x]=[e,this.style.slice()],++this.cursor.x>=this.width&&(this.cursor.x=0,this.newLine())}},{key:"moveBack",value:function(){for(var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:1,t=0;t<e;t++)--this.cursor.x<0&&(this.cursor.y>0?this.cursor.x=this.width-1:this.cursor.x=0,this.cursor.y=Math.max(0,this.cursor.y-1))}},{key:"moveForward",value:function(){for(var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:1,t=0;t<e;t++)++this.cursor.x>=this.width&&(this.cursor.x=0,++this.cursor.y>=this.height&&this.scroll())}},{key:"deleteChar",value:function(){this.moveBack(),this.screen.splice((this.cursor.y+1)*this.width,0,[" ",m.slice()]),this.screen.splice(this.cursor.y*this.width+this.cursor.x,1)}},{key:"deleteForward",value:function(e){e=Math.min(this.width,e);for(var t=0;t<e;t++)this.screen.splice((this.cursor.y+1)*this.width,0,[" ",m.slice()]);this.screen.splice(this.cursor.y*this.width+this.cursor.x,e)}},{key:"clampCursor",value:function(){this.cursor.x<0&&(this.cursor.x=0),this.cursor.y<0&&(this.cursor.y=0),this.cursor.x>this.width-1&&(this.cursor.x=this.width-1),this.cursor.y>this.height-1&&(this.cursor.y=this.height-1)}},{key:"handleParsed",value:function(e){"write"===e?this.writeChar(arguments.length<=1?void 0:arguments[1]):"delete"===e?this.deleteForward(arguments.length<=1?void 0:arguments[1]):"insert-blanks"===e?this.insertBlanks(arguments.length<=1?void 0:arguments[1]):"clear"===e?this.clear():"bell"===e?this.termScreen.load("UB"):"back"===e?this.moveBack():"new-line"===e?(this.newLine(),this.cursor.x=0):"return"===e?this.cursor.x=0:"set-cursor"===e?(this.cursor.x=arguments.length<=2?void 0:arguments[2],this.cursor.y=arguments.length<=1?void 0:arguments[1],this.clampCursor()):"move-cursor-y"===e?(this.cursor.y+=arguments.length<=1?void 0:arguments[1],this.clampCursor()):"move-cursor-x"===e?(this.cursor.x+=arguments.length<=1?void 0:arguments[1],this.clampCursor()):"move-cursor-line"===e?(this.cursor.x=0,this.cursor.y+=arguments.length<=1?void 0:arguments[1],this.clampCursor()):"set-cursor-x"===e?this.cursor.x=arguments.length<=1?void 0:arguments[1]:"set-cursor-style"===e?this.cursor.style=Math.max(0,Math.min(6,arguments.length<=1?void 0:arguments[1])):"reset-style"===e?this.style=m.slice():"add-attrs"===e?this.style[2]|=arguments.length<=1?void 0:arguments[1]:"set-color-fg"===e?(this.style[0]=arguments.length<=1?void 0:arguments[1],this.style[2]|=1):"set-color-bg"===e?(this.style[1]=arguments.length<=1?void 0:arguments[1],this.style[2]|=2):"reset-color-fg"===e?(this.style[0]=0,1&this.style[2]&&(this.style[2]^=1)):"reset-color-bg"===e?(this.style[1]=0,2&this.style[2]&&(this.style[2]^=2)):"hide-cursor"===e?this.cursor.visible=!1:"show-cursor"===e&&(this.cursor.visible=!0)}},{key:"write",value:function(e){this.parser.write(e)}},{key:"getScreenOpts",value:function(){var e="O";e+=v(25),e+=v(80),e+=v(this.theme),e+=v(7),e+=v(0),e+=v(0),e+=v(0);var t=+this.cursor.visible;return t|=96*+this.trackMouse,t|=384,t|=this.cursor.style<<9,e+=v(t)}},{key:"getButtons",value:function(){var e="B";return e+=v(this.buttonLabels.length),e+=this.buttonLabels.map(function(e){return e+""}).join("")}},{key:"getTitle",value:function(){return"TESPTerm Web UI Demo"}},{key:"getCursor",value:function(){var e="C";return e+=v(this.cursor.y),e+=v(this.cursor.x),e+=v(0)}},{key:"encodeColor",value:function(e){return e<256?v(e):(e-=256,v(4095&e|65536)+v(e>>12))}},{key:"serializeScreen",value:function(){var e="S";e+=v(0)+v(0),e+=v(this.height)+v(this.width);var t=[null,null,null],n=0,i=!0,r=!1,o=void 0;try{for(var s,a=this.screen[Symbol.iterator]();!(i=(s=a.next()).done);i=!0){var l=s.value,c=l[1].slice();if(this.rainbow){var h=n%this.width,u=Math.floor(n/this.width),d=(h+u)/10+Date.now()/1e3;this.superRainbow&&(d=(h*u+Date.now())/100+Date.now()/1e3),c[0]=g(d),c[1]=0,this.superRainbow&&(c[1]=g(d/10)),c[2]=1|c[2],!this.superRainbow&&2&c[2]&&(c[2]^=2),n++}var f=c[0],p=c[1],m=c[2],w=f!==t[0],y=p!==t[1],b=m!==t[2];w&&y?f<256&&p<256?e+=""+v(p<<8|f):(e+=""+this.encodeColor(f),e+=""+this.encodeColor(p)):w?e+=""+this.encodeColor(f):y&&(e+=""+this.encodeColor(p)),b&&(e+=""+v(m)),t=c,e+=l[0]}}catch(e){r=!0,o=e}finally{try{!i&&a.return&&a.return()}finally{if(r)throw o}}return e}},{key:"getUpdate",value:function(){var e=[],t=this.getScreenOpts(),n=this.getTitle(),i=this.getButtons(),r=this.getCursor(),o=this.serializeScreen();return this._screenOpts!==t&&(this._screenOpts=t,e.push(t)),this._title!==n&&(this._title=n,e.push(n)),this._buttons!==i&&(this._buttons=i,e.push(i)),this._cursor!==r&&(this._cursor=r,e.push(r)),this._screen!==o&&(this._screen=o,e.push(o)),e.length?"U"+v(0)+e.join(""):""}},{key:"loadTimer",value:function(){var e=this;clearInterval(this._loadTimer),this._loadTimer=setInterval(function(){var t=e.getUpdate();t&&e.termScreen.load(t)},30)}}]),e}(),y=function(e){function t(){return s(this,t),r(this,(t.__proto__||Object.getPrototypeOf(t)).apply(this,arguments))}return o(t,e),l(t,[{key:"write",value:function(e){this.emit("in",e)}},{key:"destroy",value:function(){this.emit("exit",0)}},{key:"run",value:function(){}}]),t}(c),b={buttons:[],mouseReceiver:null},_={clear:function(e){function t(){return s(this,t),r(this,(t.__proto__||Object.getPrototypeOf(t)).apply(this,arguments))}return o(t,e),l(t,[{key:"run",value:function(){this.emit("write",""),this.destroy()}}]),t}(y),screenfetch:function(e){function t(){return s(this,t),r(this,(t.__proto__||Object.getPrototypeOf(t)).apply(this,arguments))}return o(t,e),l(t,[{key:"run",value:function(){for(var e=this,t=("\n ###.                          ESPTerm Demo\n   '###.                       Hostname: "+window.location.hostname+"\n     '###.                     Shell: ESPTerm Demo Shell\n       '###.                   Resolution: 80x25@"+window.devicePixelRatio+"x\n         :###-\n       .###'\n     .###'\n   .###'      ###############\n ###'         ###############\n      ").split("\n").filter(function(e){return e.trim()}),n="",i=0;i<t.length;i++)for(var r=0;r<80;r++)t[i][r]?n+="[38;5;"+g((r+i)/10)+"m"+t[i][r]:n+=" ";this.emit("write","\r\n[?25l");!function t(){e.emit("write",n.substr(0,80)),n=n.substr(80),n.length?setTimeout(t,50):(e.emit("write","\r\n[?25h"),e.destroy())}()}}]),t}(y),"local-echo":function(e){function t(){return s(this,t),r(this,(t.__proto__||Object.getPrototypeOf(t)).apply(this,arguments))}return o(t,e),l(t,[{key:"run",value:function(){for(var e=arguments.length,t=Array(e),n=0;n<e;n++)t[n]=arguments[n];t.includes("--suppress-note")||this.emit("write","Note: not all terminal features are supported or and may not work as expected in this demo\r\n")}},{key:"write",value:function(e){this.emit("write",e)}}]),t}(y),info:function(e){function t(){return s(this,t),r(this,(t.__proto__||Object.getPrototypeOf(t)).apply(this,arguments))}return o(t,e),l(t,[{key:"run",value:function(){for(var e=this,t=arguments.length,n=Array(t),i=0;i<t;i++)n[i]=arguments[i];var r=n.includes("--fast");this.showSplash().then(function(){e.printText(r)})}},{key:"showSplash",value:function(){var e=this,t="\n              -#####- -###*..#####- ######-\n              -#*    -#-    .## .##.  *#-\n              -##### .-###*..#####-   *#-  -*##*- #*-#--#**#-*##-\n              -#*        -#-.##.      *#-  *##@#* ##.  -#* *# .#*\n              -#####--####- .##.      *#-  -*#@@- ##.  -#* *# .#*\n      ".split("\n").filter(function(e){return e.trim()}),n={" ":-231,".":4,"-":8,"*":17,"#":24},i={" ":" ",".":"░","-":"▒","*":"▓","#":"█"};for(var r in t)t[r].length<79&&(t[r]+=" ".repeat(79-t[r].length));this.emit("write","\r\n".repeat(t.length+1)),this.emit("write","".repeat(t.length)),this.emit("write","[?25l");var o=0,s=0,a=function(t,n){var i=t-o,r=n-s;e.emit("write","["+Math.abs(i)+(i>0?"C":"D")),e.emit("write","["+Math.abs(r)+(r>0?"B":"A")),o=t,s=n},l=function(r,o){if(a(r,o),"@"===t[o][r])e.emit("write","▄\b");else{var s=231+n[t[o][r]],l=i[t[o][r]];e.emit("write","[48;5;"+s+"m[38;5;"+s+"m"+l+"\b")}};return new Promise(function(n,i){var r=e,o=13,s=0;!function e(){for(var i=0;i<t.length;i++){var c=o-i;c>0&&l(c,i)}++o<70?++s>=3?(setTimeout(e,50),s=0):e():(a(0,t.length),r.emit("write","[?25h"),n())}()})}},{key:"printText",value:function(){var e=arguments.length>0&&void 0!==arguments[0]&&arguments[0],t=["","  ESPTerm is a VT100-like terminal emulator running on the ESP8266 WiFi chip.","","  This is an online demo of the web user interface, simulating a simple ","  terminal in your browser.","","  Type ls to list available commands.","  Use the links below this screen for a demo of the options and more info.",""];if(e)this.emit("write",t.join("\r\n")+"\r\n"),this.destroy();else{var n=this;!function e(){n.emit("write",t.shift()+"\r\n"),t.length?setTimeout(e,17):n.destroy()}()}}}]),t}(y),colors:function(e){function t(){return s(this,t),r(this,(t.__proto__||Object.getPrototypeOf(t)).apply(this,arguments))}return o(t,e),l(t,[{key:"run",value:function(){this.emit("write","\r\n");this.emit("write","    ");for(var e=0;e<16;e++)this.emit("write","["+(e<8?"3"+e:"9"+(e-8))+"m"),this.emit("write","foreground-color"[e]+" ");this.emit("write","\r\n    ");for(var t=0;t<16;t++)this.emit("write","["+(t<8?"4"+t:"10"+(t-8))+"m  ");this.emit("write","\r\n");for(var n=0;n<6;n++){this.emit("write","    ");for(var i=0;i<6;i++){for(var r=0;r<6;r++)this.emit("write","[48;5;"+(16+36*n+6*i+r)+"m  ");this.emit("write","")}this.emit("write","\r\n")}this.emit("write","    ");for(var o=0;o<24;o++)this.emit("write","[48;5;"+(232+o)+"m  ");this.emit("write","\r\n\n"),this.destroy()}}]),t}(y),ls:function(e){function t(){return s(this,t),r(this,(t.__proto__||Object.getPrototypeOf(t)).apply(this,arguments))}return o(t,e),l(t,[{key:"run",value:function(){this.emit("write","List of demo commands\r\n");for(var e in _)"string"!=typeof _[e]&&this.emit("write",e+"\r\n");this.destroy()}}]),t}(y),theme:function(e){function t(e){s(this,t);var n=r(this,(t.__proto__||Object.getPrototypeOf(t)).call(this));return n.shell=e,n}return o(t,e),l(t,[{key:"run",value:function(){var e=0|+(arguments.length<=0?void 0:arguments[0]),t=f.length;if(!arguments.length||!Number.isFinite(e)||e<0||e>=t)return this.emit("write","Usage: theme [0–"+(t-1)+"]\n"),void this.destroy();this.shell.terminal.theme=e,this.shell.terminal.termScreen.drawnScreenFG=[],this.emit("write",""),this.destroy()}}]),t}(y),themes:function(e){function t(){return s(this,t),r(this,(t.__proto__||Object.getPrototypeOf(t)).apply(this,arguments))}return o(t,e),l(t,[{key:"color",value:function(e){e=parseInt(e.substr(1),16);var t=e>>16,n=e>>8&255,i=255&e;this.emit("write","[48;2;"+t+";"+n+";"+i+"m"),(t+n+i)/3>127?this.emit("write",""):this.emit("write","")}},{key:"run",value:function(){for(var e in f){var t=f[e],n=("  "+e).substr(-2);this.emit("write","Theme "+n+": ");for(var i=0;i<16;i++){var r=("  "+i).substr(-2);this.color(t[i]),this.emit("write",r),this.emit("write"," ")}this.emit("write","\n")}this.destroy()}}]),t}(y),cursor:function(e){function t(){return s(this,t),r(this,(t.__proto__||Object.getPrototypeOf(t)).apply(this,arguments))}return o(t,e),l(t,[{key:"run",value:function(){for(var e=arguments.length,t=Array(e),n=0;n<e;n++)t[n]=arguments[n];var i=t.includes("--steady");t.includes("block")?this.emit("write","["+2*i+" q"):t.includes("line")?this.emit("write","["+(3+i)+" q"):t.includes("bar")||t.includes("beam")?this.emit("write","["+(5+i)+" q"):this.emit("write","Usage: cursor [block|line|bar] [--steady]\r\n"),this.destroy()}}]),t}(y),rainbow:function(e){function t(e){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};s(this,t);var i=r(this,(t.__proto__||Object.getPrototypeOf(t)).call(this));return i.shell=e,i.su=n.su,i.abort=!1,i}return o(t,e),l(t,[{key:"write",value:function(e){var t=!(arguments.length>1&&void 0!==arguments[1])||arguments[1];"y"===e?(this.shell.terminal.rainbow=!this.shell.terminal.rainbow,this.shell.terminal.superRainbow=!0,b._didWarnRainbow=!0):this.emit("write",e),t&&this.emit("write","Rainbow!\n"),this.destroy()}},{key:"run",value:function(){this.su&&!this.shell.terminal.rainbow?b._didWarnRainbow?this.write("y",!1):this.emit("write","Warning: flashy colors. Continue? [y/N] "):(this.shell.terminal.rainbow=!this.shell.terminal.rainbow,this.shell.terminal.superRainbow=!1,this.destroy())}},{key:"destroy",value:function(){this.abort=!0,a(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"destroy",this).call(this)}}]),t}(y),mouse:function(e){function t(e){s(this,t);var n=r(this,(t.__proto__||Object.getPrototypeOf(t)).call(this));return n.shell=e,n}return o(t,e),l(t,[{key:"run",value:function(){this.emit("buttons",[{label:"Exit",action:function(e){e.write("")}}]),this.shell.terminal.trackMouse=!0,b.mouseReceiver=this,this.randomData=[],this.highlighted={};for(var e="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",t=0;t<23;t++){for(var n="",i=0;i<79;i++)n+=e[Math.floor(e.length*Math.random())];this.randomData.push(n)}this.scrollOffset=0,this.render()}},{key:"render",value:function(){this.emit("write",""),this.emit("write","Mouse Demo\r\nMouse movement, clicking, and scrolling!");for(var e=0;e<23;e++){var t=e+this.scrollOffset;t=(t%this.randomData.length+this.randomData.length)%this.randomData.length;var n=this.randomData[t],i="["+(3+e)+";1H";for(var r in n)this.highlighted[80*(e+2)+ +r]&&(i+=""),i+=n[r],this.highlighted[80*(e+2)+ +r]&&(i+="");this.emit("write",i)}this.mouse&&this.emit("write","["+(this.mouse.y+1)+";"+(this.mouse.x+1)+"H")}},{key:"mouseMove",value:function(e,t){this.mouse={x:e,y:t},this.render()}},{key:"mouseDown",value:function(e,t,n){4===n?this.scrollOffset--:5===n?this.scrollOffset++:this.highlighted[80*t+e]=!this.highlighted[80*t+e],this.render()}},{key:"mouseUp",value:function(e,t,n){}},{key:"destroy",value:function(){this.shell.terminal.write(""),this.shell.terminal.trackMouse=!1,b.mouseReceiver===this&&(b.mouseReceiver=null),a(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"destroy",this).call(this)}}]),t}(y),sudo:function(e){function t(e){s(this,t);var n=r(this,(t.__proto__||Object.getPrototypeOf(t)).call(this));return n.shell=e,n.didDestroy=!1,n}return o(t,e),l(t,[{key:"run",value:function(){for(var e=this,t=arguments.length,n=Array(t),i=0;i<t;i++)n[i]=arguments[i];if(0===n.length)this.emit("write","Usage: sudo [command]\r\n"),this.destroy();else{var r=n.shift();if(this.shell.index[r]){var o=this.shell.index[r];if(o instanceof Function){var s=this.child=new o(this.shell,{su:!0});this.on("in",function(e){return s.write(e)});var a=function(t){return e.emit("write",t)},l=function(t){return e.emit("buttons",t)};s.on("write",a),s.on("buttons",l),s.on("exit",function(t){s.removeListener("write",a),s.removeListener("buttons",l),e.destroy()}),s.run.apply(s,n)}else this.emit("write",o),this.destroy()}else this.emit("write","sudo: "+r+": command not found\r\n"),this.destroy()}}},{key:"destroy",value:function(){this.didDestroy||(this.didDestroy=!0,this.child&&this.child.destroy(),a(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"destroy",this).call(this))}}]),t}(y),make:function(e){function t(e){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};s(this,t);var i=r(this,(t.__proto__||Object.getPrototypeOf(t)).call(this));return i.su=n.su,i}return o(t,e),l(t,[{key:"run",value:function(){for(var e=arguments.length,t=Array(e),n=0;n<e;n++)t[n]=arguments[n];if(0===t.length)this.emit("write","make: *** No targets specified.  Stop.\r\n");else if(3===t.length&&"me a sandwich"===t.join(" ").toLowerCase())if(this.su){var i="",r="",o="",s="";this.emit("write","                    _.---._\r\n                _.-~       ~-._\r\n            _.-~               ~-._\r\n        _.-~                       ~---._\r\n    _.-~                                 ~\\\r\n .-~                                    _.;\r\n :-._                               _.-~ ./\r\n `-._~-._                   _..__.-~ _.-~\r\n  "+o+"/  "+i+"~-._~-._              / .__..--"+o+"~-"+r+"---._\r\n"+o+" \\_____(_"+i+";-._\\.        _.-~_/"+o+"       ~)"+r+".. . \\\r\n"+r+"    /(_____  "+i+"\\`--...--~_.-~"+o+"______..-+"+r+"_______)\r\n"+r+"  .(_________/"+i+"`--...--~/"+r+"    _/ "+s+"          "+i+"/\\\r\n"+i+" /-._"+s+"     \\_     "+r+"(___./_..-~"+s+"__....."+i+"__..-~./\r\n"+i+" `-._~-._"+s+"   ~\\--------~  .-~"+i+"_..__.-~ _.-~\r\n"+i+"     ~-._~-._ "+s+"~---------`  "+i+"/ .__..--~\r\n"+i+"         ~-._\\.        _.-~_/\r\n"+i+"             \\`--...--~_.-~\r\n"+i+"              `--...--~\r\n")}else this.emit("write","make: me a sandwich : Permission denied\r\n");else this.emit("write","make: *** No rule to make target '"+t.join(" ").toLowerCase()+"'.  Stop.\r\n");this.destroy()}}]),t}(y),pwd:"/this/is/a/demo\r\n",cd:"No directories to change to\r\n",whoami:window.navigator.userAgent+"\r\n",hostname:""+window.location.hostname,uname:"ESPTerm Demo\r\n",mkdir:"Did not create a directory because this is a demo.\r\n",rm:"Did not delete anything because this is a demo.\r\n",cp:"Nothing to copy because this is a demo.\r\n",mv:"Nothing to move because this is a demo.\r\n",ln:"Nothing to link because this is a demo.\r\n",touch:"Nothing to touch\r\n",exit:"Nowhere to go\r\n",github:function(e){function t(){return s(this,t),r(this,(t.__proto__||Object.getPrototypeOf(t)).apply(this,arguments))}return o(t,e),l(t,[{key:"run",value:function(){window.open("https://github.com/espterm/espterm-firmware"),this.destroy()}}]),t}(y)},k={"local-echo":"local-echo [--suppress-note]",theme:"theme [n]",cursor:"cursor [block|line|bar] [--steady]",sudo:"sudo [command]"},x=function(){function e(t,n){var i=this;s(this,e),this.terminal=t,this.terminal.reset(),this.parser=new p(function(){return i.handleParsed.apply(i,arguments)}),this.history=[],this.historyIndex=0,this.cursorPos=0,this.lastInputLength=0,this.child=null,this.index=_,n?this.run("info"):this.prompt()}return l(e,[{key:"write",value:function(e){this.child?3===e.codePointAt(0)?this.child.destroy():this.child.write(e):this.parser.write(e)}},{key:"prompt",value:function(){var e=!(arguments.length>0&&void 0!==arguments[0])||arguments[0];0!==this.terminal.cursor.x&&this.terminal.write("⏎\r\n"),this.terminal.write("demosh "),e||this.terminal.write(""),this.terminal.write("$ "),this.history.unshift(""),this.cursorPos=0,this.setButtons()}},{key:"copyFromHistoryIndex",value:function(){if(this.historyIndex){var e=this.history[this.historyIndex];this.history[0]=e,this.historyIndex=0}}},{key:"getCompleted",value:function(){var e=arguments.length>0&&void 0!==arguments[0]&&arguments[0];if(this.history[0]){var t=this.history[0],n="";if(t.startsWith("sudo ")){var i=t.replace(/^(sudo\s+)+/,"");n=t.substr(0,t.length-i.length),t=i}for(var r in this.index)if(r.startsWith(t)&&r!==t)return e&&r in k?n+k[r]:n+r;return null}return null}},{key:"handleParsed",value:function(e){if(this.terminal.write("["+(this.lastInputLength-this.cursorPos)+"P"),this.terminal.write("\b".repeat(this.cursorPos)),"write"===e)this.copyFromHistoryIndex(),this.history[0]=this.history[0].substr(0,this.cursorPos)+(arguments.length<=1?void 0:arguments[1])+this.history[0].substr(this.cursorPos),this.cursorPos++;else if("back"===e)this.copyFromHistoryIndex(),this.history[0]=this.history[0].substr(0,this.cursorPos-1)+this.history[0].substr(this.cursorPos),--this.cursorPos<0&&(this.cursorPos=0);else if("tab"===e){var t=this.getCompleted();t&&(this.history[0]=t,this.cursorPos=this.history[0].length)}else if("move-cursor-x"===e)this.cursorPos=Math.max(0,Math.min(this.history[this.historyIndex].length,this.cursorPos+(arguments.length<=1?void 0:arguments[1])));else if("delete-line"===e)this.copyFromHistoryIndex(),this.history[0]="",this.cursorPos=0;else if("delete-word"===e){this.copyFromHistoryIndex();var n=this.history[0].substr(0,this.cursorPos).split(" ");n.pop(),this.history[0]=n.join(" ")+this.history[0].substr(this.cursorPos),this.cursorPos=n.join(" ").length}else"move-cursor-y"===e&&(this.historyIndex-=arguments.length<=1?void 0:arguments[1],this.historyIndex<0&&(this.historyIndex=0),this.historyIndex>=this.history.length&&(this.historyIndex=this.history.length-1),this.cursorPos=this.history[this.historyIndex].length);this.terminal.write(this.history[this.historyIndex]),this.terminal.write("\b".repeat(this.history[this.historyIndex].length)),this.terminal.moveForward(this.cursorPos),this.lastInputLength=this.cursorPos;var i=this.getCompleted(!0);if(0===this.historyIndex&&i&&"return"!==e){var r=i.substr(this.history[0].length);this.terminal.write(""+r+""+"\b".repeat(r.length)),this.lastInputLength+=r.length}"return"===e&&(this.terminal.write("\n"),this.parse(this.history[this.historyIndex]))}},{key:"parse",value:function(e){"help"===e&&(e="info"),e?this.run(e):this.prompt()}},{key:"run",value:function(e){var t=[""],n=!1,i=!0,r=!1,o=void 0;try{for(var s,a=e.trim()[Symbol.iterator]();!(i=(s=a.next()).done);i=!0){var l=s.value;n&&l!==n?t[t.length-1]+=l:n?n=!1:'"'===l||"'"===l?n=l:l.match(/\s/)?t[t.length-1]&&t.push(""):t[t.length-1]+=l}}catch(e){r=!0,o=e}finally{try{!i&&a.return&&a.return()}finally{if(r)throw o}}var c=t.shift();c in this.index?this.spawn(c,t):(this.terminal.write("demosh: Unknown command: "+c+"\r\n"),this.prompt(!1))}},{key:"spawn",value:function(e){var t=this,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[],r=this.index[e];if(r instanceof Function){var o;this.setButtons([]),this.child=new r(this);var s=function(e){return t.terminal.write(e)},a=function(e){return t.setButtons(e)};this.child.on("write",s),this.child.on("buttons",a),this.child.on("exit",function(e){t.child&&(t.child.removeListener("write",s),t.child.removeListener("buttons",a)),t.child=null,t.prompt(!e)}),(o=this.child).run.apply(o,i(n))}else this.terminal.write(r),this.prompt()}},{key:"setButtons",value:function(e){if(!e){var t=this,n=function(e){var n=function n(){t.write(e[0]),(e=e.substr(1))&&setTimeout(n,100)};setTimeout(n,200)};e=[{label:"Open GitHub",action:function(e){e.child&&e.child.destroy(),n("github\r")}},{label:"Help",action:function(e){e.child&&e.child.destroy(),n("info\r")}}]}e.length||e.push({label:"",action:function(){}}),this.buttons=e,this.terminal.buttonLabels=e.map(function(e){return e.label})}},{key:"onButtonPress",value:function(e){var t=this.buttons[e];t&&t.action(this,this.terminal)}}]),e}();window.demoInterface=e.exports={input:function(e){var t=e[0],n=e.substr(1);if("s"===t)this.shell.write(n);else if("b"===t){var i=n.charCodeAt(0);this.shell.onButtonPress(i-1)}else if("m"===t||"p"===t||"r"===t){var r=u(n,0),o=u(n,2),s=u(n,4),a=u(n,6);b.mouseReceiver&&("m"===t?b.mouseReceiver.mouseMove(o,r,s,a):"p"===t?b.mouseReceiver.mouseDown(o,r,s,a):"r"===t&&b.mouseReceiver.mouseUp(o,r,s,a))}},didInit:!1,init:function(e){this.didInit||(this.didInit=!0,this.terminal=new w(e),this.shell=new x(this.terminal,!0))}}},function(e,t,n){"use strict";function i(e){return("00"+e).substr(-2)}var r=Math,o=2*r.PI;t.hue2rgb=function(e,t,n){return n<0&&(n+=1),n>1&&(n-=1),6*n<1?e+6*(t-e)*n:2*n<1?t:3*n<2?e+(t-e)*(2/3-n)*6:e},t.hsl2rgb=function(e,n,i){e/=o;var r=void 0,s=void 0,a=void 0;if(0===n)r=s=a=i;else{var l=void 0,c=void 0;c=i<.5?i*(1+n):i+n-n*i,l=2*i-c,r=t.hue2rgb(l,c,e+1/3),s=t.hue2rgb(l,c,e),a=t.hue2rgb(l,c,e-1/3)}return[r,s,a]},t.rgb2hsl=function(e,t,n){var i=r.min(e,t,n),s=r.max(e,t,n),a=s-i,l=void 0,c=void 0,h=void 0;if(h=(s+i)/2,0===a)l=c=0;else{c=h<.5?a/(s+i):a/(2-s-i);var u=((s-e)/6+a/2)/a,d=((s-t)/6+a/2)/a,f=((s-n)/6+a/2)/a;e===s?l=f-d:t===s?l=1/3+u-f:n===s&&(l=2/3+d-u),l<0?l+=1:l>1&&(l-=1)}return l*=o,[l,c,h]},t.hex2rgb=function(e){var t=e.match(/^#([\da-f]{3,6})$/i);if(t){e=t[1];var n=e.length/3,i=Math.pow(16,n)-1;return[0,1,2].map(function(t){return parseInt(e.slice(t*n,(t+1)*n),16)/i})}return[0,0,0]},t.rgb255ToHex=function(e,t,n){return"#"+[e,t,n].map(function(e){return i(e.toString(16))}).join("")},t.rgb2hex=function(e,t,n){return"#"+[e,t,n].map(function(e){return i(Math.round(255*e).toString(16))}).join("")}},function(e,t,n){"use strict";var i=n(13);e.exports=function(e){return i[e]||"?"+e+"?"}},function(e,t,n){"use strict";n(10),n(2),n(3),n(11);try{n(6)}catch(e){}n(12);var i=n(1),r=n(0),o=r.qs;window.termInit=n(14),window.$=i,window.qs=o,window.themes=n(5),window.TermConf=n(24)},function(e,t,n){"use strict";/*! http://mths.be/fromcodepoint v0.1.0 by @mathias */
+String.fromCodePoint||function(){var e=function(){try{var e={},t=Object.defineProperty,n=t(e,e,e)&&t}catch(e){}return n}(),t=String.fromCharCode,n=Math.floor,i=function(){var e,i,r=[],o=-1,s=arguments.length;if(!s)return"";for(var a="";++o<s;){var l=Number(arguments[o]);if(!isFinite(l)||l<0||l>1114111||n(l)!=l)throw RangeError("Invalid code point: "+l);l<=65535?r.push(l):(l-=65536,e=55296+(l>>10),i=l%1024+56320,r.push(e,i)),(o+1==s||r.length>16384)&&(a+=t.apply(null,r),r.length=0)}return a};e?e(String,"fromCodePoint",{value:i,configurable:!0,writable:!0}):String.fromCodePoint=i}()},function(e,t,n){"use strict";function i(){d=!0,r("#content").addClass("load")}var r=n(1),o=n(0),s=o.mk,a=o.qs,l=o.qsa,c=o.cr,h=n(2),u=n(3);r.ready(function(){function e(){r("#menu").toggleClass("expanded")}r("#brand").on("click",e).on("keypress",c(e)),r(".Row.checkbox").forEach(function(e){var t=e.querySelector("input"),n=e.querySelector(".box");r(n).toggleClass("checked",t.value);var i=function(){t.value=1-t.value,r(n).toggleClass("checked",t.value)};r(e).on("click",i).on("keypress",c(i))}),r(".Box.mobcol,.Box.fold").forEach(function(e){var t=e.querySelector("h2"),n=function(){r(e).hasClass("d-expanded")?r(e).removeClass("d-expanded"):r(e).toggleClass("expanded")};r(t).on("click",n).on("keypress",c(n))}),r("form").forEach(function(e){r(e).on("keypress",function(t){10!==t.keyCode&&13!==t.keyCode||!t.ctrlKey||e.submit()})}),setInterval(function(){r(".anim-dots").each(function(e){var t=r(e),n=t.html()+".";5===n.length&&(n="."),t.html(n)})},1e3),r("input[type=number]").on("wheel",function(e){var t=r(this),n=+t.val();isNaN(n)&&(n=1);var i=+(t.attr("step")||1),o=+t.attr("min"),s=+t.attr("max");if(e.deltaY>0?n+=i:n-=i,Number.isFinite(o)&&(n=Math.max(n,+o)),Number.isFinite(s)&&(n=Math.min(n,+s)),t.val(n),"createEvent"in document){var a=document.createEvent("HTMLEvents");a.initEvent("change",!1,!0),t[0].dispatchEvent(a)}else t[0].fireEvent("onchange");e.preventDefault()});var t=window.location.search.indexOf("err=");if(-1!==t&&a(".Box.errors")){var n=decodeURIComponent(window.location.search.substr(t+4)).split(","),i=[];n.forEach(function(e){var t=l('label[for="'+e+'"]');if(t)for(var n=0;n<t.length;n++){var r=t[n];r.classList.add("error"),0===n&&i.push(r.childNodes[0].textContent.trim().replace(/: ?$/,""))}else i.push(e)}),a(".Box.errors .list").innerHTML=i.join(", "),a(".Box.errors").classList.remove("hidden")}var o=window.location.search.indexOf("msg=");if(-1!==o&&a(".Box.message")){var s=decodeURIComponent(window.location.search.substr(o+4)),d=a(".Box.message");d.innerHTML=s,d.classList.remove("hidden"),setTimeout(function(){d.classList.add("hiding"),setTimeout(function(){d.classList.add("hidden")},1e3)},2e3)}if(h.init(),u.init(),window.innerWidth>550){r(".Box h2").forEach(function(e){e.removeAttribute("tabindex")});var f=a("#brand");f&&f.addEventListener("click",function(){window.location.href="/"})}}),r._loader=function(e){r("#loader").toggleClass("show",e)};var d=!1;window.showPage=i,r.ready(function(){!0===window.noAutoShow?setTimeout(function(){if(!d){var e=s("P");e.id="load-failed",e.innerHTML='Server connection failed! Trying again<span class="anim-dots" style="width:1.5em;text-align:left;display:inline-block">.</span>',a("#screen").appendChild(e),i()}},2e3):setTimeout(function(){i()},1)})},function(e,t,n){"use strict";var i=n(1),r=n(0),o=r.mk,s=n(8),a=function(e){return"+"+(.25*e.value).toFixed(2)+" dBm"},l=function(e,t,n){i("#sta_ssid").val(e),i("#sta_password").val(t),i("#sta-nw").toggleClass("hidden",0===e.length),i("#sta-nw-nil").toggleClass("hidden",e.length>0),i("#sta-nw .essid").html(i.htmlEscape(e));var r=!!t;i("#sta-nw .passwd").toggleClass("hidden",!r),i("#sta-nw .nopasswd").toggleClass("hidden",r),i("#sta-nw .ip").html(n.length>0?s("wifi.connected_ip_is")+n:s("wifi.not_conn"))},c=function(e,t){if(200!==t)return void d(5e3);try{e=JSON.parse(e)}catch(e){return console.log(e),void d(5e3)}var n=!e.result.inProgress&&e.result.APs.length>0;if(d(n?15e3:1e3),n){var r=i("#ap-list");i("#ap-list .AP").remove(),r.toggleClass("hidden",!n),i("#ap-loader").toggleClass("hidden",n),e.result.APs.sort(function(e,t){return t.rssi-e.rssi}).forEach(function(e){if(e.enc=parseInt(e.enc),!(e.enc>4)){var t=o("div"),n=i(t).data("ssid",e.essid).data("pwd",e.enc).attr("tabindex",0).addClass("AP");e.essid===m&&n.addClass("selected");var a=o("div"),c=i.htmlEscape(e.essid);i(a).addClass("inner").htmlAppend('<div class="rssi">'+e.rssi_perc+"</div>").htmlAppend('<div class="essid" title="'+c+'">'+c+"</div>").htmlAppend('<div class="auth">'+p[e.enc]+"</div>"),n.on("click",function(){var e=i(this),t=e.data("ssid"),n="";+e.data("pwd")&&!(n=window.prompt(s("wifi.enter_passwd").replace(":ssid:",t)))||(i("#sta_password").val(n),i("#sta_ssid").val(t),l(t,n,""))}),t.appendChild(a),r[0].appendChild(t)}})}},h=function(){i("#ap-loader").removeClass("hidden"),i("#ap-scan").addClass("hidden"),i("#ap-loader .anim-dots").html("."),u()},u=function(){window._demo?c(window._demo_aps,200):i.get("http://"+window._root+"/cfg/wifi/scan",c)},d=function(e){setTimeout(u,e)},f=function(e){i(".Row.range").forEach(function(e){var t=e.querySelector("input"),n=e.querySelector(".x-disp1"),r=e.querySelector(".x-disp2"),o=a(t);i(n).html(o),i(r).html(o),i(t).on("input",function(){o=a(t),i(n).html(o),i(r).html(o)})}),i("#forget-sta").on("click",function(){return l("","",""),!1}),l(e.sta_ssid,e.sta_password,e.sta_active_ip),m=e.sta_active_ssid},v=window.WiFi={},p=["Open","WEP","WPA","WPA2","WPA/WPA2"],m=void 0;v.init=f,v.startScanning=h},function(e,t){e.exports={"wifi.connected_ip_is":"Connected, IP is ","wifi.not_conn":"Not connected.","wifi.enter_passwd":'Enter password for ":ssid:"',"term_nav.fullscreen":"Fullscreen","term_conn.connecting":"Connecting","term_conn.waiting_content":"Waiting for content","term_conn.disconnected":"Disconnected","term_conn.waiting_server":"Waiting for server","term_conn.reconnecting":"Reconnecting"}},function(e,t,n){"use strict";function i(e){if(Array.isArray(e)){for(var t=0,n=Array(e.length);t<e.length;t++)n[t]=e[t];return n}return Array.from(e)}var r=n(0),o=r.qs,s=r.mk,a=n(8),l=n(3),c=n(15),h=n(18),u=n(19),d=n(20),f=n(21),v=n(22),p=n(23);e.exports=function(e){var t=new c,n=new h(t),r=u(n,t),m=d(n,r,t);t.input=r,t.conn=n,r.termUpload=m;var g=p(r);t.on("button-labels",function(e){var t;(t=g.labels).splice.apply(t,[0,g.labels.length].concat(i(e))),g.update()});var w=null,y=function(e){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:250;clearTimeout(w),w=setTimeout(function(){t.window.statusScreen=e},n)};n.on("open",function(){y({title:a("term_conn.connecting"),loading:!0})}),n.on("connect",function(){y({title:a("term_conn.waiting_content"),loading:!0})}),n.on("load",function(){clearTimeout(w),t.window.statusScreen&&(t.window.statusScreen=null)}),n.on("disconnect",function(){y({title:a("term_conn.disconnected")},500),t.screen=[],t.screenFG=[],t.screenBG=[],t.screenAttrs=[]}),n.on("silence",function(){y({title:a("term_conn.waiting_server"),loading:!0},0)}),n.on("ping-success",function(){y({title:a("term_conn.reconnecting"),loading:!0},0)}),n.init(),r.init(e),m.init(),l.init(),window.onerror=function(e,t,n,i){return l.show("<b>JS ERROR!</b><br>"+e+"<br>at "+t+":"+n+":"+i,1e4,!0),!1},o("#screen").appendChild(t.canvas),f(t,r),v&&v(t);var b={},_=!1,k=!1,x=!1,C=t.window.padding,S=function(){_?(b.className="icn-resize-small",k?(t.window.fitIntoWidth=window.screen.width,t.window.fitIntoHeight=window.screen.height,t.window.padding=0):(t.window.fitIntoWidth=window.innerWidth,o("#term-nav").classList.contains("hidden")?t.window.fitIntoHeight=window.innerHeight:t.window.fitIntoHeight=window.innerHeight-24,t.window.padding=0)):(b.className="icn-resize-full",t.window.fitIntoWidth=x?window.innerWidth-4:0,t.window.fitIntoHeight=x?window.innerHeight:0,t.window.padding=C)};S(),window.addEventListener("resize",S);var T=function(){x=!x;var e=o("#resize-button-icon");x?(e.classList.remove("icn-resize-small"),e.classList.add("icn-resize-full")):(e.classList.remove("icn-resize-full"),e.classList.add("icn-resize-small")),S()};if(o("#term-fit-screen").addEventListener("click",function(){return T(),!1}),window.Element.prototype.requestFullscreen||window.Element.prototype.webkitRequestFullscreen){k=!0;var E=function(){!_||window.innerWidth===window.screen.width&&window.innerHeight===window.screen.height||(_=!1,S())};setInterval(E,500)}var P=s("a");P.id="fullscreen-button",P.href="#",P.addEventListener("click",function(e){if(e.preventDefault(),document.body.classList.contains("pseudo-fullscreen"))return document.body.classList.remove("pseudo-fullscreen"),_=!1,void S();_=!0,S(),t.updateSize(),k?t.canvas.requestFullscreen?t.canvas.requestFullscreen():t.canvas.webkitRequestFullscreen():document.body.classList.add("pseudo-fullscreen")}),b=s("i"),b.className="icn-resize-full",P.appendChild(b);var L=s("span");L.textContent=a("term_nav.fullscreen"),P.appendChild(L),o("#term-nav").insertBefore(P,o("#term-nav").firstChild),window.termScreen=t,window.conn=n,window.input=r,window.termUpl=m}},function(e,t,n){"use strict";function i(e){if(Array.isArray(e)){for(var t=0,n=Array(e.length);t<e.length;t++)n[t]=e[t];return n}return Array.from(e)}function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function s(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}var a=function(){function e(e,t){for(var n=0;n<t.length;n++){var i=t[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(e,i.key,i)}}return function(t,n,i){return n&&e(t.prototype,n),i&&e(t,i),t}}(),l=n(4),c=n(1),h=n(0),u=h.mk,d=h.qs,f=n(3),v=n(16),p=n(17);e.exports=function(e){function t(){r(this,t);var e=o(this,(t.__proto__||Object.getPrototypeOf(t)).call(this));e.canvas=u("canvas"),e.ctx=e.canvas.getContext("2d"),e.parser=new v(e),e.renderer=new p(e),e._debug=null,"AudioContext"in window||"webkitAudioContext"in window?e.audioCtx=new(window.AudioContext||window.webkitAudioContext):console.warn("No AudioContext!"),e.input=new Proxy({},{get:function(){return function(){return console.warn("TermScreen#input not set!")}}}),e.conn=new Proxy({},{get:function(){return function(){return console.warn("TermScreen#conn not set!")}},set:function(e,t){return function(){return console.warn("TermScreen#conn not set!")}}}),e.cursor={x:0,y:0,blinking:!0,visible:!0,hanging:!1,style:"block"},e._window={width:0,height:0,devicePixelRatio:1,fontFamily:'"DejaVu Sans Mono", "Liberation Mono", "Inconsolata", "Menlo", monospace',fontSize:20,padding:6,gridScaleX:1,gridScaleY:1.2,fitIntoWidth:0,fitIntoHeight:0,debug:!1,graphics:0,statusScreen:null},e._windowScale=1,e._padding=0,e.windowState={width:0,height:0,devicePixelRatio:0,padding:0,gridScaleX:0,gridScaleY:0,fontFamily:"",fontSize:0,fitIntoWidth:0,fitIntoHeight:0},e.selection={selectable:!0,start:[0,0],end:[0,0]},e.mouseMode={clicks:!1,movement:!1};var n=e;e.window=new Proxy(e._window,{set:function(e,t,i,r){return e[t]!==i&&(e[t]=i,n.scheduleSizeUpdate(),n.renderer.scheduleDraw("window:"+t+"="+i),n.emit("update-window:"+t,i)),!0}}),e.bracketedPaste=!1,e.blinkingCellCount=0,e.reverseVideo=!1,e.screen=[],e.screenFG=[],e.screenBG=[],e.screenAttrs=[];var s=!1,a=function(t,n){s||(s=!0,e.selection.start=e.selection.end=e.screenToGrid(t,n,!0),e.renderer.scheduleDraw("select-start"))},l=function(t,n){s&&(e.selection.end=e.screenToGrid(t,n,!0),e.renderer.scheduleDraw("select-move"))},h=function(t,n){s&&(s=!1,e.selection.end=e.screenToGrid(t,n,!0),e.renderer.scheduleDraw("select-end"),Object.assign(e.selection,e.getNormalizedSelection()))};e.canvas.addEventListener("mousedown",function(t){if((e.selection.selectable||t.altKey)&&0===t.button)a(t.offsetX,t.offsetY);else{var n;(n=e.input).onMouseDown.apply(n,i(e.screenToGrid(t.offsetX,t.offsetY)).concat([t.button+1]))}}),window.addEventListener("mousemove",function(e){l(e.offsetX,e.offsetY)}),window.addEventListener("mouseup",function(e){h(e.offsetX,e.offsetY)});var f=null,m=0,g=!1,w=function(t){var n=e.canvas.getBoundingClientRect();return[t.clientX-n.left,t.clientY-n.top]};e.canvas.addEventListener("touchstart",function(e){f=w(e.touches[0]),g=!1,m=Date.now()},{passive:!0}),e.canvas.addEventListener("touchmove",function(e){f=w(e.touches[0]),s||!1!==g?s&&(e.preventDefault(),l.apply(void 0,i(f))):m<Date.now()-500&&a.apply(void 0,i(f)),g=!0}),e.canvas.addEventListener("touchend",function(t){if(t.touches[0]&&(f=w(t.touches[0])),s){t.preventDefault(),h.apply(void 0,i(f));var n=d("#touch-select-menu");n.classList.add("open");var r=n.getBoundingClientRect(),o=e.gridToScreen((e.selection.start[0]+e.selection.end[0])/2,e.selection.start[1]-1);o[0]-=r.width/2,o[1]-=r.height/2,n.style.transform="translate("+o[0]+"px, "+o[1]+"px)"}g||e.mouseMode.clicks||e.emit("tap",Object.assign(t,{x:f[0],y:f[1]})),f=null}),e.on("tap",function(t){e.selection.start[0]!==e.selection.end[0]||e.selection.start[1]!==e.selection.end[1]?(e.selection.start=e.selection.end=[0,0],d("#touch-select-menu").classList.remove("open"),e.renderer.scheduleDraw("select-reset")):(t.preventDefault(),e.emit("open-soft-keyboard"))}),c.ready(function(){var t=d("#touch-select-copy-btn");t&&t.addEventListener("click",function(){e.copySelectionToClipboard()})}),e.canvas.addEventListener("mousemove",function(t){if(!s){var n;(n=e.input).onMouseMove.apply(n,i(e.screenToGrid(t.offsetX,t.offsetY)))}}),e.canvas.addEventListener("mouseup",function(t){if(!s){var n;(n=e.input).onMouseUp.apply(n,i(e.screenToGrid(t.offsetX,t.offsetY)).concat([t.button+1]))}});var y=0;return e.canvas.addEventListener("wheel",function(t){if(e.mouseMode.clicks){if(120===Math.abs(t.wheelDeltaY)){var n;(n=e.input).onMouseWheel.apply(n,i(e.screenToGrid(t.offsetX,t.offsetY)).concat([t.deltaY>0?1:-1]))}else if(y-=t.wheelDeltaY,Math.abs(y)>=40){var r;(r=e.input).onMouseWheel.apply(r,i(e.screenToGrid(t.offsetX,t.offsetY)).concat([y>0?1:-1])),y=0}t.preventDefault()}}),e.canvas.addEventListener("contextmenu",function(t){e.mouseMode.clicks&&t.preventDefault(),h(t.offsetX,t.offsetY)}),e}return s(t,e),a(t,[{key:"scheduleSizeUpdate",value:function(){var e=this;clearTimeout(this._scheduledSizeUpdate),this._scheduledSizeUpdate=setTimeout(function(){return e.updateSize()},1)}},{key:"getFont",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return(e.style||"normal")+" normal "+(e.weight||"normal")+" "+this.window.fontSize+"px "+this.window.fontFamily}},{key:"screenToGrid",value:function(e,t){var n=arguments.length>2&&void 0!==arguments[2]&&arguments[2],i=this.getCellSize();return e=e/this._windowScale-this._padding,t=t/this._windowScale-this._padding,e=Math.floor((e+(n?i.width/2:0))/i.width),t=Math.floor(t/i.height),e=Math.max(0,Math.min(this.window.width-1,e)),t=Math.max(0,Math.min(this.window.height-1,t)),[e,t]}},{key:"gridToScreen",value:function(e,t){var n=this,i=arguments.length>2&&void 0!==arguments[2]&&arguments[2],r=this.getCellSize();return[e*r.width,t*r.height].map(function(e){return n._padding+(i?e*n._windowScale:e)})}},{key:"getCharSize",value:function(){return this.ctx.font=this.getFont(),{width:Math.floor(this.ctx.measureText(" ").width),height:this.window.fontSize}}},{key:"getCellSize",value:function(){var e=this.getCharSize();return{width:Math.ceil(e.width*this.window.gridScaleX),height:Math.ceil(e.height*this.window.gridScaleY)}}},{key:"updateSize",value:function(){this._window.devicePixelRatio=Math.ceil(this._windowScale*(window.devicePixelRatio||1));var e=!1;for(var t in this.windowState)this.windowState.hasOwnProperty(t)&&this.windowState[t]!==this.window[t]&&(e=!0,this.windowState[t]=this.window[t]);if(e){var n=this.window,i=n.width,r=n.height,o=n.fitIntoWidth,s=n.fitIntoHeight,a=n.padding,l=this.getCellSize(),c=i*l.width,h=r*l.height,u=c;if(o&&s){var d=c/h;d<o/s?(h=s-2*a,c=h*d):(c=o-2*a,h=c/d)}this._windowScale=c/u,c+=2*a,h+=2*a,this._padding=a*(u/c);var f=this._window.devicePixelRatio=Math.ceil(this._windowScale*(window.devicePixelRatio||1));this.canvas.width=(i*l.width+2*Math.round(this._padding))*f,this.canvas.style.width=c+"px",this.canvas.height=(r*l.height+2*Math.round(this._padding))*f,this.canvas.style.height=h+"px",this.renderer.resetDrawn(),this.renderer.draw("update-size")}}},{key:"getNormalizedSelection",value:function(){var e=this.selection,t=e.start,n=e.end;if(t[1]>n[1]||t[1]===n[1]&&t[0]>n[0]){var i=[n,t];t=i[0],n=i[1]}return{start:t,end:n}}},{key:"isInSelection",value:function(e,t){var n=this.getNormalizedSelection(),i=n.start,r=n.end,o=i[0]<=e,s=e<r[0],a=t===i[1],l=t===r[1];return a&&l?o&&s:a?o:l?s:i[1]<t&&t<r[1]}},{key:"getSelectedText",value:function(){for(var e=this.window.width*this.window.height,t=[],n=-1,i=0;i<e;i++){var r=i%this.window.width,o=Math.floor(i/this.window.width);this.isInSelection(r,o)&&(n!==o&&(n=o,t.push("")),t[t.length-1]+=this.screen[i])}return t.join("\n")}},{key:"copySelectionToClipboard",value:function(){var e=this.getSelectedText();if(e){var t=u("textarea");document.body.appendChild(t),t.value=e,t.select(),document.execCommand("copy")?f.show("Copied to clipboard"):f.show("Failed to copy"),document.body.removeChild(t)}}},{key:"showNotification",value:function(e){if(console.info("Notification: "+e),window.Notification&&"granted"===window.Notification.permission){new window.Notification("ESPTerm",{body:e}).addEventListener("click",function(){return window.focus()})}else window.Notification&&"denied"!==window.Notification.permission?window.Notification.requestPermission():f.show(e)}},{key:"beep",value:function(){var e=this.audioCtx;if(e&&!(this._lastBeep&&this._lastBeep>Date.now()-50)){if(this._lastBeep=Date.now(),!this._convolver){this._convolver=e.createConvolver();for(var t=.8*e.sampleRate,n=e.createBuffer(2,t,e.sampleRate),i=0;i<t;i++)n.getChannelData(0)[i]=Math.pow(1-i/t,7+Math.random()),n.getChannelData(1)[i]=Math.pow(1-i/t,7+Math.random());this._convolver.buffer=n,this._convolver.connect(e.destination)}var r=e.createOscillator(),o=e.createGain();r.connect(o),o.gain.value=4,r.frequency.value=750,r.type="sine";var s=e.createOscillator(),a=e.createGain();s.connect(a),a.gain.value=2,s.frequency.value=400,s.type="sine",o.connect(this._convolver),a.connect(this._convolver);var l=e.currentTime;r.start(),r.stop(l+.5),s.start(l+.05),s.stop(l+.8);!function t(){e.currentTime<l+.8&&window.requestAnimationFrame(t),o.gain.value*=.8,a.gain.value*=.8}()}}},{key:"load",value:function(){var e;(e=this.parser).load.apply(e,arguments)}}]),t}(l)},function(e,t,n){"use strict";function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function r(e){var t=e.codePointAt(0);return t>57343&&(t-=2048),t-1}var o=function(){function e(e,t){for(var n=0;n<t.length;n++){var i=t[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(e,i.key,i)}}return function(t,n,i){return n&&e(t.prototype,n),i&&e(t,i),t}}(),s=n(1),a=n(0),l=a.qs;e.exports=function(){function e(t){i(this,e),this.screen=t,this.contentLoaded=!1}return o(e,[{key:"hideLoadFailedMsg",value:function(){if(!this.contentLoaded){var e=l("#load-failed");e&&e.parentNode.removeChild(e),this.contentLoaded=!0}}},{key:"loadUpdate",value:function(e){for(var t=this,n=0,i=Array.from?Array.from(e):e.split(""),o=void 0,a=!1,c=r(i[n++]);n<i.length;){var h=i[n++];if("O"===h){var u=r(i[n++]),d=r(i[n++]),f=r(i[n++]),v=65535&r(i[n++])|(65535&r(i[n++]))<<16,p=65535&r(i[n++])|(65535&r(i[n++]))<<16,m=r(i[n++]);this.screen.renderer.loadTheme(f),this.screen.renderer.setDefaultColors(v,p),a=this.screen.window.height!==u||this.screen.window.width!==d,this.screen.window.height=u,this.screen.window.width=d,this.screen.cursor.visible=!!(1&m),this.screen.input.setAlts(!!(4&m),!!(8&m),!!(16&m),!!(4096&m));var g=!!(32&m),w=!!(64&m),y=m>>9&7;y>0&&y--;var b=y>>1,_=!(1&y);0===b?this.screen.cursor.style="block":1===b?this.screen.cursor.style="line":2===b&&(this.screen.cursor.style="bar"),this.screen.cursor.blinking!==_&&(this.screen.cursor.blinking=_,this.screen.renderer.resetCursorBlink()),this.screen.input.setMouseMode(g,w),this.screen.selection.selectable=!g&&!w,s(this.screen.canvas).toggleClass("selectable",this.screen.selection.selectable),this.screen.mouseMode={clicks:g,movement:w};var k=!!(128&m),x=!!(256&m);s(".x-term-conf-btn").toggleClass("hidden",!x),s("#action-buttons").toggleClass("hidden",!k),this.screen.bracketedPaste=!!(8192&m),this.screen.reverseVideo=!!(16384&m)}else if("C"===h){var C=r(i[n++]),S=r(i[n++]),T=r(i[n++]),E=T!==this.screen.cursor.hanging||S!==this.screen.cursor.x||C!==this.screen.cursor.y;this.screen.cursor.x=S,this.screen.cursor.y=C,this.screen.cursor.hanging=!!T,E&&(this.screen.renderer.resetCursorBlink(),this.screen.emit("cursor-moved")),this.screen.renderer.scheduleDraw("cursor-moved")}else if("T"===h){for(o="";n<i.length;){var P=i[n++];if(""===P)break;o+=P}l("#screen-title").textContent=o,0===o.length&&(o="Terminal"),l("title").textContent=o+" :: ESPTerm"}else if("B"===h){for(var L=r(i[n++]),A=[],F=0;F<L;F++){for(o="";n<i.length;){var O=i[n++];if(""===O)break;o+=O}A.push(o)}this.screen.emit("button-labels",A)}else if("!"===h)this.screen.beep();else if("D"===h){var R=r(i[n++]),D=r(i[n++]),M=r(i[n++]),B=r(i[n++]),N=r(i[n++]),I=i[n++],H=i[n++],j=r(i[n++]),z=r(i[n++]);this.screen.emit("internal",{flags:R,cursorAttrs:D,regionStart:M,regionEnd:B,charsetGx:N,charsetG0:I,charsetG1:H,freeHeap:j,clientCount:z})}else"S"===h&&function(){var e=r(i[n++]),o=r(i[n++]),s=r(i[n++]),l=r(i[n++]);t.screen._debug&&t.screen.window.debug&&t.screen._debug.pushFrame([o,e,l,s]);var c=7,h=0,u=0,d=0,f=" ",v=l*s,p=t.screen.window.width*t.screen.window.height;a&&(t.screen.updateSize(),t.screen.blinkingCellCount=0,t.screen.screen=new Array(p).fill(" "),t.screen.screenFG=new Array(p).fill(" "),t.screen.screenBG=new Array(p).fill(" "),t.screen.screenAttrs=new Array(p).fill(0));for(var m=function(){var n=u,i=1&u,r=2&u,s=c,a=h;i||(s=0),r||(a=0),0!=(32&n)&&(" "===f&&0==(392&n)||c===h&&i&&r)&&(n^=32),(32&t.screen.screenAttrs[d])!=(32&n)&&(32&n?t.screen.blinkingCellCount++:t.screen.blinkingCellCount--);var v=d%l,p=Math.floor(d/l),m=(e+p)*t.screen.window.width+o+v;4&n&&!(512&n)&&i&&s<8&&(s+=8),t.screen.screen[m]=f,t.screen.screenFG[m]=s,t.screen.screenBG[m]=a,t.screen.screenAttrs[m]=n};n<i.length&&d<v;){var g=i[n++],w=g.codePointAt(0),y=void 0,b=void 0;switch(w){case 2:b=r(i[n++]);for(var _=0;_<b&&(m(),!(++d>v));_++);break;case 1:d+=r(i[n++]);break;case 3:y=r(i[n++]),c=255&y,h=y>>8&255;break;case 4:y=r(i[n++]),u=65535&y;break;case 7:u=0;break;case 5:y=r(i[n++]),65536&y&&(y&=4095,y|=(4095&r(i[n++]))<<12,y+=256),c=y;break;case 6:y=r(i[n++]),65536&y&&(y&=4095,y|=(4095&r(i[n++]))<<12,y+=256),h=y;break;default:w<32&&(g="�"),f=g,m(),d++}}t.screen.window.debug&&console.log("Blinky cells: "+t.screen.blinkingCellCount),t.screen.renderer.scheduleDraw("load",16),t.screen.conn.emit("load")}();0!=(59&c)&&this.hideLoadFailedMsg()}}},{key:"load",value:function(e){var t=e.substr(1);switch(e[0]){case"U":this.loadUpdate(t);break;case"G":this.screen.showNotification(t);break;default:console.warn("Bad data message type; ignoring.\n"+JSON.stringify(e))}}}]),e}()},function(e,t,n){"use strict";function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var r=function(){function e(e,t){for(var n=0;n<t.length;n++){var i=t[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(e,i.key,i)}}return function(t,n,i){return n&&e(t.prototype,n),i&&e(t,i),t}}(),o=n(5),s=o.themes,a=o.buildColorTable,l=o.SELECTION_FG,c=o.SELECTION_BG,h={C:"ℭ",H:"ℌ",I:"ℑ",R:"ℜ",Z:"ℨ"};e.exports=function(){function e(t){i(this,e),this.screen=t,this.ctx=t.ctx,this._palette=null,this.defaultBgNum=0,this.defaultFgNum=7,this.colorTable256=a(),this.resetDrawn(),this.blinkStyleOn=!1,this.blinkInterval=null,this.cursorBlinkOn=!1,this.cursorBlinkInterval=null,this.resetBlink(),this.resetCursorBlink()}return r(e,[{key:"resetDrawn",value:function(){this.screen.window&&this.screen.window.debug&&console.log("Resetting drawn screen"),this.drawnScreen=[],this.drawnScreenFG=[],this.drawnScreenBG=[],this.drawnScreenAttrs=[],this.drawnCursor=[-1,-1,""]}},{key:"loadTheme",value:function(e){e in s&&(this.palette=s[e])}},{key:"setDefaultColors",value:function(e,t){e===this.defaultFgNum&&t===this.defaultBgNum||(this.resetDrawn(),this.defaultFgNum=e,this.defaultBgNum=t,this.scheduleDraw("default-colors"))}},{key:"scheduleDraw",value:function(e){var t=this,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:1;clearTimeout(this._scheduledDraw),this._scheduledDraw=setTimeout(function(){return t.draw(e)},n)}},{key:"getColor",value:function(e){if(e<16&&e in this.palette)return this.palette[e];if(-1===e)return l;if(-2===e)return c;if(e>15&&e<256)return this.colorTable256[e];if(e>255){e-=256;return"rgb("+(e>>16&255)+", "+(e>>8&255)+", "+(255&e)+")"}return Date.now()/1e3%2==0?"#f0f":"#0f0"}},{key:"resetCursorBlink",value:function(){var e=this;this.cursorBlinkOn=!0,clearInterval(this.cursorBlinkInterval),this.cursorBlinkInterval=setInterval(function(){e.cursorBlinkOn=!e.screen.cursor.blinking||!e.cursorBlinkOn,e.screen.cursor.blinking&&e.scheduleDraw("cursor-blink")},500)}},{key:"resetBlink",value:function(){var e=this;this.blinkStyleOn=!0,clearInterval(this.blinkInterval);var t=0;this.blinkInterval=setInterval(function(){e.screen.blinkingCellCount<=0||(t++,t>=4&&e.blinkStyleOn?(e.blinkStyleOn=!1,t=0,e.scheduleDraw("blink-style")):t>=1&&!e.blinkStyleOn&&(e.blinkStyleOn=!0,t=0,e.scheduleDraw("blink-style")))},200)}},{key:"drawBackground",value:function(e){var t=e.x,n=e.y,i=e.cellWidth,r=e.cellHeight,o=e.bg,s=this.ctx,a=this.screen.window,l=a.width,c=a.height,h=Math.round(this.screen._padding);s.fillStyle=this.getColor(o);var u=t*i+h,d=n*r+h;if(0===t||0===n||t===l-1||n===c-1){var f=u,v=d,p=u+i,m=d+r;0===t?f-=h:t===l-1&&(p+=h),0===n?v-=h:n===c-1&&(m+=h),s.clearRect(f,v,p-f,m-v),s.fillRect(f,v,p-f,m-v)}else s.clearRect(u,d,i,r),s.fillRect(u,d,i,r)}},{key:"drawCharacter",value:function(t){var n=t.x,i=t.y,r=t.charSize,o=t.cellWidth,s=t.cellHeight,a=t.text,l=t.fg,c=t.attrs;if(a){var h=this.ctx,u=Math.round(this.screen._padding),d=!1,f=!1,v=!1;512&c&&(h.globalAlpha=.5),8&c&&(d=!0),1024&c&&(a=e.alphaToFraktur(a)),128&c&&(f=!0),256&c&&(v=!0),h.fillStyle=this.getColor(l);var p=n*o+u,m=i*s+u,g=a.codePointAt(0);if(g>=9600&&g<=9631){h.beginPath();var w=p,y=m,b=o,_=s,k=o/2,x=s/2;if(9600===g)h.rect(w,y,b,x);else if(g<=9608){var C=(1-(g-9600)/8)*_;h.rect(w,y+C,b,_-C)}else if(g<=9615){var S=(g-9608)/8*b;h.rect(w,y,b-S,_)}else if(9616===g)h.rect(w+k,y,k,_);else if(g<=9619){var T=void 0,E=void 0,P=void 0;9617===g?(T=b/4,E=_/10,P=1):9618===g?(T=b/6,E=b/10,P=1):9619===g&&(T=b/4,E=b/7,P=2);for(var L=!1,A=0;A<_;A+=E){for(var F=0;F<b;F+=T){var O=Math.min(P,_-A);h.rect(w+(L?b-F-P:F),y+A,P,O)}L=!L}}else 9620===g?h.rect(w,y,b,_/8):9621===g?h.rect(w+7/8*b,y,b/8,_):9622===g?h.rect(w,y+x,k,x):9623===g?h.rect(w+k,y+x,k,x):9624===g?h.rect(w,y,k,x):9625===g?(h.rect(w,y,k,_),h.rect(w+k,y+x,k,x)):9626===g?(h.rect(w,y,k,x),h.rect(w+k,y+x,k,x)):9627===g?(h.rect(w,y,k,_),h.rect(w+k,y,k,x)):9628===g?(h.rect(w,y,b,x),h.rect(w+k,y+x,k,x)):9629===g?h.rect(w+k,y,k,x):9630===g?(h.rect(w,y+x,k,x),h.rect(w+k,y,k,x)):9631===g&&(h.rect(w,y+x,k,x),h.rect(w+k,y,k,_));h.fill()}else g>=57520&&g<=57523?(h.beginPath(),57520===g||57521===g?(h.moveTo(p,m),h.lineTo(p+o,m+s/2),h.lineTo(p,m+s)):57522!==g&&57523!==g||(h.moveTo(p+o,m),h.lineTo(p,m+s/2),h.lineTo(p+o,m+s)),g%2==0?h.fill():(h.strokeStyle=h.fillStyle,h.stroke())):h.fillText(a,p+.5*o,m+.5*s);if(d||f||v){if(h.strokeStyle=this.getColor(l),h.lineWidth=1,h.lineCap="round",h.beginPath(),d){var R=Math.round(m+r.height)+.5;h.moveTo(p,R),h.lineTo(p+o,R)}if(f){var D=Math.round(m+.5*s)+.5;h.moveTo(p,D),h.lineTo(p+o,D)}if(v){var M=Math.round(m)+.5;h.moveTo(p,M),h.lineTo(p+o,M)}h.stroke()}h.globalAlpha=1}}},{key:"getAdjacentCells",value:function(e){for(var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:1,n=this.screen.window,i=n.width,r=n.height,o=i*r,s=[],a=-t;a<=t;a++)for(var l=-t;l<=t;l++)0===a&&0===l||s.push(e+a+l*i);return s.filter(function(e){return e>=0&&e<o})}},{key:"draw",value:function(e){var t=this,n=this.ctx,i=this.screen.window,r=i.width,o=i.height,s=i.devicePixelRatio,a=i.statusScreen;if(a)return this.drawStatus(a),void this.startDrawLoop();this.stopDrawLoop();var l=this.screen.getCharSize(),c=this.screen.getCellSize(),h=c.width,u=c.height,d=r*o;n.setTransform(s,0,0,s,0,0),this.screen.window.debug&&this.screen._debug&&this.screen._debug.drawStart(e),n.font=this.screen.getFont(),n.textAlign="center",n.textBaseline="middle";for(var f=new Map,v=new Map,p=0;p<d;p++){var m=p%r,g=Math.floor(p/r),w=this.cursorBlinkOn&&this.screen.cursor.x===m&&this.screen.cursor.y===g&&this.screen.cursor.visible,y=m===this.drawnCursor[0]&&g===this.drawnCursor[1],b=this.screen.isInSelection(m,g),_=this.screen.screen[p],k=0|this.screen.screenFG[p],x=0|this.screen.screenBG[p],C=0|this.screen.screenAttrs[p];if(1&C||(k=this.defaultFgNum),2&C||(x=this.defaultBgNum),16&C){var S=[x,k];k=S[0],x=S[1]}if(this.screen.reverseVideo){var T=[x,k];k=T[0],x=T[1]}32&C&&!this.blinkStyleOn&&(_=""),b&&(k=-1,x=-2);var E=_!==this.drawnScreen[p]||k!==this.drawnScreenFG[p]||x!==this.drawnScreenBG[p]||C!==this.drawnScreenAttrs[p]||w!==y||w&&this.screen.cursor.style!==this.drawnCursor[2]||w&&this.screen.cursor.hanging!==this.drawnCursor[3],P=68&C;f.has(P)||f.set(P,[]),f.get(P).push({cell:p,x:m,y:g,text:_,fg:k,bg:x,attrs:C,isCursor:w,inSelection:b}),v.set(p,E)}var L=new Map,A=function(e){return" "!==e&&n.measureText(e).width>=h+.05},F=!0,O=!1,R=void 0;try{for(var D,M=v.keys()[Symbol.iterator]();!(F=(D=M.next()).done);F=!0){var B=D.value;!function(e){var n=v.get(e)||L.get(e)||!1,i=t.screen.screen[e],r=A(i),o=r?2:1;if(!n){var s=!1,a=!0,l=!1,c=void 0;try{for(var h,u=t.getAdjacentCells(e,o)[Symbol.iterator]();!(a=(h=u.next()).done);a=!0){var d=h.value;if(v.get(d)&&(t.screen.window.graphics<2||r||A(t.screen.screen[d]))){s=!0;break}}}catch(e){l=!0,c=e}finally{try{!a&&u.return&&u.return()}finally{if(l)throw c}}s&&(n=!0)}L.set(e,n)}(B)}}catch(e){O=!0,R=e}finally{try{!F&&M.return&&M.return()}finally{if(O)throw R}}if(this.screen.window.graphics>=1){var N=this.screen.window.debug&&this.screen._debug,I=Math.round(this.screen._padding);n.save(),n.beginPath();for(var H=0;H<o;H++){for(var j=null,z=0;z<r;z++){var W=H*r+z,q=L.get(W);q&&null===j&&(j=z),q||null===j||(n.rect(I+j*h,I+H*u,(z-j)*h,u),N&&this.screen._debug.clipRect(j*h,H*u,(z-j)*h,u),j=null)}null!==j&&(n.rect(I+j*h,I+H*u,(r-j)*h,u),N&&this.screen._debug.clipRect(j*h,H*u,(r-j)*h,u))}n.clip()}var G=!0,U=!1,X=void 0;try{for(var K,Y=f.keys()[Symbol.iterator]();!(G=(K=Y.next()).done);G=!0){var $=K.value,J=!0,V=!1,Q=void 0;try{for(var Z,ee=f.get($)[Symbol.iterator]();!(J=(Z=ee.next()).done);J=!0){var te=Z.value,ne=te.cell,ie=te.x,re=te.y,oe=te.text,se=te.bg;if(L.get(ne)&&(this.drawBackground({x:ie,y:re,cellWidth:h,cellHeight:u,bg:se}),this.screen.window.debug&&this.screen._debug)){var ae=+L.get(ne);ae|=+v.get(ne)<<1,ae|=+A(oe)<<2,this.screen._debug.setCell(ne,ae)}}}catch(e){V=!0,Q=e}finally{try{!J&&ee.return&&ee.return()}finally{if(V)throw Q}}}}catch(e){U=!0,X=e}finally{try{!G&&Y.return&&Y.return()}finally{if(U)throw X}}this.drawnCursor=[-1,-1,-1];var le=!0,ce=!1,he=void 0;try{for(var ue,de=f.keys()[Symbol.iterator]();!(le=(ue=de.next()).done);le=!0){var fe=ue.value,ve={};4&fe&&(ve.weight="bold"),64&fe&&(ve.style="italic"),n.font=this.screen.getFont(ve);var pe=!0,me=!1,ge=void 0;try{for(var we,ye=f.get(fe)[Symbol.iterator]();!(pe=(we=ye.next()).done);pe=!0){var be=we.value,_e=be.cell,ke=be.x,xe=be.y,Ce=be.text,Se=be.fg,Te=be.bg,Ee=be.attrs,Pe=be.isCursor,Le=be.inSelection;if(L.get(_e)&&(this.drawCharacter({x:ke,y:xe,charSize:l,cellWidth:h,cellHeight:u,text:Ce,fg:Se,attrs:Ee}),this.drawnScreen[_e]=Ce,this.drawnScreenFG[_e]=Se,this.drawnScreenBG[_e]=Te,this.drawnScreenAttrs[_e]=Ee,Pe&&(this.drawnCursor=[ke,xe,this.screen.cursor.style,this.screen.cursor.hanging]),Pe&&!Le)){n.save(),n.beginPath();var Ae=ke,Fe=xe;this.screen.cursor.hanging&&(Ae+=1);var Oe=Ae*h+this.screen._padding,Re=Fe*u+this.screen._padding;if("block"===this.screen.cursor.style)n.rect(Oe,Re,h,u);else if("bar"===this.screen.cursor.style){n.rect(Oe,Re,2,u)}else if("line"===this.screen.cursor.style){n.rect(Oe,Re+l.height,h,2)}n.clip();var De=[Te,Se];Se=De[0],Te=De[1],Se===Te&&(Te=0===Se?7:0),this.drawBackground({x:Ae,y:Fe,cellWidth:h,cellHeight:u,bg:Te}),this.drawCharacter({x:Ae,y:Fe,charSize:l,cellWidth:h,cellHeight:u,text:Ce,fg:Se,attrs:Ee}),n.restore()}}}catch(e){me=!0,ge=e}finally{try{!pe&&ye.return&&ye.return()}finally{if(me)throw ge}}}}catch(e){ce=!0,he=e}finally{try{!le&&de.return&&de.return()}finally{if(ce)throw he}}this.screen.window.graphics>=1&&n.restore(),this.screen.window.debug&&this.screen._debug&&this.screen._debug.drawEnd(),this.screen.emit("draw",e)}},{key:"drawStatus",value:function(e){var t=this.ctx,n=this.screen.window,i=n.fontFamily,r=n.width,o=n.height,s=n.devicePixelRatio;this.drawnScreen=[];var a=this.screen.getCellSize(),l=r*a.width+2*this.screen._padding,c=o*a.height+2*this.screen._padding;if(t.setTransform(s,0,0,s,0,0),t.fillStyle=this.getColor(this.defaultBgNum),t.fillRect(0,0,l,c),t.font="24px "+i,t.fillStyle=this.getColor(this.defaultFgNum),t.textAlign="center",t.textBaseline="middle",t.fillText(e.title||"",l/2,c/2-50),e.loading){t.save(),t.translate(l/2,c/2+20),t.strokeStyle=this.getColor(this.defaultFgNum),t.lineWidth=5,t.lineCap="round";for(var h=Date.now()/1e3,u=0;u<12;u++){t.rotate(Math.PI/6);var d=(12*h-u)%12;t.globalAlpha=Math.max(.2,1-d/3),t.beginPath(),t.moveTo(0,15),t.lineTo(0,30),t.stroke()}t.restore()}}},{key:"startDrawLoop",value:function(){if(!this._drawTimerThread){var e=Math.random().toString(36);this._drawTimerThread=e,this.drawTimerLoop(e)}}},{key:"stopDrawLoop",value:function(){this._drawTimerThread=null}},{key:"drawTimerLoop",value:function(e){var t=this;e&&e===this._drawTimerThread&&(window.requestAnimationFrame(function(){return t.drawTimerLoop(e)}),this.draw("draw-loop"))}},{key:"palette",get:function(){return this._palette||s[0]},set:function(e){this._palette!==e&&(this._palette=e,this.resetDrawn(),this.scheduleDraw("palette"))}}],[{key:"alphaToFraktur",value:function(e){return e>="a"&&e<="z"?e=String.fromCodePoint(119997+e.charCodeAt(0)):e>="A"&&e<="Z"&&(e=h[e]||String.fromCodePoint(120003+e.charCodeAt(0))),e}}]),e}()},function(e,t,n){"use strict";function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function r(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function o(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}var s=function(){function e(e,t){for(var n=0;n<t.length;n++){var i=t[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(e,i.key,i)}}return function(t,n,i){return n&&e(t.prototype,n),i&&e(t,i),t}}(),a=n(4),l=n(1),c=void 0;try{c=n(6)}catch(e){}e.exports=function(e){function t(e){i(this,t);var n=r(this,(t.__proto__||Object.getPrototypeOf(t)).call(this));n.screen=e,n.ws=null,n.heartbeatTimeout=null,n.pingInterval=null,n.xoff=!1,n.autoXoffTimeout=null,n.reconnTimeout=null,n.forceClosing=!1;try{n.blobReader=new FileReader,n.blobReader.onload=function(e){n.onDecodedWSMessage(n.blobReader.result)},n.blobReader.onerror=function(e){console.error(e)}}catch(e){n.blobReader=null}return n.pageShown=!1,n.disconnectTimeout=null,document.addEventListener("visibilitychange",function(){!0===document.hidden?(console.info("Window lost focus, freeing socket"),n.disconnectTimeout=setTimeout(function(){n.closeSocket(),clearTimeout(n.heartbeatTimeout)},1e3)):(clearTimeout(n.disconnectTimeout),console.info("Window got focus, re-connecting"),n.init())},!1),n}return o(t,e),s(t,[{key:"onWSOpen",value:function(e){console.log("CONNECTED"),this.heartbeat(),this.send("i"),this.forceClosing=!1,this.emit("connect")}},{key:"onWSClose",value:function(e){var t=this;if(this.forceClosing)return void(this.forceClosing=!1);console.warn("SOCKET CLOSED, code "+e.code+". Reconnecting..."),e.code<1e3&&console.error("Bad code from socket!"),clearTimeout(this.reconnTimeout),this.reconnTimeout=setTimeout(function(){return t.init()},2e3),this.emit("disconnect",e.code)}},{key:"onDecodedWSMessage",value:function(e){var t=this;switch(e.charAt(0)){case".":console.log(e);break;case"-":this.xoff=!0,this.autoXoffTimeout=setTimeout(function(){t.xoff=!1},250);break;case"+":this.xoff=!1,clearTimeout(this.autoXoffTimeout);break;default:this.screen.load(e),this.pageShown||(window.showPage(),this.pageShown=!0)}this.heartbeat()}},{key:"onWSMessage",value:function(e){var t=this;if("string"==typeof e.data)this.onDecodedWSMessage(e.data);else{if(!this.blobReader)return void console.error("No FileReader!");1!==this.blobReader.readyState?this.blobReader.readAsText(e.data):setTimeout(function(){t.onWSMessage(e)},1)}}},{key:"canSend",value:function(){return!this.xoff}},{key:"send",value:function(e){return window._demo?(void 0!==window.demoInterface?c.input(e):console.log("TX: "+JSON.stringify(e)),!0):this.xoff?(console.log("Can't send, flood control."),!1):!!this.ws&&(1!==this.ws.readyState?(console.error("Socket not ready"),!1):("string"!=typeof e&&(e=JSON.stringify(e)),this.ws.send(e),!0))}},{key:"closeSocket",value:function(){this.ws&&(this.forceClosing=!0,1===this.ws.readyState&&this.ws.close(),this.ws=null)}},{key:"init",value:function(){var e=this;if(window._demo)return void(void 0===window.demoInterface?window.alert("Demoing non-demo build!"):c.init(this.screen));clearTimeout(this.reconnTimeout),clearTimeout(this.heartbeatTimeout),this.closeSocket(),this.ws=new window.WebSocket("ws://"+window._root+"/term/update.ws"),this.ws.addEventListener("open",function(){return e.onWSOpen.apply(e,arguments)}),this.ws.addEventListener("close",function(){return e.onWSClose.apply(e,arguments)}),this.ws.addEventListener("message",function(){return e.onWSMessage.apply(e,arguments)}),console.log("Opening socket."),this.heartbeat(),this.emit("open")}},{key:"heartbeat",value:function(){var e=this;clearTimeout(this.heartbeatTimeout),this.heartbeatTimeout=setTimeout(function(){return e.onHeartbeatFail()},3e3)}},{key:"sendPing",value:function(){var e=this;console.log("> ping"),this.emit("ping"),l.get("http://"+window._root+"/api/v1/ping",function(t,n){200===n?(clearInterval(e.pingInterval),console.info("Server ready, opening socket…"),e.emit("ping-success"),e.init()):e.emit("ping-fail",n)},{timeout:100,loader:!1})}},{key:"onHeartbeatFail",value:function(){var e=this;this.closeSocket(),this.emit("silence"),console.error("Heartbeat lost, probing server..."),clearInterval(this.pingInterval),this.pingInterval=setInterval(function(){e.sendPing()},1e3),setTimeout(function(){e.sendPing()},200)}}]),t}(a)},function(e,t,n){"use strict";var i=(n(1),n(0)),r=i.encode2B;e.exports=function(e,t){function n(t){return e.send("s"+t)}function i(t){e.send("b"+String.fromCharCode(t+1))}function o(e){var i=e.allFn;window.addEventListener("keypress",function(e){if(b()&&!e.ctrlKey&&!e.metaKey){var t="";e.key&&1===e.key.length?t=e.key:e.which&&229!==e.which&&(t=String.fromCodePoint(e.which)),t.length>0&&t.charCodeAt(0)>=32&&(32===e.which&&e.preventDefault(),n(t))}}),window.addEventListener("keydown",x),window.addEventListener("copy",function(e){if(b()){var n=t.getSelectedText();n&&(e.preventDefault(),e.clipboardData.setData("text/plain",n))}}),window.addEventListener("paste",function(e){if(b()){e.preventDefault();var i=e.clipboardData.getData("text/plain");i.includes("\n")||i.length>90?(l.termUpload||console.error("input.termUpload is undefined"),l.termUpload.setContent(i),l.termUpload.open()):(t.bracketedPaste&&(i="[200~"+i+"[201~"),n(i))}}),v.all_fn=i}function s(e){o(e),window.addEventListener("mousedown",function(e){0===e.button&&(C=1),1===e.button&&(S=1),2===e.button&&(T=1)}),window.addEventListener("mouseup",function(e){0===e.button&&(C=0),1===e.button&&(S=0),2===e.button&&(T=0)})}function a(){return E}for(var l=void 0,c={3:"Cancel",6:"Help",8:"Backspace",9:"Tab",12:"Clear",13:"Enter",16:"Shift",17:"Control",18:"Alt",19:"Pause",20:"CapsLock",27:"Escape",32:" ",33:"PageUp",34:"PageDown",35:"End",36:"Home",37:"ArrowLeft",38:"ArrowUp",39:"ArrowRight",40:"ArrowDown",41:"Select",42:"Print",43:"Execute",44:"PrintScreen",45:"Insert",46:"Delete",58:":",59:";",60:"<",61:"=",62:">",63:"?",64:"@",91:"Meta",92:"Meta",93:"ContextMenu",106:"Numpad*",107:"Numpad+",109:"Numpad-",110:"Numpad.",111:"Numpad/",144:"NumLock",145:"ScrollLock",160:"^",161:"!",162:'"',163:"#",164:"$",165:"%",166:"&",167:"_",168:"(",169:")",170:"*",171:"+",172:"|",173:"-",174:"{",175:"}",176:"~",186:";",187:"=",188:"Numpad,",189:"-",190:"Numpad,",192:"`",194:"Numpad,",219:"[",220:"\\",221:"]",222:"'",224:"Meta"},h=48;h<=57;h++)c[h]=String.fromCharCode(h);for(var u=65;u<=90;u++)c[u]=String.fromCharCode(u);for(var d=112;d<=131;d++)c[d]="F"+(d-112+1);for(var f=96;f<=105;f++)c[f]="Numpad"+(f-96);for(var v={np_alt:!1,cu_alt:!1,fn_alt:!1,mt_click:!1,mt_move:!1,no_keys:!1,crlf_mode:!1,all_fn:!1},p=function(e,t){return v.fn_alt?e:t},m=function(e,t){return v.cu_alt?e:t},g=function(e,t){return v.np_alt?e:t},w={Backspace:"\b",Tab:"\t",Enter:function(){return v.crlf_mode?"\r\n":"\r"},"Control+Enter":"\n",Escape:"",ArrowUp:function(){return m("OA","")},ArrowDown:function(){return m("OB","")},ArrowRight:function(){return m("OC","")},ArrowLeft:function(){return m("OD","")},Home:function(){return m("OH",p("","[1~"))},Insert:"[2~",Delete:"[3~",End:function(){return m("OF",p("","[4~"))},PageUp:"[5~",PageDown:"[6~",F1:function(){return p("OP","[11~")},F2:function(){return p("OQ","[12~")},F3:function(){return p("OR","[13~")},F4:function(){return p("OS","[14~")},F5:"[15~",F6:"[17~",F7:"[18~",F8:"[19~",F9:"[20~",F10:"[21~",F11:"[23~",F12:"[24~","Shift+F1":function(){return p("O1;2P","[25~")},"Shift+F2":function(){return p("O1;2Q","[26~")},"Shift+F3":function(){return p("O1;2R","[28~")},"Shift+F4":function(){return p("O1;2S","[29~")},"Shift+F5":function(){return p("[15;2~","[31~")},"Shift+F6":function(){return p("[17;2~","[32~")},"Shift+F7":function(){return p("[18;2~","[33~")},"Shift+F8":function(){return p("[19;2~","[34~")},"Shift+F9":function(){return p("[20;2~","[35~")},"Shift+F10":function(){return p("[21;2~","[36~")},"Shift+F11":function(){return p("[22;2~","[37~")},"Shift+F12":function(){return p("[23;2~","[38~")},Numpad0:function(){return g("Op","0")},Numpad1:function(){return g("Oq","1")},Numpad2:function(){return g("Or","2")},Numpad3:function(){return g("Os","3")},Numpad4:function(){return g("Ot","4")},Numpad5:function(){return g("Ou","5")},Numpad6:function(){return g("Ov","6")},Numpad7:function(){return g("Ow","7")},Numpad8:function(){return g("Ox","8")},Numpad9:function(){return g("Oy","9")},"Numpad*":function(){return g("OR","*")},"Numpad+":function(){return g("Ol","+")},"Numpad-":function(){return g("OS","-")},"Numpad.":function(){return g("On",".")},"Numpad/":function(){return g("OQ","/")},"Control+]":"","Control+\\":"","Control+[":"","Control+^":"","Control+_":"","Control+ArrowLeft":"[1;5D","Control+ArrowRight":"[1;5C","Control+ArrowUp":"[1;5A","Control+ArrowDown":"[1;5B","Control+Home":"[1;5H","Control+End":"[1;5F","Shift+ArrowLeft":"[1;2D","Shift+ArrowRight":"[1;2C","Shift+ArrowUp":"[1;2A","Shift+ArrowDown":"[1;2B","Shift+Home":"[1;2H","Shift+End":"[1;2F","Alt+ArrowLeft":"b","Alt+ArrowRight":"f","Meta+ArrowLeft":"","Meta+ArrowRight":"","Alt+Backspace":"","Meta+Backspace":"","Control+Shift+C":function(){t.copySelectionToClipboard()},"Control+Insert":function(){t.copySelectionToClipboard()},"Control+F12":function(){t.window.debug^=1}},y=1;y<=26;y++)w["Control+"+String.fromCharCode(64+y)]=String.fromCharCode(y);var b=function(){return!v.no_keys&&!(document.activeElement instanceof window.HTMLTextAreaElement)},_=["F5","F11","F12","Shift+F5"],k={alt:!1,ctrl:!1,meta:!1,shift:!1},x=function(e){if(b()){var t=[];(e.altKey||k.alt)&&t.push("Alt"),(e.ctrlKey||k.ctrl)&&t.push("Control"),(e.metaKey||k.meta)&&t.push("Meta"),(e.shiftKey||k.shift)&&t.push("Shift");var i=c[e.which]||e.key;if(!e.ctrlKey&&!e.metaKey||"V"!==i){var r=null;for(var o in w){var s=o.split("+");if(s.pop()===i&&s.sort().join()===t.join()){if(_.includes(o)&&!v.all_fn)continue;r=w[o];break}}r&&(r instanceof Function&&(r=r()),e.preventDefault(),"string"==typeof r&&n(r))}}},C=0,S=0,T=0,E=0;return window.addEventListener("keydown",function(e){e.ctrlKey&&(E|=1),e.shiftKey&&(E|=2),e.altKey&&(E|=4),e.metaKey&&(E|=8)}),window.addEventListener("keyup",function(e){E=0,e.ctrlKey&&(E|=1),e.shiftKey&&(E|=2),e.altKey&&(E|=4),e.metaKey&&(E|=8)}),l={init:s,sendString:n,sendButton:i,setAlts:function(e,t,n,i){v.cu_alt===e&&v.np_alt===t&&v.fn_alt===n&&v.crlf_mode===i||(v.cu_alt=e,v.np_alt=t,v.fn_alt=n,v.crlf_mode=i)},setMouseMode:function(e,t){v.mt_click=e,v.mt_move=t},onMouseMove:function(t,n){if(v.mt_move){var i=C?1:S?2:T?3:0,o=a();e.send("m"+r(n)+r(t)+r(i)+r(o))}},onMouseDown:function(t,n,i){if(v.mt_click&&!(i>3||i<1)){var o=a();e.send("p"+r(n)+r(t)+r(i)+r(o))}},onMouseUp:function(t,n,i){if(v.mt_click&&!(i>3||i<1)){var o=a();e.send("r"+r(n)+r(t)+r(i)+r(o))}},onMouseWheel:function(t,n,i){if(v.mt_click){var o=a(),s=i<0?4:5;e.send("p"+r(n)+r(t)+r(s)+r(o))}},blockKeys:function(e){v.no_keys=e},handleKeyDown:x,softModifiers:k}}},function(e,t,n){"use strict";var i=n(1),r=n(0),o=r.qs,s=n(2);e.exports=function(e,t,n){function r(){l("Ready..."),s.show("#fu_modal",a),i("#fu_form").toggleClass("busy",!1),t.blockKeys(!0)}function a(){console.log("Upload modal closed."),clearTimeout(p),v=0,t.blockKeys(!1)}function l(e){o("#fu_prog").textContent=e}function c(){var e=o("#fu_text").value;if(!e.length)return void d();f=e.split("\n"),v=0,y=0,m=+o("#fu_delay").value,m<0&&(m=0,o("#fu_delay").value=m),g={CR:"\r",LF:"\n",CRLF:"\r\n"}[o("#fu_crlf").value],i("#fu_form").toggleClass("busy",!0),l("Starting..."),h()}function h(){if(i("#fu_modal").hasClass("visible")){if(!e.canSend())return void(p=setTimeout(h,1));0===y&&(w="",0===v&&n.bracketedPaste&&(w="[200~"),w+=f[v++]+g,v===f.length&&n.bracketedPaste&&(w+="[201~"));var r=+o("#fu_chunk").value;(0===r||r>b)&&(r=b);var s=void 0;if(w.length-y<=r?(s=w.substr(y,r),y=0):(s=w.substr(y,r),y+=r),!t.sendString(s))return void l("FAILED!");var a=Math.round(v/f.length*1e3)/10;l(v+" / "+f.length+" ("+a+"%)"),f.length>v||y>0?p=setTimeout(h,m):u()}}function u(){e.canSend()?(l("Done."),d()):(l("Waiting for Tx buffer..."),setTimeout(u,100))}function d(){s.hide("#fu_modal")}var f=void 0,v=void 0,p=void 0,m=void 0,g=void 0,w=void 0,y=void 0,b=128;return{init:function(){o("#fu_file").addEventListener("change",function(e){var t=new window.FileReader,n=e.target.files[0],i=n.type||"application/octet-stream";if(console.log("Selected file type: "+i),!i.match(/text\/.*|application\/(json|csv|.*xml.*|.*script.*|x-php)/)&&!window.confirm("This does not look like a text file: "+i+"\nReally load?"))return void(o("#fu_file").value="");t.onload=function(e){var t=e.target.result.replace(/[\r\n]+/,"\n");o("#fu_text").value=t},console.log("Loading file..."),t.readAsText(n)},!1),o("#term-fu-open").addEventListener("click",function(e){e.preventDefault(),r()}),o("#term-fu-start").addEventListener("click",function(e){e.preventDefault(),c()}),o("#term-fu-close").addEventListener("click",function(e){e.preventDefault(),d()})},open:r,setContent:function(e){o("#fu_text").value=e}}}},function(e,t,n){"use strict";var i=function(){function e(e,t){var n=[],i=!0,r=!1,o=void 0;try{for(var s,a=e[Symbol.iterator]();!(i=(s=a.next()).done)&&(n.push(s.value),!t||n.length!==t);i=!0);}catch(e){r=!0,o=e}finally{try{!i&&a.return&&a.return()}finally{if(r)throw o}}return n}return function(t,n){if(Array.isArray(t))return t;if(Symbol.iterator in Object(t))return e(t,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),r=n(0),o=r.qs;e.exports=function(e,t){var n=o("#softkb-input");if(n){var r=document.createElement("div");r.id="keyboard-shortcut-bar",navigator.userAgent.match(/iPad|iPhone|iPod/)&&o("#screen").appendChild(r);var s=!1,a=function(){if(s){var t=e.gridToScreen(e.cursor.x,e.cursor.y,!0),r=i(t,2),o=r[0],a=r[1];n.style.transform="translate("+o+"px, "+a+"px)"}};n.addEventListener("focus",function(){s=!0,a(),r.classList.add("open")}),n.addEventListener("blur",function(){s=!1,r.classList.remove("open")}),e.on("cursor-moved",a),o("#term-kb-open").addEventListener("click",function(e){e.preventDefault(),n.focus()});var l="",c=function(e){null===e&&(e="");var n=!1;e.length>l.length?e.startsWith(l)?t.sendString(e.substr(l.length)):n=!0:e.length<l.length?l.startsWith(e)?t.sendString("\b".repeat(l.length-e.length)):n=!0:e!==l&&(n=!0),n&&t.sendString("\b".repeat(l.length)+e),l=e};n.addEventListener("keydown",function(e){"Unidentified"!==e.key&&(n.value="",e.stopPropagation(),t.handleKeyDown(e))}),n.addEventListener("keypress",function(e){e.stopPropagation()}),n.addEventListener("input",function(e){e.stopPropagation(),e.isComposing&&"data"in e?c(e.data):e.isComposing?c(n.value):"insertCompositionText"===e.inputType?t.sendString(e.data):"deleteContentBackward"===e.inputType?(l="",c("")):"insertText"===e.inputType&&t.sendString(e.data)}),n.addEventListener("compositionstart",function(e){l=""}),n.addEventListener("compositionend",function(e){l="",n.value=""}),e.on("open-soft-keyboard",function(){return n.focus()});var h={Control:"ctrl",Esc:27,Tab:9,"←":37,"↓":40,"↑":38,"→":39},u=!1;for(var d in h)!function(e){var n=document.createElement("button");n.classList.add("shortcut-button"),n.textContent=e,r.appendChild(n);var i=h[e];"string"==typeof i&&n.classList.add("modifier"),n.addEventListener("touchstart",function(e){u=!1,"string"==typeof i&&(t.softModifiers[i]=!0,n.classList.add("enabled"),e.preventDefault())}),window.addEventListener("touchmove",function(e){u=!0}),n.addEventListener("touchend",function(e){if(e.preventDefault(),"number"==typeof i){if(u)return;var r={which:i,preventDefault:function(){}};t.handleKeyDown(r)}else"string"==typeof i&&(n.classList.remove("enabled"),t.softModifiers[i]=!1)})}(d)}}},function(e,t,n){"use strict";function i(e){if(Array.isArray(e)){for(var t=0,n=Array(e.length);t<e.length;t++)n[t]=e[t];return n}return Array.from(e)}var r=function(){function e(e,t){var n=[],i=!0,r=!1,o=void 0;try{for(var s,a=e[Symbol.iterator]();!(i=(s=a.next()).done)&&(n.push(s.value),!t||n.length!==t);i=!0);}catch(e){r=!0,o=e}finally{try{!i&&a.return&&a.return()}finally{if(r)throw o}}return n}return function(t,n){if(Array.isArray(t))return t;if(Symbol.iterator in Object(t))return e(t,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),o=n(0),s=o.mk;e.exports=function(e){var t=s("canvas"),n=t.getContext("2d");t.classList.add("debug-canvas");var o=null,a=void 0,l=function(t){o=e.screenToGrid(t.offsetX,t.offsetY),b(),a()},c=function(){return o=null},h=function(){t.parentNode||(e.canvas.parentNode.appendChild(t),e.canvas.addEventListener("mousemove",l),e.canvas.addEventListener("mouseout",c))},u=function(){t.parentNode&&(t.parentNode.removeChild(t),e.canvas.removeEventListener("mousemove",l),e.canvas.removeEventListener("mouseout",c),c())},d=function(){var n=e.window,i=n.width,r=n.height,o=n.devicePixelRatio,s=e.getCellSize();t.width=i*s.width*o,t.height=r*s.height*o,t.style.width=i*s.width+"px",t.style.height=r*s.height+"px"},f=s("div");f.classList.add("draw-info");var v=void 0,p=void 0,m=void 0,g=new Map,w=[],y=[],b=void 0;e._debug={drawStart:function(e){m=e,v=Date.now(),w=[]},drawEnd:function(){p=Date.now(),console.log(f.textContent="Draw: "+m+" ("+(p-v)+" ms) with graphics="+e.window.graphics),b()},setCell:function(e,t){g.set(e,[t,Date.now()])},clipRect:function(){for(var e=arguments.length,t=Array(e),n=0;n<e;n++)t[n]=arguments[n];w.push(t)},pushFrame:function(e){e.push(Date.now()),y.push(e),b()}};var _=void 0,k=document.createElement("canvas");k.width=k.height=12;var x=k.getContext("2d");x.lineWidth=1,x.strokeStyle="#00f",x.beginPath(),x.moveTo(0,0),x.lineTo(-4,12),x.moveTo(4,0),x.lineTo(0,12),x.moveTo(8,0),x.lineTo(4,12),x.moveTo(12,0),x.lineTo(8,12),x.moveTo(16,0),x.lineTo(12,12),x.stroke(),_=n.createPattern(k,"repeat");var C=!1,S=0,T=0,E=function t(){C&&window.requestAnimationFrame(t);var s=(Date.now()-S)/1e3;S=Date.now(),T+=s;var a=e.window,l=a.devicePixelRatio,c=a.width,h=a.height,d=e.getCellSize(),f=d.width,v=d.height,p=c*h,m=Date.now();n.setTransform(l,0,0,l,0,0),n.clearRect(0,0,c*f,h*v);for(var b=0,k=0;k<p;k++)if(g.has(k)&&0!==g.get(k)[0]){var x=g.get(k),E=r(x,2),P=E[0],L=E[1],A=(m-L)/1e3;if(!(A>1)){b++,n.globalAlpha=.5*Math.max(0,1-A);var F=k%c,O=Math.floor(k/c);1&P&&(n.fillStyle="#f0f"),2&P&&(n.fillStyle="#0f0"),n.fillRect(F*f,O*v,f,v),4&P&&(n.lineWidth=2,n.strokeStyle="#f00",n.strokeRect(F*f,O*v,f,v))}}if(w.length){n.globalAlpha=.5,n.beginPath();var R=!0,D=!1,M=void 0;try{for(var B,N=w[Symbol.iterator]();!(R=(B=N.next()).done);R=!0){var I=B.value;n.rect.apply(n,i(I))}}catch(e){D=!0,M=e}finally{try{!R&&N.return&&N.return()}finally{if(D)throw M}}n.fillStyle=_,n.fill()}var H=!1;if(y.length){var j=[],z=!0,W=!1,q=void 0;try{for(var G,U=y[Symbol.iterator]();!(z=(G=U.next()).done);z=!0){var X=G.value,K=X[4],Y=Date.now()-K;Y>1e3?j.push(X):(H=!0,n.globalAlpha=1-Y/1e3,n.strokeStyle="#ff0",n.lineWidth=2,n.strokeRect(X[0]*f,X[1]*v,X[2]*f,X[3]*v))}}catch(e){W=!0,q=e}finally{try{!z&&U.return&&U.return()}finally{if(W)throw q}}var $=!0,J=!1,V=void 0;try{for(var Q,Z=j[Symbol.iterator]();!($=(Q=Z.next()).done);$=!0){var ee=Q.value;y.splice(y.indexOf(ee),1)}}catch(e){J=!0,V=e}finally{try{!$&&Z.return&&Z.return()}finally{if(J)throw V}}}o&&(n.save(),n.globalAlpha=1,n.lineWidth=1+.5*Math.sin(10*T),n.strokeStyle="#fff",n.lineJoin="round",n.setLineDash([2,2]),n.lineDashOffset=10*T,n.strokeRect(o[0]*f,o[1]*v,f,v),n.lineDashOffset+=2,n.strokeStyle="#000",n.strokeRect(o[0]*f,o[1]*v,f,v),n.restore()),0!==b||o||H||(C=!1,u())};b=function(){C||(h(),d(),C=!0,S=Date.now(),E())};var P=s("div");P.classList.add("debug-toolbar");var L=!1,A=s("div");A.classList.add("data-display"),P.appendChild(A);var F=s("div");F.classList.add("internal-display"),P.appendChild(F),P.appendChild(f);var O=s("div");O.classList.add("toolbar-buttons"),P.appendChild(O);var R=s("button");R.textContent="Redraw",R.addEventListener("click",function(t){e.renderer.resetDrawn(),e.renderer.draw("debug-redraw")}),O.appendChild(R);var D=s("button");D.textContent="Toggle Graphics",D.addEventListener("click",function(t){e.window.graphics=+!e.window.graphics}),O.appendChild(D);var M=function(){e.canvas.parentNode.appendChild(P)},B=function(){P.parentNode.removeChild(P)};e.on("update-window:debug",function(e){e!==L&&(L=e,e?M():(B(),u()))});var N=function(e){var t=e.toString(16);(1&e||2&e)&&(t+=":has(",1&e&&(t+="fg"),2&e&&(t+=(1&e?",":"")+"bg"),t+=")");var n=[];return 4&e&&n.push("\\[bold]bold\\()"),8&e&&n.push("\\[underline]underln\\()"),16&e&&n.push("\\[invert]invert\\()"),32&e&&n.push("blink"),64&e&&n.push("\\[italic]italic\\()"),128&e&&n.push("\\[strike]strike\\()"),256&e&&n.push("\\[overline]overln\\()"),512&e&&n.push("\\[faint]faint\\()"),1024&e&&n.push("fraktur"),n.length&&(t+=":"+n.join()),t.trim()},I=function(e){return e<256?e:"#"+("000000"+(e-256).toString(16)).substr(-6)},H=function(t){if(t<0||t>e.screen.length)return"(-)";var n=0|e.renderer.drawnScreenAttrs[t],i=0|e.renderer.drawnScreenFG[t],r=0|e.renderer.drawnScreenBG[t],o=I(i),s=I(r);o+="\\[color="+e.renderer.getColor(i).replace(/ /g,"")+"]●\\[]",s+="\\[color="+e.renderer.getColor(r).replace(/ /g,"")+"]●\\[]";var a=0|(e.renderer.drawnScreen[t]||"").codePointAt(0),l=a.toString(16).toUpperCase();l.length<4&&(l=("0000"+l).substr(-4)),l="U+"+l;var c=t%e.window.width;return"(("+Math.floor(t/e.window.width)+","+c+")="+t+":\\[bold]"+l+"\\[]:F"+o+":B"+s+":A("+N(n)+"))"},j=function(e,t){e.innerHTML="";for(var n=void 0,i={},r=function(t){var n=s("span");e.appendChild(n),n.textContent=t;for(var r in i)n[r]=i[r]};n=t.match(/\\\[(.*?)\]/);){n.index>0&&r(t.substr(0,n.index)),i={style:""};var o=n[1].split(" "),a=!0,l=!1,c=void 0;try{for(var h,u=o[Symbol.iterator]();!(a=(h=u.next()).done);a=!0){var d=h.value;if(d){var f=void 0,v=void 0;d.indexOf("=")>-1?(f=d.substr(0,d.indexOf("=")),v=d.substr(d.indexOf("=")+1)):(f=d,v=!0),"color"===f&&console.log(v),"bold"===f&&(i.style+="font-weight:bold;"),"italic"===f&&(i.style+="font-style:italic;"),"underline"===f&&(i.style+="text-decoration:underline;"),"invert"===f&&(i.style+="background:#000;filter:invert(1);"),"strike"===f&&(i.style+="text-decoration:line-through;"),"overline"===f&&(i.style+="text-decoration:overline;"),"faint"===f?i.style+="opacity:0.5;":"color"===f?i.style+="color:"+v+";":i[f]=v}}}catch(e){l=!0,c=e}finally{try{!a&&u.return&&u.return()}finally{if(l)throw c}}t=t.substr(n.index+n[0].length)}t&&r(t)},z={};a=function(){if(L){var t="C(("+e.cursor.y+","+e.cursor.x+"),hang:"+e.cursor.hanging+",vis:"+e.cursor.visible+")";if(o&&(t+=" m"+H(o[1]*e.window.width+o[0])),j(A,t),"flags"in z){var n=" ";n+=" flags:"+z.flags.toString(2),n+=" curAttrs:"+z.cursorAttrs.toString(2),n+=" Region:"+z.regionStart+"->"+z.regionEnd,n+=" Charset:"+z.charsetGx+" (0:"+z.charsetG0+",1:"+z.charsetG1+")",n+=" Heap:"+z.freeHeap,n+=" Clients:"+z.clientCount,j(F,n)}}},e.on("draw",a),e.on("internal",function(e){z=e,a()})}},function(e,t,n){"use strict";var i=n(0),r=i.qs;e.exports=function(e){var t=r("#action-buttons"),n=[],i=[],o=function(){var n=document.createElement("button");return n.classList.add("action-button"),n.setAttribute("data-n",i.length),i.push(n),t.appendChild(n),n.addEventListener("click",function(t){var i=+n.getAttribute("data-n");e.sendButton(i)}),n},s=function(){var e=i.pop();e.parentNode.removeChild(e)};return{update:function(){if(n.length>i.length)for(var e=i.length;e<n.length;e++)o();else if(i.length>n.length)for(var t=n.length;t<=i.length;t++)s();for(var r=0;r<n.length;r++){var a=n[r].trim(),l=i[r];l.textContent=a||" ",a?l.classList.remove("inactive"):l.classList.add("inactive")}},labels:n}}},function(e,t,n){"use strict";function i(){return+s("#theme").val()}function r(){var e=c(".color-example"),t=s("#default_fg").val(),n=s("#default_bg").val();/^\d+$/.test(t)?t=+t:/^#[\da-f]{6}$/i.test(t)||(t="black"),/^\d+$/.test(n)?n=+n:/^#[\da-f]{6}$/i.test(n)||(n="black");var r=i();e.dataset.fg=t,e.dataset.bg=n,a.themePreview(r),s(".colorprev.fg span").css("background",a.toHex(n,r))}var o=n(25),s=n(1),a=n(5),l=n(0),c=l.qs;t.init=function(){s("#theme").on("change",r),s("#default_fg").on("input",r),s("#default_bg").on("input",r);var e={padding:10,event:"drag",uppercase:!0,trianglePointerSize:20,size:200,parseColor:function(e){return a.toHex(e,i())}};o.initInput(c("#default_fg"),e),o.initInput(c("#default_bg"),e),s(".colorprev.bg span").on("click",function(){var e=this.dataset.bg;void 0!==e&&s("#default_bg").val(e),r()}),s(".colorprev.fg span").on("click",function(){var e=this.dataset.fg;void 0!==e&&s("#default_fg").val(e),r()});for(var t=s("#fgbg_presets"),n=0;n<a.fgbgThemes.length;n++){var l=a.fgbgThemes[n],h=l[0],u=l[1],d=l[2],f=l[3];t.htmlAppend('<span class="preset" data-xfg="'+h+'" data-xbg="'+u+'" style="color:'+h+";background:"+u+'" title="'+f+'">&nbsp;'+d+"&nbsp;</span>"),(n+1)%5==0&&t.htmlAppend("<br>")}s(".preset").on("click",function(){s("#default_fg").val(this.dataset.xfg),s("#default_bg").val(this.dataset.xbg),r()}),r()},t.nextTheme=function(){var e=c("#theme"),t=e.selectedIndex;e.options[++t%e.options.length].selected=!0,r()},t.prevTheme=function(){var e=c("#theme"),t=e.selectedIndex;e.options[(e.options.length+--t)%e.options.length].selected=!0,r()}},function(e,t,n){"use strict";function i(e){if(Array.isArray(e)){for(var t=0,n=Array(e.length);t<e.length;t++)n[t]=e[t];return n}return Array.from(e)}function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function s(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}function a(e,t){for(var n=0;n<e;n++)t(n)}function l(e,t){if(e.length)a(e.length,function(n){t(e[n],n)});else for(var n in e)e.hasOwnProperty(n)&&t(e[n],n)}var c=function(){function e(e,t){for(var n=0;n<t.length;n++){var i=t[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(e,i.key,i)}}return function(t,n,i){return n&&e(t.prototype,n),i&&e(t,i),t}}(),h=n(4),u=n(7),d=u.rgb2hex,f=u.hex2rgb,v=u.hsl2rgb,p=u.rgb2hsl,m=window,g=document,w=Math,y=2*w.PI;e.exports=function(e){function t(e,n){r(this,t);var i=o(this,(t.__proto__||Object.getPrototypeOf(t)).call(this));return i.options={size:150,padding:8,triangleSize:.8,wheelPointerColor1:"#444",wheelPointerColor2:"#eee",trianglePointerSize:16,trianglePointerColor1:"#eee",trianglePointerColor2:"#444",background:"transparent"},i.pixelRatio=window.devicePixelRatio,i.setOptions(n),i.calculateProperties(),i.createContainer(),i.createTriangle(),i.createWheel(),i.createWheelPointer(),i.createTrianglePointer(),i.attachEvents(),e=e||"#f00","string"==typeof e&&i.setHEX(e),i}return s(t,e),c(t,[{key:"calculateProperties",value:function(){var e=this.options;this.padding=e.padding,this.innerSize=e.size-2*e.padding,this.triangleSize=e.triangleSize*this.innerSize,this.wheelThickness=(this.innerSize-this.triangleSize)/2,this.wheelPointerSize=e.wheelPointerSize||this.wheelThickness,this.wheelRadius=this.innerSize/2,this.triangleRadius=this.triangleSize/2,this.triangleSideLength=w.sqrt(3)*this.triangleRadius}},{key:"calculatePositions",value:function(){var e=this.triangleRadius,t=this.hue,n=y/3,i=this.saturation,r=this.lightness,o=this.hx=w.cos(t)*e,s=this.hy=-w.sin(t)*e,a=this.sx=w.cos(t-n)*e,l=this.sy=-w.sin(t-n)*e,c=this.vx=w.cos(t+n)*e,h=this.vy=-w.sin(t+n)*e,u=(a+c)/2,d=(l+h)/2,f=(1-2*w.abs(r-.5))*i;this.x=a+(c-a)*r+(o-u)*f,this.y=l+(h-l)*r+(s-d)*f}},{key:"createContainer",value:function(){var e=this.container=g.createElement("div");e.className="color-triangle",e.style.display="block",e.style.padding=this.padding+"px",e.style.position="relative",e.style.boxShadow="0 1px 10px black",e.style.borderRadius="5px",e.style.width=e.style.height=this.innerSize+2*this.padding+"px",e.style.background=this.options.background}},{key:"createWheel",value:function(){var e=this.wheel=g.createElement("canvas");e.width=e.height=this.innerSize*this.pixelRatio,e.style.width=e.style.height=this.innerSize+"px",e.style.position="absolute",e.style.margin=e.style.padding="0",e.style.left=e.style.top=this.padding+"px",this.drawWheel(e.getContext("2d")),this.container.appendChild(e)}},{key:"drawWheel",value:function(e){var t=void 0,n=void 0;for(e.save(),e.setTransform(this.pixelRatio,0,0,this.pixelRatio,0,0),e.translate(this.wheelRadius,this.wheelRadius),t=this.wheelRadius-this.triangleRadius,n=0;n<360;n++)e.rotate(y/-360),e.beginPath(),e.fillStyle="hsl("+n+", 100%, 50%)",e.arc(this.wheelRadius-t/2,0,t/2,0,y,!0),e.fill();e.restore()}},{key:"createTriangle",value:function(){var e=this.triangle=g.createElement("canvas");e.width=e.height=this.innerSize*this.pixelRatio,e.style.width=e.style.height=this.innerSize+"px",e.style.position="absolute",e.style.margin=e.style.padding="0",e.style.left=e.style.top=this.padding+"px",this.triangleCtx=e.getContext("2d"),this.container.appendChild(e)}},{key:"drawTriangle",value:function(){var e=this.hx,t=this.hy,n=this.sx,i=this.sy,r=this.vx,o=this.vy,s=this.innerSize,a=this.triangleCtx;a.clearRect(0,0,s*this.pixelRatio,s*this.pixelRatio),a.save(),a.setTransform(this.pixelRatio,0,0,this.pixelRatio,0,0),a.translate(this.wheelRadius,this.wheelRadius),a.beginPath(),a.moveTo(e,t),a.lineTo(n,i),a.lineTo(r,o),a.closePath(),a.clip(),a.fillStyle="#000",a.fillRect(-this.wheelRadius,-this.wheelRadius,s,s);var l=a.createLinearGradient(e,t,(n+r)/2,(i+o)/2),c="hsla("+w.round(this.hue*(360/y))+", 100%, 50%, ";l.addColorStop(0,c+"1)"),l.addColorStop(1,c+"0)"),a.fillStyle=l,a.fillRect(-this.wheelRadius,-this.wheelRadius,s,s);var h=a.createLinearGradient(r,o,(e+n)/2,(t+i)/2);h.addColorStop(0,"#fff"),h.addColorStop(1,"rgba(255, 255, 255, 0)"),a.globalCompositeOperation="lighter",a.fillStyle=h,a.fillRect(-this.wheelRadius,-this.wheelRadius,s,s),a.restore()}},{key:"createWheelPointer",value:function(){var e=this.wheelPointer=g.createElement("canvas"),t=this.wheelPointerSize;e.width=e.height=t*this.pixelRatio,e.style.width=e.style.height=t+"px",e.style.position="absolute",e.style.margin=e.style.padding="0",this.drawPointer(e.getContext("2d"),t/2,this.options.wheelPointerColor1,this.options.wheelPointerColor2),this.container.appendChild(e)}},{key:"moveWheelPointer",value:function(){var e=this.wheelPointerSize/2,t=this.wheelPointer.style;t.top=this.padding+this.wheelRadius-w.sin(this.hue)*(this.triangleRadius+this.wheelThickness/2)-e+"px",t.left=this.padding+this.wheelRadius+w.cos(this.hue)*(this.triangleRadius+this.wheelThickness/2)-e+"px"}},{key:"createTrianglePointer",value:function(){var e=this.trianglePointer=g.createElement("canvas"),t=this.options.trianglePointerSize;e.width=e.height=t*this.pixelRatio,e.style.width=e.style.height=t+"px",e.style.position="absolute",e.style.margin=e.style.padding="0",this.drawPointer(e.getContext("2d"),t/2,this.options.trianglePointerColor1,this.options.trianglePointerColor2),this.container.appendChild(e)}},{key:"moveTrianglePointer",value:function(e,t){var n=this.trianglePointer.style,i=this.options.trianglePointerSize/2;n.top=this.y+this.wheelRadius+this.padding-i+"px",n.left=this.x+this.wheelRadius+this.padding-i+"px"}},{key:"drawPointer",value:function(e,t,n,i){e.setTransform(this.pixelRatio,0,0,this.pixelRatio,0,0),e.fillStyle=i,e.beginPath(),e.arc(t,t,t,0,y,!0),e.fill(),e.fillStyle=n,e.beginPath(),e.arc(t,t,t-2,0,y,!0),e.fill(),e.fillStyle=i,e.beginPath(),e.arc(t,t,t/4+2,0,y,!0),e.fill(),e.globalCompositeOperation="destination-out",e.beginPath(),e.arc(t,t,t/4,0,y,!0),e.fill()}},{key:"inject",value:function(e){e.appendChild(this.container)}},{key:"getRelativeCoordinates",value:function(e){var t=this.triangle,n=t.getBoundingClientRect();return{x:e.clientX-n.x,y:e.clientY-n.y}}},{key:"dispose",value:function(){var e=this.container.parentNode;e&&e.removeChild(this.container)}},{key:"getElement",value:function(){return this.container}},{key:"getCSS",value:function(){return"hsl("+Math.round(this.hue*(360/y))+", "+Math.round(100*this.saturation)+"%, "+Math.round(100*this.lightness)+"%)"}},{key:"getHEX",value:function(){return d.apply(void 0,i(this.getRGB()))}},{key:"setHEX",value:function(e){this.setRGB.apply(this,i(f(e)))}},{key:"getRGB",value:function(){return v.apply(void 0,i(this.getHSL()))}},{key:"setRGB",value:function(e,t,n){this.setHSL.apply(this,i(p(e,t,n)))}},{key:"getHSL",value:function(){return[this.hue,this.saturation,this.lightness]}},{key:"setHSL",value:function(e,t,n){this.hue=e,this.saturation=t,this.lightness=n,this.initColor()}},{key:"initColor",value:function(){this.calculatePositions(),this.moveWheelPointer(),this.drawTriangle(),this.moveTrianglePointer()}},{key:"attachEvents",value:function(){var e=this;this.down=null;var t=function(t){t.stopPropagation(),t.preventDefault(),g.body.addEventListener("mousemove",n,!1),g.body.addEventListener("mouseup",i,!1);var r=e.getRelativeCoordinates(t);e.map(r.x,r.y)},n=function(t){var n=e.getRelativeCoordinates(t);e.move(n.x,n.y)},i=function t(i){e.down&&(e.down=null,e.emit("dragend")),g.body.removeEventListener("mousemove",n,!1),g.body.removeEventListener("mouseup",t,!1)};this.container.addEventListener("mousedown",t,!1),this.container.addEventListener("mousemove",n,!1)}},{key:"map",value:function(e,t){var n=e,i=t;e-=this.wheelRadius,t-=this.wheelRadius;var r=w.sqrt(e*e+t*t);r>this.triangleRadius&&r<this.wheelRadius?(this.down="wheel",this.emit("dragstart"),this.move(n,i)):r<this.triangleRadius&&(this.down="triangle",this.emit("dragstart"),this.move(n,i))}},{key:"move",value:function(e,t){if(this.down){e-=this.wheelRadius,t-=this.wheelRadius;var n=w.atan2(-t,e);if(n<0&&(n+=y),"wheel"===this.down)this.hue=n,this.initColor(),this.emit("drag");else if("triangle"===this.down){var i=(n+y-this.hue)%y,r=i%(y/3)-y/6,o=.5*this.triangleRadius,s=w.tan(r)*o,a=w.sqrt(e*e+t*t),l=w.sqrt(o*o+s*s);if(a>l){var c=w.tan(r)*a,h=w.atan(c/l);h>y/6?h=y/6:h<-y/6&&(h=-y/6),n+=h-r,i=(n+y-this.hue)%y,r=i%(y/3)-y/6,s=w.tan(r)*o,a=l=w.sqrt(o*o+s*s)}e=w.round(w.cos(n)*a),t=w.round(-w.sin(n)*a);var u=this.lightness=w.sin(i)*a/this.triangleSideLength+.5,d=1-2*w.abs(u-.5),f=this.saturation=(w.cos(i)*a+this.triangleRadius/2)/(1.5*this.triangleRadius)/d;f=w.max(0,f),f=w.min(1,f),this.lightness=u,this.saturation=f,this.x=e,this.y=t,this.moveTrianglePointer(),this.emit("drag")}}}},{key:"setOptions",value:function(e){e=e||{};var t=this.options,n=this.options={};l(t,function(t,i){n[i]=e.hasOwnProperty(i)?e[i]:t})}}],[{key:"initInput",value:function(e,n){n=n||{};var i=void 0,r=function(){var r=e.value;n.parseColor&&(r=n.parseColor(r)),i?i.setHEX(r):(n.size=n.size||e.offsetWidth,n.background=m.getComputedStyle(e,null).backgroundColor,n.margin=n.margin||10,n.event=n.event||"dragend",i=new t(r,n),i.on(n.event,function(){var t=i.getHEX();e.value=n.uppercase?t.toUpperCase():t,s()}));var o=e.offsetTop;m.innerHeight-e.getBoundingClientRect().top>e.offsetHeight+n.margin+n.size?o+=e.offsetHeight+n.margin:o-=n.margin+n.size;var a=i.getElement();a.style.position="absolute",a.style.left=e.offsetLeft+"px",a.style.top=o+"px",a.style.zIndex="1338",i.inject(e.parentNode)},o=function(){i&&i.dispose()},s=function(){var t=g.createEvent("HTMLEvents");t.initEvent("input",!0,!1),e.dispatchEvent(t)};e.addEventListener("focus",r,!1),e.addEventListener("blur",o,!1),e.addEventListener("keyup",function(){e.value.match(/^#((?:[0-9A-Fa-f]{3})|(?:[0-9A-Fa-f]{6}))$/)?(r(),s()):o()},!1)}}]),t}(h)}]);
+//# sourceMappingURL=app.4a032ee-en.js.map
\ No newline at end of file
diff --git a/js/app.4a032ee-en.js.map b/js/app.4a032ee-en.js.map
new file mode 100644
index 0000000..9ce9ccc
--- /dev/null
+++ b/js/app.4a032ee-en.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["webpack:///app.4a032ee-en.js","webpack:///webpack/bootstrap 5f19c49887263bc447b9","webpack:///./js/utils.js","webpack:///./js/lib/chibi.js","webpack:///./js/modal.js","webpack:///./js/notif.js","webpack:///./node_modules/events/events.js","webpack:///./js/term/themes.js","webpack:///./js/term/demo.js","webpack:///./js/lib/color_utils.js","webpack:///./js/lang.js","webpack:///./js/index.js","webpack:///./js/lib/polyfills.js","webpack:///./js/appcommon.js","webpack:///./js/wifi.js","webpack:///./lang/en.php","webpack:///./js/term/index.js","webpack:///./js/term/screen.js","webpack:///./js/term/screen_parser.js","webpack:///./js/term/screen_renderer.js","webpack:///./js/term/connection.js","webpack:///./js/term/input.js","webpack:///./js/term/upload.js","webpack:///./js/term/soft_keyboard.js","webpack:///./js/term/debug_screen.js","webpack:///./js/term/buttons.js","webpack:///./js/term_conf.js","webpack:///./js/lib/colortriangle.js"],"names":["modules","__webpack_require__","moduleId","installedModules","exports","module","i","l","call","m","c","d","name","getter","o","Object","defineProperty","configurable","enumerable","get","n","__esModule","object","property","prototype","hasOwnProperty","p","s","mk","e","document","createElement","qs","querySelector","qsa","querySelectorAll","cr","hdl","which","parse2B","arguments","length","undefined","charCodeAt","parse3B","encode2B","lsb","msb","String","fromCharCode","encode3B","xsb","_typeof","Symbol","iterator","obj","constructor","fireReady","domready","readyfn","fireLoaded","pageloaded","loadedfn","nodeLoop","fn","nodes","cssCamel","replace","result","charAt","toUpperCase","computeStyle","elm","currentStyle","w","getComputedStyle","getPropertyValue","queryPair","value","encodeURIComponent","setCss","style","showCss","display","serializeData","subelm","j","querystring","Array","nodeName","elements","disabled","type","selected","checked","substring","classHelper","classes","action","classarray","has","split","clz","classList","remove","add","toggle","contains","insertHtml","position","tmpnodes","tmpnode","innerHTML","lastChild","parentNode","insertBefore","nextSibling","appendChild","firstChild","chibi","selector","cb","nodelist","json","nodeType","each","apply","first","shift","last","pop","odd","odds","push","even","evens","hide","show","state","removeChild","css","getClass","className","setClass","addClass","removeClass","toggleClass","set","hasClass","html","htmlBefore","htmlAfter","htmlAppend","htmlPrepend","attr","toLowerCase","cssText","setAttribute","getAttribute","data","key","val","values","check","on","event","addEventListener","attachEvent","off","removeEventListener","detachEvent","window","onload","ajax","options","opts","assign","method","nocache","timeout","loader","callback","loaderFn","_loader","url","query","indexOf","xhr","XMLHttpRequest","ts","Date","toString","open","abortTmeo","setTimeout","console","error","abort","onreadystatechange","readyState","responseText","status","clearTimeout","setRequestHeader","send","post","ready","loaded","entityMap","&","<",">","\"","'","/","`","=","htmlEscape","string","$","modal","curCloseCb","sel","closeCb","$m","init","this","stopImmediatePropagation","nt","$balloon","timerHideBegin","timerHideEnd","canCancel","stopTimeouts","message","isError","EventEmitter","_events","_maxListeners","isFunction","arg","isNumber","isObject","isUndefined","defaultMaxListeners","setMaxListeners","isNaN","TypeError","emit","er","handler","len","args","listeners","Error","err","context","slice","addListener","listener","newListener","warned","trace","once","g","removeListener","fired","list","splice","removeAllListeners","listenerCount","evlistener","emitter","_require","rgb255ToHex","themes","fgbgThemes","colorTable256","buildColorTable","fill","red","green","blue","redValue","greenValue","blueValue","gray","SELECTION_FG","SELECTION_BG","themePreview","themeN","forEach","elem","shade","dataset","fg","test","toHex","color","bg","backgroundColor","_toConsumableArray","arr","isArray","arr2","from","_possibleConstructorReturn","self","ReferenceError","_inherits","subClass","superClass","create","writable","setPrototypeOf","__proto__","_classCallCheck","instance","Constructor","_get","receiver","Function","desc","getOwnPropertyDescriptor","parent","getPrototypeOf","_createClass","defineProperties","target","props","descriptor","protoProps","staticProps","_require2","encodeAsCodePoint","fromCodePoint","ANSIParser","reset","joinChunks","currentSequence","sequence","content","numbers","map","numOr1","number","mode","r","b","text","_iteratorNormalCompletion","_didIteratorError","_iteratorError","_step","_iterator","next","done","character","code","codePointAt","match","parseSequence","return","TERM_DEFAULT_STYLE","getRainbowColor","t","Math","floor","sin","PI","ScrollingTerminal","screen","_this","width","height","termScreen","parser","handleParsed","buttonLabels","_lastLoad","now","loadTimer","showPage","cursor","x","y","visible","trackMouse","theme","rainbow","superRainbow","clear","scroll","newLine","max","moveBack","min","writeChar","deleteForward","insertBlanks","load","clampCursor","write","attributes","join","serialized","lastStyle","index","_iteratorNormalCompletion2","_didIteratorError2","_iteratorError2","_step2","_iterator2","cell","foreground","background","setForeground","setBackground","setAttributes","encodeColor","topicData","screenOpts","getScreenOpts","title","getTitle","buttons","getButtons","getCursor","serializeScreen","_screenOpts","_title","_buttons","_cursor","_screen","_this2","clearInterval","_loadTimer","setInterval","update","getUpdate","Process","_EventEmitter","demoData","mouseReceiver","demoshIndex","Clear","_Process","destroy","screenfetch","Screenfetch","_Process2","_this6","image","location","hostname","devicePixelRatio","filter","line","trim","chars","loop","substr","local-echo","_Process3","LocalEcho","_len","_key","includes","info","_Process4","Info","_this9","_len2","_key2","fast","showSplash","then","printText","_this10","splash","levels"," ",".","-","*","#","characters","repeat","cursorX","cursorY","moveTo","moveX","moveY","abs","drawCell","level","Promise","resolve","reject","cycles","dx","parts","colors","PrintColors","_Process5","ls","ListCommands","_Process6","SetTheme","shell","_this13","_Process7","maxnum","Number","isFinite","terminal","drawnScreenFG","ShowThemes","_Process8","hex","parseInt","col","SetCursor","_Process9","_len3","_key3","steady","ToggleRainbow","_this16","su","_Process10","_didWarnRainbow","mouse","ShowMouse","_this17","_Process11","label","randomData","highlighted","random","scrollOffset","render","lineData","button","sudo","Sudo","_this18","didDestroy","_Process12","_this19","_len4","_key4","child","setButtons","run","make","Make","_this20","_Process14","_len5","_key5","h","pwd","cd","whoami","navigator","userAgent","uname","mkdir","rm","cp","mv","ln","touch","exit","github","GoToGithub","_Process15","autocompleteIndex","DemoShell","printInfo","_this22","history","historyIndex","cursorPos","lastInputLength","prompt","success","unshift","current","visual","input","prefix","startsWith","newInput","copyFromHistoryIndex","completed","getCompleted","words","moveForward","rest","parse","command","inQuote","_iteratorNormalCompletion3","_didIteratorError3","_iteratorError3","_step3","_iterator3","spawn","_this23","_child","writeChars","demoInterface","onButtonPress","row","column","modifiers","mouseMove","mouseDown","mouseUp","didInit","pad","M","TAU","hue2rgb","v1","v2","hsl2rgb","var_1","var_2","rgb2hsl","d_r","d_g","d_b","hex2rgb","groups","bytes","pow","rgb2hex","round","termInit","TermConf","$defineProperty","stringFromCharCode","highSurrogate","lowSurrogate","codeUnits","codePoint","RangeError","pageShown","notify","menuOpen","inp","box","keyCode","ctrlKey","submit","$x","dots","$this","step","deltaY","evt","createEvent","initEvent","dispatchEvent","fireEvent","preventDefault","errAt","search","errs","decodeURIComponent","humanReadableErrors","lbls","lbl","childNodes","textContent","msgAt","msg","innerWidth","removeAttribute","br","href","vis","noAutoShow","bnr","id","tr","calc_dBm","toFixed","selectSta","password","ip","hasPassword","onScan","resp","rescan","JSON","log","inProgress","APs","$list","sort","a","rssi","ap","enc","item","$item","essid","curSSID","inner","escapedSSID","rssi_perc","authTypes","$th","conn_ssid","conn_pass","startScanning","scanAPs","_demo","_demo_aps","_root","time","wifiInit","cfg","disp1","disp2","sta_ssid","sta_password","sta_active_ip","sta_active_ssid","WiFi","wifi.connected_ip_is","wifi.not_conn","wifi.enter_passwd","term_nav.fullscreen","term_conn.connecting","term_conn.waiting_content","term_conn.disconnected","term_conn.waiting_server","term_conn.reconnecting","localize","Notify","TermScreen","TermConnection","TermInput","TermUpload","initSoftKeyboard","attachDebugScreen","initButtons","conn","termUpload","labels","_buttons$labels","concat","showSplashTimeout","delay","statusScreen","loading","screenFG","screenBG","screenAttrs","onerror","errorMsg","file","canvas","fullscreenIcon","isFullscreen","properFullscreen","fitScreen","screenPadding","padding","fitScreenIfNeeded","fitIntoWidth","fitIntoHeight","innerHeight","toggleFitScreen","resizeButtonIcon","Element","requestFullscreen","webkitRequestFullscreen","checkForFullscreen","body","updateSize","span","termUpl","ScreenParser","ScreenRenderer","ctx","getContext","renderer","_debug","audioCtx","AudioContext","webkitAudioContext","warn","Proxy","blinking","hanging","_window","fontFamily","fontSize","gridScaleX","gridScaleY","debug","graphics","_windowScale","_padding","windowState","selection","selectable","start","end","mouseMode","clicks","movement","scheduleSizeUpdate","scheduleDraw","bracketedPaste","blinkingCellCount","reverseVideo","selecting","selectStart","screenToGrid","selectMove","selectEnd","getNormalizedSelection","altKey","offsetX","offsetY","_this$input","onMouseDown","touchPosition","touchDownTime","touchDidMove","getTouchPositionOffset","rect","getBoundingClientRect","clientX","left","clientY","top","touches","passive","touchSelectMenu","selectionPos","gridToScreen","transform","copyButton","copySelectionToClipboard","_this$input2","onMouseMove","_this$input3","onMouseUp","aggregateWheelDelta","wheelDeltaY","_this$input4","onMouseWheel","_this$input5","_scheduledSizeUpdate","weight","rounded","cellSize","getCellSize","_this3","withScale","v","font","getFont","measureText","charSize","getCharSize","ceil","didChange","realWidth","realHeight","originalWidth","terminalAspect","resetDrawn","draw","_selection","_ref","_getNormalizedSelecti","colAfterStart","colBeforeEnd","onStartLine","onEndLine","screenLength","lines","previousLineIndex","isInSelection","selectedText","getSelectedText","textarea","select","execCommand","Notification","permission","focus","requestPermission","_lastBeep","_convolver","createConvolver","impulseLength","sampleRate","impulse","createBuffer","getChannelData","buffer","connect","destination","mainOsc","createOscillator","mainGain","createGain","gain","frequency","surrOsc","surrGain","startTime","currentTime","stop","requestAnimationFrame","_parser","du","str","num","contentLoaded","errmsg","ci","strArray","resized","topics","topic","newHeight","newWidth","defFg","defBg","loadTheme","setDefaultColors","setAlts","trackMouseClicks","trackMouseMovement","cursorShape","cursorStyle","cursorBlinking","resetCursorBlink","setMouseMode","showButtons","showConfigLinks","cursorMoved","count","beep","flags","cursorAttrs","regionStart","regionEnd","charsetGx","charsetG0","charsetG1","freeHeap","clientCount","frameY","frameX","frameHeight","frameWidth","pushFrame","attrs","lastChar","frameLength","pushCell","myAttrs","hasFG","hasBG","cellFG","cellBG","ATTR_UNDERLINE","cellXInFrame","cellYInFrame","charCode","hideLoadFailedMsg","loadUpdate","showNotification","stringify","frakturExceptions","C","H","I","R","Z","_palette","defaultBgNum","defaultFgNum","blinkStyleOn","blinkInterval","cursorBlinkOn","cursorBlinkInterval","resetBlink","drawnScreen","drawnScreenBG","drawnScreenAttrs","drawnCursor","palette","why","aggregateTime","_scheduledDraw","intervals","cellWidth","cellHeight","_screen$window","fillStyle","getColor","screenX","screenY","right","bottom","clearRect","fillRect","_ref2","underline","strike","overline","globalAlpha","alphaToFraktur","beginPath","cw","ch","c2w","c2h","offset","dotSpacingX","dotSpacingY","dotSize","alignRight","dy","dotSizeY","lineTo","strokeStyle","stroke","fillText","lineWidth","lineCap","lineY","radius","_screen$window2","cells","_this4","_screen$window3","drawStatus","startDrawLoop","stopDrawLoop","_screen$getCellSize","setTransform","drawStart","textAlign","textBaseline","fontGroups","Map","updateMap","isCursor","wasCursor","inSelection","_ref3","_ref4","didUpdate","ATTR_BOLD","redrawMap","isTextWide","keys","shouldUpdate","isWideCell","checkRadius","adjacentDidUpdate","getAdjacentCells","adjacentCell","save","redrawing","clipRect","clip","_iteratorNormalCompletion5","_didIteratorError5","_iteratorError5","_step5","_iterator5","drawBackground","setCell","_iteratorNormalCompletion4","_didIteratorError4","_iteratorError4","_step4","_iterator4","_iteratorNormalCompletion6","_didIteratorError6","_iteratorError6","_step6","_iterator6","drawCharacter","_ref5","restore","drawEnd","_screen$window4","screenWidth","screenHeight","translate","rotate","_drawTimerThread","threadID","drawTimerLoop","_this5","demo","ws","heartbeatTimeout","pingInterval","xoff","autoXoffTimeout","reconnTimeout","forceClosing","blobReader","FileReader","onDecodedWSMessage","disconnectTimeout","hidden","closeSocket","heartbeat","readAsText","onWSMessage","close","alert","WebSocket","onWSOpen","onWSClose","onHeartbeatFail","_this7","_this8","sendPing","sendString","sendButton","initKeys","allFn","shouldAcceptEvent","metaKey","handleKeyDown","clipboardData","setData","getData","setContent","all_fn","mb1","mb2","mb3","packModifiersForMouse","KEY_NAMES","3","6","8","9","12","13","16","17","18","19","20","27","32","33","34","35","36","37","38","39","40","41","42","43","44","45","46","58","59","60","61","62","63","64","91","92","93","106","107","109","110","111","144","145","160","161","162","163","164","165","166","167","168","169","170","171","172","173","174","175","176","186","187","188","189","190","192","194","219","220","221","222","224","np_alt","cu_alt","fn_alt","mt_click","mt_move","no_keys","crlf_mode","fa","alt","normal","ca","na","keymap","Backspace","Tab","Enter","Control+Enter","Escape","ArrowUp","ArrowDown","ArrowRight","ArrowLeft","Home","Insert","Delete","End","PageUp","PageDown","F1","F2","F3","F4","F5","F6","F7","F8","F9","F10","F11","F12","Shift+F1","Shift+F2","Shift+F3","Shift+F4","Shift+F5","Shift+F6","Shift+F7","Shift+F8","Shift+F9","Shift+F10","Shift+F11","Shift+F12","Numpad0","Numpad1","Numpad2","Numpad3","Numpad4","Numpad5","Numpad6","Numpad7","Numpad8","Numpad9","Numpad*","Numpad+","Numpad-","Numpad.","Numpad/","Control+]","Control+\\","Control+[","Control+^","Control+_","Control+ArrowLeft","Control+ArrowRight","Control+ArrowUp","Control+ArrowDown","Control+Home","Control+End","Shift+ArrowLeft","Shift+ArrowRight","Shift+ArrowUp","Shift+ArrowDown","Shift+Home","Shift+End","Alt+ArrowLeft","Alt+ArrowRight","Meta+ArrowLeft","Meta+ArrowRight","Alt+Backspace","Meta+Backspace","Control+Shift+C","Control+Insert","Control+F12","activeElement","HTMLTextAreaElement","keyBlacklist","softModifiers","ctrl","meta","shiftKey","binding","itemModifiers","cu","np","crlf","click","move","dir","blockKeys","yes","openUploadDialog","updateStatus","onDialogClose","fuTout","line_i","startUpload","fuClose","inline_pos","send_delay_ms","nl_str","CR","LF","CRLF","uploadLine","canSend","curLine","maxChunk","MAX_LINE_LEN","chunk","pt","closeWhenReady","reader","files","ftype","confirm","txt","_slicedToArray","sliceIterator","_arr","_n","_d","_e","_s","_i","keyInput","shortcutBar","keyboardOpen","updateInputPosition","_screen$gridToScreen","_screen$gridToScreen2","lastCompositionString","sendInputDelta","newValue","resend","stopPropagation","isComposing","inputType","shortcuts","Control","Esc","←","↓","↑","→","touchMoved","shortcut","fakeEvent","debugCanvas","mouseHoverCell","updateToolbar","startDrawing","onMouseOut","addCanvas","removeCanvas","updateCanvasSize","drawInfo","endTime","lastReason","clippedRects","updateFrames","reason","frame","clipPattern","patternCanvas","pctx","createPattern","isDrawing","lastDrawTime","drawLoop","dt","activeCells","_cells$get","_cells$get2","timestamp","elapsedTime","strokeRect","didDrawUpdateFrames","framesToDelete","elapsed","lineJoin","setLineDash","lineDashOffset","toolbar","toolbarAttached","dataDisplay","internalDisplay","redraw","fancyGraphics","attachToolbar","detachToolbar","displayCellAttrs","formatColor","getCellData","cellAttrs","fgText","bgText","cellCode","hexcode","setFormattedText","node","pushSpan","internalInfo","container","pushButton","popButton","selectedTheme","showColor","ex","ColorTriangle","uppercase","trianglePointerSize","size","parseColor","initInput","$presets","thm","tit","xfg","xbg","nextTheme","selectedIndex","prevTheme","times","win","doc","triangleSize","wheelPointerColor1","wheelPointerColor2","trianglePointerColor1","trianglePointerColor2","pixelRatio","setOptions","calculateProperties","createContainer","createTriangle","createWheel","createWheelPointer","createTrianglePointer","attachEvents","setHEX","innerSize","wheelThickness","wheelPointerSize","wheelRadius","triangleRadius","triangleSideLength","sqrt","hue","third","saturation","lightness","hx","cos","hy","sx","sy","vx","vy","mx","my","boxShadow","borderRadius","wheel","margin","drawWheel","arc","triangle","triangleCtx","closePath","grad0","createLinearGradient","hsla","addColorStop","grad1","globalCompositeOperation","wheelPointer","drawPointer","trianglePointer","color1","color2","getRGB","setRGB","getHSL","setHSL","initColor","calculatePositions","moveWheelPointer","drawTriangle","moveTrianglePointer","down","mousedown","mousemove","mouseup","xy","getRelativeCoordinates","x0","y0","rad","atan2","rad0","rad1","tan","maxR","rad2","atan","widthShare","dflt","ct","openColorTriangle","offsetWidth","getHEX","fireChangeEvent","offsetTop","offsetHeight","el","getElement","offsetLeft","zIndex","inject","closeColorTriangle","dispose"],"mappings":"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","file":"app.4a032ee-en.js","sourcesContent":["/******/ (function(modules) { // webpackBootstrap\n/******/ \t// The module cache\n/******/ \tvar installedModules = {};\n/******/\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n/******/\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(installedModules[moduleId]) {\n/******/ \t\t\treturn installedModules[moduleId].exports;\n/******/ \t\t}\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = installedModules[moduleId] = {\n/******/ \t\t\ti: moduleId,\n/******/ \t\t\tl: false,\n/******/ \t\t\texports: {}\n/******/ \t\t};\n/******/\n/******/ \t\t// Execute the module function\n/******/ \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n/******/\n/******/ \t\t// Flag the module as loaded\n/******/ \t\tmodule.l = true;\n/******/\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/\n/******/\n/******/ \t// expose the modules object (__webpack_modules__)\n/******/ \t__webpack_require__.m = modules;\n/******/\n/******/ \t// expose the module cache\n/******/ \t__webpack_require__.c = installedModules;\n/******/\n/******/ \t// define getter function for harmony exports\n/******/ \t__webpack_require__.d = function(exports, name, getter) {\n/******/ \t\tif(!__webpack_require__.o(exports, name)) {\n/******/ \t\t\tObject.defineProperty(exports, name, {\n/******/ \t\t\t\tconfigurable: false,\n/******/ \t\t\t\tenumerable: true,\n/******/ \t\t\t\tget: getter\n/******/ \t\t\t});\n/******/ \t\t}\n/******/ \t};\n/******/\n/******/ \t// getDefaultExport function for compatibility with non-harmony modules\n/******/ \t__webpack_require__.n = function(module) {\n/******/ \t\tvar getter = module && module.__esModule ?\n/******/ \t\t\tfunction getDefault() { return module['default']; } :\n/******/ \t\t\tfunction getModuleExports() { return module; };\n/******/ \t\t__webpack_require__.d(getter, 'a', getter);\n/******/ \t\treturn getter;\n/******/ \t};\n/******/\n/******/ \t// Object.prototype.hasOwnProperty.call\n/******/ \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n/******/\n/******/ \t// __webpack_public_path__\n/******/ \t__webpack_require__.p = \"\";\n/******/\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(__webpack_require__.s = 9);\n/******/ })\n/************************************************************************/\n/******/ ([\n/* 0 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\n/** Make a node */\nexports.mk = function mk(e) {\n  return document.createElement(e);\n};\n\n/** Find one by query */\nexports.qs = function qs(s) {\n  return document.querySelector(s);\n};\n\n/** Find all by query */\nexports.qsa = function qsa(s) {\n  return document.querySelectorAll(s);\n};\n\n/**\n * Filter 'spacebar' and 'return' from keypress handler,\n * and when they're pressed, fire the callback.\n * use $(...).on('keypress', cr(handler))\n */\nexports.cr = function cr(hdl) {\n  return function (e) {\n    if (e.which === 10 || e.which === 13 || e.which === 32) {\n      hdl();\n    }\n  };\n};\n\n/** Decode number from 2B encoding */\nexports.parse2B = function parse2B(s) {\n  var i = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;\n\n  return s.charCodeAt(i++) - 1 + (s.charCodeAt(i) - 1) * 127;\n};\n\n/** Decode number from 3B encoding */\nexports.parse3B = function parse3B(s) {\n  var i = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;\n\n  return s.charCodeAt(i) - 1 + (s.charCodeAt(i + 1) - 1) * 127 + (s.charCodeAt(i + 2) - 1) * 127 * 127;\n};\n\n/** Encode using 2B encoding, returns string. */\nexports.encode2B = function encode2B(n) {\n  var lsb = void 0,\n      msb = void 0;\n  lsb = n % 127;\n  n = (n - lsb) / 127;\n  lsb += 1;\n  msb = n + 1;\n  return String.fromCharCode(lsb) + String.fromCharCode(msb);\n};\n\n/** Encode using 3B encoding, returns string. */\nexports.encode3B = function encode3B(n) {\n  var lsb = void 0,\n      msb = void 0,\n      xsb = void 0;\n  lsb = n % 127;\n  n = (n - lsb) / 127;\n  lsb += 1;\n  msb = n % 127;\n  n = (n - msb) / 127;\n  msb += 1;\n  xsb = n + 1;\n  return String.fromCharCode(lsb) + String.fromCharCode(msb) + String.fromCharCode(xsb);\n};\n\n/***/ }),\n/* 1 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nvar _typeof = typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; };\n\n/*!chibi 3.0.7, Copyright 2012-2016 Kyle Barrow, released under MIT license */\n\n// MODIFIED VERSION.\n(function () {\n\t'use strict';\n\n\tvar readyfn = [],\n\t    loadedfn = [],\n\t    domready = false,\n\t    pageloaded = false,\n\t    d = document,\n\t    w = window;\n\n\t// Fire any function calls on ready event\n\tfunction fireReady() {\n\t\tvar i;\n\t\tdomready = true;\n\t\tfor (i = 0; i < readyfn.length; i += 1) {\n\t\t\treadyfn[i]();\n\t\t}\n\t\treadyfn = [];\n\t}\n\n\t// Fire any function calls on loaded event\n\tfunction fireLoaded() {\n\t\tvar i;\n\t\tpageloaded = true;\n\t\t// For browsers with no DOM loaded support\n\t\tif (!domready) {\n\t\t\tfireReady();\n\t\t}\n\t\tfor (i = 0; i < loadedfn.length; i += 1) {\n\t\t\tloadedfn[i]();\n\t\t}\n\t\tloadedfn = [];\n\t}\n\n\t// Check DOM ready, page loaded\n\tif (d.addEventListener) {\n\t\t// Standards\n\t\td.addEventListener('DOMContentLoaded', fireReady, false);\n\t\tw.addEventListener('load', fireLoaded, false);\n\t} else if (d.attachEvent) {\n\t\t// IE\n\t\td.attachEvent('onreadystatechange', fireReady);\n\t\t// IE < 9\n\t\tw.attachEvent('onload', fireLoaded);\n\t} else {\n\t\t// Anything else\n\t\tw.onload = fireLoaded;\n\t}\n\n\t// Utility functions\n\n\t// Loop through node array\n\tfunction nodeLoop(fn, nodes) {\n\t\tvar i;\n\t\t// Good idea to walk up the DOM\n\t\tfor (i = nodes.length - 1; i >= 0; i -= 1) {\n\t\t\tfn(nodes[i]);\n\t\t}\n\t}\n\n\t// Convert to camel case\n\tfunction cssCamel(property) {\n\t\treturn property.replace(/-\\w/g, function (result) {\n\t\t\treturn result.charAt(1).toUpperCase();\n\t\t});\n\t}\n\n\t// Get computed style\n\tfunction computeStyle(elm, property) {\n\t\t// IE, everything else or null\n\t\treturn elm.currentStyle ? elm.currentStyle[cssCamel(property)] : w.getComputedStyle ? w.getComputedStyle(elm, null).getPropertyValue(property) : null;\n\t}\n\n\t// Returns URI encoded query string pair\n\tfunction queryPair(name, value) {\n\t\treturn encodeURIComponent(name).replace(/%20/g, '+') + '=' + encodeURIComponent(value).replace(/%20/g, '+');\n\t}\n\n\t// Set CSS, important to wrap in try to prevent error thown on unsupported property\n\tfunction setCss(elm, property, value) {\n\t\ttry {\n\t\t\telm.style[cssCamel(property)] = value;\n\t\t} catch (e) {}\n\t}\n\n\t// Show CSS\n\tfunction showCss(elm) {\n\t\telm.style.display = '';\n\t\t// For elements still hidden by style block\n\t\tif (computeStyle(elm, 'display') === 'none') {\n\t\t\telm.style.display = 'block';\n\t\t}\n\t}\n\n\t// Serialize form & JSON values\n\tfunction serializeData(nodes) {\n\t\tvar querystring = '',\n\t\t    subelm,\n\t\t    i,\n\t\t    j;\n\t\tif (nodes.constructor === Object) {\n\t\t\t// Serialize JSON data\n\t\t\tfor (subelm in nodes) {\n\t\t\t\tif (nodes.hasOwnProperty(subelm)) {\n\t\t\t\t\tif (nodes[subelm].constructor === Array) {\n\t\t\t\t\t\tfor (i = 0; i < nodes[subelm].length; i += 1) {\n\t\t\t\t\t\t\tquerystring += '&' + queryPair(subelm, nodes[subelm][i]);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tquerystring += '&' + queryPair(subelm, nodes[subelm]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\t// Serialize node data\n\t\t\tnodeLoop(function (elm) {\n\t\t\t\tif (elm.nodeName === 'FORM') {\n\t\t\t\t\tfor (i = 0; i < elm.elements.length; i += 1) {\n\t\t\t\t\t\tsubelm = elm.elements[i];\n\n\t\t\t\t\t\tif (!subelm.disabled) {\n\t\t\t\t\t\t\tswitch (subelm.type) {\n\t\t\t\t\t\t\t\t// Ignore buttons, unsupported XHR 1 form fields\n\t\t\t\t\t\t\t\tcase 'button':\n\t\t\t\t\t\t\t\tcase 'image':\n\t\t\t\t\t\t\t\tcase 'file':\n\t\t\t\t\t\t\t\tcase 'submit':\n\t\t\t\t\t\t\t\tcase 'reset':\n\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\tcase 'select-one':\n\t\t\t\t\t\t\t\t\tif (subelm.length > 0) {\n\t\t\t\t\t\t\t\t\t\tquerystring += '&' + queryPair(subelm.name, subelm.value);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\tcase 'select-multiple':\n\t\t\t\t\t\t\t\t\tfor (j = 0; j < subelm.length; j += 1) {\n\t\t\t\t\t\t\t\t\t\tif (subelm[j].selected) {\n\t\t\t\t\t\t\t\t\t\t\tquerystring += '&' + queryPair(subelm.name, subelm[j].value);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\tcase 'checkbox':\n\t\t\t\t\t\t\t\tcase 'radio':\n\t\t\t\t\t\t\t\t\tif (subelm.checked) {\n\t\t\t\t\t\t\t\t\t\tquerystring += '&' + queryPair(subelm.name, subelm.value);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\t// Everything else including shinny new HTML5 input types\n\t\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\t\tquerystring += '&' + queryPair(subelm.name, subelm.value);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}, nodes);\n\t\t}\n\t\t// Tidy up first &\n\t\treturn querystring.length > 0 ? querystring.substring(1) : '';\n\t}\n\n\t// Class helper\n\tfunction classHelper(classes, action, nodes) {\n\t\tvar classarray,\n\t\t    search,\n\t\t    i,\n\t\t    replace,\n\t\t    has = false;\n\t\tif (classes) {\n\t\t\t// Trim any whitespace\n\t\t\tclassarray = classes.split(/\\s+/);\n\t\t\tnodeLoop(function (elm) {\n\t\t\t\tfor (i = 0; i < classarray.length; i += 1) {\n\t\t\t\t\tvar clz = classarray[i];\n\t\t\t\t\tif (action === 'remove') {\n\t\t\t\t\t\telm.classList.remove(clz);\n\t\t\t\t\t} else if (action === 'add') {\n\t\t\t\t\t\telm.classList.add(clz);\n\t\t\t\t\t} else if (action === 'toggle') {\n\t\t\t\t\t\telm.classList.toggle(clz);\n\t\t\t\t\t} else if (action === 'has') {\n\t\t\t\t\t\tif (elm.classList.contains(clz)) {\n\t\t\t\t\t\t\thas = true;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// search = new RegExp('\\\\b' + classarray[i] + '\\\\b', 'g');\n\t\t\t\t\t// replace = new RegExp(' *' + classarray[i] + '\\\\b', 'g');\n\t\t\t\t\t// if (action === 'remove') {\n\t\t\t\t\t// \telm.className = elm.className.replace(search, '');\n\t\t\t\t\t// } else if (action === 'toggle') {\n\t\t\t\t\t// \telm.className = (elm.className.match(search)) ? elm.className.replace(replace, '') : elm.className + ' ' + classarray[i];\n\t\t\t\t\t// } else if (action === 'has') {\n\t\t\t\t\t// \tif (elm.className.match(search)) {\n\t\t\t\t\t// \t\thas = true;\n\t\t\t\t\t// \t\tbreak;\n\t\t\t\t\t// \t}\n\t\t\t\t\t// }\n\t\t\t\t}\n\t\t\t}, nodes);\n\t\t}\n\t\treturn has;\n\t}\n\n\t// HTML insertion helper\n\tfunction insertHtml(value, position, nodes) {\n\t\tvar tmpnodes, tmpnode;\n\t\tif (value) {\n\t\t\tnodeLoop(function (elm) {\n\t\t\t\t// No insertAdjacentHTML support for FF < 8 and IE doesn't allow insertAdjacentHTML table manipulation, so use this instead\n\t\t\t\t// Convert string to node. We can't innerHTML on a document fragment\n\t\t\t\ttmpnodes = d.createElement('div');\n\t\t\t\ttmpnodes.innerHTML = value;\n\t\t\t\twhile ((tmpnode = tmpnodes.lastChild) !== null) {\n\t\t\t\t\t// Catch error in unlikely case elm has been removed\n\t\t\t\t\ttry {\n\t\t\t\t\t\tif (position === 'before') {\n\t\t\t\t\t\t\telm.parentNode.insertBefore(tmpnode, elm);\n\t\t\t\t\t\t} else if (position === 'after') {\n\t\t\t\t\t\t\telm.parentNode.insertBefore(tmpnode, elm.nextSibling);\n\t\t\t\t\t\t} else if (position === 'append') {\n\t\t\t\t\t\t\telm.appendChild(tmpnode);\n\t\t\t\t\t\t} else if (position === 'prepend') {\n\t\t\t\t\t\t\telm.insertBefore(tmpnode, elm.firstChild);\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}, nodes);\n\t\t}\n\t}\n\n\t// Get nodes and return chibi\n\tfunction chibi(selector) {\n\t\tvar cb,\n\t\t    nodes = [],\n\t\t    json = false,\n\t\t    nodelist,\n\t\t    i;\n\n\t\tif (selector) {\n\n\t\t\t// Element node, would prefer to use (selector instanceof HTMLElement) but no IE support\n\t\t\tif (selector.nodeType && selector.nodeType === 1) {\n\t\t\t\tnodes = [selector]; // return element as node list\n\t\t\t} else if ((typeof selector === 'undefined' ? 'undefined' : _typeof(selector)) === 'object') {\n\t\t\t\t// JSON, document object or node list, would prefer to use (selector instanceof NodeList) but no IE support\n\t\t\t\tjson = typeof selector.length !== 'number';\n\t\t\t\tnodes = selector;\n\t\t\t} else if (typeof selector === 'string') {\n\t\t\t\tnodelist = d.querySelectorAll(selector);\n\n\t\t\t\t// Convert node list to array so results have full access to array methods\n\t\t\t\t// Array.prototype.slice.call not supported in IE < 9 and often slower than loop anyway\n\t\t\t\tfor (i = 0; i < nodelist.length; i += 1) {\n\t\t\t\t\tnodes[i] = nodelist[i];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Only attach nodes if not JSON\n\t\tcb = json ? {} : nodes;\n\n\t\t// Public functions\n\n\t\t// Executes a function on nodes\n\t\tcb.each = function (fn) {\n\t\t\tif (typeof fn === 'function') {\n\t\t\t\tnodeLoop(function (elm) {\n\t\t\t\t\t// <= IE 8 loses scope so need to apply\n\t\t\t\t\treturn fn.apply(elm, arguments);\n\t\t\t\t}, nodes);\n\t\t\t}\n\t\t\treturn cb;\n\t\t};\n\t\t// Find first\n\t\tcb.first = function () {\n\t\t\treturn chibi(nodes.shift());\n\t\t};\n\t\t// Find last\n\t\tcb.last = function () {\n\t\t\treturn chibi(nodes.pop());\n\t\t};\n\t\t// Find odd\n\t\tcb.odd = function () {\n\t\t\tvar odds = [],\n\t\t\t    i;\n\t\t\tfor (i = 0; i < nodes.length; i += 2) {\n\t\t\t\todds.push(nodes[i]);\n\t\t\t}\n\t\t\treturn chibi(odds);\n\t\t};\n\t\t// Find even\n\t\tcb.even = function () {\n\t\t\tvar evens = [],\n\t\t\t    i;\n\t\t\tfor (i = 1; i < nodes.length; i += 2) {\n\t\t\t\tevens.push(nodes[i]);\n\t\t\t}\n\t\t\treturn chibi(evens);\n\t\t};\n\t\t// Hide node\n\t\tcb.hide = function () {\n\t\t\tnodeLoop(function (elm) {\n\t\t\t\telm.style.display = 'none';\n\t\t\t}, nodes);\n\t\t\treturn cb;\n\t\t};\n\t\t// Show node\n\t\tcb.show = function () {\n\t\t\tnodeLoop(function (elm) {\n\t\t\t\tshowCss(elm);\n\t\t\t}, nodes);\n\t\t\treturn cb;\n\t\t};\n\t\t// Toggle node display\n\t\tcb.toggle = function (state) {\n\t\t\tif (typeof state != 'undefined') {\n\t\t\t\t// ADDED\n\t\t\t\tif (state) cb.show();else cb.hide();\n\t\t\t} else {\n\t\t\t\tnodeLoop(function (elm) {\n\t\t\t\t\t// computeStyle instead of style.display == 'none' catches elements that are hidden via style block\n\t\t\t\t\tif (computeStyle(elm, 'display') === 'none') {\n\t\t\t\t\t\tshowCss(elm);\n\t\t\t\t\t} else {\n\t\t\t\t\t\telm.style.display = 'none';\n\t\t\t\t\t}\n\t\t\t\t}, nodes);\n\t\t\t}\n\t\t\treturn cb;\n\t\t};\n\t\t// Remove node\n\t\tcb.remove = function () {\n\t\t\tnodeLoop(function (elm) {\n\t\t\t\t// Catch error in unlikely case elm has been removed\n\t\t\t\ttry {\n\t\t\t\t\telm.parentNode.removeChild(elm);\n\t\t\t\t} catch (e) {}\n\t\t\t}, nodes);\n\t\t\treturn chibi();\n\t\t};\n\t\t// Get/Set CSS\n\t\tcb.css = function (property, value) {\n\t\t\tif (property) {\n\t\t\t\tif (value || value === '') {\n\t\t\t\t\tnodeLoop(function (elm) {\n\t\t\t\t\t\tsetCss(elm, property, value);\n\t\t\t\t\t}, nodes);\n\t\t\t\t\treturn cb;\n\t\t\t\t}\n\t\t\t\tif (nodes[0]) {\n\t\t\t\t\tif (nodes[0].style[cssCamel(property)]) {\n\t\t\t\t\t\treturn nodes[0].style[cssCamel(property)];\n\t\t\t\t\t}\n\t\t\t\t\tif (computeStyle(nodes[0], property)) {\n\t\t\t\t\t\treturn computeStyle(nodes[0], property);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t\t// Get class(es)\n\t\tcb.getClass = function () {\n\t\t\tif (nodes[0] && nodes[0].className.length > 0) {\n\t\t\t\t// Weak IE trim support\n\t\t\t\treturn nodes[0].className.replace(/^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g, '').replace(/\\s+/, ' ');\n\t\t\t}\n\t\t};\n\t\t// Set (replaces) classes\n\t\tcb.setClass = function (classes) {\n\t\t\tif (classes || classes === '') {\n\t\t\t\tnodeLoop(function (elm) {\n\t\t\t\t\telm.className = classes;\n\t\t\t\t}, nodes);\n\t\t\t}\n\t\t\treturn cb;\n\t\t};\n\t\t// Add class\n\t\tcb.addClass = function (classes) {\n\t\t\tclassHelper(classes, 'add', nodes);\n\t\t\t// if (classes) {\n\t\t\t// \tnodeLoop(function (elm) {\n\t\t\t// \t\telm.className += ' ' + classes;\n\t\t\t// \t}, nodes);\n\t\t\t// }\n\t\t\treturn cb;\n\t\t};\n\t\t// Remove class\n\t\tcb.removeClass = function (classes) {\n\t\t\tclassHelper(classes, 'remove', nodes);\n\t\t\treturn cb;\n\t\t};\n\t\t// Toggle class\n\t\tcb.toggleClass = function (classes, set) {\n\t\t\tvar method = typeof set === 'undefined' ? 'toggle' : +set ? 'add' : 'remove';\n\t\t\tclassHelper(classes, method, nodes);\n\t\t\treturn cb;\n\t\t};\n\t\t// Has class\n\t\tcb.hasClass = function (classes) {\n\t\t\treturn classHelper(classes, 'has', nodes);\n\t\t};\n\t\t// Get/set HTML\n\t\tcb.html = function (value) {\n\t\t\tif (value || value === '') {\n\t\t\t\tnodeLoop(function (elm) {\n\t\t\t\t\telm.innerHTML = value;\n\t\t\t\t}, nodes);\n\t\t\t\treturn cb;\n\t\t\t}\n\t\t\tif (nodes[0]) {\n\t\t\t\treturn nodes[0].innerHTML;\n\t\t\t}\n\t\t};\n\t\t// Insert HTML before selector\n\t\tcb.htmlBefore = function (value) {\n\t\t\tinsertHtml(value, 'before', nodes);\n\t\t\treturn cb;\n\t\t};\n\t\t// Insert HTML after selector\n\t\tcb.htmlAfter = function (value) {\n\t\t\tinsertHtml(value, 'after', nodes);\n\t\t\treturn cb;\n\t\t};\n\t\t// Insert HTML after selector innerHTML\n\t\tcb.htmlAppend = function (value) {\n\t\t\tinsertHtml(value, 'append', nodes);\n\t\t\treturn cb;\n\t\t};\n\t\t// Insert HTML before selector innerHTML\n\t\tcb.htmlPrepend = function (value) {\n\t\t\tinsertHtml(value, 'prepend', nodes);\n\t\t\treturn cb;\n\t\t};\n\t\t// Get/Set HTML attributes\n\t\tcb.attr = function (property, value) {\n\t\t\tif (property) {\n\t\t\t\tproperty = property.toLowerCase();\n\t\t\t\t// IE < 9 doesn't allow style or class via get/setAttribute so switch. cssText returns prettier CSS anyway\n\t\t\t\tif (typeof value !== 'undefined') {\n\t\t\t\t\t//FIXED BUG HERE\n\t\t\t\t\tnodeLoop(function (elm) {\n\t\t\t\t\t\tif (property === 'style') {\n\t\t\t\t\t\t\telm.style.cssText = value;\n\t\t\t\t\t\t} else if (property === 'class') {\n\t\t\t\t\t\t\telm.className = value;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\telm.setAttribute(property, value);\n\t\t\t\t\t\t}\n\t\t\t\t\t}, nodes);\n\t\t\t\t\treturn cb;\n\t\t\t\t}\n\t\t\t\tif (nodes[0]) {\n\t\t\t\t\tif (property === 'style') {\n\t\t\t\t\t\tif (nodes[0].style.cssText) {\n\t\t\t\t\t\t\treturn nodes[0].style.cssText;\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (property === 'class') {\n\t\t\t\t\t\tif (nodes[0].className) {\n\t\t\t\t\t\t\treturn nodes[0].className;\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif (nodes[0].getAttribute(property)) {\n\t\t\t\t\t\t\treturn nodes[0].getAttribute(property);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t\t// Get/Set HTML data property\n\t\tcb.data = function (key, value) {\n\t\t\tif (key) {\n\t\t\t\treturn cb.attr('data-' + key, value);\n\t\t\t}\n\t\t};\n\t\t// Get/Set form element values\n\t\tcb.val = function (value) {\n\t\t\tvar values, i, j;\n\t\t\tif (typeof value != 'undefined') {\n\t\t\t\t// FIXED A BUG HERE\n\t\t\t\tnodeLoop(function (elm) {\n\t\t\t\t\tswitch (elm.nodeName) {\n\t\t\t\t\t\tcase 'SELECT':\n\t\t\t\t\t\t\tif (typeof value === 'string' || typeof value === 'number') {\n\t\t\t\t\t\t\t\tvalue = [value];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tfor (i = 0; i < elm.length; i += 1) {\n\t\t\t\t\t\t\t\t// Multiple select\n\t\t\t\t\t\t\t\tfor (j = 0; j < value.length; j += 1) {\n\t\t\t\t\t\t\t\t\telm[i].selected = '';\n\t\t\t\t\t\t\t\t\tif (elm[i].value === \"\" + value[j]) {\n\t\t\t\t\t\t\t\t\t\telm[i].selected = 'selected';\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'INPUT':\n\t\t\t\t\t\tcase 'TEXTAREA':\n\t\t\t\t\t\tcase 'BUTTON':\n\t\t\t\t\t\t\telm.value = value;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}, nodes);\n\n\t\t\t\treturn cb;\n\t\t\t}\n\t\t\tif (nodes[0]) {\n\t\t\t\tswitch (nodes[0].nodeName) {\n\t\t\t\t\tcase 'SELECT':\n\t\t\t\t\t\tvalues = [];\n\t\t\t\t\t\tfor (i = 0; i < nodes[0].length; i += 1) {\n\t\t\t\t\t\t\tif (nodes[0][i].selected) {\n\t\t\t\t\t\t\t\tvalues.push(nodes[0][i].value);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn values.length > 1 ? values : values[0];\n\t\t\t\t\tcase 'INPUT':\n\t\t\t\t\tcase 'TEXTAREA':\n\t\t\t\t\tcase 'BUTTON':\n\t\t\t\t\t\treturn nodes[0].value;\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t\t// Return matching checked checkbox or radios\n\t\tcb.checked = function (check) {\n\t\t\tif (typeof check === 'boolean') {\n\t\t\t\tnodeLoop(function (elm) {\n\t\t\t\t\tif (elm.nodeName === 'INPUT' && (elm.type === 'checkbox' || elm.type === 'radio')) {\n\t\t\t\t\t\telm.checked = check;\n\t\t\t\t\t}\n\t\t\t\t}, nodes);\n\t\t\t\treturn cb;\n\t\t\t}\n\t\t\tif (nodes[0] && nodes[0].nodeName === 'INPUT' && (nodes[0].type === 'checkbox' || nodes[0].type === 'radio')) {\n\t\t\t\treturn !!nodes[0].checked;\n\t\t\t}\n\t\t};\n\t\t// Add event handler\n\t\tcb.on = function (event, fn) {\n\t\t\tif (selector === w || selector === d) {\n\t\t\t\tnodes = [selector];\n\t\t\t}\n\t\t\tnodeLoop(function (elm) {\n\t\t\t\tif (d.addEventListener) {\n\t\t\t\t\telm.addEventListener(event, fn, false);\n\t\t\t\t} else if (d.attachEvent) {\n\t\t\t\t\t// <= IE 8 loses scope so need to apply, we add this to object so we can detach later (can't detach anonymous functions)\n\t\t\t\t\telm[event + fn] = function () {\n\t\t\t\t\t\treturn fn.apply(elm, arguments);\n\t\t\t\t\t};\n\t\t\t\t\telm.attachEvent('on' + event, elm[event + fn]);\n\t\t\t\t}\n\t\t\t}, nodes);\n\t\t\treturn cb;\n\t\t};\n\t\t// Remove event handler\n\t\tcb.off = function (event, fn) {\n\t\t\tif (selector === w || selector === d) {\n\t\t\t\tnodes = [selector];\n\t\t\t}\n\t\t\tnodeLoop(function (elm) {\n\t\t\t\tif (d.addEventListener) {\n\t\t\t\t\telm.removeEventListener(event, fn, false);\n\t\t\t\t} else if (d.attachEvent) {\n\t\t\t\t\telm.detachEvent('on' + event, elm[event + fn]);\n\t\t\t\t\t// Tidy up\n\t\t\t\t\telm[event + fn] = null;\n\t\t\t\t}\n\t\t\t}, nodes);\n\t\t\treturn cb;\n\t\t};\n\t\treturn cb;\n\t}\n\n\t// Basic XHR\n\tchibi.ajax = function (options) {\n\t\t// if options is a number, it's timeout in ms\n\t\tvar opts = Object.assign({\n\t\t\tmethod: 'GET',\n\t\t\tnocache: true,\n\t\t\ttimeout: 5000,\n\t\t\tloader: true,\n\t\t\tcallback: null\n\t\t}, options);\n\t\topts.method = opts.method.toUpperCase();\n\n\t\tvar loaderFn = opts.loader ? chibi._loader : function () {};\n\t\tvar url = opts.url;\n\t\tvar method = opts.method;\n\t\tvar query = null;\n\n\t\tif (opts.data) {\n\t\t\tquery = serializeData(opts.data);\n\t\t}\n\n\t\tif (query && method === 'GET') {\n\t\t\turl += url.indexOf('?') === -1 ? '?' + query : '&' + query;\n\t\t\tquery = null;\n\t\t}\n\n\t\tvar xhr = new XMLHttpRequest();\n\n\t\t// prevent caching\n\t\tif (opts.nocache) {\n\t\t\tvar ts = (+new Date()).toString(36);\n\t\t\turl += (url.indexOf('?') === -1 ? '?' : '&') + '_=' + ts;\n\t\t}\n\n\t\tloaderFn(true);\n\n\t\txhr.open(method, url, true);\n\t\txhr.timeout = opts.timeout;\n\n\t\t// Abort after given timeout\n\t\tvar abortTmeo = setTimeout(function () {\n\t\t\tconsole.error(\"XHR timed out.\");\n\t\t\txhr.abort();\n\t\t\tloaderFn(false);\n\t\t}, opts.timeout + 10);\n\n\t\txhr.onreadystatechange = function () {\n\t\t\tif (xhr.readyState === 4) {\n\t\t\t\tloaderFn(false);\n\n\t\t\t\topts.callback && opts.callback(xhr.responseText, xhr.status);\n\n\t\t\t\tclearTimeout(abortTmeo);\n\t\t\t}\n\t\t};\n\n\t\txhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');\n\t\tif (method === 'POST') {\n\t\t\txhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');\n\t\t}\n\n\t\txhr.send(query);\n\t\treturn xhr;\n\t};\n\n\tchibi._loader = function () {};\n\n\t// Alias to cb.ajax(url, 'get', callback)\n\tchibi.get = function (url, callback, opts) {\n\t\topts = opts || {};\n\t\topts.url = url;\n\t\topts.callback = callback;\n\t\topts.method = 'GET';\n\t\treturn chibi.ajax(opts);\n\t};\n\n\t// Alias to cb.ajax(url, 'post', callback)\n\tchibi.post = function (url, callback, opts) {\n\t\topts = opts || {};\n\t\topts.url = url;\n\t\topts.callback = callback;\n\t\topts.method = 'POST';\n\t\treturn chibi.ajax(opts);\n\t};\n\n\t// Fire on DOM ready\n\tchibi.ready = function (fn) {\n\t\tif (fn) {\n\t\t\tif (domready) {\n\t\t\t\tfn();\n\t\t\t\treturn chibi;\n\t\t\t} else {\n\t\t\t\treadyfn.push(fn);\n\t\t\t}\n\t\t}\n\t};\n\n\t// Fire on page loaded\n\tchibi.loaded = function (fn) {\n\t\tif (fn) {\n\t\t\tif (pageloaded) {\n\t\t\t\tfn();\n\t\t\t\treturn chibi;\n\t\t\t} else {\n\t\t\t\tloadedfn.push(fn);\n\t\t\t}\n\t\t}\n\t};\n\n\tvar entityMap = {\n\t\t'&': '&amp;',\n\t\t'<': '&lt;',\n\t\t'>': '&gt;',\n\t\t'\"': '&quot;',\n\t\t\"'\": '&#39;',\n\t\t'/': '&#x2F;',\n\t\t'`': '&#x60;',\n\t\t'=': '&#x3D;'\n\t};\n\n\tchibi.htmlEscape = function (string) {\n\t\treturn String(string).replace(/[&<>\"'`=\\/]/g, function (s) {\n\t\t\treturn entityMap[s];\n\t\t});\n\t};\n\n\t// Set Chibi's global namespace here ($)\n\tmodule.exports = chibi;\n})();\n\n/***/ }),\n/* 2 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nvar $ = __webpack_require__(1);\n\n/** Module for toggling a modal overlay */\nvar modal = {};\nvar curCloseCb = null;\n\nmodal.show = function (sel, closeCb) {\n  var $m = $(sel);\n  $m.removeClass('hidden visible');\n  setTimeout(function () {\n    $m.addClass('visible');\n  }, 1);\n  curCloseCb = closeCb;\n};\n\nmodal.hide = function (sel) {\n  var $m = $(sel);\n  $m.removeClass('visible');\n  setTimeout(function () {\n    $m.addClass('hidden');\n    if (curCloseCb) curCloseCb();\n  }, 500); // transition time\n};\n\nmodal.init = function () {\n  // close modal by click outside the dialog\n  $('.Modal').on('click', function () {\n    if ($(this).hasClass('no-close')) return; // this is a no-close modal\n    modal.hide(this);\n  });\n\n  $('.Dialog').on('click', function (e) {\n    e.stopImmediatePropagation();\n  });\n\n  // Hide all modals on esc\n  $(window).on('keydown', function (e) {\n    if (e.which === 27) {\n      modal.hide('.Modal');\n    }\n  });\n};\n\nmodule.exports = modal;\n\n/***/ }),\n/* 3 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nvar $ = __webpack_require__(1);\nvar modal = __webpack_require__(2);\n\nvar nt = {};\nvar sel = '#notif';\nvar $balloon = void 0;\n\nvar timerHideBegin = void 0; // timeout to start hiding (transition)\nvar timerHideEnd = void 0; // timeout to add the hidden class\nvar canCancel = false;\n\nvar stopTimeouts = function stopTimeouts() {\n  clearTimeout(timerHideBegin);\n  clearTimeout(timerHideEnd);\n};\n\nnt.show = function (message, timeout, isError) {\n  $balloon.toggleClass('error', isError === true);\n  $balloon.html(message);\n  modal.show($balloon);\n  stopTimeouts();\n\n  if (!timeout || timeout <= 0) {\n    timeout = 2500;\n  }\n\n  timerHideBegin = setTimeout(nt.hide, timeout);\n\n  canCancel = false;\n  setTimeout(function () {\n    canCancel = true;\n  }, 500);\n};\n\nnt.hide = function () {\n  var $m = $(sel);\n  $m.removeClass('visible');\n  timerHideEnd = setTimeout(function () {\n    $m.addClass('hidden');\n  }, 250); // transition time\n};\n\nnt.init = function () {\n  $balloon = $(sel);\n\n  // close by click outside\n  $(document).on('click', function () {\n    if (!canCancel) return;\n    nt.hide(this);\n  });\n\n  // click caused by selecting, prevent it from bubbling\n  $balloon.on('click', function (e) {\n    e.stopImmediatePropagation();\n    return false;\n  });\n\n  // stop fading if moused\n  $balloon.on('mouseenter', function () {\n    stopTimeouts();\n    $balloon.removeClass('hidden').addClass('visible');\n  });\n};\n\nmodule.exports = nt;\n\n/***/ }),\n/* 4 */\n/***/ (function(module, exports) {\n\n// Copyright Joyent, Inc. and other Node contributors.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a\n// copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to permit\n// persons to whom the Software is furnished to do so, subject to the\n// following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n// USE OR OTHER DEALINGS IN THE SOFTWARE.\n\nfunction EventEmitter() {\n  this._events = this._events || {};\n  this._maxListeners = this._maxListeners || undefined;\n}\nmodule.exports = EventEmitter;\n\n// Backwards-compat with node 0.10.x\nEventEmitter.EventEmitter = EventEmitter;\n\nEventEmitter.prototype._events = undefined;\nEventEmitter.prototype._maxListeners = undefined;\n\n// By default EventEmitters will print a warning if more than 10 listeners are\n// added to it. This is a useful default which helps finding memory leaks.\nEventEmitter.defaultMaxListeners = 10;\n\n// Obviously not all Emitters should be limited to 10. This function allows\n// that to be increased. Set to zero for unlimited.\nEventEmitter.prototype.setMaxListeners = function(n) {\n  if (!isNumber(n) || n < 0 || isNaN(n))\n    throw TypeError('n must be a positive number');\n  this._maxListeners = n;\n  return this;\n};\n\nEventEmitter.prototype.emit = function(type) {\n  var er, handler, len, args, i, listeners;\n\n  if (!this._events)\n    this._events = {};\n\n  // If there is no 'error' event listener then throw.\n  if (type === 'error') {\n    if (!this._events.error ||\n        (isObject(this._events.error) && !this._events.error.length)) {\n      er = arguments[1];\n      if (er instanceof Error) {\n        throw er; // Unhandled 'error' event\n      } else {\n        // At least give some kind of context to the user\n        var err = new Error('Uncaught, unspecified \"error\" event. (' + er + ')');\n        err.context = er;\n        throw err;\n      }\n    }\n  }\n\n  handler = this._events[type];\n\n  if (isUndefined(handler))\n    return false;\n\n  if (isFunction(handler)) {\n    switch (arguments.length) {\n      // fast cases\n      case 1:\n        handler.call(this);\n        break;\n      case 2:\n        handler.call(this, arguments[1]);\n        break;\n      case 3:\n        handler.call(this, arguments[1], arguments[2]);\n        break;\n      // slower\n      default:\n        args = Array.prototype.slice.call(arguments, 1);\n        handler.apply(this, args);\n    }\n  } else if (isObject(handler)) {\n    args = Array.prototype.slice.call(arguments, 1);\n    listeners = handler.slice();\n    len = listeners.length;\n    for (i = 0; i < len; i++)\n      listeners[i].apply(this, args);\n  }\n\n  return true;\n};\n\nEventEmitter.prototype.addListener = function(type, listener) {\n  var m;\n\n  if (!isFunction(listener))\n    throw TypeError('listener must be a function');\n\n  if (!this._events)\n    this._events = {};\n\n  // To avoid recursion in the case that type === \"newListener\"! Before\n  // adding it to the listeners, first emit \"newListener\".\n  if (this._events.newListener)\n    this.emit('newListener', type,\n              isFunction(listener.listener) ?\n              listener.listener : listener);\n\n  if (!this._events[type])\n    // Optimize the case of one listener. Don't need the extra array object.\n    this._events[type] = listener;\n  else if (isObject(this._events[type]))\n    // If we've already got an array, just append.\n    this._events[type].push(listener);\n  else\n    // Adding the second element, need to change to array.\n    this._events[type] = [this._events[type], listener];\n\n  // Check for listener leak\n  if (isObject(this._events[type]) && !this._events[type].warned) {\n    if (!isUndefined(this._maxListeners)) {\n      m = this._maxListeners;\n    } else {\n      m = EventEmitter.defaultMaxListeners;\n    }\n\n    if (m && m > 0 && this._events[type].length > m) {\n      this._events[type].warned = true;\n      console.error('(node) warning: possible EventEmitter memory ' +\n                    'leak detected. %d listeners added. ' +\n                    'Use emitter.setMaxListeners() to increase limit.',\n                    this._events[type].length);\n      if (typeof console.trace === 'function') {\n        // not supported in IE 10\n        console.trace();\n      }\n    }\n  }\n\n  return this;\n};\n\nEventEmitter.prototype.on = EventEmitter.prototype.addListener;\n\nEventEmitter.prototype.once = function(type, listener) {\n  if (!isFunction(listener))\n    throw TypeError('listener must be a function');\n\n  var fired = false;\n\n  function g() {\n    this.removeListener(type, g);\n\n    if (!fired) {\n      fired = true;\n      listener.apply(this, arguments);\n    }\n  }\n\n  g.listener = listener;\n  this.on(type, g);\n\n  return this;\n};\n\n// emits a 'removeListener' event iff the listener was removed\nEventEmitter.prototype.removeListener = function(type, listener) {\n  var list, position, length, i;\n\n  if (!isFunction(listener))\n    throw TypeError('listener must be a function');\n\n  if (!this._events || !this._events[type])\n    return this;\n\n  list = this._events[type];\n  length = list.length;\n  position = -1;\n\n  if (list === listener ||\n      (isFunction(list.listener) && list.listener === listener)) {\n    delete this._events[type];\n    if (this._events.removeListener)\n      this.emit('removeListener', type, listener);\n\n  } else if (isObject(list)) {\n    for (i = length; i-- > 0;) {\n      if (list[i] === listener ||\n          (list[i].listener && list[i].listener === listener)) {\n        position = i;\n        break;\n      }\n    }\n\n    if (position < 0)\n      return this;\n\n    if (list.length === 1) {\n      list.length = 0;\n      delete this._events[type];\n    } else {\n      list.splice(position, 1);\n    }\n\n    if (this._events.removeListener)\n      this.emit('removeListener', type, listener);\n  }\n\n  return this;\n};\n\nEventEmitter.prototype.removeAllListeners = function(type) {\n  var key, listeners;\n\n  if (!this._events)\n    return this;\n\n  // not listening for removeListener, no need to emit\n  if (!this._events.removeListener) {\n    if (arguments.length === 0)\n      this._events = {};\n    else if (this._events[type])\n      delete this._events[type];\n    return this;\n  }\n\n  // emit removeListener for all listeners on all events\n  if (arguments.length === 0) {\n    for (key in this._events) {\n      if (key === 'removeListener') continue;\n      this.removeAllListeners(key);\n    }\n    this.removeAllListeners('removeListener');\n    this._events = {};\n    return this;\n  }\n\n  listeners = this._events[type];\n\n  if (isFunction(listeners)) {\n    this.removeListener(type, listeners);\n  } else if (listeners) {\n    // LIFO order\n    while (listeners.length)\n      this.removeListener(type, listeners[listeners.length - 1]);\n  }\n  delete this._events[type];\n\n  return this;\n};\n\nEventEmitter.prototype.listeners = function(type) {\n  var ret;\n  if (!this._events || !this._events[type])\n    ret = [];\n  else if (isFunction(this._events[type]))\n    ret = [this._events[type]];\n  else\n    ret = this._events[type].slice();\n  return ret;\n};\n\nEventEmitter.prototype.listenerCount = function(type) {\n  if (this._events) {\n    var evlistener = this._events[type];\n\n    if (isFunction(evlistener))\n      return 1;\n    else if (evlistener)\n      return evlistener.length;\n  }\n  return 0;\n};\n\nEventEmitter.listenerCount = function(emitter, type) {\n  return emitter.listenerCount(type);\n};\n\nfunction isFunction(arg) {\n  return typeof arg === 'function';\n}\n\nfunction isNumber(arg) {\n  return typeof arg === 'number';\n}\n\nfunction isObject(arg) {\n  return typeof arg === 'object' && arg !== null;\n}\n\nfunction isUndefined(arg) {\n  return arg === void 0;\n}\n\n\n/***/ }),\n/* 5 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nvar $ = __webpack_require__(1);\n\nvar _require = __webpack_require__(7),\n    rgb255ToHex = _require.rgb255ToHex;\n\nvar themes = exports.themes = [[// 0 - Tango - terminator\n'#111213', '#CC0000', '#4E9A06', '#C4A000', '#3465A4', '#75507B', '#06989A', '#D3D7CF', '#555753', '#EF2929', '#8AE234', '#FCE94F', '#729FCF', '#AD7FA8', '#34E2E2', '#EEEEEC'], [// 1 - Linux (CGA) - terminator\n'#000000', '#aa0000', '#00aa00', '#aa5500', '#0000aa', '#aa00aa', '#00aaaa', '#aaaaaa', '#555555', '#ff5555', '#55ff55', '#ffff55', '#5555ff', '#ff55ff', '#55ffff', '#ffffff'], [// 2 - xterm - terminator\n'#000000', '#cd0000', '#00cd00', '#cdcd00', '#0000ee', '#cd00cd', '#00cdcd', '#e5e5e5', '#7f7f7f', '#ff0000', '#00ff00', '#ffff00', '#5c5cff', '#ff00ff', '#00ffff', '#ffffff'], [// 3 - rxvt - terminator\n'#000000', '#cd0000', '#00cd00', '#cdcd00', '#0000cd', '#cd00cd', '#00cdcd', '#faebd7', '#404040', '#ff0000', '#00ff00', '#ffff00', '#0000ff', '#ff00ff', '#00ffff', '#ffffff'], [// 4 - Ambience - terminator\n'#2e3436', '#cc0000', '#4e9a06', '#c4a000', '#3465a4', '#75507b', '#06989a', '#d3d7cf', '#555753', '#ef2929', '#8ae234', '#fce94f', '#729fcf', '#ad7fa8', '#34e2e2', '#eeeeec'], [// 5 - Solarized Dark - terminator\n'#073642', '#dc322f', '#859900', '#b58900', '#268bd2', '#d33682', '#2aa198', '#eee8d5', '#002b36', '#cb4b16', '#586e75', '#657b83', '#839496', '#6c71c4', '#93a1a1', '#fdf6e3'], [// 6 - CGA NTSC - wikipedia\n'#000000', '#69001A', '#117800', '#769100', '#1A00A6', '#8019AB', '#289E76', '#A4A4A4', '#484848', '#C54E76', '#6DD441', '#D2ED46', '#765BFF', '#DC75FF', '#84FAD2', '#FFFFFF'], [// 7 - ZX Spectrum - wikipedia\n'#000000', '#aa0000', '#00aa00', '#aaaa00', '#0000aa', '#aa00aa', '#00aaaa', '#aaaaaa', '#000000', '#ff0000', '#00FF00', '#ffff00', '#0000ff', '#ff00ff', '#00ffff', '#ffffff'], [// 8 - Apple II - wikipedia\n'#000000', '#722640', '#0E5940', '#808080', '#40337F', '#E434FE', '#1B9AFE', '#BFB3FF', '#404C00', '#E46501', '#1BCB01', '#BFCC80', '#808080', '#F1A6BF', '#8DD9BF', '#ffffff'], [// 9 - Commodore - wikipedia\n'#000000', '#8D3E37', '#55A049', '#AAB95D', '#40318D', '#80348B', '#72C1C8', '#D59F74', '#8B5429', '#B86962', '#94E089', '#FFFFB2', '#8071CC', '#AA5FB6', '#87D6DD', '#ffffff'], [// 10 - Solarized Light - https://github.com/sgerrand/xfce4-terminal-colors-solarized\n'#eee8d5', '#dc322f', '#859900', '#b58900', '#268bd2', '#d33682', '#2aa198', '#073642', '#fdf6e3', '#cb4b16', '#93a1a1', '#839496', '#657b83', '#6c71c4', '#586e75', '#002b36'], [// 11 - Solarized Dark High contrast - https://github.com/sgerrand/xfce4-terminal-colors-solarized\n'#073642', '#dc322f', '#859900', '#b58900', '#268bd2', '#d33682', '#2aa198', '#fdf6e3', '#002b36', '#cb4b16', '#657b83', '#839496', '#93a1a1', '#6c71c4', '#eee8d5', '#fdf6e3']];\n\nexports.fgbgThemes = [['#AAAAAA', '#000000', 'Lnx', 'Linux'], ['#FFFFFF', '#000000', 'W+K', 'White on Black'], ['#00FF00', '#000000', 'Lim', 'Lime'], ['#E53C00', '#000000', 'Nix', 'Nixie'], ['#EFF0F1', '#31363B', 'Brz', 'Breeze'], ['#FFFFFF', '#300A24', 'Amb', 'Ambiance'], ['#839496', '#002B36', 'SoD', 'Solarized Dark'], ['#93a1a1', '#002b36', 'SoH', 'Solarized Dark (High Contrast)'], ['#657B83', '#FDF6E3', 'SoL', 'Solarized Light'], ['#000000', '#FFD75F', 'Wsp', 'Wasp'], ['#000000', '#FFFFDD', 'K+Y', 'Black on Yellow'], ['#000000', '#FFFFFF', 'K+W', 'Black on White']];\n\nvar colorTable256 = null;\n\nexports.buildColorTable = function () {\n  if (colorTable256 !== null) return colorTable256;\n\n  // 256color lookup table\n  // should not be used to look up 0-15 (will return transparent)\n  colorTable256 = new Array(16).fill('#000000');\n\n  // fill color table\n  // colors 16-231 are a 6x6x6 color cube\n  for (var red = 0; red < 6; red++) {\n    for (var green = 0; green < 6; green++) {\n      for (var blue = 0; blue < 6; blue++) {\n        var redValue = red * 40 + (red ? 55 : 0);\n        var greenValue = green * 40 + (green ? 55 : 0);\n        var blueValue = blue * 40 + (blue ? 55 : 0);\n        colorTable256.push(rgb255ToHex(redValue, greenValue, blueValue));\n      }\n    }\n  }\n  // colors 232-255 are a grayscale ramp, sans black and white\n  for (var gray = 0; gray < 24; gray++) {\n    var value = gray * 10 + 8;\n    colorTable256.push(rgb255ToHex(value, value, value));\n  }\n\n  return colorTable256;\n};\n\nexports.SELECTION_FG = '#333';\nexports.SELECTION_BG = '#b2d7fe';\n\nexports.themePreview = function (themeN) {\n  $('[data-fg]').forEach(function (elem) {\n    var shade = elem.dataset.fg;\n    if (/^\\d+$/.test(shade)) shade = exports.toHex(shade, themeN);\n    elem.style.color = shade;\n  });\n  $('[data-bg]').forEach(function (elem) {\n    var shade = elem.dataset.bg;\n    if (/^\\d+$/.test(shade)) shade = exports.toHex(shade, themeN);\n    elem.style.backgroundColor = shade;\n  });\n};\n\nexports.toHex = function (shade, themeN) {\n  if (/^\\d+$/.test(shade)) {\n    shade = +shade;\n    if (shade < 16) shade = themes[themeN][shade];else {\n      shade = exports.buildColorTable()[shade];\n    }\n  }\n  return shade;\n};\n\n/***/ }),\n/* 6 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nvar _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if (\"value\" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } };\n\nvar _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();\n\nfunction _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }\n\nfunction _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return call && (typeof call === \"object\" || typeof call === \"function\") ? call : self; }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function, not \" + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nvar EventEmitter = __webpack_require__(4);\n\nvar _require = __webpack_require__(0),\n    parse2B = _require.parse2B;\n\nvar _require2 = __webpack_require__(5),\n    themes = _require2.themes;\n\nvar encodeAsCodePoint = function encodeAsCodePoint(i) {\n  return String.fromCodePoint(i + (i >= 0xD800 ? 0x801 : 1));\n};\n\nvar ANSIParser = function () {\n  function ANSIParser(handler) {\n    _classCallCheck(this, ANSIParser);\n\n    this.reset();\n    this.handler = handler;\n    this.joinChunks = true;\n  }\n\n  _createClass(ANSIParser, [{\n    key: 'reset',\n    value: function reset() {\n      this.currentSequence = 0;\n      this.sequence = '';\n    }\n  }, {\n    key: 'parseSequence',\n    value: function parseSequence(sequence) {\n      if (sequence[0] === '[') {\n        var type = sequence[sequence.length - 1];\n        var content = sequence.substring(1, sequence.length - 1);\n\n        var numbers = content ? content.split(';').map(function (i) {\n          return +i.replace(/\\D/g, '');\n        }) : [];\n        var numOr1 = numbers.length ? numbers[0] : 1;\n        if (type === 'H') {\n          this.handler('set-cursor', (numbers[0] | 0) - 1, (numbers[1] | 0) - 1);\n        } else if (type >= 'A' && type <= 'D') {\n          this.handler('move-cursor-' + (type <= 'B' ? 'y' : 'x'), (type === 'B' || type === 'C' ? 1 : -1) * numOr1);\n        } else if (type === 'E' || type === 'F') {\n          this.handler('move-cursor-line', (type === 'E' ? 1 : -1) * numOr1);\n        } else if (type === 'G') {\n          this.handler('set-cursor-x', numOr1 - 1);\n        } else if (type === 'J') {\n          var number = numbers.length ? numbers[0] : 2;\n          if (number === 2) this.handler('clear');\n        } else if (type === 'P') {\n          this.handler('delete', numOr1);\n        } else if (type === '@') {\n          this.handler('insert-blanks', numOr1);\n        } else if (type === 'q') this.handler('set-cursor-style', numOr1);else if (type === 'm') {\n          if (!numbers.length) {\n            this.handler('reset-style');\n            return;\n          }\n          var _type = void 0;\n          while (_type = numbers.shift()) {\n            if (_type === 0) this.handler('reset-style');else if (_type === 1) this.handler('add-attrs', 1 << 2); // bold\n            else if (_type === 2) this.handler('add-attrs', 1 << 9); // faint\n              else if (_type === 3) this.handler('add-attrs', 1 << 6); // italic\n                else if (_type === 4) this.handler('add-attrs', 1 << 3); // underline\n                  else if (_type === 5 || _type === 6) this.handler('add-attrs', 1 << 5); // blink\n                    else if (_type === 7) this.handler('add-attrs', 1 << 4); // invert\n                      else if (_type === 9) this.handler('add-attrs', 1 << 7); // strike\n                        else if (_type === 20) this.handler('add-attrs', 1 << 10); // fraktur\n                          else if (_type >= 30 && _type <= 37) this.handler('set-color-fg', _type % 10);else if (_type >= 40 && _type <= 47) this.handler('set-color-bg', _type % 10);else if (_type === 39) this.handler('reset-color-fg');else if (_type === 49) this.handler('reset-color-bg');else if (_type >= 90 && _type <= 98) this.handler('set-color-fg', _type % 10 + 8);else if (_type >= 100 && _type <= 108) this.handler('set-color-bg', _type % 10 + 8);else if (_type === 38 || _type === 48) {\n                              var mode = numbers.shift();\n                              if (mode === 2) {\n                                var r = numbers.shift();\n                                var g = numbers.shift();\n                                var b = numbers.shift();\n                                var color = (r << 16 | g << 8 | b) + 256;\n                                if (_type === 38) this.handler('set-color-fg', color);\n                                if (_type === 48) this.handler('set-color-bg', color);\n                              } else if (mode === 5) {\n                                var _color = (numbers.shift() | 0) & 0xFF;\n                                if (_type === 38) this.handler('set-color-fg', _color);\n                                if (_type === 48) this.handler('set-color-bg', _color);\n                              }\n                            }\n          }\n        } else if (type === 'h' || type === 'l') {\n          if (content === '?25') {\n            if (type === 'h') this.handler('show-cursor');else if (type === 'l') this.handler('hide-cursor');\n          }\n        }\n      }\n    }\n  }, {\n    key: 'write',\n    value: function write(text) {\n      var _iteratorNormalCompletion = true;\n      var _didIteratorError = false;\n      var _iteratorError = undefined;\n\n      try {\n        for (var _iterator = text.toString()[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {\n          var character = _step.value;\n\n          var code = character.codePointAt(0);\n          if (code === 0x1b) this.currentSequence = 1;else if (this.currentSequence === 1 && character === '[') {\n            this.currentSequence = 2;\n            this.sequence += '[';\n          } else if (this.currentSequence && character.match(/[\\x40-\\x7e]/)) {\n            this.parseSequence(this.sequence + character);\n            this.currentSequence = 0;\n            this.sequence = '';\n          } else if (this.currentSequence > 1) this.sequence += character;else if (this.currentSequence === 1) {\n            // something something nothing\n            this.currentSequence = 0;\n            this.handler('write', character);\n          } else if (code < 0x03) this.handler('_null');else if (code === 0x03) this.handler('sigint');else if (code <= 0x06) this.handler('_null');else if (code === 0x07) this.handler('bell');else if (code === 0x08) this.handler('back');else if (code === 0x09) this.handler('tab');else if (code === 0x0a) this.handler('new-line');else if (code === 0x0d) this.handler('return');else if (code === 0x15) this.handler('delete-line');else if (code === 0x17) this.handler('delete-word');else this.handler('write', character);\n        }\n      } catch (err) {\n        _didIteratorError = true;\n        _iteratorError = err;\n      } finally {\n        try {\n          if (!_iteratorNormalCompletion && _iterator.return) {\n            _iterator.return();\n          }\n        } finally {\n          if (_didIteratorError) {\n            throw _iteratorError;\n          }\n        }\n      }\n\n      if (!this.joinChunks) this.reset();\n    }\n  }]);\n\n  return ANSIParser;\n}();\n\nvar TERM_DEFAULT_STYLE = [0, 0, 0];\n\nvar getRainbowColor = function getRainbowColor(t) {\n  var r = Math.floor(Math.sin(t) * 2.5 + 2.5);\n  var g = Math.floor(Math.sin(t + 2 / 3 * Math.PI) * 2.5 + 2.5);\n  var b = Math.floor(Math.sin(t + 4 / 3 * Math.PI) * 2.5 + 2.5);\n  return 16 + 36 * r + 6 * g + b;\n};\n\nvar ScrollingTerminal = function () {\n  function ScrollingTerminal(screen) {\n    var _this = this;\n\n    _classCallCheck(this, ScrollingTerminal);\n\n    this.width = 80;\n    this.height = 25;\n    this.termScreen = screen;\n    this.parser = new ANSIParser(function () {\n      return _this.handleParsed.apply(_this, arguments);\n    });\n    this.buttonLabels = [];\n\n    this.reset();\n\n    this._lastLoad = Date.now();\n    this.loadTimer();\n\n    window.showPage();\n  }\n\n  _createClass(ScrollingTerminal, [{\n    key: 'reset',\n    value: function reset() {\n      this.style = TERM_DEFAULT_STYLE.slice();\n      this.cursor = { x: 0, y: 0, style: 1, visible: true };\n      this.trackMouse = false;\n      this.theme = 0;\n      this.rainbow = this.superRainbow = false;\n      this.parser.reset();\n      this.clear();\n    }\n  }, {\n    key: 'clear',\n    value: function clear() {\n      this.screen = [];\n      for (var i = 0; i < this.width * this.height; i++) {\n        this.screen.push([' ', this.style.slice()]);\n      }\n    }\n  }, {\n    key: 'scroll',\n    value: function scroll() {\n      this.screen.splice(0, this.width);\n      for (var i = 0; i < this.width; i++) {\n        this.screen.push([' ', TERM_DEFAULT_STYLE.slice()]);\n      }\n      this.cursor.y--;\n    }\n  }, {\n    key: 'newLine',\n    value: function newLine() {\n      this.cursor.y++;\n      if (this.cursor.y >= this.height) this.scroll();\n    }\n  }, {\n    key: 'writeChar',\n    value: function writeChar(character) {\n      this.screen[this.cursor.y * this.width + this.cursor.x] = [character, this.style.slice()];\n      this.cursor.x++;\n      if (this.cursor.x >= this.width) {\n        this.cursor.x = 0;\n        this.newLine();\n      }\n    }\n  }, {\n    key: 'moveBack',\n    value: function moveBack() {\n      var n = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;\n\n      for (var i = 0; i < n; i++) {\n        this.cursor.x--;\n        if (this.cursor.x < 0) {\n          if (this.cursor.y > 0) this.cursor.x = this.width - 1;else this.cursor.x = 0;\n          this.cursor.y = Math.max(0, this.cursor.y - 1);\n        }\n      }\n    }\n  }, {\n    key: 'moveForward',\n    value: function moveForward() {\n      var n = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;\n\n      for (var i = 0; i < n; i++) {\n        this.cursor.x++;\n        if (this.cursor.x >= this.width) {\n          this.cursor.x = 0;\n          this.cursor.y++;\n          if (this.cursor.y >= this.height) this.scroll();\n        }\n      }\n    }\n  }, {\n    key: 'deleteChar',\n    value: function deleteChar() {\n      // FIXME unused?\n      this.moveBack();\n      this.screen.splice((this.cursor.y + 1) * this.width, 0, [' ', TERM_DEFAULT_STYLE.slice()]);\n      this.screen.splice(this.cursor.y * this.width + this.cursor.x, 1);\n    }\n  }, {\n    key: 'deleteForward',\n    value: function deleteForward(n) {\n      n = Math.min(this.width, n);\n      for (var i = 0; i < n; i++) {\n        this.screen.splice((this.cursor.y + 1) * this.width, 0, [' ', TERM_DEFAULT_STYLE.slice()]);\n      }this.screen.splice(this.cursor.y * this.width + this.cursor.x, n);\n    }\n  }, {\n    key: 'clampCursor',\n    value: function clampCursor() {\n      if (this.cursor.x < 0) this.cursor.x = 0;\n      if (this.cursor.y < 0) this.cursor.y = 0;\n      if (this.cursor.x > this.width - 1) this.cursor.x = this.width - 1;\n      if (this.cursor.y > this.height - 1) this.cursor.y = this.height - 1;\n    }\n  }, {\n    key: 'handleParsed',\n    value: function handleParsed(action) {\n      if (action === 'write') {\n        this.writeChar(arguments.length <= 1 ? undefined : arguments[1]);\n      } else if (action === 'delete') {\n        this.deleteForward(arguments.length <= 1 ? undefined : arguments[1]);\n      } else if (action === 'insert-blanks') {\n        this.insertBlanks(arguments.length <= 1 ? undefined : arguments[1]); // FIXME undefined?\n      } else if (action === 'clear') {\n        this.clear();\n      } else if (action === 'bell') {\n        this.termScreen.load('U\\x01B');\n      } else if (action === 'back') {\n        this.moveBack();\n      } else if (action === 'new-line') {\n        this.newLine();\n        this.cursor.x = 0;\n      } else if (action === 'return') {\n        this.cursor.x = 0;\n      } else if (action === 'set-cursor') {\n        this.cursor.x = arguments.length <= 2 ? undefined : arguments[2];\n        this.cursor.y = arguments.length <= 1 ? undefined : arguments[1];\n        this.clampCursor();\n      } else if (action === 'move-cursor-y') {\n        this.cursor.y += arguments.length <= 1 ? undefined : arguments[1];\n        this.clampCursor();\n      } else if (action === 'move-cursor-x') {\n        this.cursor.x += arguments.length <= 1 ? undefined : arguments[1];\n        this.clampCursor();\n      } else if (action === 'move-cursor-line') {\n        this.cursor.x = 0;\n        this.cursor.y += arguments.length <= 1 ? undefined : arguments[1];\n        this.clampCursor();\n      } else if (action === 'set-cursor-x') {\n        this.cursor.x = arguments.length <= 1 ? undefined : arguments[1];\n      } else if (action === 'set-cursor-style') {\n        this.cursor.style = Math.max(0, Math.min(6, arguments.length <= 1 ? undefined : arguments[1]));\n      } else if (action === 'reset-style') {\n        this.style = TERM_DEFAULT_STYLE.slice();\n      } else if (action === 'add-attrs') {\n        this.style[2] |= arguments.length <= 1 ? undefined : arguments[1];\n      } else if (action === 'set-color-fg') {\n        this.style[0] = arguments.length <= 1 ? undefined : arguments[1];\n        this.style[2] |= 1;\n      } else if (action === 'set-color-bg') {\n        this.style[1] = arguments.length <= 1 ? undefined : arguments[1];\n        this.style[2] |= 1 << 1;\n      } else if (action === 'reset-color-fg') {\n        this.style[0] = 0;\n        if (this.style[2] & 1) this.style[2] ^= 1;\n      } else if (action === 'reset-color-bg') {\n        this.style[1] = 0;\n        if (this.style[2] & 1 << 1) this.style[2] ^= 1 << 1;\n      } else if (action === 'hide-cursor') {\n        this.cursor.visible = false;\n      } else if (action === 'show-cursor') {\n        this.cursor.visible = true;\n      }\n    }\n  }, {\n    key: 'write',\n    value: function write(text) {\n      this.parser.write(text);\n    }\n  }, {\n    key: 'getScreenOpts',\n    value: function getScreenOpts() {\n      var data = 'O';\n      data += encodeAsCodePoint(25);\n      data += encodeAsCodePoint(80);\n      data += encodeAsCodePoint(this.theme);\n      data += encodeAsCodePoint(7);\n      data += encodeAsCodePoint(0);\n      data += encodeAsCodePoint(0);\n      data += encodeAsCodePoint(0);\n      var attributes = +this.cursor.visible;\n      attributes |= (3 << 5) * +this.trackMouse; // track mouse controls both\n      attributes |= 3 << 7; // buttons/links always visible\n      attributes |= this.cursor.style << 9;\n      data += encodeAsCodePoint(attributes);\n      return data;\n    }\n  }, {\n    key: 'getButtons',\n    value: function getButtons() {\n      var data = 'B';\n      data += encodeAsCodePoint(this.buttonLabels.length);\n      data += this.buttonLabels.map(function (x) {\n        return x + '\\x01';\n      }).join('');\n      return data;\n    }\n  }, {\n    key: 'getTitle',\n    value: function getTitle() {\n      return 'TESPTerm Web UI Demo\\x01';\n    }\n  }, {\n    key: 'getCursor',\n    value: function getCursor() {\n      var data = 'C';\n      data += encodeAsCodePoint(this.cursor.y);\n      data += encodeAsCodePoint(this.cursor.x);\n      data += encodeAsCodePoint(0);\n      return data;\n    }\n  }, {\n    key: 'encodeColor',\n    value: function encodeColor(color) {\n      if (color < 256) {\n        return encodeAsCodePoint(color);\n      } else {\n        color -= 256;\n        return encodeAsCodePoint(color & 0xFFF | 0x10000) + encodeAsCodePoint(color >> 12);\n      }\n    }\n  }, {\n    key: 'serializeScreen',\n    value: function serializeScreen() {\n      var serialized = 'S';\n      serialized += encodeAsCodePoint(0) + encodeAsCodePoint(0);\n      serialized += encodeAsCodePoint(this.height) + encodeAsCodePoint(this.width);\n\n      var lastStyle = [null, null, null];\n      var index = 0;\n      var _iteratorNormalCompletion2 = true;\n      var _didIteratorError2 = false;\n      var _iteratorError2 = undefined;\n\n      try {\n        for (var _iterator2 = this.screen[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {\n          var cell = _step2.value;\n\n          var style = cell[1].slice();\n          if (this.rainbow) {\n            var x = index % this.width;\n            var y = Math.floor(index / this.width);\n            // C instead of F in mask and 1 << 8 in attrs to change attr bits 1 and 2\n            var t = (x + y) / 10 + Date.now() / 1000;\n            if (this.superRainbow) {\n              t = (x * y + Date.now()) / 100 + Date.now() / 1000;\n            }\n            style[0] = getRainbowColor(t);\n            style[1] = 0;\n            if (this.superRainbow) style[1] = getRainbowColor(t / 10);\n            style[2] = style[2] | 1;\n            if (!this.superRainbow && style[2] & 1 << 1) style[2] ^= 1 << 1;\n            index++;\n          }\n\n          var foreground = style[0];\n          var background = style[1];\n          var attributes = style[2];\n          var setForeground = foreground !== lastStyle[0];\n          var setBackground = background !== lastStyle[1];\n          var setAttributes = attributes !== lastStyle[2];\n\n          if (setForeground && setBackground) {\n            if (foreground < 256 && background < 256) {\n              serialized += '\\x03' + encodeAsCodePoint(background << 8 | foreground);\n            } else {\n              serialized += '\\x05' + this.encodeColor(foreground);\n              serialized += '\\x06' + this.encodeColor(background);\n            }\n          } else if (setForeground) serialized += '\\x05' + this.encodeColor(foreground);else if (setBackground) serialized += '\\x06' + this.encodeColor(background);\n          if (setAttributes) serialized += '\\x04' + encodeAsCodePoint(attributes);\n          lastStyle = style;\n\n          serialized += cell[0];\n        }\n      } catch (err) {\n        _didIteratorError2 = true;\n        _iteratorError2 = err;\n      } finally {\n        try {\n          if (!_iteratorNormalCompletion2 && _iterator2.return) {\n            _iterator2.return();\n          }\n        } finally {\n          if (_didIteratorError2) {\n            throw _iteratorError2;\n          }\n        }\n      }\n\n      return serialized;\n    }\n  }, {\n    key: 'getUpdate',\n    value: function getUpdate() {\n      var topics = 0;\n      var topicData = [];\n      var screenOpts = this.getScreenOpts();\n      var title = this.getTitle();\n      var buttons = this.getButtons();\n      var cursor = this.getCursor();\n      var screen = this.serializeScreen();\n      if (this._screenOpts !== screenOpts) {\n        this._screenOpts = screenOpts;\n        topicData.push(screenOpts);\n      }\n      if (this._title !== title) {\n        this._title = title;\n        topicData.push(title);\n      }\n      if (this._buttons !== buttons) {\n        this._buttons = buttons;\n        topicData.push(buttons);\n      }\n      if (this._cursor !== cursor) {\n        this._cursor = cursor;\n        topicData.push(cursor);\n      }\n      if (this._screen !== screen) {\n        this._screen = screen;\n        topicData.push(screen);\n      }\n      if (!topicData.length) return '';\n      return 'U' + encodeAsCodePoint(topics) + topicData.join('');\n    }\n  }, {\n    key: 'loadTimer',\n    value: function loadTimer() {\n      var _this2 = this;\n\n      clearInterval(this._loadTimer);\n      this._loadTimer = setInterval(function () {\n        var update = _this2.getUpdate();\n        if (update) _this2.termScreen.load(update);\n      }, 30);\n    }\n  }]);\n\n  return ScrollingTerminal;\n}();\n\nvar Process = function (_EventEmitter) {\n  _inherits(Process, _EventEmitter);\n\n  function Process() {\n    _classCallCheck(this, Process);\n\n    return _possibleConstructorReturn(this, (Process.__proto__ || Object.getPrototypeOf(Process)).apply(this, arguments));\n  }\n\n  _createClass(Process, [{\n    key: 'write',\n    value: function write(data) {\n      this.emit('in', data);\n    }\n  }, {\n    key: 'destroy',\n    value: function destroy() {\n      // death.\n      this.emit('exit', 0);\n    }\n  }, {\n    key: 'run',\n    value: function run() {\n      // noop\n    }\n  }]);\n\n  return Process;\n}(EventEmitter);\n\nvar demoData = {\n  buttons: [],\n  mouseReceiver: null\n};\n\nvar demoshIndex = {\n  clear: function (_Process) {\n    _inherits(Clear, _Process);\n\n    function Clear() {\n      _classCallCheck(this, Clear);\n\n      return _possibleConstructorReturn(this, (Clear.__proto__ || Object.getPrototypeOf(Clear)).apply(this, arguments));\n    }\n\n    _createClass(Clear, [{\n      key: 'run',\n      value: function run() {\n        this.emit('write', '\\x1b[2J\\x1b[1;1H');\n        this.destroy();\n      }\n    }]);\n\n    return Clear;\n  }(Process),\n  screenfetch: function (_Process2) {\n    _inherits(Screenfetch, _Process2);\n\n    function Screenfetch() {\n      _classCallCheck(this, Screenfetch);\n\n      return _possibleConstructorReturn(this, (Screenfetch.__proto__ || Object.getPrototypeOf(Screenfetch)).apply(this, arguments));\n    }\n\n    _createClass(Screenfetch, [{\n      key: 'run',\n      value: function run() {\n        var _this6 = this;\n\n        var image = ('\\n ###.                          ESPTerm Demo\\n   \\'###.                       Hostname: ' + window.location.hostname + '\\n     \\'###.                     Shell: ESPTerm Demo Shell\\n       \\'###.                   Resolution: 80x25@' + window.devicePixelRatio + 'x\\n         :###-\\n       .###\\'\\n     .###\\'\\n   .###\\'      ###############\\n ###\\'         ###############\\n      ').split('\\n').filter(function (line) {\n          return line.trim();\n        });\n\n        var chars = '';\n        for (var y = 0; y < image.length; y++) {\n          for (var x = 0; x < 80; x++) {\n            if (image[y][x]) {\n              chars += '\\x1B[38;5;' + getRainbowColor((x + y) / 10) + 'm' + image[y][x];\n            } else chars += ' ';\n          }\n        }\n\n        this.emit('write', '\\r\\n\\x1b[?25l');\n        var loop = function loop() {\n          _this6.emit('write', chars.substr(0, 80));\n          chars = chars.substr(80);\n          if (chars.length) setTimeout(loop, 50);else {\n            _this6.emit('write', '\\r\\n\\x1b[?25h');\n            _this6.destroy();\n          }\n        };\n        loop();\n      }\n    }]);\n\n    return Screenfetch;\n  }(Process),\n  'local-echo': function (_Process3) {\n    _inherits(LocalEcho, _Process3);\n\n    function LocalEcho() {\n      _classCallCheck(this, LocalEcho);\n\n      return _possibleConstructorReturn(this, (LocalEcho.__proto__ || Object.getPrototypeOf(LocalEcho)).apply(this, arguments));\n    }\n\n    _createClass(LocalEcho, [{\n      key: 'run',\n      value: function run() {\n        for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {\n          args[_key] = arguments[_key];\n        }\n\n        if (!args.includes('--suppress-note')) {\n          this.emit('write', '\\x1b[38;5;239mNote: not all terminal features are supported or and may not work as expected in this demo\\x1b[0m\\r\\n');\n        }\n      }\n    }, {\n      key: 'write',\n      value: function write(data) {\n        this.emit('write', data);\n      }\n    }]);\n\n    return LocalEcho;\n  }(Process),\n  'info': function (_Process4) {\n    _inherits(Info, _Process4);\n\n    function Info() {\n      _classCallCheck(this, Info);\n\n      return _possibleConstructorReturn(this, (Info.__proto__ || Object.getPrototypeOf(Info)).apply(this, arguments));\n    }\n\n    _createClass(Info, [{\n      key: 'run',\n      value: function run() {\n        var _this9 = this;\n\n        for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {\n          args[_key2] = arguments[_key2];\n        }\n\n        var fast = args.includes('--fast');\n        this.showSplash().then(function () {\n          _this9.printText(fast);\n        });\n      }\n    }, {\n      key: 'showSplash',\n      value: function showSplash() {\n        var _this10 = this;\n\n        var splash = '\\n              -#####- -###*..#####- ######-\\n              -#*    -#-    .## .##.  *#-\\n              -##### .-###*..#####-   *#-  -*##*- #*-#--#**#-*##-\\n              -#*        -#-.##.      *#-  *##@#* ##.  -#* *# .#*\\n              -#####--####- .##.      *#-  -*#@@- ##.  -#* *# .#*\\n      '.split('\\n').filter(function (line) {\n          return line.trim();\n        });\n        var levels = {\n          ' ': -231,\n          '.': 4,\n          '-': 8,\n          '*': 17,\n          '#': 24\n        };\n        var characters = {\n          ' ': ' ',\n          '.': '░',\n          '-': '▒',\n          '*': '▓',\n          '#': '█'\n        };\n        for (var i in splash) {\n          if (splash[i].length < 79) splash[i] += ' '.repeat(79 - splash[i].length);\n        }\n        this.emit('write', '\\r\\n'.repeat(splash.length + 1));\n        this.emit('write', '\\x1b[A'.repeat(splash.length));\n        this.emit('write', '\\x1b[?25l');\n\n        var cursorX = 0;\n        var cursorY = 0;\n        var moveTo = function moveTo(x, y) {\n          var moveX = x - cursorX;\n          var moveY = y - cursorY;\n          _this10.emit('write', '\\x1B[' + Math.abs(moveX) + (moveX > 0 ? 'C' : 'D'));\n          _this10.emit('write', '\\x1B[' + Math.abs(moveY) + (moveY > 0 ? 'B' : 'A'));\n          cursorX = x;\n          cursorY = y;\n        };\n        var drawCell = function drawCell(x, y) {\n          moveTo(x, y);\n          if (splash[y][x] === '@') {\n            _this10.emit('write', '\\x1b[48;5;238m\\x1b[38;5;255m▄\\b');\n          } else {\n            var level = 231 + levels[splash[y][x]];\n            var character = characters[splash[y][x]];\n            _this10.emit('write', '\\x1B[48;5;' + level + 'm\\x1B[38;5;' + level + 'm' + character + '\\b');\n          }\n        };\n        return new Promise(function (resolve, reject) {\n          var self = _this10;\n          var x = 13;\n          var cycles = 0;\n          var loop = function loop() {\n            for (var y = 0; y < splash.length; y++) {\n              var dx = x - y;\n              if (dx > 0) drawCell(dx, y);\n            }\n\n            if (++x < 70) {\n              if (++cycles >= 3) {\n                setTimeout(loop, 50);\n                cycles = 0;\n              } else loop();\n            } else {\n              moveTo(0, splash.length);\n              self.emit('write', '\\x1b[m\\x1b[?25h');\n              resolve();\n            }\n          };\n          loop();\n        });\n      }\n    }, {\n      key: 'printText',\n      value: function printText() {\n        var fast = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;\n\n        // lots of printing\n        var parts = ['', '  ESPTerm is a VT100-like terminal emulator running on the ESP8266 WiFi chip.', '', '  \\x1b[93mThis is an online demo of the web user interface, simulating a simple ', '  terminal in your browser.\\x1b[m', '', '  Type \\x1b[92mls\\x1b[m to list available commands.', '  Use the \\x1b[94mlinks\\x1b[m below this screen for a demo of the options and more info.', ''];\n\n        if (fast) {\n          this.emit('write', parts.join('\\r\\n') + '\\r\\n');\n          this.destroy();\n        } else {\n          var self = this;\n          var loop = function loop() {\n            self.emit('write', parts.shift() + '\\r\\n');\n            if (parts.length) setTimeout(loop, 17);else self.destroy();\n          };\n          loop();\n        }\n      }\n    }]);\n\n    return Info;\n  }(Process),\n  colors: function (_Process5) {\n    _inherits(PrintColors, _Process5);\n\n    function PrintColors() {\n      _classCallCheck(this, PrintColors);\n\n      return _possibleConstructorReturn(this, (PrintColors.__proto__ || Object.getPrototypeOf(PrintColors)).apply(this, arguments));\n    }\n\n    _createClass(PrintColors, [{\n      key: 'run',\n      value: function run() {\n        this.emit('write', '\\r\\n');\n        var fgtext = 'foreground-color';\n        this.emit('write', '    ');\n        for (var i = 0; i < 16; i++) {\n          this.emit('write', '\\x1b[' + (i < 8 ? '3' + i : '9' + (i - 8)) + 'm');\n          this.emit('write', fgtext[i] + ' ');\n        }\n        this.emit('write', '\\r\\n    ');\n        for (var _i = 0; _i < 16; _i++) {\n          this.emit('write', '\\x1b[' + (_i < 8 ? '4' + _i : '10' + (_i - 8)) + 'm  ');\n        }\n        this.emit('write', '\\x1b[m\\r\\n');\n        for (var r = 0; r < 6; r++) {\n          this.emit('write', '    ');\n          for (var g = 0; g < 6; g++) {\n            for (var b = 0; b < 6; b++) {\n              this.emit('write', '\\x1B[48;5;' + (16 + r * 36 + g * 6 + b) + 'm  ');\n            }\n            this.emit('write', '\\x1b[m');\n          }\n          this.emit('write', '\\r\\n');\n        }\n        this.emit('write', '    ');\n        for (var _g = 0; _g < 24; _g++) {\n          this.emit('write', '\\x1B[48;5;' + (232 + _g) + 'm  ');\n        }\n        this.emit('write', '\\x1b[m\\r\\n\\n');\n        this.destroy();\n      }\n    }]);\n\n    return PrintColors;\n  }(Process),\n  ls: function (_Process6) {\n    _inherits(ListCommands, _Process6);\n\n    function ListCommands() {\n      _classCallCheck(this, ListCommands);\n\n      return _possibleConstructorReturn(this, (ListCommands.__proto__ || Object.getPrototypeOf(ListCommands)).apply(this, arguments));\n    }\n\n    _createClass(ListCommands, [{\n      key: 'run',\n      value: function run() {\n        this.emit('write', '\\x1b[92mList of demo commands\\x1b[m\\r\\n');\n        for (var i in demoshIndex) {\n          if (typeof demoshIndex[i] === 'string') continue;\n          this.emit('write', i + '\\r\\n');\n        }\n        this.destroy();\n      }\n    }]);\n\n    return ListCommands;\n  }(Process),\n  theme: function (_Process7) {\n    _inherits(SetTheme, _Process7);\n\n    function SetTheme(shell) {\n      _classCallCheck(this, SetTheme);\n\n      var _this13 = _possibleConstructorReturn(this, (SetTheme.__proto__ || Object.getPrototypeOf(SetTheme)).call(this));\n\n      _this13.shell = shell;\n      return _this13;\n    }\n\n    _createClass(SetTheme, [{\n      key: 'run',\n      value: function run() {\n        var theme = +(arguments.length <= 0 ? undefined : arguments[0]) | 0;\n        var maxnum = themes.length;\n        if (!arguments.length || !Number.isFinite(theme) || theme < 0 || theme >= maxnum) {\n          this.emit('write', '\\x1B[31mUsage: theme [0\\u2013' + (maxnum - 1) + ']\\n');\n          this.destroy();\n          return;\n        }\n        this.shell.terminal.theme = theme;\n        // HACK: reset drawn screen to prevent only partly redrawn screen\n        this.shell.terminal.termScreen.drawnScreenFG = [];\n        this.emit('write', '');\n        this.destroy();\n      }\n    }]);\n\n    return SetTheme;\n  }(Process),\n  themes: function (_Process8) {\n    _inherits(ShowThemes, _Process8);\n\n    function ShowThemes() {\n      _classCallCheck(this, ShowThemes);\n\n      return _possibleConstructorReturn(this, (ShowThemes.__proto__ || Object.getPrototypeOf(ShowThemes)).apply(this, arguments));\n    }\n\n    _createClass(ShowThemes, [{\n      key: 'color',\n      value: function color(hex) {\n        hex = parseInt(hex.substr(1), 16);\n        var r = hex >> 16;\n        var g = hex >> 8 & 0xFF;\n        var b = hex & 0xFF;\n        this.emit('write', '\\x1B[48;2;' + r + ';' + g + ';' + b + 'm');\n        if ((r + g + b) / 3 > 127) {\n          this.emit('write', '\\x1b[38;5;16m');\n        } else {\n          this.emit('write', '\\x1b[38;5;255m');\n        }\n      }\n    }, {\n      key: 'run',\n      value: function run() {\n        for (var i in themes) {\n          var theme = themes[i];\n\n          var name = ('  ' + i).substr(-2);\n\n          this.emit('write', 'Theme ' + name + ': ');\n\n          for (var col = 0; col < 16; col++) {\n            var text = ('  ' + col).substr(-2);\n            this.color(theme[col]);\n            this.emit('write', text);\n            this.emit('write', '\\x1b[m ');\n          }\n\n          this.emit('write', '\\n');\n        }\n\n        this.destroy();\n      }\n    }]);\n\n    return ShowThemes;\n  }(Process),\n  cursor: function (_Process9) {\n    _inherits(SetCursor, _Process9);\n\n    function SetCursor() {\n      _classCallCheck(this, SetCursor);\n\n      return _possibleConstructorReturn(this, (SetCursor.__proto__ || Object.getPrototypeOf(SetCursor)).apply(this, arguments));\n    }\n\n    _createClass(SetCursor, [{\n      key: 'run',\n      value: function run() {\n        for (var _len3 = arguments.length, args = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {\n          args[_key3] = arguments[_key3];\n        }\n\n        var steady = args.includes('--steady');\n        if (args.includes('block')) {\n          this.emit('write', '\\x1B[' + 2 * steady + ' q');\n        } else if (args.includes('line')) {\n          this.emit('write', '\\x1B[' + (3 + steady) + ' q');\n        } else if (args.includes('bar') || args.includes('beam')) {\n          this.emit('write', '\\x1B[' + (5 + steady) + ' q');\n        } else {\n          this.emit('write', '\\x1b[31mUsage: cursor [block|line|bar] [--steady]\\r\\n');\n        }\n        this.destroy();\n      }\n    }]);\n\n    return SetCursor;\n  }(Process),\n  rainbow: function (_Process10) {\n    _inherits(ToggleRainbow, _Process10);\n\n    function ToggleRainbow(shell) {\n      var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n\n      _classCallCheck(this, ToggleRainbow);\n\n      var _this16 = _possibleConstructorReturn(this, (ToggleRainbow.__proto__ || Object.getPrototypeOf(ToggleRainbow)).call(this));\n\n      _this16.shell = shell;\n      _this16.su = options.su;\n      _this16.abort = false;\n      return _this16;\n    }\n\n    _createClass(ToggleRainbow, [{\n      key: 'write',\n      value: function write(data) {\n        var newLine = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;\n\n        if (data === 'y') {\n          this.shell.terminal.rainbow = !this.shell.terminal.rainbow;\n          this.shell.terminal.superRainbow = true;\n          demoData._didWarnRainbow = true;\n        } else {\n          this.emit('write', data);\n        }\n        if (newLine) this.emit('write', '\\x1b[0;32m\\x1b[G\\x1b[79PRainbow!\\n');\n        this.destroy();\n      }\n    }, {\n      key: 'run',\n      value: function run() {\n        if (this.su && !this.shell.terminal.rainbow) {\n          if (!demoData._didWarnRainbow) {\n            this.emit('write', '\\x1b[31;1mWarning: flashy colors. Continue? [y/N] ');\n          } else {\n            this.write('y', false);\n          }\n        } else {\n          this.shell.terminal.rainbow = !this.shell.terminal.rainbow;\n          this.shell.terminal.superRainbow = false;\n          this.destroy();\n        }\n      }\n    }, {\n      key: 'destroy',\n      value: function destroy() {\n        this.abort = true;\n        _get(ToggleRainbow.prototype.__proto__ || Object.getPrototypeOf(ToggleRainbow.prototype), 'destroy', this).call(this);\n      }\n    }]);\n\n    return ToggleRainbow;\n  }(Process),\n  mouse: function (_Process11) {\n    _inherits(ShowMouse, _Process11);\n\n    function ShowMouse(shell) {\n      _classCallCheck(this, ShowMouse);\n\n      var _this17 = _possibleConstructorReturn(this, (ShowMouse.__proto__ || Object.getPrototypeOf(ShowMouse)).call(this));\n\n      _this17.shell = shell;\n      return _this17;\n    }\n\n    _createClass(ShowMouse, [{\n      key: 'run',\n      value: function run() {\n        this.emit('buttons', [{\n          label: 'Exit',\n          action: function action(shell) {\n            shell.write('\\x03');\n          }\n        }]);\n\n        this.shell.terminal.trackMouse = true;\n        demoData.mouseReceiver = this;\n        this.randomData = [];\n        this.highlighted = {};\n        var characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';\n        for (var i = 0; i < 23; i++) {\n          var line = '';\n          for (var j = 0; j < 79; j++) {\n            line += characters[Math.floor(characters.length * Math.random())];\n          }\n          this.randomData.push(line);\n        }\n        this.scrollOffset = 0;\n        this.render();\n      }\n    }, {\n      key: 'render',\n      value: function render() {\n        this.emit('write', '\\x1b[m\\x1b[2J\\x1b[1;1H');\n        this.emit('write', '\\x1b[97m\\x1b[1mMouse Demo\\r\\n\\x1b[mMouse movement, clicking, and scrolling!');\n\n        // render random data for scrolling\n        for (var y = 0; y < 23; y++) {\n          var index = y + this.scrollOffset;\n          // proper modulo:\n          index = (index % this.randomData.length + this.randomData.length) % this.randomData.length;\n          var line = this.randomData[index];\n          var lineData = '\\x1B[' + (3 + y) + ';1H\\x1B[38;5;239m';\n          for (var x in line) {\n            if (this.highlighted[(y + 2) * 80 + +x]) lineData += '\\x1b[97m';\n            lineData += line[x];\n            if (this.highlighted[(y + 2) * 80 + +x]) lineData += '\\x1b[38;5;239m';\n          }\n          this.emit('write', lineData);\n        }\n\n        // move cursor to mouse\n        if (this.mouse) {\n          this.emit('write', '\\x1B[' + (this.mouse.y + 1) + ';' + (this.mouse.x + 1) + 'H');\n        }\n      }\n    }, {\n      key: 'mouseMove',\n      value: function mouseMove(x, y) {\n        this.mouse = { x: x, y: y };\n        this.render();\n      }\n    }, {\n      key: 'mouseDown',\n      value: function mouseDown(x, y, button) {\n        if (button === 4) this.scrollOffset--;else if (button === 5) this.scrollOffset++;else this.highlighted[y * 80 + x] = !this.highlighted[y * 80 + x];\n        this.render();\n      }\n    }, {\n      key: 'mouseUp',\n      value: function mouseUp(x, y, button) {}\n    }, {\n      key: 'destroy',\n      value: function destroy() {\n        this.shell.terminal.write('\\x1b[2J\\x1b[1;1H');\n        this.shell.terminal.trackMouse = false;\n        if (demoData.mouseReceiver === this) demoData.mouseReceiver = null;\n        _get(ShowMouse.prototype.__proto__ || Object.getPrototypeOf(ShowMouse.prototype), 'destroy', this).call(this);\n      }\n    }]);\n\n    return ShowMouse;\n  }(Process),\n  sudo: function (_Process12) {\n    _inherits(Sudo, _Process12);\n\n    function Sudo(shell) {\n      _classCallCheck(this, Sudo);\n\n      var _this18 = _possibleConstructorReturn(this, (Sudo.__proto__ || Object.getPrototypeOf(Sudo)).call(this));\n\n      _this18.shell = shell;\n      _this18.didDestroy = false;\n      return _this18;\n    }\n\n    _createClass(Sudo, [{\n      key: 'run',\n      value: function run() {\n        var _this19 = this;\n\n        for (var _len4 = arguments.length, args = Array(_len4), _key4 = 0; _key4 < _len4; _key4++) {\n          args[_key4] = arguments[_key4];\n        }\n\n        if (args.length === 0) {\n          this.emit('write', '\\x1b[31mUsage: sudo [command]\\x1b[m\\r\\n');\n          this.destroy();\n        } else {\n          var name = args.shift();\n          if (this.shell.index[name]) {\n            var _Process13 = this.shell.index[name];\n            if (_Process13 instanceof Function) {\n              var child = this.child = new _Process13(this.shell, { su: true });\n              this.on('in', function (data) {\n                return child.write(data);\n              });\n              var write = function write(data) {\n                return _this19.emit('write', data);\n              };\n              var setButtons = function setButtons(buttons) {\n                return _this19.emit('buttons', buttons);\n              };\n              child.on('write', write);\n              child.on('buttons', setButtons);\n              child.on('exit', function (code) {\n                child.removeListener('write', write);\n                child.removeListener('buttons', setButtons);\n                _this19.destroy();\n              });\n              child.run.apply(child, args);\n            } else {\n              this.emit('write', _Process13);\n              this.destroy();\n            }\n          } else {\n            this.emit('write', 'sudo: ' + name + ': command not found\\r\\n');\n            this.destroy();\n          }\n        }\n      }\n    }, {\n      key: 'destroy',\n      value: function destroy() {\n        if (this.didDestroy) return;\n        this.didDestroy = true;\n        if (this.child) this.child.destroy();\n        _get(Sudo.prototype.__proto__ || Object.getPrototypeOf(Sudo.prototype), 'destroy', this).call(this);\n      }\n    }]);\n\n    return Sudo;\n  }(Process),\n  make: function (_Process14) {\n    _inherits(Make, _Process14);\n\n    function Make(shell) {\n      var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n\n      _classCallCheck(this, Make);\n\n      var _this20 = _possibleConstructorReturn(this, (Make.__proto__ || Object.getPrototypeOf(Make)).call(this));\n\n      _this20.su = options.su;\n      return _this20;\n    }\n\n    _createClass(Make, [{\n      key: 'run',\n      value: function run() {\n        for (var _len5 = arguments.length, args = Array(_len5), _key5 = 0; _key5 < _len5; _key5++) {\n          args[_key5] = arguments[_key5];\n        }\n\n        if (args.length === 0) this.emit('write', '\\x1b[31mmake: *** No targets specified.  Stop.\\x1b[0m\\r\\n');else if (args.length === 3 && args.join(' ').toLowerCase() === 'me a sandwich') {\n          if (this.su) {\n            var b = '\\x1b[33m';\n            var r = '\\x1b[0m';\n            var l = '\\x1b[32m';\n            var c = '\\x1b[38;5;229m';\n            var h = '\\x1b[38;5;225m';\n            this.emit('write', '                    ' + b + '_.---._\\r\\n' + '                _.-~       ~-._\\r\\n' + '            _.-~               ~-._\\r\\n' + '        _.-~                       ~---._\\r\\n' + '    _.-~                                 ~\\\\\\r\\n' + ' .-~                                    _.;\\r\\n' + ' :-._                               _.-~ ./\\r\\n' + ' `-._~-._                   _..__.-~ _.-~\\r\\n' + ('  ' + c + '/  ' + b + '~-._~-._              / .__..--' + c + '~-' + l + '---._\\r\\n') + (c + ' \\\\_____(_' + b + ';-._\\\\.        _.-~_/' + c + '       ~)' + l + '.. . \\\\\\r\\n') + (l + '    /(_____  ' + b + '\\\\`--...--~_.-~' + c + '______..-+' + l + '_______)\\r\\n') + (l + '  .(_________/' + b + '`--...--~/' + l + '    _/ ' + h + '          ' + b + '/\\\\\\r\\n') + (b + ' /-._' + h + '     \\\\_     ' + l + '(___./_..-~' + h + '__.....' + b + '__..-~./\\r\\n') + (b + ' `-._~-._' + h + '   ~\\\\--------~  .-~' + b + '_..__.-~ _.-~\\r\\n') + (b + '     ~-._~-._ ' + h + '~---------`  ' + b + '/ .__..--~\\r\\n') + (b + '         ~-._\\\\.        _.-~_/\\r\\n') + (b + '             \\\\`--...--~_.-~\\r\\n') + (b + '              `--...--~' + r + '\\r\\n'));\n          } else {\n            this.emit('write', '\\x1b[31mmake: me a sandwich : Permission denied\\x1b[0m\\r\\n');\n          }\n        } else {\n          this.emit('write', '\\x1B[31mmake: *** No rule to make target \\'' + args.join(' ').toLowerCase() + '\\'.  Stop.\\x1B[0m\\r\\n');\n        }\n        this.destroy();\n      }\n    }]);\n\n    return Make;\n  }(Process),\n  pwd: '/this/is/a/demo\\r\\n',\n  cd: '\\x1b[38;5;239mNo directories to change to\\r\\n',\n  whoami: window.navigator.userAgent + '\\r\\n',\n  hostname: '' + window.location.hostname,\n  uname: 'ESPTerm Demo\\r\\n',\n  mkdir: '\\x1b[38;5;239mDid not create a directory because this is a demo.\\r\\n',\n  rm: '\\x1b[38;5;239mDid not delete anything because this is a demo.\\r\\n',\n  cp: '\\x1b[38;5;239mNothing to copy because this is a demo.\\r\\n',\n  mv: '\\x1b[38;5;239mNothing to move because this is a demo.\\r\\n',\n  ln: '\\x1b[38;5;239mNothing to link because this is a demo.\\r\\n',\n  touch: '\\x1b[38;5;239mNothing to touch\\r\\n',\n  exit: '\\x1b[38;5;239mNowhere to go\\r\\n',\n  github: function (_Process15) {\n    _inherits(GoToGithub, _Process15);\n\n    function GoToGithub() {\n      _classCallCheck(this, GoToGithub);\n\n      return _possibleConstructorReturn(this, (GoToGithub.__proto__ || Object.getPrototypeOf(GoToGithub)).apply(this, arguments));\n    }\n\n    _createClass(GoToGithub, [{\n      key: 'run',\n      value: function run() {\n        window.open('https://github.com/espterm/espterm-firmware');\n        this.destroy();\n      }\n    }]);\n\n    return GoToGithub;\n  }(Process)\n};\nvar autocompleteIndex = {\n  'local-echo': 'local-echo [--suppress-note]',\n  theme: 'theme [n]',\n  cursor: 'cursor [block|line|bar] [--steady]',\n  sudo: 'sudo [command]'\n};\n\nvar DemoShell = function () {\n  function DemoShell(terminal, printInfo) {\n    var _this22 = this;\n\n    _classCallCheck(this, DemoShell);\n\n    this.terminal = terminal;\n    this.terminal.reset();\n    this.parser = new ANSIParser(function () {\n      return _this22.handleParsed.apply(_this22, arguments);\n    });\n    this.history = [];\n    this.historyIndex = 0;\n    this.cursorPos = 0;\n    this.lastInputLength = 0;\n    this.child = null;\n    this.index = demoshIndex;\n\n    if (printInfo) this.run('info');else this.prompt();\n  }\n\n  _createClass(DemoShell, [{\n    key: 'write',\n    value: function write(text) {\n      if (this.child) {\n        if (text.codePointAt(0) === 3) this.child.destroy();else this.child.write(text);\n      } else this.parser.write(text);\n    }\n  }, {\n    key: 'prompt',\n    value: function prompt() {\n      var success = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;\n\n      if (this.terminal.cursor.x !== 0) this.terminal.write('\\x1b[m\\x1b[38;5;238m⏎\\r\\n');\n      this.terminal.write('\\x1b[34;1mdemosh \\x1b[m');\n      if (!success) this.terminal.write('\\x1b[31m');\n      this.terminal.write('$ \\x1b[m');\n      this.history.unshift('');\n      this.cursorPos = 0;\n\n      this.setButtons();\n    }\n  }, {\n    key: 'copyFromHistoryIndex',\n    value: function copyFromHistoryIndex() {\n      if (!this.historyIndex) return;\n      var current = this.history[this.historyIndex];\n      this.history[0] = current;\n      this.historyIndex = 0;\n    }\n  }, {\n    key: 'getCompleted',\n    value: function getCompleted() {\n      var visual = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;\n\n      if (this.history[0]) {\n        var input = this.history[0];\n        var prefix = '';\n        if (input.startsWith('sudo ')) {\n          var newInput = input.replace(/^(sudo\\s+)+/, '');\n          prefix = input.substr(0, input.length - newInput.length);\n          input = newInput;\n        }\n        for (var name in this.index) {\n          if (name.startsWith(input) && name !== input) {\n            if (visual && name in autocompleteIndex) return prefix + autocompleteIndex[name];\n            return prefix + name;\n          }\n        }\n        return null;\n      }\n      return null;\n    }\n  }, {\n    key: 'handleParsed',\n    value: function handleParsed(action) {\n      this.terminal.write('\\x1B[' + (this.lastInputLength - this.cursorPos) + 'P');\n      this.terminal.write('\\b\\x1b[P'.repeat(this.cursorPos));\n\n      if (action === 'write') {\n        this.copyFromHistoryIndex();\n        this.history[0] = this.history[0].substr(0, this.cursorPos) + (arguments.length <= 1 ? undefined : arguments[1]) + this.history[0].substr(this.cursorPos);\n        this.cursorPos++;\n      } else if (action === 'back') {\n        this.copyFromHistoryIndex();\n        this.history[0] = this.history[0].substr(0, this.cursorPos - 1) + this.history[0].substr(this.cursorPos);\n        this.cursorPos--;\n        if (this.cursorPos < 0) this.cursorPos = 0;\n      } else if (action === 'tab') {\n        var _completed = this.getCompleted();\n        if (_completed) {\n          this.history[0] = _completed;\n          this.cursorPos = this.history[0].length;\n        }\n      } else if (action === 'move-cursor-x') {\n        this.cursorPos = Math.max(0, Math.min(this.history[this.historyIndex].length, this.cursorPos + (arguments.length <= 1 ? undefined : arguments[1])));\n      } else if (action === 'delete-line') {\n        this.copyFromHistoryIndex();\n        this.history[0] = '';\n        this.cursorPos = 0;\n      } else if (action === 'delete-word') {\n        this.copyFromHistoryIndex();\n        var words = this.history[0].substr(0, this.cursorPos).split(' ');\n        words.pop();\n        this.history[0] = words.join(' ') + this.history[0].substr(this.cursorPos);\n        this.cursorPos = words.join(' ').length;\n      } else if (action === 'move-cursor-y') {\n        this.historyIndex -= arguments.length <= 1 ? undefined : arguments[1];\n        if (this.historyIndex < 0) this.historyIndex = 0;\n        if (this.historyIndex >= this.history.length) this.historyIndex = this.history.length - 1;\n        this.cursorPos = this.history[this.historyIndex].length;\n      }\n\n      this.terminal.write(this.history[this.historyIndex]);\n      this.terminal.write('\\b'.repeat(this.history[this.historyIndex].length));\n      this.terminal.moveForward(this.cursorPos);\n\n      this.lastInputLength = this.cursorPos;\n\n      var completed = this.getCompleted(true);\n      if (this.historyIndex === 0 && completed && action !== 'return') {\n        // show closest match faintly\n        var rest = completed.substr(this.history[0].length);\n        this.terminal.write('\\x1B[2m' + rest + '\\x1B[m' + '\\b'.repeat(rest.length));\n        this.lastInputLength += rest.length;\n      }\n\n      if (action === 'return') {\n        this.terminal.write('\\n');\n        this.parse(this.history[this.historyIndex]);\n      }\n    }\n  }, {\n    key: 'parse',\n    value: function parse(input) {\n      if (input === 'help') input = 'info';\n      // TODO: basic chaining (i.e. semicolon)\n      if (input) this.run(input);else this.prompt();\n    }\n  }, {\n    key: 'run',\n    value: function run(command) {\n      var parts = [''];\n\n      var inQuote = false;\n      var _iteratorNormalCompletion3 = true;\n      var _didIteratorError3 = false;\n      var _iteratorError3 = undefined;\n\n      try {\n        for (var _iterator3 = command.trim()[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {\n          var character = _step3.value;\n\n          if (inQuote && character !== inQuote) {\n            parts[parts.length - 1] += character;\n          } else if (inQuote) {\n            inQuote = false;\n          } else if (character === '\"' || character === \"'\") {\n            inQuote = character;\n          } else if (character.match(/\\s/)) {\n            if (parts[parts.length - 1]) parts.push('');\n          } else parts[parts.length - 1] += character;\n        }\n      } catch (err) {\n        _didIteratorError3 = true;\n        _iteratorError3 = err;\n      } finally {\n        try {\n          if (!_iteratorNormalCompletion3 && _iterator3.return) {\n            _iterator3.return();\n          }\n        } finally {\n          if (_didIteratorError3) {\n            throw _iteratorError3;\n          }\n        }\n      }\n\n      var name = parts.shift();\n\n      if (name in this.index) {\n        this.spawn(name, parts);\n      } else {\n        this.terminal.write('demosh: Unknown command: ' + name + '\\r\\n');\n        this.prompt(false);\n      }\n    }\n  }, {\n    key: 'spawn',\n    value: function spawn(name) {\n      var _this23 = this;\n\n      var args = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];\n\n      var Process = this.index[name];\n      if (Process instanceof Function) {\n        var _child;\n\n        this.setButtons([]);\n        this.child = new Process(this);\n        var write = function write(data) {\n          return _this23.terminal.write(data);\n        };\n        var setButtons = function setButtons(buttons) {\n          return _this23.setButtons(buttons);\n        };\n        this.child.on('write', write);\n        this.child.on('buttons', setButtons);\n        this.child.on('exit', function (code) {\n          if (_this23.child) {\n            _this23.child.removeListener('write', write);\n            _this23.child.removeListener('buttons', setButtons);\n          }\n          _this23.child = null;\n          _this23.prompt(!code);\n        });\n        (_child = this.child).run.apply(_child, _toConsumableArray(args));\n      } else {\n        this.terminal.write(Process);\n        this.prompt();\n      }\n    }\n  }, {\n    key: 'setButtons',\n    value: function setButtons(buttons) {\n      if (!buttons) {\n        var shell = this;\n        var writeChars = function writeChars(chars) {\n          var loop = function loop() {\n            shell.write(chars[0]);\n            chars = chars.substr(1);\n            if (chars) setTimeout(loop, 100);\n          };\n          setTimeout(loop, 200);\n        };\n\n        buttons = [{\n          label: 'Open GitHub',\n          action: function action(shell) {\n            if (shell.child) shell.child.destroy();\n            writeChars('github\\r');\n          }\n        }, {\n          label: 'Help',\n          action: function action(shell) {\n            if (shell.child) shell.child.destroy();\n            writeChars('info\\r');\n          }\n        }];\n      }\n      if (!buttons.length) buttons.push({ label: '', action: function action() {}\n      });\n      this.buttons = buttons;\n      this.terminal.buttonLabels = buttons.map(function (x) {\n        return x.label;\n      });\n    }\n  }, {\n    key: 'onButtonPress',\n    value: function onButtonPress(index) {\n      var button = this.buttons[index];\n      if (!button) return;\n      button.action(this, this.terminal);\n    }\n  }]);\n\n  return DemoShell;\n}();\n\nwindow.demoInterface = module.exports = {\n  input: function input(data) {\n    var type = data[0];\n    var content = data.substr(1);\n\n    if (type === 's') {\n      this.shell.write(content);\n    } else if (type === 'b') {\n      var button = content.charCodeAt(0);\n      this.shell.onButtonPress(button - 1);\n    } else if (type === 'm' || type === 'p' || type === 'r') {\n      var row = parse2B(content, 0);\n      var column = parse2B(content, 2);\n      var _button = parse2B(content, 4);\n      var modifiers = parse2B(content, 6);\n\n      if (demoData.mouseReceiver) {\n        if (type === 'm') demoData.mouseReceiver.mouseMove(column, row, _button, modifiers);else if (type === 'p') demoData.mouseReceiver.mouseDown(column, row, _button, modifiers);else if (type === 'r') demoData.mouseReceiver.mouseUp(column, row, _button, modifiers);\n      }\n    }\n  },\n\n  didInit: false,\n  init: function init(screen) {\n    if (this.didInit) return;\n    this.didInit = true;\n    this.terminal = new ScrollingTerminal(screen);\n    this.shell = new DemoShell(this.terminal, true);\n  }\n};\n\n/***/ }),\n/* 7 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\n/*\n * Copyright (c) 2010 Tim Baumann\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n// NOTE:\n// Extracted from ColorTriangle and\n// Converted to ES6 by MightyPork (2017)\n\n/*******************\n * Color conversion *\n *******************/\n\nvar M = Math;\nvar TAU = 2 * M.PI;\n\nexports.hue2rgb = function (v1, v2, h) {\n  if (h < 0) h += 1;\n  if (h > 1) h -= 1;\n\n  if (6 * h < 1) return v1 + (v2 - v1) * 6 * h;\n  if (2 * h < 1) return v2;\n  if (3 * h < 2) return v1 + (v2 - v1) * (2 / 3 - h) * 6;\n  return v1;\n};\n\nexports.hsl2rgb = function (h, s, l) {\n  h /= TAU;\n  var r = void 0,\n      g = void 0,\n      b = void 0;\n\n  if (s === 0) {\n    r = g = b = l;\n  } else {\n    var var_1 = void 0,\n        var_2 = void 0;\n\n    if (l < 0.5) var_2 = l * (1 + s);else var_2 = l + s - s * l;\n\n    var_1 = 2 * l - var_2;\n\n    r = exports.hue2rgb(var_1, var_2, h + 1 / 3);\n    g = exports.hue2rgb(var_1, var_2, h);\n    b = exports.hue2rgb(var_1, var_2, h - 1 / 3);\n  }\n  return [r, g, b];\n};\n\nexports.rgb2hsl = function (r, g, b) {\n  var min = M.min(r, g, b);\n  var max = M.max(r, g, b);\n  var d = max - min; // delta\n\n  var h = void 0,\n      s = void 0,\n      l = void 0;\n\n  l = (max + min) / 2;\n\n  if (d === 0) {\n    // gray\n    h = s = 0; // HSL results from 0 to 1\n  } else {\n    // chroma\n    if (l < 0.5) s = d / (max + min);else s = d / (2 - max - min);\n\n    var d_r = ((max - r) / 6 + d / 2) / d;\n    var d_g = ((max - g) / 6 + d / 2) / d;\n    var d_b = ((max - b) / 6 + d / 2) / d; // deltas\n\n    if (r === max) h = d_b - d_g;else if (g === max) h = 1 / 3 + d_r - d_b;else if (b === max) h = 2 / 3 + d_g - d_r;\n\n    if (h < 0) h += 1;else if (h > 1) h -= 1;\n  }\n  h *= TAU;\n  return [h, s, l];\n};\n\nexports.hex2rgb = function (hex) {\n  var groups = hex.match(/^#([\\da-f]{3,6})$/i);\n  if (groups) {\n    hex = groups[1];\n    var bytes = hex.length / 3;\n    var max = Math.pow(16, bytes) - 1;\n    return [0, 1, 2].map(function (x) {\n      return parseInt(hex.slice(x * bytes, (x + 1) * bytes), 16) / max;\n    });\n  }\n  return [0, 0, 0];\n};\n\nfunction pad(n) {\n  return ('00' + n).substr(-2);\n}\n\nexports.rgb255ToHex = function (r, g, b) {\n  return '#' + [r, g, b].map(function (x) {\n    return pad(x.toString(16));\n  }).join('');\n};\n\nexports.rgb2hex = function (r, g, b) {\n  return '#' + [r, g, b].map(function (x) {\n    return pad(Math.round(x * 255).toString(16));\n  }).join('');\n};\n\n/***/ }),\n/* 8 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nvar data = __webpack_require__(13);\n\nmodule.exports = function localize(key) {\n  return data[key] || '?' + key + '?';\n};\n\n/***/ }),\n/* 9 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\n__webpack_require__(10);\n__webpack_require__(2);\n__webpack_require__(3);\n__webpack_require__(11);\ntry {\n  __webpack_require__(6);\n} catch (err) {}\n__webpack_require__(12);\n\nvar $ = __webpack_require__(1);\n\nvar _require = __webpack_require__(0),\n    qs = _require.qs;\n\n/* Export stuff to the global scope for inline scripts */\n\n\nwindow.termInit = __webpack_require__(14);\nwindow.$ = $;\nwindow.qs = qs;\n\nwindow.themes = __webpack_require__(5);\n\nwindow.TermConf = __webpack_require__(24);\n\n/***/ }),\n/* 10 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\n/*! http://mths.be/fromcodepoint v0.1.0 by @mathias */\nif (!String.fromCodePoint) {\n  (function () {\n    var defineProperty = function () {\n      // IE 8 only supports `Object.defineProperty` on DOM elements\n      try {\n        var object = {};\n        var $defineProperty = Object.defineProperty;\n        var result = $defineProperty(object, object, object) && $defineProperty;\n      } catch (error) {}\n      return result;\n    }();\n    var stringFromCharCode = String.fromCharCode;\n    var floor = Math.floor;\n    var fromCodePoint = function fromCodePoint() {\n      var MAX_SIZE = 0x4000;\n      var codeUnits = [];\n      var highSurrogate;\n      var lowSurrogate;\n      var index = -1;\n      var length = arguments.length;\n      if (!length) {\n        return '';\n      }\n      var result = '';\n      while (++index < length) {\n        var codePoint = Number(arguments[index]);\n        if (!isFinite(codePoint) || // `NaN`, `+Infinity`, or `-Infinity`\n        codePoint < 0 || // not a valid Unicode code point\n        codePoint > 0x10FFFF || // not a valid Unicode code point\n        floor(codePoint) != codePoint // not an integer\n        ) {\n            throw RangeError('Invalid code point: ' + codePoint);\n          }\n        if (codePoint <= 0xFFFF) {\n          // BMP code point\n          codeUnits.push(codePoint);\n        } else {\n          // Astral code point; split in surrogate halves\n          // http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae\n          codePoint -= 0x10000;\n          highSurrogate = (codePoint >> 10) + 0xD800;\n          lowSurrogate = codePoint % 0x400 + 0xDC00;\n          codeUnits.push(highSurrogate, lowSurrogate);\n        }\n        if (index + 1 == length || codeUnits.length > MAX_SIZE) {\n          result += stringFromCharCode.apply(null, codeUnits);\n          codeUnits.length = 0;\n        }\n      }\n      return result;\n    };\n    if (defineProperty) {\n      defineProperty(String, 'fromCodePoint', {\n        'value': fromCodePoint,\n        'configurable': true,\n        'writable': true\n      });\n    } else {\n      String.fromCodePoint = fromCodePoint;\n    }\n  })();\n}\n\n/***/ }),\n/* 11 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nvar $ = __webpack_require__(1);\n\nvar _require = __webpack_require__(0),\n    mk = _require.mk,\n    qs = _require.qs,\n    qsa = _require.qsa,\n    cr = _require.cr;\n\nvar modal = __webpack_require__(2);\nvar notify = __webpack_require__(3);\n\n/** Global generic init */\n$.ready(function () {\n  // Opening menu on mobile / narrow screen\n  function menuOpen() {\n    $('#menu').toggleClass('expanded');\n  }\n  $('#brand').on('click', menuOpen).on('keypress', cr(menuOpen));\n\n  // Checkbox UI (checkbox CSS and hidden input with int value)\n  $('.Row.checkbox').forEach(function (x) {\n    var inp = x.querySelector('input');\n    var box = x.querySelector('.box');\n\n    $(box).toggleClass('checked', inp.value);\n\n    var hdl = function hdl() {\n      inp.value = 1 - inp.value;\n      $(box).toggleClass('checked', inp.value);\n    };\n\n    $(x).on('click', hdl).on('keypress', cr(hdl));\n  });\n\n  // Expanding boxes on mobile\n  $('.Box.mobcol,.Box.fold').forEach(function (x) {\n    var h = x.querySelector('h2');\n\n    var hdl = function hdl() {\n      if ($(x).hasClass('d-expanded')) {\n        $(x).removeClass('d-expanded');\n      } else {\n        $(x).toggleClass('expanded');\n      }\n    };\n    $(h).on('click', hdl).on('keypress', cr(hdl));\n  });\n\n  $('form').forEach(function (x) {\n    $(x).on('keypress', function (e) {\n      if ((e.keyCode === 10 || e.keyCode === 13) && e.ctrlKey) {\n        x.submit();\n      }\n    });\n  });\n\n  // loader dots...\n  setInterval(function () {\n    $('.anim-dots').each(function (x) {\n      var $x = $(x);\n      var dots = $x.html() + '.';\n      if (dots.length === 5) dots = '.';\n      $x.html(dots);\n    });\n  }, 1000);\n\n  // flipping number boxes with the mouse wheel\n  $('input[type=number]').on('wheel', function (e) {\n    var $this = $(this);\n    var val = +$this.val();\n    if (isNaN(val)) val = 1;\n\n    var step = +($this.attr('step') || 1);\n    var min = +$this.attr('min');\n    var max = +$this.attr('max');\n    if (e.deltaY > 0) {\n      val += step;\n    } else {\n      val -= step;\n    }\n\n    if (Number.isFinite(min)) val = Math.max(val, +min);\n    if (Number.isFinite(max)) val = Math.min(val, +max);\n    $this.val(val);\n\n    if ('createEvent' in document) {\n      var evt = document.createEvent('HTMLEvents');\n      evt.initEvent('change', false, true);\n      $this[0].dispatchEvent(evt);\n    } else {\n      $this[0].fireEvent('onchange');\n    }\n\n    e.preventDefault();\n  });\n\n  // populate the form errors box from GET arg ?err=...\n  // (a way to pass errors back from server via redirect)\n  var errAt = window.location.search.indexOf('err=');\n  if (errAt !== -1 && qs('.Box.errors')) {\n    var errs = decodeURIComponent(window.location.search.substr(errAt + 4)).split(',');\n    var humanReadableErrors = [];\n    errs.forEach(function (er) {\n      var lbls = qsa('label[for=\"' + er + '\"]');\n      if (lbls) {\n        for (var i = 0; i < lbls.length; i++) {\n          var lbl = lbls[i];\n          lbl.classList.add('error');\n          if (i === 0) humanReadableErrors.push(lbl.childNodes[0].textContent.trim().replace(/: ?$/, ''));\n        }\n      } else {\n        humanReadableErrors.push(er);\n      }\n    });\n\n    qs('.Box.errors .list').innerHTML = humanReadableErrors.join(', ');\n    qs('.Box.errors').classList.remove('hidden');\n  }\n\n  var msgAt = window.location.search.indexOf('msg=');\n  if (msgAt !== -1 && qs('.Box.message')) {\n    var msg = decodeURIComponent(window.location.search.substr(msgAt + 4));\n    var box = qs('.Box.message');\n    box.innerHTML = msg;\n    box.classList.remove('hidden');\n    setTimeout(function () {\n      box.classList.add('hiding');\n      setTimeout(function () {\n        box.classList.add('hidden');\n      }, 1000);\n    }, 2000);\n  }\n\n  modal.init();\n  notify.init();\n\n  // remove tabindices from h2 if wide\n  if (window.innerWidth > 550) {\n    $('.Box h2').forEach(function (x) {\n      x.removeAttribute('tabindex');\n    });\n\n    // brand works as a link back to term in widescreen mode\n    var br = qs('#brand');\n    br && br.addEventListener('click', function () {\n      window.location.href = '/'; // go to terminal\n    });\n  }\n});\n\n// setup the ajax loader\n$._loader = function (vis) {\n  $('#loader').toggleClass('show', vis);\n};\n\nvar pageShown = false;\n// reveal content on load\nfunction showPage() {\n  pageShown = true;\n  $('#content').addClass('load');\n}\n// HACKITY HACK: fix this later\nwindow.showPage = showPage;\n\n// Auto reveal pages other than the terminal (sets window.noAutoShow)\n$.ready(function () {\n  if (window.noAutoShow === true) {\n    setTimeout(function () {\n      if (!pageShown) {\n        var bnr = mk('P');\n        bnr.id = 'load-failed';\n        bnr.innerHTML = 'Server connection failed! Trying again' + '<span class=\"anim-dots\" style=\"width:1.5em;text-align:left;display:inline-block\">.</span>';\n        qs('#screen').appendChild(bnr);\n        showPage();\n      }\n    }, 2000);\n  } else {\n    setTimeout(function () {\n      showPage();\n    }, 1);\n  }\n});\n\n/***/ }),\n/* 12 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nvar $ = __webpack_require__(1);\n\nvar _require = __webpack_require__(0),\n    mk = _require.mk;\n\nvar tr = __webpack_require__(8);\n\n{\n\n  // Get XX % for a slider input\n  var calc_dBm = function calc_dBm(inp) {\n    return '+' + (inp.value * 0.25).toFixed(2) + ' dBm';\n  };\n\n  // Display selected STA SSID etc\n\n\n  var selectSta = function selectSta(name, password, ip) {\n    $('#sta_ssid').val(name);\n    $('#sta_password').val(password);\n\n    $('#sta-nw').toggleClass('hidden', name.length === 0);\n    $('#sta-nw-nil').toggleClass('hidden', name.length > 0);\n\n    $('#sta-nw .essid').html($.htmlEscape(name));\n    var hasPassword = !!password;\n\n    // (the following is kind of confusing with the double-double negations,\n    // but it works)\n    $('#sta-nw .passwd').toggleClass('hidden', !hasPassword);\n    $('#sta-nw .nopasswd').toggleClass('hidden', hasPassword);\n\n    $('#sta-nw .ip').html(ip.length > 0 ? tr('wifi.connected_ip_is') + ip : tr('wifi.not_conn'));\n  };\n\n  /** Update display for received response */\n\n\n  var onScan = function onScan(resp, status) {\n    // var ap_json = {\n    //  \"result\": {\n    //    \"inProgress\": \"0\",\n    //    \"APs\": [\n    //      {\"essid\": \"Chlivek\", \"bssid\": \"88:f7:c7:52:b3:99\", \"rssi\": \"204\", \"enc\": \"4\", \"channel\": \"1\"},\n    //      {\"essid\": \"TyNikdy\", \"bssid\": \"5c:f4:ab:0d:f1:1b\", \"rssi\": \"164\", \"enc\": \"3\", \"channel\": \"1\"},\n    //    ]\n    //  }\n    // };\n\n    if (status !== 200) {\n      // bad response\n      rescan(5000); // wait 5s then retry\n      return;\n    }\n\n    try {\n      resp = JSON.parse(resp);\n    } catch (e) {\n      console.log(e);\n      rescan(5000);\n      return;\n    }\n\n    var done = !resp.result.inProgress && resp.result.APs.length > 0;\n    rescan(done ? 15000 : 1000);\n    if (!done) return; // no redraw yet\n\n    // clear the AP list\n    var $list = $('#ap-list');\n    // remove old APs\n    $('#ap-list .AP').remove();\n\n    $list.toggleClass('hidden', !done);\n    $('#ap-loader').toggleClass('hidden', done);\n\n    // scan done\n    resp.result.APs.sort(function (a, b) {\n      return b.rssi - a.rssi;\n    }).forEach(function (ap) {\n      ap.enc = parseInt(ap.enc);\n\n      if (ap.enc > 4) return; // hide unsupported auths\n\n      var item = mk('div');\n\n      var $item = $(item).data('ssid', ap.essid).data('pwd', ap.enc).attr('tabindex', 0).addClass('AP');\n\n      // mark current SSID\n      if (ap.essid === curSSID) {\n        $item.addClass('selected');\n      }\n\n      var inner = mk('div');\n      var escapedSSID = $.htmlEscape(ap.essid);\n      $(inner).addClass('inner').htmlAppend('<div class=\"rssi\">' + ap.rssi_perc + '</div>').htmlAppend('<div class=\"essid\" title=\"' + escapedSSID + '\">' + escapedSSID + '</div>').htmlAppend('<div class=\"auth\">' + authTypes[ap.enc] + '</div>');\n\n      $item.on('click', function () {\n        var $th = $(this);\n\n        var conn_ssid = $th.data('ssid');\n        var conn_pass = '';\n\n        if (+$th.data('pwd')) {\n          // this AP needs a password\n          conn_pass = window.prompt(tr('wifi.enter_passwd').replace(':ssid:', conn_ssid));\n          if (!conn_pass) return;\n        }\n\n        $('#sta_password').val(conn_pass);\n        $('#sta_ssid').val(conn_ssid);\n        selectSta(conn_ssid, conn_pass, '');\n      });\n\n      item.appendChild(inner);\n      $list[0].appendChild(item);\n    });\n  };\n\n  var startScanning = function startScanning() {\n    $('#ap-loader').removeClass('hidden');\n    $('#ap-scan').addClass('hidden');\n    $('#ap-loader .anim-dots').html('.');\n\n    scanAPs();\n  };\n\n  /** Ask the CGI what APs are visible (async) */\n\n\n  var scanAPs = function scanAPs() {\n    if (window._demo) {\n      onScan(window._demo_aps, 200);\n    } else {\n      $.get('http://' + window._root + '/cfg/wifi/scan', onScan);\n    }\n  };\n\n  var rescan = function rescan(time) {\n    setTimeout(scanAPs, time);\n  };\n\n  /** Set up the WiFi page */\n\n\n  var wifiInit = function wifiInit(cfg) {\n    // Update slider value displays\n    $('.Row.range').forEach(function (x) {\n      var inp = x.querySelector('input');\n      var disp1 = x.querySelector('.x-disp1');\n      var disp2 = x.querySelector('.x-disp2');\n      var t = calc_dBm(inp);\n      $(disp1).html(t);\n      $(disp2).html(t);\n      $(inp).on('input', function () {\n        t = calc_dBm(inp);\n        $(disp1).html(t);\n        $(disp2).html(t);\n      });\n    });\n\n    // Forget STA credentials\n    $('#forget-sta').on('click', function () {\n      selectSta('', '', '');\n      return false;\n    });\n\n    selectSta(cfg.sta_ssid, cfg.sta_password, cfg.sta_active_ip);\n    curSSID = cfg.sta_active_ssid;\n  };\n\n  var w = window.WiFi = {};\n\n  var authTypes = ['Open', 'WEP', 'WPA', 'WPA2', 'WPA/WPA2'];\n  var curSSID = void 0;\n\n  w.init = wifiInit;\n  w.startScanning = startScanning;\n}\n\n/***/ }),\n/* 13 */\n/***/ (function(module, exports) {\n\n/* Generated language file */\nmodule.exports={\"wifi.connected_ip_is\":\"Connected, IP is \",\"wifi.not_conn\":\"Not connected.\",\"wifi.enter_passwd\":\"Enter password for \\\":ssid:\\\"\",\"term_nav.fullscreen\":\"Fullscreen\",\"term_conn.connecting\":\"Connecting\",\"term_conn.waiting_content\":\"Waiting for content\",\"term_conn.disconnected\":\"Disconnected\",\"term_conn.waiting_server\":\"Waiting for server\",\"term_conn.reconnecting\":\"Reconnecting\"}\n\n\n/***/ }),\n/* 14 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nfunction _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }\n\nvar _require = __webpack_require__(0),\n    qs = _require.qs,\n    mk = _require.mk;\n\nvar localize = __webpack_require__(8);\nvar Notify = __webpack_require__(3);\nvar TermScreen = __webpack_require__(15);\nvar TermConnection = __webpack_require__(18);\nvar TermInput = __webpack_require__(19);\nvar TermUpload = __webpack_require__(20);\nvar initSoftKeyboard = __webpack_require__(21);\nvar attachDebugScreen = __webpack_require__(22);\nvar initButtons = __webpack_require__(23);\n\n/** Init the terminal sub-module - called from HTML */\nmodule.exports = function (opts) {\n  var screen = new TermScreen();\n  var conn = new TermConnection(screen);\n  var input = TermInput(conn, screen);\n  var termUpload = TermUpload(conn, input, screen);\n  screen.input = input;\n  screen.conn = conn;\n  input.termUpload = termUpload;\n\n  var buttons = initButtons(input);\n  screen.on('button-labels', function (labels) {\n    var _buttons$labels;\n\n    // TODO: don't use pointers for this\n    (_buttons$labels = buttons.labels).splice.apply(_buttons$labels, [0, buttons.labels.length].concat(_toConsumableArray(labels)));\n    buttons.update();\n  });\n\n  var showSplashTimeout = null;\n  var showSplash = function showSplash(obj) {\n    var delay = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 250;\n\n    clearTimeout(showSplashTimeout);\n    showSplashTimeout = setTimeout(function () {\n      screen.window.statusScreen = obj;\n    }, delay);\n  };\n\n  conn.on('open', function () {\n    // console.log('*open')\n    showSplash({ title: localize('term_conn.connecting'), loading: true });\n  });\n  conn.on('connect', function () {\n    // console.log('*connect')\n    showSplash({ title: localize('term_conn.waiting_content'), loading: true });\n  });\n  conn.on('load', function () {\n    // console.log('*load')\n    clearTimeout(showSplashTimeout);\n    if (screen.window.statusScreen) screen.window.statusScreen = null;\n  });\n  conn.on('disconnect', function () {\n    // console.log('*disconnect')\n    showSplash({ title: localize('term_conn.disconnected') }, 500);\n    screen.screen = [];\n    screen.screenFG = [];\n    screen.screenBG = [];\n    screen.screenAttrs = [];\n  });\n  conn.on('silence', function () {\n    // console.log('*silence')\n    showSplash({ title: localize('term_conn.waiting_server'), loading: true }, 0);\n  });\n  // conn.on('ping-fail', () => { screen.window.statusScreen = { title: 'Disconnected' } })\n  conn.on('ping-success', function () {\n    // console.log('*ping-success')\n    showSplash({ title: localize('term_conn.reconnecting'), loading: true }, 0);\n  });\n\n  conn.init();\n  input.init(opts);\n  termUpload.init();\n  Notify.init();\n\n  window.onerror = function (errorMsg, file, line, col) {\n    Notify.show('<b>JS ERROR!</b><br>' + errorMsg + '<br>at ' + file + ':' + line + ':' + col, 10000, true);\n    return false;\n  };\n\n  qs('#screen').appendChild(screen.canvas);\n\n  initSoftKeyboard(screen, input);\n  if (attachDebugScreen) attachDebugScreen(screen);\n\n  var fullscreenIcon = {}; // dummy\n  var isFullscreen = false;\n  var properFullscreen = false;\n  var fitScreen = false;\n  var screenPadding = screen.window.padding;\n  var fitScreenIfNeeded = function fitScreenIfNeeded() {\n    if (isFullscreen) {\n      fullscreenIcon.className = 'icn-resize-small';\n      if (properFullscreen) {\n        screen.window.fitIntoWidth = window.screen.width;\n        screen.window.fitIntoHeight = window.screen.height;\n        screen.window.padding = 0;\n      } else {\n        screen.window.fitIntoWidth = window.innerWidth;\n        if (qs('#term-nav').classList.contains('hidden')) {\n          screen.window.fitIntoHeight = window.innerHeight;\n        } else {\n          screen.window.fitIntoHeight = window.innerHeight - 24;\n        }\n        screen.window.padding = 0;\n      }\n    } else {\n      fullscreenIcon.className = 'icn-resize-full';\n      screen.window.fitIntoWidth = fitScreen ? window.innerWidth - 4 : 0;\n      screen.window.fitIntoHeight = fitScreen ? window.innerHeight : 0;\n      screen.window.padding = screenPadding;\n    }\n  };\n  fitScreenIfNeeded();\n  window.addEventListener('resize', fitScreenIfNeeded);\n\n  var toggleFitScreen = function toggleFitScreen() {\n    fitScreen = !fitScreen;\n    var resizeButtonIcon = qs('#resize-button-icon');\n    if (fitScreen) {\n      resizeButtonIcon.classList.remove('icn-resize-small');\n      resizeButtonIcon.classList.add('icn-resize-full');\n    } else {\n      resizeButtonIcon.classList.remove('icn-resize-full');\n      resizeButtonIcon.classList.add('icn-resize-small');\n    }\n    fitScreenIfNeeded();\n  };\n\n  qs('#term-fit-screen').addEventListener('click', function () {\n    toggleFitScreen();\n    return false;\n  });\n\n  // add fullscreen mode & button\n  if (window.Element.prototype.requestFullscreen || window.Element.prototype.webkitRequestFullscreen) {\n    properFullscreen = true;\n\n    var checkForFullscreen = function checkForFullscreen() {\n      // document.fullscreenElement is not really supported yet, so here's a hack\n      if (isFullscreen && (window.innerWidth !== window.screen.width || window.innerHeight !== window.screen.height)) {\n        isFullscreen = false;\n        fitScreenIfNeeded();\n      }\n    };\n    setInterval(checkForFullscreen, 500);\n  }\n\n  // (why are the buttons anchors?)\n  var button = mk('a');\n  button.id = 'fullscreen-button';\n  button.href = '#';\n  button.addEventListener('click', function (e) {\n    e.preventDefault();\n\n    if (document.body.classList.contains('pseudo-fullscreen')) {\n      document.body.classList.remove('pseudo-fullscreen');\n      isFullscreen = false;\n      fitScreenIfNeeded();\n      return;\n    }\n\n    isFullscreen = true;\n    fitScreenIfNeeded();\n    screen.updateSize();\n\n    if (properFullscreen) {\n      if (screen.canvas.requestFullscreen) screen.canvas.requestFullscreen();else screen.canvas.webkitRequestFullscreen();\n    } else {\n      document.body.classList.add('pseudo-fullscreen');\n    }\n  });\n  fullscreenIcon = mk('i');\n  fullscreenIcon.className = 'icn-resize-full';\n  button.appendChild(fullscreenIcon);\n  var span = mk('span');\n  span.textContent = localize('term_nav.fullscreen');\n  button.appendChild(span);\n  qs('#term-nav').insertBefore(button, qs('#term-nav').firstChild);\n\n  // for debugging\n  window.termScreen = screen;\n  window.conn = conn;\n  window.input = input;\n  window.termUpl = termUpload;\n};\n\n/***/ }),\n/* 15 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nvar _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();\n\nfunction _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return call && (typeof call === \"object\" || typeof call === \"function\") ? call : self; }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function, not \" + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }\n\nvar EventEmitter = __webpack_require__(4);\nvar $ = __webpack_require__(1);\n\nvar _require = __webpack_require__(0),\n    mk = _require.mk,\n    qs = _require.qs;\n\nvar notify = __webpack_require__(3);\nvar ScreenParser = __webpack_require__(16);\nvar ScreenRenderer = __webpack_require__(17);\n\nmodule.exports = function (_EventEmitter) {\n  _inherits(TermScreen, _EventEmitter);\n\n  function TermScreen() {\n    _classCallCheck(this, TermScreen);\n\n    var _this = _possibleConstructorReturn(this, (TermScreen.__proto__ || Object.getPrototypeOf(TermScreen)).call(this));\n\n    _this.canvas = mk('canvas');\n    _this.ctx = _this.canvas.getContext('2d');\n\n    _this.parser = new ScreenParser(_this);\n    _this.renderer = new ScreenRenderer(_this);\n\n    // debug screen handle\n    _this._debug = null;\n\n    if ('AudioContext' in window || 'webkitAudioContext' in window) {\n      _this.audioCtx = new (window.AudioContext || window.webkitAudioContext)();\n    } else {\n      console.warn('No AudioContext!');\n    }\n\n    // dummy. Handle for Input\n    _this.input = new Proxy({}, {\n      get: function get() {\n        return function () {\n          return console.warn('TermScreen#input not set!');\n        };\n      }\n    });\n    // dummy. Handle for Conn\n    _this.conn = new Proxy({}, {\n      get: function get() {\n        return function () {\n          return console.warn('TermScreen#conn not set!');\n        };\n      },\n      set: function set(a, b) {\n        return function () {\n          return console.warn('TermScreen#conn not set!');\n        };\n      }\n    });\n\n    _this.cursor = {\n      x: 0,\n      y: 0,\n      blinking: true,\n      visible: true,\n      hanging: false,\n      style: 'block'\n    };\n\n    _this._window = {\n      width: 0,\n      height: 0,\n      devicePixelRatio: 1,\n      fontFamily: '\"DejaVu Sans Mono\", \"Liberation Mono\", \"Inconsolata\", \"Menlo\", monospace',\n      fontSize: 20,\n      padding: 6,\n      gridScaleX: 1.0,\n      gridScaleY: 1.2,\n      fitIntoWidth: 0,\n      fitIntoHeight: 0,\n      debug: false,\n      graphics: 0,\n      statusScreen: null\n\n      // scaling caused by fitIntoWidth/fitIntoHeight\n    };_this._windowScale = 1;\n\n    // actual padding, as it may be disabled by fullscreen mode etc.\n    _this._padding = 0;\n\n    // properties of this.window that require updating size and redrawing\n    _this.windowState = {\n      width: 0,\n      height: 0,\n      devicePixelRatio: 0,\n      padding: 0,\n      gridScaleX: 0,\n      gridScaleY: 0,\n      fontFamily: '',\n      fontSize: 0,\n      fitIntoWidth: 0,\n      fitIntoHeight: 0\n\n      // current selection\n    };_this.selection = {\n      // when false, this will prevent selection in favor of mouse events,\n      // though alt can be held to override it\n      selectable: true,\n\n      // selection start and end (x, y) tuples\n      start: [0, 0],\n      end: [0, 0]\n\n      // mouse features\n    };_this.mouseMode = { clicks: false, movement: false\n\n      // make writing to window update size and draw\n    };var self = _this;\n    _this.window = new Proxy(_this._window, {\n      set: function set(target, key, value, receiver) {\n        if (target[key] !== value) {\n          target[key] = value;\n          self.scheduleSizeUpdate();\n          self.renderer.scheduleDraw('window:' + key + '=' + value);\n          self.emit('update-window:' + key, value);\n        }\n        return true;\n      }\n    });\n\n    _this.bracketedPaste = false;\n    _this.blinkingCellCount = 0;\n    _this.reverseVideo = false;\n\n    _this.screen = [];\n    _this.screenFG = [];\n    _this.screenBG = [];\n    _this.screenAttrs = [];\n\n    var selecting = false;\n\n    var selectStart = function selectStart(x, y) {\n      if (selecting) return;\n      selecting = true;\n      _this.selection.start = _this.selection.end = _this.screenToGrid(x, y, true);\n      _this.renderer.scheduleDraw('select-start');\n    };\n\n    var selectMove = function selectMove(x, y) {\n      if (!selecting) return;\n      _this.selection.end = _this.screenToGrid(x, y, true);\n      _this.renderer.scheduleDraw('select-move');\n    };\n\n    var selectEnd = function selectEnd(x, y) {\n      if (!selecting) return;\n      selecting = false;\n      _this.selection.end = _this.screenToGrid(x, y, true);\n      _this.renderer.scheduleDraw('select-end');\n      Object.assign(_this.selection, _this.getNormalizedSelection());\n    };\n\n    // bind event listeners\n\n    _this.canvas.addEventListener('mousedown', function (e) {\n      if ((_this.selection.selectable || e.altKey) && e.button === 0) {\n        selectStart(e.offsetX, e.offsetY);\n      } else {\n        var _this$input;\n\n        (_this$input = _this.input).onMouseDown.apply(_this$input, _toConsumableArray(_this.screenToGrid(e.offsetX, e.offsetY)).concat([e.button + 1]));\n      }\n    });\n\n    window.addEventListener('mousemove', function (e) {\n      selectMove(e.offsetX, e.offsetY);\n    });\n\n    window.addEventListener('mouseup', function (e) {\n      selectEnd(e.offsetX, e.offsetY);\n    });\n\n    // touch event listeners\n\n    var touchPosition = null;\n    var touchDownTime = 0;\n    var touchSelectMinTime = 500;\n    var touchDidMove = false;\n\n    var getTouchPositionOffset = function getTouchPositionOffset(touch) {\n      var rect = _this.canvas.getBoundingClientRect();\n      return [touch.clientX - rect.left, touch.clientY - rect.top];\n    };\n\n    _this.canvas.addEventListener('touchstart', function (e) {\n      touchPosition = getTouchPositionOffset(e.touches[0]);\n      touchDidMove = false;\n      touchDownTime = Date.now();\n    }, { passive: true });\n\n    _this.canvas.addEventListener('touchmove', function (e) {\n      touchPosition = getTouchPositionOffset(e.touches[0]);\n\n      if (!selecting && touchDidMove === false) {\n        if (touchDownTime < Date.now() - touchSelectMinTime) {\n          selectStart.apply(undefined, _toConsumableArray(touchPosition));\n        }\n      } else if (selecting) {\n        e.preventDefault();\n        selectMove.apply(undefined, _toConsumableArray(touchPosition));\n      }\n\n      touchDidMove = true;\n    });\n\n    _this.canvas.addEventListener('touchend', function (e) {\n      if (e.touches[0]) {\n        touchPosition = getTouchPositionOffset(e.touches[0]);\n      }\n\n      if (selecting) {\n        e.preventDefault();\n        selectEnd.apply(undefined, _toConsumableArray(touchPosition));\n\n        // selection ended; show touch select menu\n        var touchSelectMenu = qs('#touch-select-menu');\n        touchSelectMenu.classList.add('open');\n        var rect = touchSelectMenu.getBoundingClientRect();\n\n        // use middle position for x and one line above for y\n        var selectionPos = _this.gridToScreen((_this.selection.start[0] + _this.selection.end[0]) / 2, _this.selection.start[1] - 1);\n        selectionPos[0] -= rect.width / 2;\n        selectionPos[1] -= rect.height / 2;\n        touchSelectMenu.style.transform = 'translate(' + selectionPos[0] + 'px, ' + selectionPos[1] + 'px)';\n      }\n\n      if (!touchDidMove && !_this.mouseMode.clicks) {\n        _this.emit('tap', Object.assign(e, {\n          x: touchPosition[0],\n          y: touchPosition[1]\n        }));\n      }\n\n      touchPosition = null;\n    });\n\n    _this.on('tap', function (e) {\n      if (_this.selection.start[0] !== _this.selection.end[0] || _this.selection.start[1] !== _this.selection.end[1]) {\n        // selection is not empty\n        // reset selection\n        _this.selection.start = _this.selection.end = [0, 0];\n        qs('#touch-select-menu').classList.remove('open');\n        _this.renderer.scheduleDraw('select-reset');\n      } else {\n        e.preventDefault();\n        _this.emit('open-soft-keyboard');\n      }\n    });\n\n    $.ready(function () {\n      var copyButton = qs('#touch-select-copy-btn');\n      if (copyButton) {\n        copyButton.addEventListener('click', function () {\n          _this.copySelectionToClipboard();\n        });\n      }\n    });\n\n    _this.canvas.addEventListener('mousemove', function (e) {\n      if (!selecting) {\n        var _this$input2;\n\n        (_this$input2 = _this.input).onMouseMove.apply(_this$input2, _toConsumableArray(_this.screenToGrid(e.offsetX, e.offsetY)));\n      }\n    });\n\n    _this.canvas.addEventListener('mouseup', function (e) {\n      if (!selecting) {\n        var _this$input3;\n\n        (_this$input3 = _this.input).onMouseUp.apply(_this$input3, _toConsumableArray(_this.screenToGrid(e.offsetX, e.offsetY)).concat([e.button + 1]));\n      }\n    });\n\n    var aggregateWheelDelta = 0;\n    _this.canvas.addEventListener('wheel', function (e) {\n      if (_this.mouseMode.clicks) {\n        if (Math.abs(e.wheelDeltaY) === 120) {\n          var _this$input4;\n\n          // mouse wheel scrolling\n          (_this$input4 = _this.input).onMouseWheel.apply(_this$input4, _toConsumableArray(_this.screenToGrid(e.offsetX, e.offsetY)).concat([e.deltaY > 0 ? 1 : -1]));\n        } else {\n          // smooth scrolling\n          aggregateWheelDelta -= e.wheelDeltaY;\n          if (Math.abs(aggregateWheelDelta) >= 40) {\n            var _this$input5;\n\n            (_this$input5 = _this.input).onMouseWheel.apply(_this$input5, _toConsumableArray(_this.screenToGrid(e.offsetX, e.offsetY)).concat([aggregateWheelDelta > 0 ? 1 : -1]));\n            aggregateWheelDelta = 0;\n          }\n        }\n\n        // prevent page scrolling\n        e.preventDefault();\n      }\n    });\n\n    _this.canvas.addEventListener('contextmenu', function (e) {\n      if (_this.mouseMode.clicks) {\n        // prevent mouse keys getting stuck\n        e.preventDefault();\n      }\n      selectEnd(e.offsetX, e.offsetY);\n    });\n    return _this;\n  }\n\n  /**\n   * Schedule a size update in the next millisecond\n   */\n\n\n  _createClass(TermScreen, [{\n    key: 'scheduleSizeUpdate',\n    value: function scheduleSizeUpdate() {\n      var _this2 = this;\n\n      clearTimeout(this._scheduledSizeUpdate);\n      this._scheduledSizeUpdate = setTimeout(function () {\n        return _this2.updateSize();\n      }, 1);\n    }\n\n    /**\n     * Returns a CSS font string with this TermScreen's font settings and the\n     * font modifiers.\n     * @param {Object} modifiers\n     * @param {string} [modifiers.style] - the font style\n     * @param {string} [modifiers.weight] - the font weight\n     * @returns {string} a CSS font string\n     */\n\n  }, {\n    key: 'getFont',\n    value: function getFont() {\n      var modifiers = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n\n      var fontStyle = modifiers.style || 'normal';\n      var fontWeight = modifiers.weight || 'normal';\n      return fontStyle + ' normal ' + fontWeight + ' ' + this.window.fontSize + 'px ' + this.window.fontFamily;\n    }\n\n    /**\n     * Converts screen coordinates to grid coordinates.\n     * @param {number} x - x in pixels\n     * @param {number} y - y in pixels\n     * @param {boolean} rounded - whether to round the coord, used for select highlighting\n     * @returns {number[]} a tuple of (x, y) in cells\n     */\n\n  }, {\n    key: 'screenToGrid',\n    value: function screenToGrid(x, y) {\n      var rounded = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;\n\n      var cellSize = this.getCellSize();\n\n      x = x / this._windowScale - this._padding;\n      y = y / this._windowScale - this._padding;\n      x = Math.floor((x + (rounded ? cellSize.width / 2 : 0)) / cellSize.width);\n      y = Math.floor(y / cellSize.height);\n      x = Math.max(0, Math.min(this.window.width - 1, x));\n      y = Math.max(0, Math.min(this.window.height - 1, y));\n\n      return [x, y];\n    }\n\n    /**\n     * Converts grid coordinates to screen coordinates.\n     * @param {number} x - x in cells\n     * @param {number} y - y in cells\n     * @param {boolean} [withScale] - when true, will apply window scale\n     * @returns {number[]} a tuple of (x, y) in pixels\n     */\n\n  }, {\n    key: 'gridToScreen',\n    value: function gridToScreen(x, y) {\n      var _this3 = this;\n\n      var withScale = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;\n\n      var cellSize = this.getCellSize();\n\n      return [x * cellSize.width, y * cellSize.height].map(function (v) {\n        return _this3._padding + (withScale ? v * _this3._windowScale : v);\n      });\n    }\n\n    /**\n     * The character size, used for calculating the cell size. The space character\n     * is used for measuring.\n     * @returns {Object} the character size with `width` and `height` in pixels\n     */\n\n  }, {\n    key: 'getCharSize',\n    value: function getCharSize() {\n      this.ctx.font = this.getFont();\n\n      return {\n        width: Math.floor(this.ctx.measureText(' ').width),\n        height: this.window.fontSize\n      };\n    }\n\n    /**\n     * The cell size, which is the character size multiplied by the grid scale.\n     * @returns {Object} the cell size with `width` and `height` in pixels\n     */\n\n  }, {\n    key: 'getCellSize',\n    value: function getCellSize() {\n      var charSize = this.getCharSize();\n\n      return {\n        width: Math.ceil(charSize.width * this.window.gridScaleX),\n        height: Math.ceil(charSize.height * this.window.gridScaleY)\n      };\n    }\n\n    /**\n     * Updates the canvas size if it changed\n     */\n\n  }, {\n    key: 'updateSize',\n    value: function updateSize() {\n      // see below (this is just updating it)\n      this._window.devicePixelRatio = Math.ceil(this._windowScale * (window.devicePixelRatio || 1));\n\n      var didChange = false;\n      for (var key in this.windowState) {\n        if (this.windowState.hasOwnProperty(key) && this.windowState[key] !== this.window[key]) {\n          didChange = true;\n          this.windowState[key] = this.window[key];\n        }\n      }\n\n      if (didChange) {\n        var _window = this.window,\n            width = _window.width,\n            height = _window.height,\n            fitIntoWidth = _window.fitIntoWidth,\n            fitIntoHeight = _window.fitIntoHeight,\n            padding = _window.padding;\n\n        var cellSize = this.getCellSize();\n\n        // real height of the canvas element in pixels\n        var realWidth = width * cellSize.width;\n        var realHeight = height * cellSize.height;\n        var originalWidth = realWidth;\n\n        if (fitIntoWidth && fitIntoHeight) {\n          var terminalAspect = realWidth / realHeight;\n          var fitAspect = fitIntoWidth / fitIntoHeight;\n\n          if (terminalAspect < fitAspect) {\n            // align heights\n            realHeight = fitIntoHeight - 2 * padding;\n            realWidth = realHeight * terminalAspect;\n          } else {\n            // align widths\n            realWidth = fitIntoWidth - 2 * padding;\n            realHeight = realWidth / terminalAspect;\n          }\n        }\n\n        // store new window scale\n        this._windowScale = realWidth / originalWidth;\n\n        realWidth += 2 * padding;\n        realHeight += 2 * padding;\n\n        // store padding\n        this._padding = padding * (originalWidth / realWidth);\n\n        // the DPR must be rounded to a very nice value to prevent gaps between cells\n        var devicePixelRatio = this._window.devicePixelRatio = Math.ceil(this._windowScale * (window.devicePixelRatio || 1));\n\n        this.canvas.width = (width * cellSize.width + 2 * Math.round(this._padding)) * devicePixelRatio;\n        this.canvas.style.width = realWidth + 'px';\n        this.canvas.height = (height * cellSize.height + 2 * Math.round(this._padding)) * devicePixelRatio;\n        this.canvas.style.height = realHeight + 'px';\n\n        // the screen has been cleared (by changing canvas width)\n        this.renderer.resetDrawn();\n\n        // draw immediately; the canvas shouldn't flash\n        this.renderer.draw('update-size');\n      }\n    }\n\n    /**\n     * Returns a normalized version of the current selection, such that `start`\n     * is always before `end`.\n     * @returns {Object} the normalized selection, with `start` and `end`\n     */\n\n  }, {\n    key: 'getNormalizedSelection',\n    value: function getNormalizedSelection() {\n      var _selection = this.selection,\n          start = _selection.start,\n          end = _selection.end;\n      // if the start line is after the end line, or if they're both on the same\n      // line but the start column comes after the end column, swap\n\n      if (start[1] > end[1] || start[1] === end[1] && start[0] > end[0]) {\n        var _ref = [end, start];\n        start = _ref[0];\n        end = _ref[1];\n      }\n      return { start: start, end: end };\n    }\n\n    /**\n     * Returns whether or not a given cell is in the current selection.\n     * @param {number} col - the column (x)\n     * @param {number} line - the line (y)\n     * @returns {boolean}\n     */\n\n  }, {\n    key: 'isInSelection',\n    value: function isInSelection(col, line) {\n      var _getNormalizedSelecti = this.getNormalizedSelection(),\n          start = _getNormalizedSelecti.start,\n          end = _getNormalizedSelecti.end;\n\n      var colAfterStart = start[0] <= col;\n      var colBeforeEnd = col < end[0];\n      var onStartLine = line === start[1];\n      var onEndLine = line === end[1];\n\n      if (onStartLine && onEndLine) return colAfterStart && colBeforeEnd;else if (onStartLine) return colAfterStart;else if (onEndLine) return colBeforeEnd;else return start[1] < line && line < end[1];\n    }\n\n    /**\n     * Sweeps for selected cells and joins them in a multiline string.\n     * @returns {string} the selection\n     */\n\n  }, {\n    key: 'getSelectedText',\n    value: function getSelectedText() {\n      var screenLength = this.window.width * this.window.height;\n      var lines = [];\n      var previousLineIndex = -1;\n\n      for (var cell = 0; cell < screenLength; cell++) {\n        var x = cell % this.window.width;\n        var y = Math.floor(cell / this.window.width);\n\n        if (this.isInSelection(x, y)) {\n          if (previousLineIndex !== y) {\n            previousLineIndex = y;\n            lines.push('');\n          }\n          lines[lines.length - 1] += this.screen[cell];\n        }\n      }\n\n      return lines.join('\\n');\n    }\n\n    /**\n     * Copies the selection to clipboard and creates a notification balloon.\n     */\n\n  }, {\n    key: 'copySelectionToClipboard',\n    value: function copySelectionToClipboard() {\n      var selectedText = this.getSelectedText();\n      // don't copy anything if nothing is selected\n      if (!selectedText) return;\n      var textarea = mk('textarea');\n      document.body.appendChild(textarea);\n      textarea.value = selectedText;\n      textarea.select();\n      if (document.execCommand('copy')) {\n        notify.show('Copied to clipboard');\n      } else {\n        notify.show('Failed to copy');\n      }\n      document.body.removeChild(textarea);\n    }\n\n    /**\n     * Shows an actual notification (if possible) or a notification balloon.\n     * @param {string} text - the notification content\n     */\n\n  }, {\n    key: 'showNotification',\n    value: function showNotification(text) {\n      console.info('Notification: ' + text);\n      if (window.Notification && window.Notification.permission === 'granted') {\n        var notification = new window.Notification('ESPTerm', {\n          body: text\n        });\n        notification.addEventListener('click', function () {\n          return window.focus();\n        });\n      } else {\n        if (window.Notification && window.Notification.permission !== 'denied') {\n          window.Notification.requestPermission();\n        } else {\n          // Fallback using the built-in notification balloon\n          notify.show(text);\n        }\n      }\n    }\n\n    /**\n     * Creates a beep sound.\n     */\n\n  }, {\n    key: 'beep',\n    value: function beep() {\n      var audioCtx = this.audioCtx;\n      if (!audioCtx) return;\n\n      // prevent screeching\n      if (this._lastBeep && this._lastBeep > Date.now() - 50) return;\n      this._lastBeep = Date.now();\n\n      if (!this._convolver) {\n        this._convolver = audioCtx.createConvolver();\n        var impulseLength = audioCtx.sampleRate * 0.8;\n        var impulse = audioCtx.createBuffer(2, impulseLength, audioCtx.sampleRate);\n        for (var i = 0; i < impulseLength; i++) {\n          impulse.getChannelData(0)[i] = Math.pow(1 - i / impulseLength, 7 + Math.random());\n          impulse.getChannelData(1)[i] = Math.pow(1 - i / impulseLength, 7 + Math.random());\n        }\n        this._convolver.buffer = impulse;\n        this._convolver.connect(audioCtx.destination);\n      }\n\n      // main beep\n      var mainOsc = audioCtx.createOscillator();\n      var mainGain = audioCtx.createGain();\n      mainOsc.connect(mainGain);\n      mainGain.gain.value = 4;\n      mainOsc.frequency.value = 750;\n      mainOsc.type = 'sine';\n\n      // surrogate beep (making it sound like 'oops')\n      var surrOsc = audioCtx.createOscillator();\n      var surrGain = audioCtx.createGain();\n      surrOsc.connect(surrGain);\n      surrGain.gain.value = 2;\n      surrOsc.frequency.value = 400;\n      surrOsc.type = 'sine';\n\n      mainGain.connect(this._convolver);\n      surrGain.connect(this._convolver);\n\n      var startTime = audioCtx.currentTime;\n      mainOsc.start();\n      mainOsc.stop(startTime + 0.5);\n      surrOsc.start(startTime + 0.05);\n      surrOsc.stop(startTime + 0.8);\n\n      var loop = function loop() {\n        if (audioCtx.currentTime < startTime + 0.8) window.requestAnimationFrame(loop);\n        mainGain.gain.value *= 0.8;\n        surrGain.gain.value *= 0.8;\n      };\n      loop();\n    }\n  }, {\n    key: 'load',\n    value: function load() {\n      var _parser;\n\n      (_parser = this.parser).load.apply(_parser, arguments);\n    }\n  }]);\n\n  return TermScreen;\n}(EventEmitter);\n\n/***/ }),\n/* 16 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nvar _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nvar $ = __webpack_require__(1);\n\nvar _require = __webpack_require__(0),\n    qs = _require.qs;\n\n// constants for decoding the update blob\n\n\nvar SEQ_SKIP = 1;\nvar SEQ_REPEAT = 2;\nvar SEQ_SET_COLORS = 3;\nvar SEQ_SET_ATTRS = 4;\nvar SEQ_SET_FG = 5;\nvar SEQ_SET_BG = 6;\nvar SEQ_SET_ATTR_0 = 7;\n\nfunction du(str) {\n  var num = str.codePointAt(0);\n  if (num > 0xDFFF) num -= 0x800;\n  return num - 1;\n}\n\n/* eslint-disable no-multi-spaces */\nvar TOPIC_SCREEN_OPTS = 'O';\nvar TOPIC_CONTENT = 'S';\nvar TOPIC_TITLE = 'T';\nvar TOPIC_BUTTONS = 'B';\nvar TOPIC_CURSOR = 'C';\nvar TOPIC_INTERNAL = 'D';\nvar TOPIC_BELL = '!';\n\nvar OPT_CURSOR_VISIBLE = 1 << 0;\nvar OPT_DEBUGBAR = 1 << 1;\nvar OPT_CURSORS_ALT_MODE = 1 << 2;\nvar OPT_NUMPAD_ALT_MODE = 1 << 3;\nvar OPT_FN_ALT_MODE = 1 << 4;\nvar OPT_CLICK_TRACKING = 1 << 5;\nvar OPT_MOVE_TRACKING = 1 << 6;\nvar OPT_SHOW_BUTTONS = 1 << 7;\nvar OPT_SHOW_CONFIG_LINKS = 1 << 8;\n// const OPT_CURSOR_SHAPE   = (7 << 9)\nvar OPT_CRLF_MODE = 1 << 12;\nvar OPT_BRACKETED_PASTE = 1 << 13;\nvar OPT_REVERSE_VIDEO = 1 << 14;\n\nvar ATTR_FG = 1 << 0; // 1 if not using default background color (ignore cell bg) - color extension bit\nvar ATTR_BG = 1 << 1; // 1 if not using default foreground color (ignore cell fg) - color extension bit\nvar ATTR_BOLD = 1 << 2; // Bold font\nvar ATTR_UNDERLINE = 1 << 3; // Underline decoration\nvar ATTR_INVERSE = 1 << 4; // Invert colors - this is useful so we can clear then with SGR manipulation commands\nvar ATTR_BLINK = 1 << 5; // Blinking\nvar ATTR_ITALIC = 1 << 6; // Italic font\nvar ATTR_STRIKE = 1 << 7; // Strike-through decoration\nvar ATTR_OVERLINE = 1 << 8; // Over-line decoration\nvar ATTR_FAINT = 1 << 9; // Faint foreground color (reduced alpha)\nvar ATTR_FRAKTUR = 1 << 10; // Fraktur font (unicode substitution)\n/* eslint-enable no-multi-spaces */\n\nmodule.exports = function () {\n  function ScreenParser(screen) {\n    _classCallCheck(this, ScreenParser);\n\n    this.screen = screen;\n\n    // true if TermScreen#load was called at least once\n    this.contentLoaded = false;\n  }\n\n  /**\n   * Hide the warning message about failed data load\n   */\n\n\n  _createClass(ScreenParser, [{\n    key: 'hideLoadFailedMsg',\n    value: function hideLoadFailedMsg() {\n      if (!this.contentLoaded) {\n        var errmsg = qs('#load-failed');\n        if (errmsg) errmsg.parentNode.removeChild(errmsg);\n        this.contentLoaded = true;\n      }\n    }\n  }, {\n    key: 'loadUpdate',\n    value: function loadUpdate(str) {\n      var _this = this;\n\n      // console.log(`update ${str}`)\n      // current index\n      var ci = 0;\n      var strArray = Array.from ? Array.from(str) : str.split('');\n\n      var text = void 0;\n      var resized = false;\n      var topics = du(strArray[ci++]);\n      // this.screen.cursor.hanging = !!(attributes & (1 << 1))\n\n      while (ci < strArray.length) {\n        var topic = strArray[ci++];\n\n        if (topic === TOPIC_SCREEN_OPTS) {\n          var newHeight = du(strArray[ci++]);\n          var newWidth = du(strArray[ci++]);\n          var theme = du(strArray[ci++]);\n          var defFg = du(strArray[ci++]) & 0xFFFF | (du(strArray[ci++]) & 0xFFFF) << 16;\n          var defBg = du(strArray[ci++]) & 0xFFFF | (du(strArray[ci++]) & 0xFFFF) << 16;\n          var attributes = du(strArray[ci++]);\n\n          // theming\n          this.screen.renderer.loadTheme(theme);\n          this.screen.renderer.setDefaultColors(defFg, defBg);\n\n          // apply size\n          resized = this.screen.window.height !== newHeight || this.screen.window.width !== newWidth;\n          this.screen.window.height = newHeight;\n          this.screen.window.width = newWidth;\n\n          // process attributes\n          this.screen.cursor.visible = !!(attributes & OPT_CURSOR_VISIBLE);\n\n          this.screen.input.setAlts(!!(attributes & OPT_CURSORS_ALT_MODE), !!(attributes & OPT_NUMPAD_ALT_MODE), !!(attributes & OPT_FN_ALT_MODE), !!(attributes & OPT_CRLF_MODE));\n\n          var trackMouseClicks = !!(attributes & OPT_CLICK_TRACKING);\n          var trackMouseMovement = !!(attributes & OPT_MOVE_TRACKING);\n\n          // 0 - Block blink     2 - Block steady (1 is unused)\n          // 3 - Underline blink 4 - Underline steady\n          // 5 - I-bar blink     6 - I-bar steady\n          var cursorShape = attributes >> 9 & 0x07;\n          // if it's not zero, decrement such that the two most significant bits\n          // are the type and the least significant bit is the blink state\n          if (cursorShape > 0) cursorShape--;\n          var cursorStyle = cursorShape >> 1;\n          var cursorBlinking = !(cursorShape & 1);\n          if (cursorStyle === 0) this.screen.cursor.style = 'block';else if (cursorStyle === 1) this.screen.cursor.style = 'line';else if (cursorStyle === 2) this.screen.cursor.style = 'bar';\n          if (this.screen.cursor.blinking !== cursorBlinking) {\n            this.screen.cursor.blinking = cursorBlinking;\n            this.screen.renderer.resetCursorBlink();\n          }\n\n          this.screen.input.setMouseMode(trackMouseClicks, trackMouseMovement);\n          this.screen.selection.selectable = !trackMouseClicks && !trackMouseMovement;\n          $(this.screen.canvas).toggleClass('selectable', this.screen.selection.selectable);\n          this.screen.mouseMode = {\n            clicks: trackMouseClicks,\n            movement: trackMouseMovement\n          };\n\n          var showButtons = !!(attributes & OPT_SHOW_BUTTONS);\n          var showConfigLinks = !!(attributes & OPT_SHOW_CONFIG_LINKS);\n\n          $('.x-term-conf-btn').toggleClass('hidden', !showConfigLinks);\n          $('#action-buttons').toggleClass('hidden', !showButtons);\n\n          this.screen.bracketedPaste = !!(attributes & OPT_BRACKETED_PASTE);\n          this.screen.reverseVideo = !!(attributes & OPT_REVERSE_VIDEO);\n\n          var debugbar = !!(attributes & OPT_DEBUGBAR);\n          // TODO do something with debugbar\n        } else if (topic === TOPIC_CURSOR) {\n\n          // cursor position\n          var cursorY = du(strArray[ci++]);\n          var cursorX = du(strArray[ci++]);\n          var hanging = du(strArray[ci++]);\n\n          var cursorMoved = hanging !== this.screen.cursor.hanging || cursorX !== this.screen.cursor.x || cursorY !== this.screen.cursor.y;\n\n          this.screen.cursor.x = cursorX;\n          this.screen.cursor.y = cursorY;\n\n          this.screen.cursor.hanging = !!hanging;\n\n          if (cursorMoved) {\n            this.screen.renderer.resetCursorBlink();\n            this.screen.emit('cursor-moved');\n          }\n\n          this.screen.renderer.scheduleDraw('cursor-moved');\n        } else if (topic === TOPIC_TITLE) {\n\n          // TODO optimize this\n          text = '';\n          while (ci < strArray.length) {\n            var c = strArray[ci++];\n            if (c !== '\\x01') {\n              text += c;\n            } else {\n              break;\n            }\n          }\n\n          qs('#screen-title').textContent = text;\n          if (text.length === 0) text = 'Terminal';\n          qs('title').textContent = text + ' :: ESPTerm';\n        } else if (topic === TOPIC_BUTTONS) {\n          var count = du(strArray[ci++]);\n\n          var labels = [];\n          for (var j = 0; j < count; j++) {\n            text = '';\n            while (ci < strArray.length) {\n              var _c = strArray[ci++];\n              if (_c === '\\x01') break;\n              text += _c;\n            }\n            labels.push(text);\n          }\n\n          this.screen.emit('button-labels', labels);\n        } else if (topic === TOPIC_BELL) {\n\n          this.screen.beep();\n        } else if (topic === TOPIC_INTERNAL) {\n          // debug info\n\n          var flags = du(strArray[ci++]);\n          var cursorAttrs = du(strArray[ci++]);\n          var regionStart = du(strArray[ci++]);\n          var regionEnd = du(strArray[ci++]);\n          var charsetGx = du(strArray[ci++]);\n          var charsetG0 = strArray[ci++];\n          var charsetG1 = strArray[ci++];\n          var freeHeap = du(strArray[ci++]);\n          var clientCount = du(strArray[ci++]);\n\n          this.screen.emit('internal', {\n            flags: flags,\n            cursorAttrs: cursorAttrs,\n            regionStart: regionStart,\n            regionEnd: regionEnd,\n            charsetGx: charsetGx,\n            charsetG0: charsetG0,\n            charsetG1: charsetG1,\n            freeHeap: freeHeap,\n            clientCount: clientCount\n          });\n        } else if (topic === TOPIC_CONTENT) {\n          (function () {\n            // set screen content\n\n            var frameY = du(strArray[ci++]);\n            var frameX = du(strArray[ci++]);\n            var frameHeight = du(strArray[ci++]);\n            var frameWidth = du(strArray[ci++]);\n\n            if (_this.screen._debug && _this.screen.window.debug) {\n              _this.screen._debug.pushFrame([frameX, frameY, frameWidth, frameHeight]);\n            }\n\n            // content\n            var fg = 7;\n            var bg = 0;\n            var attrs = 0;\n            var cell = 0; // cell index\n            var lastChar = ' ';\n            var frameLength = frameWidth * frameHeight;\n            var screenLength = _this.screen.window.width * _this.screen.window.height;\n\n            if (resized) {\n              _this.screen.updateSize();\n              _this.screen.blinkingCellCount = 0;\n              _this.screen.screen = new Array(screenLength).fill(' ');\n              _this.screen.screenFG = new Array(screenLength).fill(' ');\n              _this.screen.screenBG = new Array(screenLength).fill(' ');\n              _this.screen.screenAttrs = new Array(screenLength).fill(0);\n            }\n\n            var MASK_LINE_ATTR = ATTR_UNDERLINE | ATTR_OVERLINE | ATTR_STRIKE;\n            var MASK_BLINK = ATTR_BLINK;\n\n            var pushCell = function pushCell() {\n              // Remove blink attribute if it wouldn't have any effect\n              var myAttrs = attrs;\n              var hasFG = attrs & ATTR_FG;\n              var hasBG = attrs & ATTR_BG;\n              var cellFG = fg;\n              var cellBG = bg;\n\n              // use 0,0 if no fg/bg. this is to match back-end implementation\n              // and allow leaving out fg/bg setting for cells with none\n              if (!hasFG) cellFG = 0;\n              if (!hasBG) cellBG = 0;\n\n              if ((myAttrs & MASK_BLINK) !== 0 && (lastChar === ' ' && (myAttrs & MASK_LINE_ATTR) === 0 || // no line styles\n              fg === bg && hasFG && hasBG // invisible text\n              )) {\n                myAttrs ^= MASK_BLINK;\n              }\n              // update blinking cells counter if blink state changed\n              if ((_this.screen.screenAttrs[cell] & MASK_BLINK) !== (myAttrs & MASK_BLINK)) {\n                if (myAttrs & MASK_BLINK) _this.screen.blinkingCellCount++;else _this.screen.blinkingCellCount--;\n              }\n\n              var cellXInFrame = cell % frameWidth;\n              var cellYInFrame = Math.floor(cell / frameWidth);\n              var index = (frameY + cellYInFrame) * _this.screen.window.width + frameX + cellXInFrame;\n\n              // 8 dark system colors turn bright when bold\n              if (myAttrs & ATTR_BOLD && !(myAttrs & ATTR_FAINT) && hasFG && cellFG < 8) {\n                cellFG += 8;\n              }\n\n              _this.screen.screen[index] = lastChar;\n              _this.screen.screenFG[index] = cellFG;\n              _this.screen.screenBG[index] = cellBG;\n              _this.screen.screenAttrs[index] = myAttrs;\n            };\n\n            while (ci < strArray.length && cell < frameLength) {\n              var character = strArray[ci++];\n              var charCode = character.codePointAt(0);\n\n              var data = void 0,\n                  _count = void 0;\n              switch (charCode) {\n                case SEQ_REPEAT:\n                  _count = du(strArray[ci++]);\n                  for (var _j = 0; _j < _count; _j++) {\n                    pushCell();\n                    if (++cell > frameLength) break;\n                  }\n                  break;\n\n                case SEQ_SKIP:\n                  cell += du(strArray[ci++]);\n                  break;\n\n                case SEQ_SET_COLORS:\n                  data = du(strArray[ci++]);\n                  fg = data & 0xFF;\n                  bg = data >> 8 & 0xFF;\n                  break;\n\n                case SEQ_SET_ATTRS:\n                  data = du(strArray[ci++]);\n                  attrs = data & 0xFFFF;\n                  break;\n\n                case SEQ_SET_ATTR_0:\n                  attrs = 0;\n                  break;\n\n                case SEQ_SET_FG:\n                  data = du(strArray[ci++]);\n                  if (data & 0x10000) {\n                    data &= 0xFFF;\n                    data |= (du(strArray[ci++]) & 0xFFF) << 12;\n                    data += 256;\n                  }\n                  fg = data;\n                  break;\n\n                case SEQ_SET_BG:\n                  data = du(strArray[ci++]);\n                  if (data & 0x10000) {\n                    data &= 0xFFF;\n                    data |= (du(strArray[ci++]) & 0xFFF) << 12;\n                    data += 256;\n                  }\n                  bg = data;\n                  break;\n\n                default:\n                  if (charCode < 32) character = '\\uFFFD';\n                  lastChar = character;\n                  pushCell();\n                  cell++;\n              }\n            }\n\n            if (_this.screen.window.debug) console.log('Blinky cells: ' + _this.screen.blinkingCellCount);\n\n            _this.screen.renderer.scheduleDraw('load', 16);\n            _this.screen.conn.emit('load');\n          })();\n        }\n\n        if ((topics & 0x3B) !== 0) this.hideLoadFailedMsg();\n      }\n    }\n\n    /**\n     * Loads a message from the server, and optionally a theme.\n     * @param {string} str - the message\n     */\n\n  }, {\n    key: 'load',\n    value: function load(str) {\n      var content = str.substr(1);\n\n      // This is a good place for debugging the message\n      // console.log(str)\n\n      switch (str[0]) {\n        case 'U':\n          this.loadUpdate(content);\n          break;\n\n        case 'G':\n          this.screen.showNotification(content);\n          break;\n\n        default:\n          console.warn('Bad data message type; ignoring.\\n' + JSON.stringify(str));\n      }\n    }\n  }]);\n\n  return ScreenParser;\n}();\n\n/***/ }),\n/* 17 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nvar _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nvar _require = __webpack_require__(5),\n    themes = _require.themes,\n    buildColorTable = _require.buildColorTable,\n    SELECTION_FG = _require.SELECTION_FG,\n    SELECTION_BG = _require.SELECTION_BG;\n\n// Some non-bold Fraktur symbols are outside the contiguous block\n\n\nvar frakturExceptions = {\n  'C': '\\u212D',\n  'H': '\\u210C',\n  'I': '\\u2111',\n  'R': '\\u211C',\n  'Z': '\\u2128'\n\n  // TODO do not repeat - this is also defined in screen_parser ...\n  /* eslint-disable no-multi-spaces */\n};var ATTR_FG = 1 << 0; // 1 if not using default background color (ignore cell bg) - color extension bit\nvar ATTR_BG = 1 << 1; // 1 if not using default foreground color (ignore cell fg) - color extension bit\nvar ATTR_BOLD = 1 << 2; // Bold font\nvar ATTR_UNDERLINE = 1 << 3; // Underline decoration\nvar ATTR_INVERSE = 1 << 4; // Invert colors - this is useful so we can clear then with SGR manipulation commands\nvar ATTR_BLINK = 1 << 5; // Blinking\nvar ATTR_ITALIC = 1 << 6; // Italic font\nvar ATTR_STRIKE = 1 << 7; // Strike-through decoration\nvar ATTR_OVERLINE = 1 << 8; // Over-line decoration\nvar ATTR_FAINT = 1 << 9; // Faint foreground color (reduced alpha)\nvar ATTR_FRAKTUR = 1 << 10; // Fraktur font (unicode substitution)\n/* eslint-enable no-multi-spaces */\n\nmodule.exports = function () {\n  function ScreenRenderer(screen) {\n    _classCallCheck(this, ScreenRenderer);\n\n    this.screen = screen;\n    this.ctx = screen.ctx;\n\n    this._palette = null; // colors 0-15\n    this.defaultBgNum = 0;\n    this.defaultFgNum = 7;\n\n    // 256color lookup table\n    // should not be used to look up 0-15 (will return transparent)\n    this.colorTable256 = buildColorTable();\n\n    this.resetDrawn();\n\n    this.blinkStyleOn = false;\n    this.blinkInterval = null;\n    this.cursorBlinkOn = false;\n    this.cursorBlinkInterval = null;\n\n    // start blink timers\n    this.resetBlink();\n    this.resetCursorBlink();\n  }\n\n  _createClass(ScreenRenderer, [{\n    key: 'resetDrawn',\n    value: function resetDrawn() {\n      // used to determine if a cell should be redrawn; storing the current state\n      // as it is on screen\n      if (this.screen.window && this.screen.window.debug) {\n        console.log('Resetting drawn screen');\n      }\n      this.drawnScreen = [];\n      this.drawnScreenFG = [];\n      this.drawnScreenBG = [];\n      this.drawnScreenAttrs = [];\n      this.drawnCursor = [-1, -1, ''];\n    }\n\n    /**\n     * The color palette. Should define 16 colors in an array.\n     * @type {string[]}\n     */\n\n  }, {\n    key: 'loadTheme',\n    value: function loadTheme(i) {\n      if (i in themes) this.palette = themes[i];\n    }\n  }, {\n    key: 'setDefaultColors',\n    value: function setDefaultColors(fg, bg) {\n      if (fg !== this.defaultFgNum || bg !== this.defaultBgNum) {\n        this.resetDrawn();\n        this.defaultFgNum = fg;\n        this.defaultBgNum = bg;\n        this.scheduleDraw('default-colors');\n      }\n    }\n\n    /**\n     * Schedule a draw in the next millisecond\n     * @param {string} why - the reason why the draw occured (for debugging)\n     * @param {number} [aggregateTime] - time to wait for more scheduleDraw calls\n     *   to occur. 1 ms by default.\n     */\n\n  }, {\n    key: 'scheduleDraw',\n    value: function scheduleDraw(why) {\n      var _this = this;\n\n      var aggregateTime = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;\n\n      clearTimeout(this._scheduledDraw);\n      this._scheduledDraw = setTimeout(function () {\n        return _this.draw(why);\n      }, aggregateTime);\n    }\n\n    /**\n     * Returns the specified color. If `i` is in the palette, it will return the\n     * palette color. If `i` is between 16 and 255, it will return the 256color\n     * value. If `i` is larger than 255, it will return an RGB color value. If `i`\n     * is -1 (foreground) or -2 (background), it will return the selection colors.\n     * @param {number} i - the color\n     * @returns {string} the CSS color\n     */\n\n  }, {\n    key: 'getColor',\n    value: function getColor(i) {\n      // return palette color if it exists\n      if (i < 16 && i in this.palette) return this.palette[i];\n\n      // -1 for selection foreground, -2 for selection background\n      if (i === -1) return SELECTION_FG;\n      if (i === -2) return SELECTION_BG;\n\n      // 256 color\n      if (i > 15 && i < 256) return this.colorTable256[i];\n\n      // true color, encoded as (hex) + 256 (such that #000 == 256)\n      if (i > 255) {\n        i -= 256;\n        var red = i >> 16 & 0xFF;\n        var green = i >> 8 & 0xFF;\n        var blue = i & 0xFF;\n        return 'rgb(' + red + ', ' + green + ', ' + blue + ')';\n      }\n\n      // return error color\n      return Date.now() / 1000 % 2 === 0 ? '#f0f' : '#0f0';\n    }\n\n    /**\n     * Resets the cursor blink to on and restarts the timer\n     */\n\n  }, {\n    key: 'resetCursorBlink',\n    value: function resetCursorBlink() {\n      var _this2 = this;\n\n      this.cursorBlinkOn = true;\n      clearInterval(this.cursorBlinkInterval);\n      this.cursorBlinkInterval = setInterval(function () {\n        _this2.cursorBlinkOn = _this2.screen.cursor.blinking ? !_this2.cursorBlinkOn : true;\n        if (_this2.screen.cursor.blinking) _this2.scheduleDraw('cursor-blink');\n      }, 500);\n    }\n\n    /**\n     * Resets the blink style to on and restarts the timer\n     */\n\n  }, {\n    key: 'resetBlink',\n    value: function resetBlink() {\n      var _this3 = this;\n\n      this.blinkStyleOn = true;\n      clearInterval(this.blinkInterval);\n      var intervals = 0;\n      this.blinkInterval = setInterval(function () {\n        if (_this3.screen.blinkingCellCount <= 0) return;\n\n        intervals++;\n        if (intervals >= 4 && _this3.blinkStyleOn) {\n          _this3.blinkStyleOn = false;\n          intervals = 0;\n          _this3.scheduleDraw('blink-style');\n        } else if (intervals >= 1 && !_this3.blinkStyleOn) {\n          _this3.blinkStyleOn = true;\n          intervals = 0;\n          _this3.scheduleDraw('blink-style');\n        }\n      }, 200);\n    }\n\n    /**\n     * Draws a cell's background with the given parameters.\n     * @param {Object} options\n     * @param {number} options.x - x in cells\n     * @param {number} options.y - y in cells\n     * @param {number} options.cellWidth - cell width in pixels\n     * @param {number} options.cellHeight - cell height in pixels\n     * @param {number} options.bg - the background color\n     */\n\n  }, {\n    key: 'drawBackground',\n    value: function drawBackground(_ref) {\n      var x = _ref.x,\n          y = _ref.y,\n          cellWidth = _ref.cellWidth,\n          cellHeight = _ref.cellHeight,\n          bg = _ref.bg;\n\n      var ctx = this.ctx;\n      var _screen$window = this.screen.window,\n          width = _screen$window.width,\n          height = _screen$window.height;\n\n      var padding = Math.round(this.screen._padding);\n      ctx.fillStyle = this.getColor(bg);\n      var screenX = x * cellWidth + padding;\n      var screenY = y * cellHeight + padding;\n      var isBorderCell = x === 0 || y === 0 || x === width - 1 || y === height - 1;\n      if (isBorderCell) {\n        var left = screenX;\n        var top = screenY;\n        var right = screenX + cellWidth;\n        var bottom = screenY + cellHeight;\n        if (x === 0) left -= padding;else if (x === width - 1) right += padding;\n        if (y === 0) top -= padding;else if (y === height - 1) bottom += padding;\n        ctx.clearRect(left, top, right - left, bottom - top);\n        ctx.fillRect(left, top, right - left, bottom - top);\n      } else {\n        ctx.clearRect(screenX, screenY, cellWidth, cellHeight);\n        ctx.fillRect(screenX, screenY, cellWidth, cellHeight);\n      }\n    }\n\n    /**\n     * Draws a cell's character with the given parameters. Won't do anything if\n     * text is an empty string.\n     * @param {Object} options\n     * @param {number} options.x - x in cells\n     * @param {number} options.y - y in cells\n     * @param {Object} options.charSize - the character size, an object with\n     *   `width` and `height` in pixels\n     * @param {number} options.cellWidth - cell width in pixels\n     * @param {number} options.cellHeight - cell height in pixels\n     * @param {string} options.text - the cell content\n     * @param {number} options.fg - the foreground color\n     * @param {number} options.attrs - the cell's attributes\n     */\n\n  }, {\n    key: 'drawCharacter',\n    value: function drawCharacter(_ref2) {\n      var x = _ref2.x,\n          y = _ref2.y,\n          charSize = _ref2.charSize,\n          cellWidth = _ref2.cellWidth,\n          cellHeight = _ref2.cellHeight,\n          text = _ref2.text,\n          fg = _ref2.fg,\n          attrs = _ref2.attrs;\n\n      if (!text) return;\n\n      var ctx = this.ctx;\n      var padding = Math.round(this.screen._padding);\n\n      var underline = false;\n      var strike = false;\n      var overline = false;\n      if (attrs & ATTR_FAINT) ctx.globalAlpha = 0.5;\n      if (attrs & ATTR_UNDERLINE) underline = true;\n      if (attrs & ATTR_FRAKTUR) text = ScreenRenderer.alphaToFraktur(text);\n      if (attrs & ATTR_STRIKE) strike = true;\n      if (attrs & ATTR_OVERLINE) overline = true;\n\n      ctx.fillStyle = this.getColor(fg);\n\n      var screenX = x * cellWidth + padding;\n      var screenY = y * cellHeight + padding;\n\n      var codePoint = text.codePointAt(0);\n      if (codePoint >= 0x2580 && codePoint <= 0x259F) {\n        // block elements\n        ctx.beginPath();\n        var left = screenX;\n        var top = screenY;\n        var cw = cellWidth;\n        var ch = cellHeight;\n        var c2w = cellWidth / 2;\n        var c2h = cellHeight / 2;\n\n        // http://www.fileformat.info/info/unicode/block/block_elements/utf8test.htm\n        //         0x00  0x01  0x02  0x03  0x04  0x05  0x06  0x07  0x08  0x09  0x0A  0x0B  0x0C  0x0D  0x0E  0x0F\n        // 0x2580     ▀     ▁     ▂     ▃     ▄     ▅     ▆     ▇     █     ▉     ▊     ▋     ▌     ▍     ▎     ▏\n        // 0x2590     ▐     ░     ▒     ▓     ▔     ▕     ▖     ▗     ▘     ▙     ▚     ▛     ▜     ▝     ▞     ▟\n\n        if (codePoint === 0x2580) {\n          // upper half block >▀<\n          ctx.rect(left, top, cw, c2h);\n        } else if (codePoint <= 0x2588) {\n          // lower n eighth block (increasing) >▁< to >█<\n          var offset = (1 - (codePoint - 0x2580) / 8) * ch;\n          ctx.rect(left, top + offset, cw, ch - offset);\n        } else if (codePoint <= 0x258F) {\n          // left n eighth block (decreasing) >▉< to >▏<\n          var _offset = (codePoint - 0x2588) / 8 * cw;\n          ctx.rect(left, top, cw - _offset, ch);\n        } else if (codePoint === 0x2590) {\n          // right half block >▐<\n          ctx.rect(left + c2w, top, c2w, ch);\n        } else if (codePoint <= 0x2593) {\n          // shading >░< >▒< >▓<\n\n          // dot spacing by dividing cell size by a constant. This could be\n          // reworked to always return a whole number, but that would require\n          // prime factorization, and doing that without a loop would let you\n          // take over the world, which is not within the scope of this project.\n          var dotSpacingX = void 0,\n              dotSpacingY = void 0,\n              dotSize = void 0;\n          if (codePoint === 0x2591) {\n            dotSpacingX = cw / 4;\n            dotSpacingY = ch / 10;\n            dotSize = 1;\n          } else if (codePoint === 0x2592) {\n            dotSpacingX = cw / 6;\n            dotSpacingY = cw / 10;\n            dotSize = 1;\n          } else if (codePoint === 0x2593) {\n            dotSpacingX = cw / 4;\n            dotSpacingY = cw / 7;\n            dotSize = 2;\n          }\n\n          var alignRight = false;\n          for (var dy = 0; dy < ch; dy += dotSpacingY) {\n            for (var dx = 0; dx < cw; dx += dotSpacingX) {\n              // prevent overflow\n              var dotSizeY = Math.min(dotSize, ch - dy);\n              ctx.rect(left + (alignRight ? cw - dx - dotSize : dx), top + dy, dotSize, dotSizeY);\n            }\n            alignRight = !alignRight;\n          }\n        } else if (codePoint === 0x2594) {\n          // upper one eighth block >▔<\n          ctx.rect(left, top, cw, ch / 8);\n        } else if (codePoint === 0x2595) {\n          // right one eighth block >▕<\n          ctx.rect(left + 7 / 8 * cw, top, cw / 8, ch);\n        } else if (codePoint === 0x2596) {\n          // left bottom quadrant >▖<\n          ctx.rect(left, top + c2h, c2w, c2h);\n        } else if (codePoint === 0x2597) {\n          // right bottom quadrant >▗<\n          ctx.rect(left + c2w, top + c2h, c2w, c2h);\n        } else if (codePoint === 0x2598) {\n          // left top quadrant >▘<\n          ctx.rect(left, top, c2w, c2h);\n        } else if (codePoint === 0x2599) {\n          // left chair >▙<\n          ctx.rect(left, top, c2w, ch);\n          ctx.rect(left + c2w, top + c2h, c2w, c2h);\n        } else if (codePoint === 0x259A) {\n          // quadrants lt rb >▚<\n          ctx.rect(left, top, c2w, c2h);\n          ctx.rect(left + c2w, top + c2h, c2w, c2h);\n        } else if (codePoint === 0x259B) {\n          // left chair upside down >▛<\n          ctx.rect(left, top, c2w, ch);\n          ctx.rect(left + c2w, top, c2w, c2h);\n        } else if (codePoint === 0x259C) {\n          // right chair upside down >▜<\n          ctx.rect(left, top, cw, c2h);\n          ctx.rect(left + c2w, top + c2h, c2w, c2h);\n        } else if (codePoint === 0x259D) {\n          // right top quadrant >▝<\n          ctx.rect(left + c2w, top, c2w, c2h);\n        } else if (codePoint === 0x259E) {\n          // quadrants lb rt >▞<\n          ctx.rect(left, top + c2h, c2w, c2h);\n          ctx.rect(left + c2w, top, c2w, c2h);\n        } else if (codePoint === 0x259F) {\n          // right chair upside down >▟<\n          ctx.rect(left, top + c2h, c2w, c2h);\n          ctx.rect(left + c2w, top, c2w, ch);\n        }\n\n        ctx.fill();\n      } else if (codePoint >= 0xE0B0 && codePoint <= 0xE0B3) {\n        // powerline symbols, except branch, line, and lock. Basically, just the triangles\n        ctx.beginPath();\n\n        if (codePoint === 0xE0B0 || codePoint === 0xE0B1) {\n          // right-pointing triangle\n          ctx.moveTo(screenX, screenY);\n          ctx.lineTo(screenX + cellWidth, screenY + cellHeight / 2);\n          ctx.lineTo(screenX, screenY + cellHeight);\n        } else if (codePoint === 0xE0B2 || codePoint === 0xE0B3) {\n          // left-pointing triangle\n          ctx.moveTo(screenX + cellWidth, screenY);\n          ctx.lineTo(screenX, screenY + cellHeight / 2);\n          ctx.lineTo(screenX + cellWidth, screenY + cellHeight);\n        }\n\n        if (codePoint % 2 === 0) {\n          // triangle\n          ctx.fill();\n        } else {\n          // chevron\n          ctx.strokeStyle = ctx.fillStyle;\n          ctx.stroke();\n        }\n      } else {\n        // Draw other characters using the text renderer\n        ctx.fillText(text, screenX + 0.5 * cellWidth, screenY + 0.5 * cellHeight);\n      }\n\n      // -- line drawing - a reference for a possible future rect/line implementation ---\n      // http://www.fileformat.info/info/unicode/block/box_drawing/utf8test.htm\n      //         0x00  0x01  0x02  0x03  0x04  0x05  0x06  0x07  0x08  0x09  0x0A  0x0B  0x0C  0x0D  0x0E  0x0F\n      // 0x2500     ─     ━     │     ┃     ┄     ┅     ┆     ┇     ┈     ┉     ┊     ┋     ┌     ┍     ┎     ┏\n      // 0x2510     ┐     ┑     ┒     ┓     └     ┕     ┖     ┗     ┘     ┙     ┚     ┛     ├     ┝     ┞     ┟\n      // 0x2520     ┠     ┡     ┢     ┣     ┤     ┥     ┦     ┧     ┨     ┩     ┪     ┫     ┬     ┭     ┮     ┯\n      // 0x2530     ┰     ┱     ┲     ┳     ┴     ┵     ┶     ┷     ┸     ┹     ┺     ┻     ┼     ┽     ┾     ┿\n      // 0x2540     ╀     ╁     ╂     ╃     ╄     ╅     ╆     ╇     ╈     ╉     ╊     ╋     ╌     ╍     ╎     ╏\n      // 0x2550     ═     ║     ╒     ╓     ╔     ╕     ╖     ╗     ╘     ╙     ╚     ╛     ╜     ╝     ╞     ╟\n      // 0x2560     ╠     ╡     ╢     ╣     ╤     ╥     ╦     ╧     ╨     ╩     ╪     ╫     ╬     ╭     ╮     ╯\n      // 0x2570     ╰     ╱     ╲     ╳     ╴     ╵     ╶     ╷     ╸     ╹     ╺     ╻     ╼     ╽     ╾     ╿\n\n      if (underline || strike || overline) {\n        ctx.strokeStyle = this.getColor(fg);\n        ctx.lineWidth = 1;\n        ctx.lineCap = 'round';\n        ctx.beginPath();\n\n        if (underline) {\n          var lineY = Math.round(screenY + charSize.height) + 0.5;\n          ctx.moveTo(screenX, lineY);\n          ctx.lineTo(screenX + cellWidth, lineY);\n        }\n\n        if (strike) {\n          var _lineY = Math.round(screenY + 0.5 * cellHeight) + 0.5;\n          ctx.moveTo(screenX, _lineY);\n          ctx.lineTo(screenX + cellWidth, _lineY);\n        }\n\n        if (overline) {\n          var _lineY2 = Math.round(screenY) + 0.5;\n          ctx.moveTo(screenX, _lineY2);\n          ctx.lineTo(screenX + cellWidth, _lineY2);\n        }\n\n        ctx.stroke();\n      }\n\n      ctx.globalAlpha = 1;\n    }\n\n    /**\n     * Returns all adjacent cell indices given a radius.\n     * @param {number} cell - the center cell index\n     * @param {number} [radius] - the radius. 1 by default\n     * @returns {number[]} an array of cell indices\n     */\n\n  }, {\n    key: 'getAdjacentCells',\n    value: function getAdjacentCells(cell) {\n      var radius = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;\n      var _screen$window2 = this.screen.window,\n          width = _screen$window2.width,\n          height = _screen$window2.height;\n\n      var screenLength = width * height;\n\n      var cells = [];\n\n      for (var x = -radius; x <= radius; x++) {\n        for (var y = -radius; y <= radius; y++) {\n          if (x === 0 && y === 0) continue;\n          cells.push(cell + x + y * width);\n        }\n      }\n\n      return cells.filter(function (cell) {\n        return cell >= 0 && cell < screenLength;\n      });\n    }\n\n    /**\n     * Updates the screen.\n     * @param {string} why - the draw reason (for debugging)\n     */\n\n  }, {\n    key: 'draw',\n    value: function draw(why) {\n      var _this4 = this;\n\n      var ctx = this.ctx;\n      var _screen$window3 = this.screen.window,\n          width = _screen$window3.width,\n          height = _screen$window3.height,\n          devicePixelRatio = _screen$window3.devicePixelRatio,\n          statusScreen = _screen$window3.statusScreen;\n\n\n      if (statusScreen) {\n        // draw status screen instead\n        this.drawStatus(statusScreen);\n        this.startDrawLoop();\n        return;\n      } else this.stopDrawLoop();\n\n      var charSize = this.screen.getCharSize();\n\n      var _screen$getCellSize = this.screen.getCellSize(),\n          cellWidth = _screen$getCellSize.width,\n          cellHeight = _screen$getCellSize.height;\n\n      var screenLength = width * height;\n\n      ctx.setTransform(devicePixelRatio, 0, 0, devicePixelRatio, 0, 0);\n\n      if (this.screen.window.debug && this.screen._debug) this.screen._debug.drawStart(why);\n\n      ctx.font = this.screen.getFont();\n      ctx.textAlign = 'center';\n      ctx.textBaseline = 'middle';\n\n      // bits in the attr value that affect the font\n      var FONT_MASK = ATTR_BOLD | ATTR_ITALIC;\n\n      // Map of (attrs & FONT_MASK) -> Array of cell indices\n      var fontGroups = new Map();\n\n      // Map of (cell index) -> boolean, whether or not a cell has updated\n      var updateMap = new Map();\n\n      for (var cell = 0; cell < screenLength; cell++) {\n        var x = cell % width;\n        var y = Math.floor(cell / width);\n        var isCursor = this.cursorBlinkOn && this.screen.cursor.x === x && this.screen.cursor.y === y && this.screen.cursor.visible;\n\n        var wasCursor = x === this.drawnCursor[0] && y === this.drawnCursor[1];\n\n        var inSelection = this.screen.isInSelection(x, y);\n\n        var text = this.screen.screen[cell];\n        var fg = this.screen.screenFG[cell] | 0;\n        var bg = this.screen.screenBG[cell] | 0;\n        var attrs = this.screen.screenAttrs[cell] | 0;\n\n        if (!(attrs & ATTR_FG)) fg = this.defaultFgNum;\n        if (!(attrs & ATTR_BG)) bg = this.defaultBgNum;\n\n        if (attrs & ATTR_INVERSE) {\n          ;var _ref3 = [bg, fg];\n          fg = _ref3[0];\n          bg = _ref3[1];\n        } // swap - reversed character colors\n        if (this.screen.reverseVideo) {\n          ;var _ref4 = [bg, fg];\n          fg = _ref4[0];\n          bg = _ref4[1];\n        } // swap - reversed all screen\n\n        if (attrs & ATTR_BLINK && !this.blinkStyleOn) {\n          // blinking is enabled and blink style is off\n          // set text to nothing so drawCharacter doesn't draw anything\n          text = '';\n        }\n\n        if (inSelection) {\n          fg = -1;\n          bg = -2;\n        }\n\n        var didUpdate = text !== this.drawnScreen[cell] || // text updated\n        fg !== this.drawnScreenFG[cell] || // foreground updated, and this cell has text\n        bg !== this.drawnScreenBG[cell] || // background updated\n        attrs !== this.drawnScreenAttrs[cell] || // attributes updated\n        isCursor !== wasCursor || // cursor blink/position updated\n        isCursor && this.screen.cursor.style !== this.drawnCursor[2] || // cursor style updated\n        isCursor && this.screen.cursor.hanging !== this.drawnCursor[3]; // cursor hanging updated\n\n        var font = attrs & FONT_MASK;\n        if (!fontGroups.has(font)) fontGroups.set(font, []);\n\n        fontGroups.get(font).push({ cell: cell, x: x, y: y, text: text, fg: fg, bg: bg, attrs: attrs, isCursor: isCursor, inSelection: inSelection });\n        updateMap.set(cell, didUpdate);\n      }\n\n      // Map of (cell index) -> boolean, whether or not a cell should be redrawn\n      var redrawMap = new Map();\n\n      var isTextWide = function isTextWide(text) {\n        return text !== ' ' && ctx.measureText(text).width >= cellWidth + 0.05;\n      };\n\n      // decide for each cell if it should be redrawn\n      var updateRedrawMapAt = function updateRedrawMapAt(cell) {\n        var shouldUpdate = updateMap.get(cell) || redrawMap.get(cell) || false;\n\n        // TODO: fonts (necessary?)\n        var text = _this4.screen.screen[cell];\n        var isWideCell = isTextWide(text);\n        var checkRadius = isWideCell ? 2 : 1;\n\n        if (!shouldUpdate) {\n          // check adjacent cells\n          var adjacentDidUpdate = false;\n\n          var _iteratorNormalCompletion = true;\n          var _didIteratorError = false;\n          var _iteratorError = undefined;\n\n          try {\n            for (var _iterator = _this4.getAdjacentCells(cell, checkRadius)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {\n              var adjacentCell = _step.value;\n\n              // update this cell if:\n              // - the adjacent cell updated (For now, this'll always be true because characters can be slightly larger than they say they are)\n              // - the adjacent cell updated and this cell or the adjacent cell is wide\n              if (updateMap.get(adjacentCell) && (_this4.screen.window.graphics < 2 || isWideCell || isTextWide(_this4.screen.screen[adjacentCell]))) {\n                adjacentDidUpdate = true;\n                break;\n              }\n            }\n          } catch (err) {\n            _didIteratorError = true;\n            _iteratorError = err;\n          } finally {\n            try {\n              if (!_iteratorNormalCompletion && _iterator.return) {\n                _iterator.return();\n              }\n            } finally {\n              if (_didIteratorError) {\n                throw _iteratorError;\n              }\n            }\n          }\n\n          if (adjacentDidUpdate) shouldUpdate = true;\n        }\n\n        redrawMap.set(cell, shouldUpdate);\n      };\n\n      var _iteratorNormalCompletion2 = true;\n      var _didIteratorError2 = false;\n      var _iteratorError2 = undefined;\n\n      try {\n        for (var _iterator2 = updateMap.keys()[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {\n          var _cell = _step2.value;\n          updateRedrawMapAt(_cell);\n        } // mask to redrawing regions only\n      } catch (err) {\n        _didIteratorError2 = true;\n        _iteratorError2 = err;\n      } finally {\n        try {\n          if (!_iteratorNormalCompletion2 && _iterator2.return) {\n            _iterator2.return();\n          }\n        } finally {\n          if (_didIteratorError2) {\n            throw _iteratorError2;\n          }\n        }\n      }\n\n      if (this.screen.window.graphics >= 1) {\n        var debug = this.screen.window.debug && this.screen._debug;\n        var padding = Math.round(this.screen._padding);\n        ctx.save();\n        ctx.beginPath();\n        for (var _y = 0; _y < height; _y++) {\n          var regionStart = null;\n          for (var _x3 = 0; _x3 < width; _x3++) {\n            var _cell2 = _y * width + _x3;\n            var redrawing = redrawMap.get(_cell2);\n            if (redrawing && regionStart === null) regionStart = _x3;\n            if (!redrawing && regionStart !== null) {\n              ctx.rect(padding + regionStart * cellWidth, padding + _y * cellHeight, (_x3 - regionStart) * cellWidth, cellHeight);\n              if (debug) this.screen._debug.clipRect(regionStart * cellWidth, _y * cellHeight, (_x3 - regionStart) * cellWidth, cellHeight);\n              regionStart = null;\n            }\n          }\n          if (regionStart !== null) {\n            ctx.rect(padding + regionStart * cellWidth, padding + _y * cellHeight, (width - regionStart) * cellWidth, cellHeight);\n            if (debug) this.screen._debug.clipRect(regionStart * cellWidth, _y * cellHeight, (width - regionStart) * cellWidth, cellHeight);\n          }\n        }\n        ctx.clip();\n      }\n\n      // pass 1: backgrounds\n      var _iteratorNormalCompletion3 = true;\n      var _didIteratorError3 = false;\n      var _iteratorError3 = undefined;\n\n      try {\n        for (var _iterator3 = fontGroups.keys()[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {\n          var _font = _step3.value;\n          var _iteratorNormalCompletion5 = true;\n          var _didIteratorError5 = false;\n          var _iteratorError5 = undefined;\n\n          try {\n            for (var _iterator5 = fontGroups.get(_font)[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) {\n              var data = _step5.value;\n              var _cell3 = data.cell,\n                  _x4 = data.x,\n                  _y2 = data.y,\n                  _text = data.text,\n                  _bg = data.bg;\n\n\n              if (redrawMap.get(_cell3)) {\n                this.drawBackground({ x: _x4, y: _y2, cellWidth: cellWidth, cellHeight: cellHeight, bg: _bg });\n\n                if (this.screen.window.debug && this.screen._debug) {\n                  // set cell flags\n                  var flags = +redrawMap.get(_cell3);\n                  flags |= +updateMap.get(_cell3) << 1;\n                  flags |= +isTextWide(_text) << 2;\n                  this.screen._debug.setCell(_cell3, flags);\n                }\n              }\n            }\n          } catch (err) {\n            _didIteratorError5 = true;\n            _iteratorError5 = err;\n          } finally {\n            try {\n              if (!_iteratorNormalCompletion5 && _iterator5.return) {\n                _iterator5.return();\n              }\n            } finally {\n              if (_didIteratorError5) {\n                throw _iteratorError5;\n              }\n            }\n          }\n        }\n\n        // reset drawn cursor\n      } catch (err) {\n        _didIteratorError3 = true;\n        _iteratorError3 = err;\n      } finally {\n        try {\n          if (!_iteratorNormalCompletion3 && _iterator3.return) {\n            _iterator3.return();\n          }\n        } finally {\n          if (_didIteratorError3) {\n            throw _iteratorError3;\n          }\n        }\n      }\n\n      this.drawnCursor = [-1, -1, -1];\n\n      // pass 2: characters\n      var _iteratorNormalCompletion4 = true;\n      var _didIteratorError4 = false;\n      var _iteratorError4 = undefined;\n\n      try {\n        for (var _iterator4 = fontGroups.keys()[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {\n          var _font2 = _step4.value;\n\n          // set font once because in Firefox, this is a really slow action for some\n          // reason\n          var modifiers = {};\n          if (_font2 & ATTR_BOLD) modifiers.weight = 'bold';\n          if (_font2 & ATTR_ITALIC) modifiers.style = 'italic';\n          ctx.font = this.screen.getFont(modifiers);\n\n          var _iteratorNormalCompletion6 = true;\n          var _didIteratorError6 = false;\n          var _iteratorError6 = undefined;\n\n          try {\n            for (var _iterator6 = fontGroups.get(_font2)[Symbol.iterator](), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) {\n              var _data = _step6.value;\n              var _cell4 = _data.cell,\n                  _x5 = _data.x,\n                  _y3 = _data.y,\n                  _text2 = _data.text,\n                  _fg = _data.fg,\n                  _bg2 = _data.bg,\n                  _attrs = _data.attrs,\n                  _isCursor = _data.isCursor,\n                  _inSelection = _data.inSelection;\n\n\n              if (redrawMap.get(_cell4)) {\n                this.drawCharacter({\n                  x: _x5, y: _y3, charSize: charSize, cellWidth: cellWidth, cellHeight: cellHeight, text: _text2, fg: _fg, attrs: _attrs\n                });\n\n                this.drawnScreen[_cell4] = _text2;\n                this.drawnScreenFG[_cell4] = _fg;\n                this.drawnScreenBG[_cell4] = _bg2;\n                this.drawnScreenAttrs[_cell4] = _attrs;\n\n                if (_isCursor) this.drawnCursor = [_x5, _y3, this.screen.cursor.style, this.screen.cursor.hanging];\n\n                // draw cursor\n                if (_isCursor && !_inSelection) {\n                  ctx.save();\n                  ctx.beginPath();\n\n                  var cursorX = _x5;\n                  var cursorY = _y3;\n\n                  if (this.screen.cursor.hanging) {\n                    // draw hanging cursor in the margin\n                    cursorX += 1;\n                  }\n\n                  var screenX = cursorX * cellWidth + this.screen._padding;\n                  var screenY = cursorY * cellHeight + this.screen._padding;\n                  if (this.screen.cursor.style === 'block') {\n                    // block\n                    ctx.rect(screenX, screenY, cellWidth, cellHeight);\n                  } else if (this.screen.cursor.style === 'bar') {\n                    // vertical bar\n                    var barWidth = 2;\n                    ctx.rect(screenX, screenY, barWidth, cellHeight);\n                  } else if (this.screen.cursor.style === 'line') {\n                    // underline\n                    var lineHeight = 2;\n                    ctx.rect(screenX, screenY + charSize.height, cellWidth, lineHeight);\n                  }\n                  ctx.clip()\n\n                  // swap foreground/background\n                  ;\n\n                  // HACK: ensure cursor is visible\n                  var _ref5 = [_bg2, _fg];\n                  _fg = _ref5[0];\n                  _bg2 = _ref5[1];\n                  if (_fg === _bg2) _bg2 = _fg === 0 ? 7 : 0;\n\n                  this.drawBackground({ x: cursorX, y: cursorY, cellWidth: cellWidth, cellHeight: cellHeight, bg: _bg2 });\n                  this.drawCharacter({\n                    x: cursorX, y: cursorY, charSize: charSize, cellWidth: cellWidth, cellHeight: cellHeight, text: _text2, fg: _fg, attrs: _attrs\n                  });\n                  ctx.restore();\n                }\n              }\n            }\n          } catch (err) {\n            _didIteratorError6 = true;\n            _iteratorError6 = err;\n          } finally {\n            try {\n              if (!_iteratorNormalCompletion6 && _iterator6.return) {\n                _iterator6.return();\n              }\n            } finally {\n              if (_didIteratorError6) {\n                throw _iteratorError6;\n              }\n            }\n          }\n        }\n      } catch (err) {\n        _didIteratorError4 = true;\n        _iteratorError4 = err;\n      } finally {\n        try {\n          if (!_iteratorNormalCompletion4 && _iterator4.return) {\n            _iterator4.return();\n          }\n        } finally {\n          if (_didIteratorError4) {\n            throw _iteratorError4;\n          }\n        }\n      }\n\n      if (this.screen.window.graphics >= 1) ctx.restore();\n\n      if (this.screen.window.debug && this.screen._debug) this.screen._debug.drawEnd();\n\n      this.screen.emit('draw', why);\n    }\n  }, {\n    key: 'drawStatus',\n    value: function drawStatus(statusScreen) {\n      var ctx = this.ctx;\n      var _screen$window4 = this.screen.window,\n          fontFamily = _screen$window4.fontFamily,\n          width = _screen$window4.width,\n          height = _screen$window4.height,\n          devicePixelRatio = _screen$window4.devicePixelRatio;\n\n      // reset drawnScreen to force redraw when statusScreen is disabled\n\n      this.drawnScreen = [];\n\n      var cellSize = this.screen.getCellSize();\n      var screenWidth = width * cellSize.width + 2 * this.screen._padding;\n      var screenHeight = height * cellSize.height + 2 * this.screen._padding;\n\n      ctx.setTransform(devicePixelRatio, 0, 0, devicePixelRatio, 0, 0);\n      ctx.fillStyle = this.getColor(this.defaultBgNum);\n      ctx.fillRect(0, 0, screenWidth, screenHeight);\n\n      ctx.font = '24px ' + fontFamily;\n      ctx.fillStyle = this.getColor(this.defaultFgNum);\n      ctx.textAlign = 'center';\n      ctx.textBaseline = 'middle';\n      ctx.fillText(statusScreen.title || '', screenWidth / 2, screenHeight / 2 - 50);\n\n      if (statusScreen.loading) {\n        // show loading spinner\n        ctx.save();\n        ctx.translate(screenWidth / 2, screenHeight / 2 + 20);\n\n        ctx.strokeStyle = this.getColor(this.defaultFgNum);\n        ctx.lineWidth = 5;\n        ctx.lineCap = 'round';\n\n        var t = Date.now() / 1000;\n\n        for (var i = 0; i < 12; i++) {\n          ctx.rotate(Math.PI / 6);\n          var offset = (t * 12 - i) % 12;\n          ctx.globalAlpha = Math.max(0.2, 1 - offset / 3);\n          ctx.beginPath();\n          ctx.moveTo(0, 15);\n          ctx.lineTo(0, 30);\n          ctx.stroke();\n        }\n\n        ctx.restore();\n      }\n    }\n  }, {\n    key: 'startDrawLoop',\n    value: function startDrawLoop() {\n      if (this._drawTimerThread) return;\n      var threadID = Math.random().toString(36);\n      this._drawTimerThread = threadID;\n      this.drawTimerLoop(threadID);\n    }\n  }, {\n    key: 'stopDrawLoop',\n    value: function stopDrawLoop() {\n      this._drawTimerThread = null;\n    }\n  }, {\n    key: 'drawTimerLoop',\n    value: function drawTimerLoop(threadID) {\n      var _this5 = this;\n\n      if (!threadID || threadID !== this._drawTimerThread) return;\n      window.requestAnimationFrame(function () {\n        return _this5.drawTimerLoop(threadID);\n      });\n      this.draw('draw-loop');\n    }\n\n    /**\n     * Converts an alphabetic character to its fraktur variant.\n     * @param {string} character - the character\n     * @returns {string} the converted character\n     */\n\n  }, {\n    key: 'palette',\n    get: function get() {\n      return this._palette || themes[0];\n    }\n\n    /** @type {string[]} */\n    ,\n    set: function set(palette) {\n      if (this._palette !== palette) {\n        this._palette = palette;\n        this.resetDrawn();\n        this.scheduleDraw('palette');\n      }\n    }\n  }], [{\n    key: 'alphaToFraktur',\n    value: function alphaToFraktur(character) {\n      if (character >= 'a' && character <= 'z') {\n        character = String.fromCodePoint(0x1d51e - 0x61 + character.charCodeAt(0));\n      } else if (character >= 'A' && character <= 'Z') {\n        character = frakturExceptions[character] || String.fromCodePoint(0x1d504 - 0x41 + character.charCodeAt(0));\n      }\n      return character;\n    }\n  }]);\n\n  return ScreenRenderer;\n}();\n\n/***/ }),\n/* 18 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nvar _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return call && (typeof call === \"object\" || typeof call === \"function\") ? call : self; }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function, not \" + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }\n\nvar EventEmitter = __webpack_require__(4);\nvar $ = __webpack_require__(1);\nvar demo = void 0;\ntry {\n  demo = __webpack_require__(6);\n} catch (err) {}\n\nvar RECONN_DELAY = 2000;\nvar HEARTBEAT_TIME = 3000;\n\n/** Handle connections */\nmodule.exports = function (_EventEmitter) {\n  _inherits(TermConnection, _EventEmitter);\n\n  function TermConnection(screen) {\n    _classCallCheck(this, TermConnection);\n\n    var _this = _possibleConstructorReturn(this, (TermConnection.__proto__ || Object.getPrototypeOf(TermConnection)).call(this));\n\n    _this.screen = screen;\n    _this.ws = null;\n    _this.heartbeatTimeout = null;\n    _this.pingInterval = null;\n    _this.xoff = false;\n    _this.autoXoffTimeout = null;\n    _this.reconnTimeout = null;\n    _this.forceClosing = false;\n\n    try {\n      _this.blobReader = new FileReader();\n      _this.blobReader.onload = function (evt) {\n        _this.onDecodedWSMessage(_this.blobReader.result);\n      };\n      _this.blobReader.onerror = function (evt) {\n        console.error(evt);\n      };\n    } catch (e) {\n      _this.blobReader = null;\n    }\n\n    _this.pageShown = false;\n\n    _this.disconnectTimeout = null;\n\n    document.addEventListener('visibilitychange', function () {\n      if (document.hidden === true) {\n        console.info('Window lost focus, freeing socket');\n        // Delayed, avoid disconnecting if the background time is short\n        _this.disconnectTimeout = setTimeout(function () {\n          _this.closeSocket();\n          clearTimeout(_this.heartbeatTimeout);\n        }, 1000);\n      } else {\n        clearTimeout(_this.disconnectTimeout);\n        console.info('Window got focus, re-connecting');\n        _this.init();\n      }\n    }, false);\n    return _this;\n  }\n\n  _createClass(TermConnection, [{\n    key: 'onWSOpen',\n    value: function onWSOpen(evt) {\n      console.log('CONNECTED');\n      this.heartbeat();\n      this.send('i');\n      this.forceClosing = false;\n\n      this.emit('connect');\n    }\n  }, {\n    key: 'onWSClose',\n    value: function onWSClose(evt) {\n      var _this2 = this;\n\n      if (this.forceClosing) {\n        this.forceClosing = false;\n        return;\n      }\n      console.warn('SOCKET CLOSED, code ' + evt.code + '. Reconnecting...');\n      if (evt.code < 1000) {\n        console.error('Bad code from socket!');\n        // this sometimes happens for unknown reasons, code < 1000 is invalid\n        // location.reload()\n      }\n\n      clearTimeout(this.reconnTimeout);\n      this.reconnTimeout = setTimeout(function () {\n        return _this2.init();\n      }, RECONN_DELAY);\n\n      this.emit('disconnect', evt.code);\n    }\n  }, {\n    key: 'onDecodedWSMessage',\n    value: function onDecodedWSMessage(str) {\n      var _this3 = this;\n\n      switch (str.charAt(0)) {\n        case '.':\n          console.log(str);\n          // heartbeat, no-op message\n          break;\n\n        case '-':\n          // console.log('xoff');\n          this.xoff = true;\n          this.autoXoffTimeout = setTimeout(function () {\n            _this3.xoff = false;\n          }, 250);\n          break;\n\n        case '+':\n          // console.log('xon');\n          this.xoff = false;\n          clearTimeout(this.autoXoffTimeout);\n          break;\n\n        default:\n          this.screen.load(str);\n          if (!this.pageShown) {\n            window.showPage();\n            this.pageShown = true;\n          }\n          break;\n      }\n      this.heartbeat();\n    }\n  }, {\n    key: 'onWSMessage',\n    value: function onWSMessage(evt) {\n      var _this4 = this;\n\n      if (typeof evt.data === 'string') this.onDecodedWSMessage(evt.data);else {\n        if (!this.blobReader) {\n          console.error('No FileReader!');\n          return;\n        }\n\n        if (this.blobReader.readyState !== 1) {\n          this.blobReader.readAsText(evt.data);\n        } else {\n          setTimeout(function () {\n            _this4.onWSMessage(evt);\n          }, 1);\n        }\n      }\n    }\n  }, {\n    key: 'canSend',\n    value: function canSend() {\n      return !this.xoff;\n    }\n  }, {\n    key: 'send',\n    value: function send(message) {\n      if (window._demo) {\n        if (typeof window.demoInterface !== 'undefined') {\n          demo.input(message);\n        } else {\n          console.log('TX: ' + JSON.stringify(message));\n        }\n        return true; // Simulate success\n      }\n      if (this.xoff) {\n        // TODO queue\n        console.log(\"Can't send, flood control.\");\n        return false;\n      }\n\n      if (!this.ws) return false; // for dry testing\n      if (this.ws.readyState !== 1) {\n        console.error('Socket not ready');\n        return false;\n      }\n      if (typeof message !== 'string') {\n        message = JSON.stringify(message);\n      }\n      this.ws.send(message);\n      return true;\n    }\n\n    /** Safely close the socket */\n\n  }, {\n    key: 'closeSocket',\n    value: function closeSocket() {\n      if (this.ws) {\n        this.forceClosing = true;\n        if (this.ws.readyState === 1) this.ws.close();\n        this.ws = null;\n      }\n    }\n  }, {\n    key: 'init',\n    value: function init() {\n      var _this5 = this;\n\n      if (window._demo) {\n        if (typeof window.demoInterface === 'undefined') {\n          window.alert('Demoing non-demo build!'); // this will catch mistakes when deploying to the website\n        } else {\n          demo.init(this.screen);\n        }\n        return;\n      }\n\n      clearTimeout(this.reconnTimeout);\n      clearTimeout(this.heartbeatTimeout);\n\n      this.closeSocket();\n\n      this.ws = new window.WebSocket('ws://' + window._root + '/term/update.ws');\n      this.ws.addEventListener('open', function () {\n        return _this5.onWSOpen.apply(_this5, arguments);\n      });\n      this.ws.addEventListener('close', function () {\n        return _this5.onWSClose.apply(_this5, arguments);\n      });\n      this.ws.addEventListener('message', function () {\n        return _this5.onWSMessage.apply(_this5, arguments);\n      });\n      console.log('Opening socket.');\n      this.heartbeat();\n\n      this.emit('open');\n    }\n  }, {\n    key: 'heartbeat',\n    value: function heartbeat() {\n      var _this6 = this;\n\n      clearTimeout(this.heartbeatTimeout);\n      this.heartbeatTimeout = setTimeout(function () {\n        return _this6.onHeartbeatFail();\n      }, HEARTBEAT_TIME);\n    }\n  }, {\n    key: 'sendPing',\n    value: function sendPing() {\n      var _this7 = this;\n\n      console.log('> ping');\n      this.emit('ping');\n      $.get('http://' + window._root + '/api/v1/ping', function (resp, status) {\n        if (status === 200) {\n          clearInterval(_this7.pingInterval);\n          console.info('Server ready, opening socket…');\n          _this7.emit('ping-success');\n          _this7.init();\n          // location.reload()\n        } else _this7.emit('ping-fail', status);\n      }, {\n        timeout: 100,\n        loader: false // we have loader on-screen\n      });\n    }\n  }, {\n    key: 'onHeartbeatFail',\n    value: function onHeartbeatFail() {\n      var _this8 = this;\n\n      this.closeSocket();\n      this.emit('silence');\n      console.error('Heartbeat lost, probing server...');\n      clearInterval(this.pingInterval);\n      this.pingInterval = setInterval(function () {\n        _this8.sendPing();\n      }, 1000);\n\n      // first ping, if this gets through, it'll will reduce delay\n      setTimeout(function () {\n        _this8.sendPing();\n      }, 200);\n    }\n  }]);\n\n  return TermConnection;\n}(EventEmitter);\n\n/***/ }),\n/* 19 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nvar $ = __webpack_require__(1);\n\nvar _require = __webpack_require__(0),\n    encode2B = _require.encode2B;\n\n/**\n * User input\n *\n * --- Rx messages: ---\n * S - screen content (binary encoding of the entire screen with simple compression)\n * T - text labels - Title and buttons, \\0x01-separated\n * B - beep\n * . - heartbeat\n *\n * --- Tx messages ---\n * s - string\n * b - action button\n * p - mb press\n * r - mb release\n * m - mouse move\n */\n\n\nmodule.exports = function (conn, screen) {\n  // handle for input object\n  var input = void 0;\n\n  var KEY_NAMES = {\n    0x03: 'Cancel',\n    0x06: 'Help',\n    0x08: 'Backspace',\n    0x09: 'Tab',\n    0x0C: 'Clear',\n    0x0D: 'Enter',\n    0x10: 'Shift',\n    0x11: 'Control',\n    0x12: 'Alt',\n    0x13: 'Pause',\n    0x14: 'CapsLock',\n    0x1B: 'Escape',\n    0x20: ' ',\n    0x21: 'PageUp',\n    0x22: 'PageDown',\n    0x23: 'End',\n    0x24: 'Home',\n    0x25: 'ArrowLeft',\n    0x26: 'ArrowUp',\n    0x27: 'ArrowRight',\n    0x28: 'ArrowDown',\n    0x29: 'Select',\n    0x2A: 'Print',\n    0x2B: 'Execute',\n    0x2C: 'PrintScreen',\n    0x2D: 'Insert',\n    0x2E: 'Delete',\n    0x3A: ':',\n    0x3B: ';',\n    0x3C: '<',\n    0x3D: '=',\n    0x3E: '>',\n    0x3F: '?',\n    0x40: '@',\n    0x5B: 'Meta',\n    0x5C: 'Meta',\n    0x5D: 'ContextMenu',\n    0x6A: 'Numpad*',\n    0x6B: 'Numpad+',\n    0x6D: 'Numpad-',\n    0x6E: 'Numpad.',\n    0x6F: 'Numpad/',\n    0x90: 'NumLock',\n    0x91: 'ScrollLock',\n    0xA0: '^',\n    0xA1: '!',\n    0xA2: '\"',\n    0xA3: '#',\n    0xA4: '$',\n    0xA5: '%',\n    0xA6: '&',\n    0xA7: '_',\n    0xA8: '(',\n    0xA9: ')',\n    0xAA: '*',\n    0xAB: '+',\n    0xAC: '|',\n    0xAD: '-',\n    0xAE: '{',\n    0xAF: '}',\n    0xB0: '~',\n    0xBA: ';',\n    0xBB: '=',\n    0xBC: 'Numpad,',\n    0xBD: '-',\n    0xBE: 'Numpad,',\n    0xC0: '`',\n    0xC2: 'Numpad,',\n    0xDB: '[',\n    0xDC: '\\\\',\n    0xDD: ']',\n    0xDE: \"'\",\n    0xE0: 'Meta'\n    // numbers 0-9\n  };for (var i = 0x30; i <= 0x39; i++) {\n    KEY_NAMES[i] = String.fromCharCode(i);\n  } // characters A-Z\n  for (var _i = 0x41; _i <= 0x5A; _i++) {\n    KEY_NAMES[_i] = String.fromCharCode(_i);\n  } // function F1-F20\n  for (var _i2 = 0x70; _i2 <= 0x83; _i2++) {\n    KEY_NAMES[_i2] = 'F' + (_i2 - 0x70 + 1);\n  } // numpad 0-9\n  for (var _i3 = 0x60; _i3 <= 0x69; _i3++) {\n    KEY_NAMES[_i3] = 'Numpad' + (_i3 - 0x60);\n  }var cfg = {\n    np_alt: false, // Application Numpad Mode\n    cu_alt: false, // Application Cursors Mode\n    fn_alt: false, // SS3 function keys mode\n    mt_click: false, // Mouse click tracking\n    mt_move: false, // Mouse move tracking\n    no_keys: false, // Suppress any key / clipboard event intercepting\n    crlf_mode: false, // Enter sends CR LF\n    all_fn: false // Capture also F5, F11 and F12\n\n\n    /** Fn alt choice for key message */\n  };var fa = function fa(alt, normal) {\n    return cfg.fn_alt ? alt : normal;\n  };\n\n  /** Cursor alt choice for key message */\n  var ca = function ca(alt, normal) {\n    return cfg.cu_alt ? alt : normal;\n  };\n\n  /** Numpad alt choice for key message */\n  var na = function na(alt, normal) {\n    return cfg.np_alt ? alt : normal;\n  };\n\n  var keymap = {\n    /* eslint-disable key-spacing */\n    'Backspace': '\\x08',\n    'Tab': '\\x09',\n    'Enter': function Enter() {\n      return cfg.crlf_mode ? '\\x0d\\x0a' : '\\x0d';\n    },\n    'Control+Enter': '\\x0a',\n    'Escape': '\\x1b',\n    'ArrowUp': function ArrowUp() {\n      return ca('\\x1bOA', '\\x1b[A');\n    },\n    'ArrowDown': function ArrowDown() {\n      return ca('\\x1bOB', '\\x1b[B');\n    },\n    'ArrowRight': function ArrowRight() {\n      return ca('\\x1bOC', '\\x1b[C');\n    },\n    'ArrowLeft': function ArrowLeft() {\n      return ca('\\x1bOD', '\\x1b[D');\n    },\n    'Home': function Home() {\n      return ca('\\x1bOH', fa('\\x1b[H', '\\x1b[1~'));\n    },\n    'Insert': '\\x1b[2~',\n    'Delete': '\\x1b[3~',\n    'End': function End() {\n      return ca('\\x1bOF', fa('\\x1b[F', '\\x1b[4~'));\n    },\n    'PageUp': '\\x1b[5~',\n    'PageDown': '\\x1b[6~',\n    'F1': function F1() {\n      return fa('\\x1bOP', '\\x1b[11~');\n    },\n    'F2': function F2() {\n      return fa('\\x1bOQ', '\\x1b[12~');\n    },\n    'F3': function F3() {\n      return fa('\\x1bOR', '\\x1b[13~');\n    },\n    'F4': function F4() {\n      return fa('\\x1bOS', '\\x1b[14~');\n    },\n    'F5': '\\x1b[15~', // note the disconnect\n    'F6': '\\x1b[17~',\n    'F7': '\\x1b[18~',\n    'F8': '\\x1b[19~',\n    'F9': '\\x1b[20~',\n    'F10': '\\x1b[21~', // note the disconnect\n    'F11': '\\x1b[23~',\n    'F12': '\\x1b[24~',\n    'Shift+F1': function ShiftF1() {\n      return fa('\\x1bO1;2P', '\\x1b[25~');\n    },\n    'Shift+F2': function ShiftF2() {\n      return fa('\\x1bO1;2Q', '\\x1b[26~');\n    }, // note the disconnect\n    'Shift+F3': function ShiftF3() {\n      return fa('\\x1bO1;2R', '\\x1b[28~');\n    },\n    'Shift+F4': function ShiftF4() {\n      return fa('\\x1bO1;2S', '\\x1b[29~');\n    }, // note the disconnect\n    'Shift+F5': function ShiftF5() {\n      return fa('\\x1b[15;2~', '\\x1b[31~');\n    },\n    'Shift+F6': function ShiftF6() {\n      return fa('\\x1b[17;2~', '\\x1b[32~');\n    },\n    'Shift+F7': function ShiftF7() {\n      return fa('\\x1b[18;2~', '\\x1b[33~');\n    },\n    'Shift+F8': function ShiftF8() {\n      return fa('\\x1b[19;2~', '\\x1b[34~');\n    },\n    'Shift+F9': function ShiftF9() {\n      return fa('\\x1b[20;2~', '\\x1b[35~');\n    }, // 35-38 are not standard - but what is?\n    'Shift+F10': function ShiftF10() {\n      return fa('\\x1b[21;2~', '\\x1b[36~');\n    },\n    'Shift+F11': function ShiftF11() {\n      return fa('\\x1b[22;2~', '\\x1b[37~');\n    },\n    'Shift+F12': function ShiftF12() {\n      return fa('\\x1b[23;2~', '\\x1b[38~');\n    },\n    'Numpad0': function Numpad0() {\n      return na('\\x1bOp', '0');\n    },\n    'Numpad1': function Numpad1() {\n      return na('\\x1bOq', '1');\n    },\n    'Numpad2': function Numpad2() {\n      return na('\\x1bOr', '2');\n    },\n    'Numpad3': function Numpad3() {\n      return na('\\x1bOs', '3');\n    },\n    'Numpad4': function Numpad4() {\n      return na('\\x1bOt', '4');\n    },\n    'Numpad5': function Numpad5() {\n      return na('\\x1bOu', '5');\n    },\n    'Numpad6': function Numpad6() {\n      return na('\\x1bOv', '6');\n    },\n    'Numpad7': function Numpad7() {\n      return na('\\x1bOw', '7');\n    },\n    'Numpad8': function Numpad8() {\n      return na('\\x1bOx', '8');\n    },\n    'Numpad9': function Numpad9() {\n      return na('\\x1bOy', '9');\n    },\n    'Numpad*': function Numpad() {\n      return na('\\x1bOR', '*');\n    },\n    'Numpad+': function Numpad() {\n      return na('\\x1bOl', '+');\n    },\n    'Numpad-': function Numpad() {\n      return na('\\x1bOS', '-');\n    },\n    'Numpad.': function Numpad() {\n      return na('\\x1bOn', '.');\n    },\n    'Numpad/': function Numpad() {\n      return na('\\x1bOQ', '/');\n    },\n    // we don't implement numlock key (should change in numpad_alt mode,\n    // but it's even more useless than the rest and also has the side\n    // effect of changing the user's numlock state)\n\n    // shortcuts\n    'Control+]': '\\x1b', // alternate way to enter ESC\n    'Control+\\\\': '\\x1c',\n    'Control+[': '\\x1d',\n    'Control+^': '\\x1e',\n    'Control+_': '\\x1f',\n\n    // extra controls\n    'Control+ArrowLeft': '\\x1f[1;5D',\n    'Control+ArrowRight': '\\x1f[1;5C',\n    'Control+ArrowUp': '\\x1f[1;5A',\n    'Control+ArrowDown': '\\x1f[1;5B',\n    'Control+Home': '\\x1f[1;5H',\n    'Control+End': '\\x1f[1;5F',\n\n    // extra shift controls\n    'Shift+ArrowLeft': '\\x1f[1;2D',\n    'Shift+ArrowRight': '\\x1f[1;2C',\n    'Shift+ArrowUp': '\\x1f[1;2A',\n    'Shift+ArrowDown': '\\x1f[1;2B',\n    'Shift+Home': '\\x1f[1;2H',\n    'Shift+End': '\\x1f[1;2F',\n\n    // macOS text editing commands\n    'Alt+ArrowLeft': '\\x1bb', // ⌥← to go back a word (^[b)\n    'Alt+ArrowRight': '\\x1bf', // ⌥→ to go forward one word (^[f)\n    'Meta+ArrowLeft': '\\x01', // ⌘← to go to the beginning of a line (^A)\n    'Meta+ArrowRight': '\\x05', // ⌘→ to go to the end of a line (^E)\n    'Alt+Backspace': '\\x17', // ⌥⌫ to delete a word (^W)\n    'Meta+Backspace': '\\x15', // ⌘⌫ to delete to the beginning of a line (^U)\n\n    // copy to clipboard\n    'Control+Shift+C': function ControlShiftC() {\n      screen.copySelectionToClipboard();\n    },\n    'Control+Insert': function ControlInsert() {\n      screen.copySelectionToClipboard();\n    },\n\n\n    // toggle debug mode\n    'Control+F12': function ControlF12() {\n      screen.window.debug ^= 1;\n    }\n    /* eslint-enable key-spacing */\n\n  };\n\n  // ctrl+[A-Z] sent as simple low ASCII codes\n  for (var _i4 = 1; _i4 <= 26; _i4++) {\n    keymap['Control+' + String.fromCharCode(0x40 + _i4)] = String.fromCharCode(_i4);\n  }\n\n  /** Send a literal message */\n  function sendString(str) {\n    return conn.send('s' + str);\n  }\n\n  /** Send a button event */\n  function sendButton(index) {\n    conn.send('b' + String.fromCharCode(index + 1));\n  }\n\n  var shouldAcceptEvent = function shouldAcceptEvent() {\n    if (cfg.no_keys) return false;\n    if (document.activeElement instanceof window.HTMLTextAreaElement) return false;\n    return true;\n  };\n\n  var keyBlacklist = ['F5', 'F11', 'F12', 'Shift+F5'];\n\n  var softModifiers = {\n    alt: false,\n    ctrl: false,\n    meta: false,\n    shift: false\n  };\n\n  var handleKeyDown = function handleKeyDown(e) {\n    if (!shouldAcceptEvent()) return;\n\n    var modifiers = [];\n    // sorted alphabetically\n    if (e.altKey || softModifiers.alt) modifiers.push('Alt');\n    if (e.ctrlKey || softModifiers.ctrl) modifiers.push('Control');\n    if (e.metaKey || softModifiers.meta) modifiers.push('Meta');\n    if (e.shiftKey || softModifiers.shift) modifiers.push('Shift');\n\n    var key = KEY_NAMES[e.which] || e.key;\n\n    // ignore clipboard events\n    if ((e.ctrlKey || e.metaKey) && key === 'V') return;\n\n    var binding = null;\n\n    for (var name in keymap) {\n      var itemModifiers = name.split('+');\n      var itemKey = itemModifiers.pop();\n\n      if (itemKey === key && itemModifiers.sort().join() === modifiers.join()) {\n        if (keyBlacklist.includes(name) && !cfg.all_fn) continue;\n        binding = keymap[name];\n        break;\n      }\n    }\n\n    if (binding) {\n      if (binding instanceof Function) binding = binding();\n      e.preventDefault();\n      if (typeof binding === 'string') {\n        sendString(binding);\n      }\n    }\n  };\n\n  /** Bind/rebind key messages */\n  function initKeys(_ref) {\n    var allFn = _ref.allFn;\n\n    // This takes care of text characters typed\n    window.addEventListener('keypress', function (evt) {\n      if (!shouldAcceptEvent()) return;\n      if (evt.ctrlKey || evt.metaKey) return;\n\n      var str = '';\n      if (evt.key && evt.key.length === 1) str = evt.key;else if (evt.which && evt.which !== 229) str = String.fromCodePoint(evt.which);\n\n      if (str.length > 0 && str.charCodeAt(0) >= 32) {\n        // prevent space from scrolling\n        if (evt.which === 32) evt.preventDefault();\n        sendString(str);\n      }\n    });\n\n    window.addEventListener('keydown', handleKeyDown);\n    window.addEventListener('copy', function (e) {\n      if (!shouldAcceptEvent()) return;\n      var selectedText = screen.getSelectedText();\n      if (selectedText) {\n        e.preventDefault();\n        e.clipboardData.setData('text/plain', selectedText);\n      }\n    });\n    window.addEventListener('paste', function (e) {\n      if (!shouldAcceptEvent()) return;\n      e.preventDefault();\n      var string = e.clipboardData.getData('text/plain');\n      if (string.includes('\\n') || string.length > 90) {\n        if (!input.termUpload) console.error('input.termUpload is undefined');\n        input.termUpload.setContent(string);\n        input.termUpload.open();\n      } else {\n        // simple string, just paste it\n        if (screen.bracketedPaste) string = '\\x1B[200~' + string + '\\x1B[201~';\n        sendString(string);\n      }\n    });\n\n    cfg.all_fn = allFn;\n  }\n\n  // mouse button states\n  var mb1 = 0;\n  var mb2 = 0;\n  var mb3 = 0;\n\n  /** Init the Input module */\n  function init(opts) {\n    initKeys(opts);\n\n    // global mouse state tracking - for motion reporting\n    window.addEventListener('mousedown', function (evt) {\n      if (evt.button === 0) mb1 = 1;\n      if (evt.button === 1) mb2 = 1;\n      if (evt.button === 2) mb3 = 1;\n    });\n\n    window.addEventListener('mouseup', function (evt) {\n      if (evt.button === 0) mb1 = 0;\n      if (evt.button === 1) mb2 = 0;\n      if (evt.button === 2) mb3 = 0;\n    });\n  }\n\n  // record modifier keys\n  // bits: Meta, Alt, Shift, Ctrl\n  var modifiers = 0;\n\n  window.addEventListener('keydown', function (e) {\n    if (e.ctrlKey) modifiers |= 1;\n    if (e.shiftKey) modifiers |= 2;\n    if (e.altKey) modifiers |= 4;\n    if (e.metaKey) modifiers |= 8;\n  });\n  window.addEventListener('keyup', function (e) {\n    modifiers = 0;\n    if (e.ctrlKey) modifiers |= 1;\n    if (e.shiftKey) modifiers |= 2;\n    if (e.altKey) modifiers |= 4;\n    if (e.metaKey) modifiers |= 8;\n  });\n\n  /** Prepare modifiers byte for mouse message */\n  function packModifiersForMouse() {\n    return modifiers;\n  }\n\n  input = {\n    /** Init the Input module */\n    init: init,\n\n    /** Send a literal string message */\n    sendString: sendString,\n    sendButton: sendButton,\n\n    /** Enable alternate key modes (cursors, numpad, fn) */\n    setAlts: function setAlts(cu, np, fn, crlf) {\n      if (cfg.cu_alt !== cu || cfg.np_alt !== np || cfg.fn_alt !== fn || cfg.crlf_mode !== crlf) {\n        cfg.cu_alt = cu;\n        cfg.np_alt = np;\n        cfg.fn_alt = fn;\n        cfg.crlf_mode = crlf;\n      }\n    },\n\n    setMouseMode: function setMouseMode(click, move) {\n      cfg.mt_click = click;\n      cfg.mt_move = move;\n    },\n\n\n    // Mouse events\n    onMouseMove: function onMouseMove(x, y) {\n      if (!cfg.mt_move) return;\n      var b = mb1 ? 1 : mb2 ? 2 : mb3 ? 3 : 0;\n      var m = packModifiersForMouse();\n      conn.send('m' + encode2B(y) + encode2B(x) + encode2B(b) + encode2B(m));\n    },\n    onMouseDown: function onMouseDown(x, y, b) {\n      if (!cfg.mt_click) return;\n      if (b > 3 || b < 1) return;\n      var m = packModifiersForMouse();\n      conn.send('p' + encode2B(y) + encode2B(x) + encode2B(b) + encode2B(m));\n    },\n    onMouseUp: function onMouseUp(x, y, b) {\n      if (!cfg.mt_click) return;\n      if (b > 3 || b < 1) return;\n      var m = packModifiersForMouse();\n      conn.send('r' + encode2B(y) + encode2B(x) + encode2B(b) + encode2B(m));\n      // console.log(\"B \",b,\" M \",m);\n    },\n    onMouseWheel: function onMouseWheel(x, y, dir) {\n      if (!cfg.mt_click) return;\n      // -1 ... btn 4 (away from user)\n      // +1 ... btn 5 (towards user)\n      var m = packModifiersForMouse();\n      var b = dir < 0 ? 4 : 5;\n      conn.send('p' + encode2B(y) + encode2B(x) + encode2B(b) + encode2B(m));\n      // console.log(\"B \",b,\" M \",m);\n    },\n\n\n    /**\n     * Prevent capturing keys. This is used for text input\n     * modals on the terminal screen\n     */\n    blockKeys: function blockKeys(yes) {\n      cfg.no_keys = yes;\n    },\n\n\n    handleKeyDown: handleKeyDown,\n    softModifiers: softModifiers\n  };\n  return input;\n};\n\n/***/ }),\n/* 20 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nvar $ = __webpack_require__(1);\n\nvar _require = __webpack_require__(0),\n    qs = _require.qs;\n\nvar modal = __webpack_require__(2);\n\n/** File upload utility */\nmodule.exports = function (conn, input, screen) {\n  var lines = void 0,\n      // array of lines without newlines\n  line_i = void 0,\n      // current line index\n  fuTout = void 0,\n      // timeout handle for line sending\n  send_delay_ms = void 0,\n      // delay between lines (ms)\n  nl_str = void 0,\n      // newline string to use\n  curLine = void 0,\n      // current line (when using fuOil)\n  inline_pos = void 0; // Offset in line (for long lines)\n\n  // lines longer than this are split to chunks\n  // sending a super-ling string through the socket is not a good idea\n  var MAX_LINE_LEN = 128;\n\n  function openUploadDialog() {\n    updateStatus('Ready...');\n    modal.show('#fu_modal', onDialogClose);\n    $('#fu_form').toggleClass('busy', false);\n    input.blockKeys(true);\n  }\n\n  function onDialogClose() {\n    console.log('Upload modal closed.');\n    clearTimeout(fuTout);\n    line_i = 0;\n    input.blockKeys(false);\n  }\n\n  function updateStatus(msg) {\n    qs('#fu_prog').textContent = msg;\n  }\n\n  function startUpload() {\n    var v = qs('#fu_text').value;\n    if (!v.length) {\n      fuClose();\n      return;\n    }\n\n    lines = v.split('\\n');\n    line_i = 0;\n    inline_pos = 0; // offset in line\n    send_delay_ms = +qs('#fu_delay').value;\n\n    // sanitize - 0 causes overflows\n    if (send_delay_ms < 0) {\n      send_delay_ms = 0;\n      qs('#fu_delay').value = send_delay_ms;\n    }\n\n    nl_str = {\n      'CR': '\\r',\n      'LF': '\\n',\n      'CRLF': '\\r\\n'\n    }[qs('#fu_crlf').value];\n\n    $('#fu_form').toggleClass('busy', true);\n    updateStatus('Starting...');\n    uploadLine();\n  }\n\n  function uploadLine() {\n    if (!$('#fu_modal').hasClass('visible')) {\n      // Modal is closed, cancel\n      return;\n    }\n\n    if (!conn.canSend()) {\n      // postpone\n      fuTout = setTimeout(uploadLine, 1);\n      return;\n    }\n\n    if (inline_pos === 0) {\n      curLine = '';\n      if (line_i === 0) {\n        if (screen.bracketedPaste) {\n          curLine = '\\x1b[200~';\n        }\n      }\n\n      curLine += lines[line_i++] + nl_str;\n\n      if (line_i === lines.length) {\n        if (screen.bracketedPaste) {\n          curLine += '\\x1b[201~';\n        }\n      }\n    }\n\n    var maxChunk = +qs('#fu_chunk').value;\n    if (maxChunk === 0 || maxChunk > MAX_LINE_LEN) {\n      maxChunk = MAX_LINE_LEN;\n    }\n\n    var chunk = void 0;\n    if (curLine.length - inline_pos <= maxChunk) {\n      chunk = curLine.substr(inline_pos, maxChunk);\n      inline_pos = 0;\n    } else {\n      chunk = curLine.substr(inline_pos, maxChunk);\n      inline_pos += maxChunk;\n    }\n\n    if (!input.sendString(chunk)) {\n      updateStatus('FAILED!');\n      return;\n    }\n\n    var pt = Math.round(line_i / lines.length * 1000) / 10;\n    updateStatus(line_i + ' / ' + lines.length + ' (' + pt + '%)');\n\n    if (lines.length > line_i || inline_pos > 0) {\n      fuTout = setTimeout(uploadLine, send_delay_ms);\n    } else {\n      closeWhenReady();\n    }\n  }\n\n  function closeWhenReady() {\n    if (!conn.canSend()) {\n      // stuck in XOFF still, wait to process...\n      updateStatus('Waiting for Tx buffer...');\n      setTimeout(closeWhenReady, 100);\n    } else {\n      updateStatus('Done.');\n      // delay to show it\n      fuClose();\n    }\n  }\n\n  function fuClose() {\n    modal.hide('#fu_modal');\n  }\n\n  return {\n    init: function init() {\n      qs('#fu_file').addEventListener('change', function (evt) {\n        var reader = new window.FileReader();\n        var file = evt.target.files[0];\n        var ftype = file.type || 'application/octet-stream';\n        console.log('Selected file type: ' + ftype);\n        if (!ftype.match(/text\\/.*|application\\/(json|csv|.*xml.*|.*script.*|x-php)/)) {\n          // Deny load of blobs like img - can crash browser and will get corrupted anyway\n          if (!window.confirm('This does not look like a text file: ' + ftype + '\\nReally load?')) {\n            qs('#fu_file').value = '';\n            return;\n          }\n        }\n        reader.onload = function (e) {\n          var txt = e.target.result.replace(/[\\r\\n]+/, '\\n');\n          qs('#fu_text').value = txt;\n        };\n        console.log('Loading file...');\n        reader.readAsText(file);\n      }, false);\n\n      qs('#term-fu-open').addEventListener('click', function (e) {\n        e.preventDefault();\n        openUploadDialog();\n      });\n\n      qs('#term-fu-start').addEventListener('click', function (e) {\n        e.preventDefault();\n        startUpload();\n      });\n\n      qs('#term-fu-close').addEventListener('click', function (e) {\n        e.preventDefault();\n        fuClose();\n      });\n    },\n    open: openUploadDialog,\n    setContent: function setContent(content) {\n      qs('#fu_text').value = content;\n    }\n  };\n};\n\n/***/ }),\n/* 21 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nvar _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i[\"return\"]) _i[\"return\"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError(\"Invalid attempt to destructure non-iterable instance\"); } }; }();\n\nvar _require = __webpack_require__(0),\n    qs = _require.qs;\n\nmodule.exports = function (screen, input) {\n  var keyInput = qs('#softkb-input');\n  if (!keyInput) return; // abort, we're not on the terminal page\n\n  var shortcutBar = document.createElement('div');\n  shortcutBar.id = 'keyboard-shortcut-bar';\n  if (navigator.userAgent.match(/iPad|iPhone|iPod/)) {\n    qs('#screen').appendChild(shortcutBar);\n  }\n\n  var keyboardOpen = false;\n\n  // moves the input to where the cursor is on the canvas.\n  // this is because most browsers will always scroll to wherever the focused\n  // input is\n  var updateInputPosition = function updateInputPosition() {\n    if (!keyboardOpen) return;\n\n    var _screen$gridToScreen = screen.gridToScreen(screen.cursor.x, screen.cursor.y, true),\n        _screen$gridToScreen2 = _slicedToArray(_screen$gridToScreen, 2),\n        x = _screen$gridToScreen2[0],\n        y = _screen$gridToScreen2[1];\n\n    keyInput.style.transform = 'translate(' + x + 'px, ' + y + 'px)';\n  };\n\n  keyInput.addEventListener('focus', function () {\n    keyboardOpen = true;\n    updateInputPosition();\n    shortcutBar.classList.add('open');\n  });\n\n  keyInput.addEventListener('blur', function () {\n    keyboardOpen = false;\n    shortcutBar.classList.remove('open');\n  });\n\n  screen.on('cursor-moved', updateInputPosition);\n\n  qs('#term-kb-open').addEventListener('click', function (e) {\n    e.preventDefault();\n    keyInput.focus();\n  });\n\n  // Chrome for Android doesn't send proper keydown/keypress events with\n  // real key values instead of 229 “Unidentified,” so here's a workaround\n  // that deals with the input composition events.\n\n  var lastCompositionString = '';\n\n  // sends the difference between the last and the new composition string\n  var sendInputDelta = function sendInputDelta(newValue) {\n    if (newValue === null) newValue = ''; // this sometimes happens, why?\n    var resend = false;\n    if (newValue.length > lastCompositionString.length) {\n      if (newValue.startsWith(lastCompositionString)) {\n        // characters have been added at the end\n        input.sendString(newValue.substr(lastCompositionString.length));\n      } else resend = true;\n    } else if (newValue.length < lastCompositionString.length) {\n      if (lastCompositionString.startsWith(newValue)) {\n        // characters have been removed at the end\n        input.sendString('\\b'.repeat(lastCompositionString.length - newValue.length));\n      } else resend = true;\n    } else if (newValue !== lastCompositionString) resend = true;\n\n    if (resend) {\n      // the entire string changed; resend everything\n      input.sendString('\\b'.repeat(lastCompositionString.length) + newValue);\n    }\n    lastCompositionString = newValue;\n  };\n\n  keyInput.addEventListener('keydown', function (e) {\n    if (e.key === 'Unidentified') return;\n\n    keyInput.value = '';\n\n    e.stopPropagation();\n    input.handleKeyDown(e);\n  });\n\n  keyInput.addEventListener('keypress', function (e) {\n    // prevent key duplication on iOS (because Safari *does* send proper events)\n    e.stopPropagation();\n  });\n\n  keyInput.addEventListener('input', function (e) {\n    e.stopPropagation();\n\n    if (e.isComposing && 'data' in e) {\n      sendInputDelta(e.data);\n    } else if (e.isComposing) {\n      // Firefox Mobile doesn't support InputEvent#data, so here's a hack\n      // that just takes the input value and uses that\n      sendInputDelta(keyInput.value);\n    } else {\n      if (e.inputType === 'insertCompositionText') input.sendString(e.data);else if (e.inputType === 'deleteContentBackward') {\n        lastCompositionString = '';\n        sendInputDelta('');\n      } else if (e.inputType === 'insertText') {\n        input.sendString(e.data);\n      }\n    }\n  });\n\n  keyInput.addEventListener('compositionstart', function (e) {\n    lastCompositionString = '';\n  });\n\n  keyInput.addEventListener('compositionend', function (e) {\n    lastCompositionString = '';\n    keyInput.value = '';\n  });\n\n  screen.on('open-soft-keyboard', function () {\n    return keyInput.focus();\n  });\n\n  // shortcut bar\n  var shortcuts = {\n    Control: 'ctrl',\n    Esc: 0x1b,\n    Tab: 0x09,\n    '←': 0x25,\n    '↓': 0x28,\n    '↑': 0x26,\n    '→': 0x27\n  };\n\n  var touchMoved = false;\n\n  var _loop = function _loop(shortcut) {\n    var button = document.createElement('button');\n    button.classList.add('shortcut-button');\n    button.textContent = shortcut;\n    shortcutBar.appendChild(button);\n\n    var key = shortcuts[shortcut];\n    if (typeof key === 'string') button.classList.add('modifier');\n    button.addEventListener('touchstart', function (e) {\n      touchMoved = false;\n      if (typeof key === 'string') {\n        // modifier button\n        input.softModifiers[key] = true;\n        button.classList.add('enabled');\n\n        // prevent default. This prevents scrolling, but also prevents the\n        // selection popup\n        e.preventDefault();\n      }\n    });\n    window.addEventListener('touchmove', function (e) {\n      touchMoved = true;\n    });\n    button.addEventListener('touchend', function (e) {\n      e.preventDefault();\n      if (typeof key === 'number') {\n        if (touchMoved) return;\n        var fakeEvent = { which: key, preventDefault: function preventDefault() {} };\n        input.handleKeyDown(fakeEvent);\n      } else if (typeof key === 'string') {\n        button.classList.remove('enabled');\n        input.softModifiers[key] = false;\n      }\n    });\n  };\n\n  for (var shortcut in shortcuts) {\n    _loop(shortcut);\n  }\n};\n\n/***/ }),\n/* 22 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nvar _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i[\"return\"]) _i[\"return\"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError(\"Invalid attempt to destructure non-iterable instance\"); } }; }();\n\nfunction _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }\n\nvar _require = __webpack_require__(0),\n    mk = _require.mk;\n\nmodule.exports = function attachDebugScreen(screen) {\n  var debugCanvas = mk('canvas');\n  var ctx = debugCanvas.getContext('2d');\n\n  debugCanvas.classList.add('debug-canvas');\n\n  var mouseHoverCell = null;\n  var updateToolbar = void 0;\n\n  var onMouseMove = function onMouseMove(e) {\n    mouseHoverCell = screen.screenToGrid(e.offsetX, e.offsetY);\n    startDrawing();\n    updateToolbar();\n  };\n  var onMouseOut = function onMouseOut() {\n    return mouseHoverCell = null;\n  };\n\n  var addCanvas = function addCanvas() {\n    if (!debugCanvas.parentNode) {\n      screen.canvas.parentNode.appendChild(debugCanvas);\n      screen.canvas.addEventListener('mousemove', onMouseMove);\n      screen.canvas.addEventListener('mouseout', onMouseOut);\n    }\n  };\n  var removeCanvas = function removeCanvas() {\n    if (debugCanvas.parentNode) {\n      debugCanvas.parentNode.removeChild(debugCanvas);\n      screen.canvas.removeEventListener('mousemove', onMouseMove);\n      screen.canvas.removeEventListener('mouseout', onMouseOut);\n      onMouseOut();\n    }\n  };\n  var updateCanvasSize = function updateCanvasSize() {\n    var _screen$window = screen.window,\n        width = _screen$window.width,\n        height = _screen$window.height,\n        devicePixelRatio = _screen$window.devicePixelRatio;\n\n    var cellSize = screen.getCellSize();\n    debugCanvas.width = width * cellSize.width * devicePixelRatio;\n    debugCanvas.height = height * cellSize.height * devicePixelRatio;\n    debugCanvas.style.width = width * cellSize.width + 'px';\n    debugCanvas.style.height = height * cellSize.height + 'px';\n  };\n\n  var drawInfo = mk('div');\n  drawInfo.classList.add('draw-info');\n\n  var startTime = void 0,\n      endTime = void 0,\n      lastReason = void 0;\n  var cells = new Map();\n  var clippedRects = [];\n  var updateFrames = [];\n\n  var startDrawing = void 0;\n\n  screen._debug = {\n    drawStart: function drawStart(reason) {\n      lastReason = reason;\n      startTime = Date.now();\n      clippedRects = [];\n    },\n    drawEnd: function drawEnd() {\n      endTime = Date.now();\n      console.log(drawInfo.textContent = 'Draw: ' + lastReason + ' (' + (endTime - startTime) + ' ms) with graphics=' + screen.window.graphics);\n      startDrawing();\n    },\n    setCell: function setCell(cell, flags) {\n      cells.set(cell, [flags, Date.now()]);\n    },\n    clipRect: function clipRect() {\n      for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {\n        args[_key] = arguments[_key];\n      }\n\n      clippedRects.push(args);\n    },\n    pushFrame: function pushFrame(frame) {\n      frame.push(Date.now());\n      updateFrames.push(frame);\n      startDrawing();\n    }\n  };\n\n  var clipPattern = void 0;\n  {\n    var patternCanvas = document.createElement('canvas');\n    patternCanvas.width = patternCanvas.height = 12;\n    var pctx = patternCanvas.getContext('2d');\n    pctx.lineWidth = 1;\n    pctx.strokeStyle = '#00f';\n    pctx.beginPath();\n    pctx.moveTo(0, 0);\n    pctx.lineTo(0 - 4, 12);\n    pctx.moveTo(4, 0);\n    pctx.lineTo(4 - 4, 12);\n    pctx.moveTo(8, 0);\n    pctx.lineTo(8 - 4, 12);\n    pctx.moveTo(12, 0);\n    pctx.lineTo(12 - 4, 12);\n    pctx.moveTo(16, 0);\n    pctx.lineTo(16 - 4, 12);\n    pctx.stroke();\n    clipPattern = ctx.createPattern(patternCanvas, 'repeat');\n  }\n\n  var isDrawing = false;\n  var lastDrawTime = 0;\n  var t = 0;\n\n  var drawLoop = function drawLoop() {\n    if (isDrawing) window.requestAnimationFrame(drawLoop);\n\n    var dt = (Date.now() - lastDrawTime) / 1000;\n    lastDrawTime = Date.now();\n    t += dt;\n\n    var _screen$window2 = screen.window,\n        devicePixelRatio = _screen$window2.devicePixelRatio,\n        width = _screen$window2.width,\n        height = _screen$window2.height;\n\n    var _screen$getCellSize = screen.getCellSize(),\n        cellWidth = _screen$getCellSize.width,\n        cellHeight = _screen$getCellSize.height;\n\n    var screenLength = width * height;\n    var now = Date.now();\n\n    ctx.setTransform(devicePixelRatio, 0, 0, devicePixelRatio, 0, 0);\n    ctx.clearRect(0, 0, width * cellWidth, height * cellHeight);\n\n    var activeCells = 0;\n    for (var cell = 0; cell < screenLength; cell++) {\n      if (!cells.has(cell) || cells.get(cell)[0] === 0) continue;\n\n      var _cells$get = cells.get(cell),\n          _cells$get2 = _slicedToArray(_cells$get, 2),\n          flags = _cells$get2[0],\n          timestamp = _cells$get2[1];\n\n      var elapsedTime = (now - timestamp) / 1000;\n\n      if (elapsedTime > 1) continue;\n\n      activeCells++;\n      ctx.globalAlpha = 0.5 * Math.max(0, 1 - elapsedTime);\n\n      var x = cell % width;\n      var y = Math.floor(cell / width);\n\n      if (flags & 1) {\n        // redrawn\n        ctx.fillStyle = '#f0f';\n      }\n      if (flags & 2) {\n        // updated\n        ctx.fillStyle = '#0f0';\n      }\n\n      ctx.fillRect(x * cellWidth, y * cellHeight, cellWidth, cellHeight);\n\n      if (flags & 4) {\n        // wide cell\n        ctx.lineWidth = 2;\n        ctx.strokeStyle = '#f00';\n        ctx.strokeRect(x * cellWidth, y * cellHeight, cellWidth, cellHeight);\n      }\n    }\n\n    if (clippedRects.length) {\n      ctx.globalAlpha = 0.5;\n      ctx.beginPath();\n\n      var _iteratorNormalCompletion = true;\n      var _didIteratorError = false;\n      var _iteratorError = undefined;\n\n      try {\n        for (var _iterator = clippedRects[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {\n          var rect = _step.value;\n\n          ctx.rect.apply(ctx, _toConsumableArray(rect));\n        }\n      } catch (err) {\n        _didIteratorError = true;\n        _iteratorError = err;\n      } finally {\n        try {\n          if (!_iteratorNormalCompletion && _iterator.return) {\n            _iterator.return();\n          }\n        } finally {\n          if (_didIteratorError) {\n            throw _iteratorError;\n          }\n        }\n      }\n\n      ctx.fillStyle = clipPattern;\n      ctx.fill();\n    }\n\n    var didDrawUpdateFrames = false;\n    if (updateFrames.length) {\n      var framesToDelete = [];\n      var _iteratorNormalCompletion2 = true;\n      var _didIteratorError2 = false;\n      var _iteratorError2 = undefined;\n\n      try {\n        for (var _iterator2 = updateFrames[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {\n          var frame = _step2.value;\n\n          var time = frame[4];\n          var elapsed = Date.now() - time;\n          if (elapsed > 1000) framesToDelete.push(frame);else {\n            didDrawUpdateFrames = true;\n            ctx.globalAlpha = 1 - elapsed / 1000;\n            ctx.strokeStyle = '#ff0';\n            ctx.lineWidth = 2;\n            ctx.strokeRect(frame[0] * cellWidth, frame[1] * cellHeight, frame[2] * cellWidth, frame[3] * cellHeight);\n          }\n        }\n      } catch (err) {\n        _didIteratorError2 = true;\n        _iteratorError2 = err;\n      } finally {\n        try {\n          if (!_iteratorNormalCompletion2 && _iterator2.return) {\n            _iterator2.return();\n          }\n        } finally {\n          if (_didIteratorError2) {\n            throw _iteratorError2;\n          }\n        }\n      }\n\n      var _iteratorNormalCompletion3 = true;\n      var _didIteratorError3 = false;\n      var _iteratorError3 = undefined;\n\n      try {\n        for (var _iterator3 = framesToDelete[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {\n          var _frame = _step3.value;\n\n          updateFrames.splice(updateFrames.indexOf(_frame), 1);\n        }\n      } catch (err) {\n        _didIteratorError3 = true;\n        _iteratorError3 = err;\n      } finally {\n        try {\n          if (!_iteratorNormalCompletion3 && _iterator3.return) {\n            _iterator3.return();\n          }\n        } finally {\n          if (_didIteratorError3) {\n            throw _iteratorError3;\n          }\n        }\n      }\n    }\n\n    if (mouseHoverCell) {\n      ctx.save();\n      ctx.globalAlpha = 1;\n      ctx.lineWidth = 1 + 0.5 * Math.sin(t * 10);\n      ctx.strokeStyle = '#fff';\n      ctx.lineJoin = 'round';\n      ctx.setLineDash([2, 2]);\n      ctx.lineDashOffset = t * 10;\n      ctx.strokeRect(mouseHoverCell[0] * cellWidth, mouseHoverCell[1] * cellHeight, cellWidth, cellHeight);\n      ctx.lineDashOffset += 2;\n      ctx.strokeStyle = '#000';\n      ctx.strokeRect(mouseHoverCell[0] * cellWidth, mouseHoverCell[1] * cellHeight, cellWidth, cellHeight);\n      ctx.restore();\n    }\n\n    if (activeCells === 0 && !mouseHoverCell && !didDrawUpdateFrames) {\n      isDrawing = false;\n      removeCanvas();\n    }\n  };\n\n  startDrawing = function startDrawing() {\n    if (isDrawing) return;\n    addCanvas();\n    updateCanvasSize();\n    isDrawing = true;\n    lastDrawTime = Date.now();\n    drawLoop();\n  };\n\n  // debug toolbar\n  var toolbar = mk('div');\n  toolbar.classList.add('debug-toolbar');\n  var toolbarAttached = false;\n  var dataDisplay = mk('div');\n  dataDisplay.classList.add('data-display');\n  toolbar.appendChild(dataDisplay);\n  var internalDisplay = mk('div');\n  internalDisplay.classList.add('internal-display');\n  toolbar.appendChild(internalDisplay);\n  toolbar.appendChild(drawInfo);\n  var buttons = mk('div');\n  buttons.classList.add('toolbar-buttons');\n  toolbar.appendChild(buttons);\n\n  {\n    var redraw = mk('button');\n    redraw.textContent = 'Redraw';\n    redraw.addEventListener('click', function (e) {\n      screen.renderer.resetDrawn();\n      screen.renderer.draw('debug-redraw');\n    });\n    buttons.appendChild(redraw);\n\n    var fancyGraphics = mk('button');\n    fancyGraphics.textContent = 'Toggle Graphics';\n    fancyGraphics.addEventListener('click', function (e) {\n      screen.window.graphics = +!screen.window.graphics;\n    });\n    buttons.appendChild(fancyGraphics);\n  }\n\n  var attachToolbar = function attachToolbar() {\n    screen.canvas.parentNode.appendChild(toolbar);\n  };\n  var detachToolbar = function detachToolbar() {\n    toolbar.parentNode.removeChild(toolbar);\n  };\n\n  screen.on('update-window:debug', function (debug) {\n    if (debug !== toolbarAttached) {\n      toolbarAttached = debug;\n      if (debug) attachToolbar();else {\n        detachToolbar();\n        removeCanvas();\n      }\n    }\n  });\n\n  var displayCellAttrs = function displayCellAttrs(attrs) {\n    var result = attrs.toString(16);\n    if (attrs & 1 || attrs & 2) {\n      result += ':has(';\n      if (attrs & 1) result += 'fg';\n      if (attrs & 2) result += (attrs & 1 ? ',' : '') + 'bg';\n      result += ')';\n    }\n    var attributes = [];\n    if (attrs & 1 << 2) attributes.push('\\\\[bold]bold\\\\()');\n    if (attrs & 1 << 3) attributes.push('\\\\[underline]underln\\\\()');\n    if (attrs & 1 << 4) attributes.push('\\\\[invert]invert\\\\()');\n    if (attrs & 1 << 5) attributes.push('blink');\n    if (attrs & 1 << 6) attributes.push('\\\\[italic]italic\\\\()');\n    if (attrs & 1 << 7) attributes.push('\\\\[strike]strike\\\\()');\n    if (attrs & 1 << 8) attributes.push('\\\\[overline]overln\\\\()');\n    if (attrs & 1 << 9) attributes.push('\\\\[faint]faint\\\\()');\n    if (attrs & 1 << 10) attributes.push('fraktur');\n    if (attributes.length) result += ':' + attributes.join();\n    return result.trim();\n  };\n\n  var formatColor = function formatColor(color) {\n    return color < 256 ? color : '#' + ('000000' + (color - 256).toString(16)).substr(-6);\n  };\n  var getCellData = function getCellData(cell) {\n    if (cell < 0 || cell > screen.screen.length) return '(-)';\n    var cellAttrs = screen.renderer.drawnScreenAttrs[cell] | 0;\n    var cellFG = screen.renderer.drawnScreenFG[cell] | 0;\n    var cellBG = screen.renderer.drawnScreenBG[cell] | 0;\n    var fgText = formatColor(cellFG);\n    var bgText = formatColor(cellBG);\n    fgText += '\\\\[color=' + screen.renderer.getColor(cellFG).replace(/ /g, '') + ']\\u25CF\\\\[]';\n    bgText += '\\\\[color=' + screen.renderer.getColor(cellBG).replace(/ /g, '') + ']\\u25CF\\\\[]';\n    var cellCode = (screen.renderer.drawnScreen[cell] || '').codePointAt(0) | 0;\n    var hexcode = cellCode.toString(16).toUpperCase();\n    if (hexcode.length < 4) hexcode = ('0000' + hexcode).substr(-4);\n    hexcode = 'U+' + hexcode;\n    var x = cell % screen.window.width;\n    var y = Math.floor(cell / screen.window.width);\n    return '((' + y + ',' + x + ')=' + cell + ':\\\\[bold]' + hexcode + '\\\\[]:F' + fgText + ':B' + bgText + ':A(' + displayCellAttrs(cellAttrs) + '))';\n  };\n\n  var setFormattedText = function setFormattedText(node, text) {\n    node.innerHTML = '';\n\n    var match = void 0;\n    var attrs = {};\n\n    var pushSpan = function pushSpan(content) {\n      var span = mk('span');\n      node.appendChild(span);\n      span.textContent = content;\n      for (var key in attrs) {\n        span[key] = attrs[key];\n      }\n    };\n\n    while (match = text.match(/\\\\\\[(.*?)\\]/)) {\n      if (match.index > 0) pushSpan(text.substr(0, match.index));\n\n      attrs = { style: '' };\n      var data = match[1].split(' ');\n      var _iteratorNormalCompletion4 = true;\n      var _didIteratorError4 = false;\n      var _iteratorError4 = undefined;\n\n      try {\n        for (var _iterator4 = data[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {\n          var attr = _step4.value;\n\n          if (!attr) continue;\n          var key = void 0,\n              value = void 0;\n          if (attr.indexOf('=') > -1) {\n            key = attr.substr(0, attr.indexOf('='));\n            value = attr.substr(attr.indexOf('=') + 1);\n          } else {\n            key = attr;\n            value = true;\n          }\n\n          if (key === 'color') console.log(value);\n\n          if (key === 'bold') attrs.style += 'font-weight:bold;';\n          if (key === 'italic') attrs.style += 'font-style:italic;';\n          if (key === 'underline') attrs.style += 'text-decoration:underline;';\n          if (key === 'invert') attrs.style += 'background:#000;filter:invert(1);';\n          if (key === 'strike') attrs.style += 'text-decoration:line-through;';\n          if (key === 'overline') attrs.style += 'text-decoration:overline;';\n          if (key === 'faint') attrs.style += 'opacity:0.5;';else if (key === 'color') attrs.style += 'color:' + value + ';';else attrs[key] = value;\n        }\n      } catch (err) {\n        _didIteratorError4 = true;\n        _iteratorError4 = err;\n      } finally {\n        try {\n          if (!_iteratorNormalCompletion4 && _iterator4.return) {\n            _iterator4.return();\n          }\n        } finally {\n          if (_didIteratorError4) {\n            throw _iteratorError4;\n          }\n        }\n      }\n\n      text = text.substr(match.index + match[0].length);\n    }\n\n    if (text) pushSpan(text);\n  };\n\n  var internalInfo = {};\n\n  updateToolbar = function updateToolbar() {\n    if (!toolbarAttached) return;\n    var text = 'C((' + screen.cursor.y + ',' + screen.cursor.x + '),hang:' + screen.cursor.hanging + ',vis:' + screen.cursor.visible + ')';\n    if (mouseHoverCell) {\n      text += ' m' + getCellData(mouseHoverCell[1] * screen.window.width + mouseHoverCell[0]);\n    }\n    setFormattedText(dataDisplay, text);\n\n    if ('flags' in internalInfo) {\n      // we got ourselves some internal data\n      var _text = ' ';\n      _text += ' flags:' + internalInfo.flags.toString(2);\n      _text += ' curAttrs:' + internalInfo.cursorAttrs.toString(2);\n      _text += ' Region:' + internalInfo.regionStart + '->' + internalInfo.regionEnd;\n      _text += ' Charset:' + internalInfo.charsetGx + ' (0:' + internalInfo.charsetG0 + ',1:' + internalInfo.charsetG1 + ')';\n      _text += ' Heap:' + internalInfo.freeHeap;\n      _text += ' Clients:' + internalInfo.clientCount;\n      setFormattedText(internalDisplay, _text);\n    }\n  };\n\n  screen.on('draw', updateToolbar);\n  screen.on('internal', function (data) {\n    internalInfo = data;\n    updateToolbar();\n  });\n};\n\n/***/ }),\n/* 23 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nvar _require = __webpack_require__(0),\n    qs = _require.qs;\n\nmodule.exports = function initButtons(input) {\n  var container = qs('#action-buttons');\n\n  // button labels\n  var labels = [];\n\n  // button elements\n  var buttons = [];\n\n  // add a button element\n  var pushButton = function pushButton() {\n    var button = document.createElement('button');\n    button.classList.add('action-button');\n    button.setAttribute('data-n', buttons.length);\n    buttons.push(button);\n    container.appendChild(button);\n\n    button.addEventListener('click', function (e) {\n      // might as well use the attribute ¯\\_(ツ)_/¯\n      var index = +button.getAttribute('data-n');\n      input.sendButton(index);\n    });\n\n    return button;\n  };\n\n  // remove a button element\n  var popButton = function popButton() {\n    var button = buttons.pop();\n    button.parentNode.removeChild(button);\n  };\n\n  // sync with DOM\n  var update = function updateButtons() {\n    if (labels.length > buttons.length) {\n      for (var i = buttons.length; i < labels.length; i++) {\n        pushButton();\n      }\n    } else if (buttons.length > labels.length) {\n      for (var _i = labels.length; _i <= buttons.length; _i++) {\n        popButton();\n      }\n    }\n\n    for (var _i2 = 0; _i2 < labels.length; _i2++) {\n      var label = labels[_i2].trim();\n      var button = buttons[_i2];\n      button.textContent = label || '\\xA0'; // label or nbsp\n      if (!label) button.classList.add('inactive');else button.classList.remove('inactive');\n    }\n  };\n\n  return { update: update, labels: labels };\n};\n\n/***/ }),\n/* 24 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nvar ColorTriangle = __webpack_require__(25);\nvar $ = __webpack_require__(1);\nvar themes = __webpack_require__(5);\n\nvar _require = __webpack_require__(0),\n    qs = _require.qs;\n\nfunction selectedTheme() {\n  return +$('#theme').val();\n}\n\nexports.init = function () {\n  $('#theme').on('change', showColor);\n\n  $('#default_fg').on('input', showColor);\n  $('#default_bg').on('input', showColor);\n\n  var opts = {\n    padding: 10,\n    event: 'drag',\n    uppercase: true,\n    trianglePointerSize: 20,\n    // wheelPointerSize: 12,\n    size: 200,\n    parseColor: function parseColor(color) {\n      return themes.toHex(color, selectedTheme());\n    }\n  };\n\n  ColorTriangle.initInput(qs('#default_fg'), opts);\n  ColorTriangle.initInput(qs('#default_bg'), opts);\n\n  $('.colorprev.bg span').on('click', function () {\n    var bg = this.dataset.bg;\n    if (typeof bg != 'undefined') $('#default_bg').val(bg);\n    showColor();\n  });\n\n  $('.colorprev.fg span').on('click', function () {\n    var fg = this.dataset.fg;\n    if (typeof fg != 'undefined') $('#default_fg').val(fg);\n    showColor();\n  });\n\n  var $presets = $('#fgbg_presets');\n  for (var i = 0; i < themes.fgbgThemes.length; i++) {\n    var thm = themes.fgbgThemes[i];\n    var fg = thm[0];\n    var bg = thm[1];\n    var lbl = thm[2];\n    var tit = thm[3];\n    $presets.htmlAppend('<span class=\"preset\" ' + 'data-xfg=\"' + fg + '\" data-xbg=\"' + bg + '\" ' + 'style=\"color:' + fg + ';background:' + bg + '\" title=\"' + tit + '\">&nbsp;' + lbl + '&nbsp;</span>');\n\n    if ((i + 1) % 5 === 0) $presets.htmlAppend('<br>');\n  }\n\n  $('.preset').on('click', function () {\n    $('#default_fg').val(this.dataset.xfg);\n    $('#default_bg').val(this.dataset.xbg);\n    showColor();\n  });\n\n  showColor();\n};\n\nfunction showColor() {\n  var ex = qs('.color-example');\n  var fg = $('#default_fg').val();\n  var bg = $('#default_bg').val();\n\n  if (/^\\d+$/.test(fg)) {\n    fg = +fg;\n  } else if (!/^#[\\da-f]{6}$/i.test(fg)) {\n    fg = 'black';\n  }\n\n  if (/^\\d+$/.test(bg)) {\n    bg = +bg;\n  } else if (!/^#[\\da-f]{6}$/i.test(bg)) {\n    bg = 'black';\n  }\n\n  var themeN = selectedTheme();\n  ex.dataset.fg = fg;\n  ex.dataset.bg = bg;\n\n  themes.themePreview(themeN);\n\n  $('.colorprev.fg span').css('background', themes.toHex(bg, themeN));\n}\n\nexports.nextTheme = function () {\n  var sel = qs('#theme');\n  var i = sel.selectedIndex;\n  sel.options[++i % sel.options.length].selected = true;\n  showColor();\n};\n\nexports.prevTheme = function () {\n  var sel = qs('#theme');\n  var i = sel.selectedIndex;\n  sel.options[(sel.options.length + --i) % sel.options.length].selected = true;\n  showColor();\n};\n\n/***/ }),\n/* 25 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nvar _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();\n\nfunction _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return call && (typeof call === \"object\" || typeof call === \"function\") ? call : self; }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function, not \" + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }\n\n/*\n * Copyright (c) 2010 Tim Baumann\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n// NOTE: Converted to ES6 by MightyPork (2017)\n// Modified for ESPTerm\n\nvar EventEmitter = __webpack_require__(4);\n\nvar _require = __webpack_require__(7),\n    rgb2hex = _require.rgb2hex,\n    hex2rgb = _require.hex2rgb,\n    hsl2rgb = _require.hsl2rgb,\n    rgb2hsl = _require.rgb2hsl;\n\nvar win = window;\nvar doc = document;\nvar M = Math;\nvar TAU = 2 * M.PI;\n\nfunction times(i, fn) {\n  for (var j = 0; j < i; j++) {\n    fn(j);\n  }\n}\n\nfunction each(obj, fn) {\n  if (obj.length) {\n    times(obj.length, function (i) {\n      fn(obj[i], i);\n    });\n  } else {\n    for (var key in obj) {\n      if (obj.hasOwnProperty(key)) {\n        fn(obj[key], key);\n      }\n    }\n  }\n}\n\nmodule.exports = function (_EventEmitter) {\n  _inherits(ColorTriangle, _EventEmitter);\n\n  /****************\n   * ColorTriangle *\n   ****************/\n\n  // Constructor function:\n  function ColorTriangle(color, options) {\n    _classCallCheck(this, ColorTriangle);\n\n    var _this = _possibleConstructorReturn(this, (ColorTriangle.__proto__ || Object.getPrototypeOf(ColorTriangle)).call(this));\n\n    _this.options = {\n      size: 150,\n      padding: 8,\n      triangleSize: 0.8,\n      wheelPointerColor1: '#444',\n      wheelPointerColor2: '#eee',\n      trianglePointerSize: 16,\n      // wheelPointerSize: 16,\n      trianglePointerColor1: '#eee',\n      trianglePointerColor2: '#444',\n      background: 'transparent'\n    };\n\n    _this.pixelRatio = window.devicePixelRatio;\n\n    _this.setOptions(options);\n    _this.calculateProperties();\n\n    _this.createContainer();\n    _this.createTriangle();\n    _this.createWheel();\n    _this.createWheelPointer();\n    _this.createTrianglePointer();\n    _this.attachEvents();\n\n    color = color || '#f00';\n    if (typeof color == 'string') {\n      _this.setHEX(color);\n    }\n    return _this;\n  }\n\n  _createClass(ColorTriangle, [{\n    key: 'calculateProperties',\n    value: function calculateProperties() {\n      var opts = this.options;\n\n      this.padding = opts.padding;\n      this.innerSize = opts.size - opts.padding * 2;\n      this.triangleSize = opts.triangleSize * this.innerSize;\n      this.wheelThickness = (this.innerSize - this.triangleSize) / 2;\n      this.wheelPointerSize = opts.wheelPointerSize || this.wheelThickness;\n\n      this.wheelRadius = this.innerSize / 2;\n      this.triangleRadius = this.triangleSize / 2;\n      this.triangleSideLength = M.sqrt(3) * this.triangleRadius;\n    }\n  }, {\n    key: 'calculatePositions',\n    value: function calculatePositions() {\n      var r = this.triangleRadius;\n      var hue = this.hue;\n      var third = TAU / 3;\n      var s = this.saturation;\n      var l = this.lightness;\n\n      // Colored point\n      var hx = this.hx = M.cos(hue) * r;\n      var hy = this.hy = -M.sin(hue) * r;\n      // Black point\n      var sx = this.sx = M.cos(hue - third) * r;\n      var sy = this.sy = -M.sin(hue - third) * r;\n      // White point\n      var vx = this.vx = M.cos(hue + third) * r;\n      var vy = this.vy = -M.sin(hue + third) * r;\n      // Current point\n      var mx = (sx + vx) / 2;\n      var my = (sy + vy) / 2;\n      var a = (1 - 2 * M.abs(l - 0.5)) * s;\n      this.x = sx + (vx - sx) * l + (hx - mx) * a;\n      this.y = sy + (vy - sy) * l + (hy - my) * a;\n    }\n  }, {\n    key: 'createContainer',\n    value: function createContainer() {\n      var c = this.container = doc.createElement('div');\n      c.className = 'color-triangle';\n\n      c.style.display = 'block';\n      c.style.padding = this.padding + 'px';\n      c.style.position = 'relative';\n      c.style.boxShadow = '0 1px 10px black';\n      c.style.borderRadius = '5px';\n      c.style.width = c.style.height = this.innerSize + 2 * this.padding + 'px';\n      c.style.background = this.options.background;\n    }\n  }, {\n    key: 'createWheel',\n    value: function createWheel() {\n      var c = this.wheel = doc.createElement('canvas');\n      c.width = c.height = this.innerSize * this.pixelRatio;\n      c.style.width = c.style.height = this.innerSize + 'px';\n      c.style.position = 'absolute';\n      c.style.margin = c.style.padding = '0';\n      c.style.left = c.style.top = this.padding + 'px';\n\n      this.drawWheel(c.getContext('2d'));\n      this.container.appendChild(c);\n    }\n  }, {\n    key: 'drawWheel',\n    value: function drawWheel(ctx) {\n      var s = void 0,\n          i = void 0;\n\n      ctx.save();\n      ctx.setTransform(this.pixelRatio, 0, 0, this.pixelRatio, 0, 0);\n      ctx.translate(this.wheelRadius, this.wheelRadius);\n      s = this.wheelRadius - this.triangleRadius;\n      // Draw a circle for every color\n      for (i = 0; i < 360; i++) {\n        ctx.rotate(TAU / -360); // rotate one degree\n        ctx.beginPath();\n        ctx.fillStyle = 'hsl(' + i + ', 100%, 50%)';\n        ctx.arc(this.wheelRadius - s / 2, 0, s / 2, 0, TAU, true);\n        ctx.fill();\n      }\n      ctx.restore();\n    }\n  }, {\n    key: 'createTriangle',\n    value: function createTriangle() {\n      var c = this.triangle = doc.createElement('canvas');\n\n      c.width = c.height = this.innerSize * this.pixelRatio;\n      c.style.width = c.style.height = this.innerSize + 'px';\n      c.style.position = 'absolute';\n      c.style.margin = c.style.padding = '0';\n      c.style.left = c.style.top = this.padding + 'px';\n\n      this.triangleCtx = c.getContext('2d');\n\n      this.container.appendChild(c);\n    }\n  }, {\n    key: 'drawTriangle',\n    value: function drawTriangle() {\n      var hx = this.hx;\n      var hy = this.hy;\n      var sx = this.sx;\n      var sy = this.sy;\n      var vx = this.vx;\n      var vy = this.vy;\n      var size = this.innerSize;\n\n      var ctx = this.triangleCtx;\n\n      // clear\n      ctx.clearRect(0, 0, size * this.pixelRatio, size * this.pixelRatio);\n\n      ctx.save();\n      ctx.setTransform(this.pixelRatio, 0, 0, this.pixelRatio, 0, 0);\n      ctx.translate(this.wheelRadius, this.wheelRadius);\n\n      // make a triangle\n      ctx.beginPath();\n      ctx.moveTo(hx, hy);\n      ctx.lineTo(sx, sy);\n      ctx.lineTo(vx, vy);\n      ctx.closePath();\n      ctx.clip();\n\n      ctx.fillStyle = '#000';\n      ctx.fillRect(-this.wheelRadius, -this.wheelRadius, size, size);\n      // => black triangle\n\n      // create gradient from hsl(hue, 1, 1) to transparent\n      var grad0 = ctx.createLinearGradient(hx, hy, (sx + vx) / 2, (sy + vy) / 2);\n      var hsla = 'hsla(' + M.round(this.hue * (360 / TAU)) + ', 100%, 50%, ';\n      grad0.addColorStop(0, hsla + '1)');\n      grad0.addColorStop(1, hsla + '0)');\n      ctx.fillStyle = grad0;\n      ctx.fillRect(-this.wheelRadius, -this.wheelRadius, size, size);\n      // => gradient: one side of the triangle is black, the opponent angle is $color\n\n      // create color gradient from white to transparent\n      var grad1 = ctx.createLinearGradient(vx, vy, (hx + sx) / 2, (hy + sy) / 2);\n      grad1.addColorStop(0, '#fff');\n      grad1.addColorStop(1, 'rgba(255, 255, 255, 0)');\n      ctx.globalCompositeOperation = 'lighter';\n      ctx.fillStyle = grad1;\n      ctx.fillRect(-this.wheelRadius, -this.wheelRadius, size, size);\n      // => white angle\n\n      ctx.restore();\n    }\n\n    // The two pointers\n\n  }, {\n    key: 'createWheelPointer',\n    value: function createWheelPointer() {\n      var c = this.wheelPointer = doc.createElement('canvas');\n      var size = this.wheelPointerSize;\n      c.width = c.height = size * this.pixelRatio;\n      c.style.width = c.style.height = size + 'px';\n      c.style.position = 'absolute';\n      c.style.margin = c.style.padding = '0';\n      this.drawPointer(c.getContext('2d'), size / 2, this.options.wheelPointerColor1, this.options.wheelPointerColor2);\n      this.container.appendChild(c);\n    }\n  }, {\n    key: 'moveWheelPointer',\n    value: function moveWheelPointer() {\n      var r = this.wheelPointerSize / 2;\n      var s = this.wheelPointer.style;\n      s.top = this.padding + this.wheelRadius - M.sin(this.hue) * (this.triangleRadius + this.wheelThickness / 2) - r + 'px';\n      s.left = this.padding + this.wheelRadius + M.cos(this.hue) * (this.triangleRadius + this.wheelThickness / 2) - r + 'px';\n    }\n  }, {\n    key: 'createTrianglePointer',\n    value: function createTrianglePointer() {\n      // create pointer in the triangle\n      var c = this.trianglePointer = doc.createElement('canvas');\n      var size = this.options.trianglePointerSize;\n\n      c.width = c.height = size * this.pixelRatio;\n      c.style.width = c.style.height = size + 'px';\n      c.style.position = 'absolute';\n      c.style.margin = c.style.padding = '0';\n      this.drawPointer(c.getContext('2d'), size / 2, this.options.trianglePointerColor1, this.options.trianglePointerColor2);\n      this.container.appendChild(c);\n    }\n  }, {\n    key: 'moveTrianglePointer',\n    value: function moveTrianglePointer(x, y) {\n      var s = this.trianglePointer.style;\n      var r = this.options.trianglePointerSize / 2;\n      s.top = this.y + this.wheelRadius + this.padding - r + 'px';\n      s.left = this.x + this.wheelRadius + this.padding - r + 'px';\n    }\n  }, {\n    key: 'drawPointer',\n    value: function drawPointer(ctx, r, color1, color2) {\n      ctx.setTransform(this.pixelRatio, 0, 0, this.pixelRatio, 0, 0);\n      ctx.fillStyle = color2;\n      ctx.beginPath();\n      ctx.arc(r, r, r, 0, TAU, true);\n      ctx.fill(); // => black circle\n      ctx.fillStyle = color1;\n      ctx.beginPath();\n      ctx.arc(r, r, r - 2, 0, TAU, true);\n      ctx.fill(); // => white circle with 1px black border\n      ctx.fillStyle = color2;\n      ctx.beginPath();\n      ctx.arc(r, r, r / 4 + 2, 0, TAU, true);\n      ctx.fill(); // => black circle with big white border and a small black border\n      ctx.globalCompositeOperation = 'destination-out';\n      ctx.beginPath();\n      ctx.arc(r, r, r / 4, 0, TAU, true);\n      ctx.fill(); // => transparent center\n    }\n\n    // The Element and the DOM\n\n  }, {\n    key: 'inject',\n    value: function inject(parent) {\n      parent.appendChild(this.container);\n    }\n  }, {\n    key: 'getRelativeCoordinates',\n    value: function getRelativeCoordinates(evt) {\n      var elem = this.triangle;\n      var rect = elem.getBoundingClientRect();\n\n      return {\n        x: evt.clientX - rect.x,\n        y: evt.clientY - rect.y\n      };\n    }\n  }, {\n    key: 'dispose',\n    value: function dispose() {\n      var parent = this.container.parentNode;\n      if (parent) {\n        parent.removeChild(this.container);\n      }\n    }\n  }, {\n    key: 'getElement',\n    value: function getElement() {\n      return this.container;\n    }\n\n    // Color accessors\n\n  }, {\n    key: 'getCSS',\n    value: function getCSS() {\n      var h = Math.round(this.hue * (360 / TAU));\n      var s = Math.round(this.saturation * 100);\n      var l = Math.round(this.lightness * 100);\n\n      return 'hsl(' + h + ', ' + s + '%, ' + l + '%)';\n    }\n  }, {\n    key: 'getHEX',\n    value: function getHEX() {\n      return rgb2hex.apply(undefined, _toConsumableArray(this.getRGB()));\n    }\n  }, {\n    key: 'setHEX',\n    value: function setHEX(hex) {\n      this.setRGB.apply(this, _toConsumableArray(hex2rgb(hex)));\n    }\n  }, {\n    key: 'getRGB',\n    value: function getRGB() {\n      return hsl2rgb.apply(undefined, _toConsumableArray(this.getHSL()));\n    }\n  }, {\n    key: 'setRGB',\n    value: function setRGB(r, g, b) {\n      this.setHSL.apply(this, _toConsumableArray(rgb2hsl(r, g, b)));\n    }\n  }, {\n    key: 'getHSL',\n    value: function getHSL() {\n      return [this.hue, this.saturation, this.lightness];\n    }\n  }, {\n    key: 'setHSL',\n    value: function setHSL(h, s, l) {\n      this.hue = h;\n      this.saturation = s;\n      this.lightness = l;\n\n      this.initColor();\n    }\n  }, {\n    key: 'initColor',\n    value: function initColor() {\n      this.calculatePositions();\n      this.moveWheelPointer();\n      this.drawTriangle();\n      this.moveTrianglePointer();\n    }\n\n    // Mouse event handling\n\n  }, {\n    key: 'attachEvents',\n    value: function attachEvents() {\n      var _this2 = this;\n\n      this.down = null;\n\n      var mousedown = function mousedown(evt) {\n        evt.stopPropagation();\n        evt.preventDefault();\n\n        doc.body.addEventListener('mousemove', mousemove, false);\n        doc.body.addEventListener('mouseup', mouseup, false);\n\n        var xy = _this2.getRelativeCoordinates(evt);\n        _this2.map(xy.x, xy.y);\n      };\n\n      var mousemove = function mousemove(evt) {\n        var xy = _this2.getRelativeCoordinates(evt);\n        _this2.move(xy.x, xy.y);\n      };\n\n      var mouseup = function mouseup(evt) {\n        if (_this2.down) {\n          _this2.down = null;\n          _this2.emit('dragend');\n        }\n        doc.body.removeEventListener('mousemove', mousemove, false);\n        doc.body.removeEventListener('mouseup', mouseup, false);\n      };\n\n      this.container.addEventListener('mousedown', mousedown, false);\n      this.container.addEventListener('mousemove', mousemove, false);\n    }\n  }, {\n    key: 'map',\n    value: function map(x, y) {\n      var x0 = x;\n      var y0 = y;\n      x -= this.wheelRadius;\n      y -= this.wheelRadius;\n\n      var r = M.sqrt(x * x + y * y); // Pythagoras\n      if (r > this.triangleRadius && r < this.wheelRadius) {\n        // Wheel\n        this.down = 'wheel';\n        this.emit('dragstart');\n        this.move(x0, y0);\n      } else if (r < this.triangleRadius) {\n        // Inner circle\n        this.down = 'triangle';\n        this.emit('dragstart');\n        this.move(x0, y0);\n      }\n    }\n  }, {\n    key: 'move',\n    value: function move(x, y) {\n      if (!this.down) {\n        return;\n      }\n\n      x -= this.wheelRadius;\n      y -= this.wheelRadius;\n\n      var rad = M.atan2(-y, x);\n      if (rad < 0) {\n        rad += TAU;\n      }\n\n      if (this.down === 'wheel') {\n        this.hue = rad;\n        this.initColor();\n        this.emit('drag');\n      } else if (this.down === 'triangle') {\n        // get radius and max radius\n        var rad0 = (rad + TAU - this.hue) % TAU;\n        var rad1 = rad0 % (TAU / 3) - TAU / 6;\n        var a = 0.5 * this.triangleRadius;\n        var b = M.tan(rad1) * a;\n        var r = M.sqrt(x * x + y * y); // Pythagoras\n        var maxR = M.sqrt(a * a + b * b); // Pythagoras\n\n        if (r > maxR) {\n          var dx = M.tan(rad1) * r;\n          var rad2 = M.atan(dx / maxR);\n          if (rad2 > TAU / 6) {\n            rad2 = TAU / 6;\n          } else if (rad2 < -TAU / 6) {\n            rad2 = -TAU / 6;\n          }\n          rad += rad2 - rad1;\n\n          rad0 = (rad + TAU - this.hue) % TAU;\n          rad1 = rad0 % (TAU / 3) - TAU / 6;\n          b = M.tan(rad1) * a;\n          r = maxR = M.sqrt(a * a + b * b); // Pythagoras\n        }\n\n        x = M.round(M.cos(rad) * r);\n        y = M.round(-M.sin(rad) * r);\n\n        var l = this.lightness = M.sin(rad0) * r / this.triangleSideLength + 0.5;\n\n        var widthShare = 1 - M.abs(l - 0.5) * 2;\n        var s = this.saturation = (M.cos(rad0) * r + this.triangleRadius / 2) / (1.5 * this.triangleRadius) / widthShare;\n        s = M.max(0, s); // cannot be lower than 0\n        s = M.min(1, s); // cannot be greater than 1\n\n        this.lightness = l;\n        this.saturation = s;\n\n        this.x = x;\n        this.y = y;\n        this.moveTrianglePointer();\n\n        this.emit('drag');\n      }\n    }\n\n    /***************\n     * Init helpers *\n     ***************/\n\n  }, {\n    key: 'setOptions',\n\n\n    /*******************\n     * Helper functions *\n     *******************/\n\n    value: function setOptions(opts) {\n      opts = opts || {};\n      var dflt = this.options;\n      var options = this.options = {};\n\n      each(dflt, function (val, key) {\n        options[key] = opts.hasOwnProperty(key) ? opts[key] : val;\n      });\n    }\n  }], [{\n    key: 'initInput',\n    value: function initInput(input, options) {\n      options = options || {};\n\n      var ct = void 0;\n      var openColorTriangle = function openColorTriangle() {\n        var hex = input.value;\n        if (options.parseColor) hex = options.parseColor(hex);\n        if (!ct) {\n          options.size = options.size || input.offsetWidth;\n          options.background = win.getComputedStyle(input, null).backgroundColor;\n          options.margin = options.margin || 10;\n          options.event = options.event || 'dragend';\n\n          ct = new ColorTriangle(hex, options);\n          ct.on(options.event, function () {\n            var hex = ct.getHEX();\n            input.value = options.uppercase ? hex.toUpperCase() : hex;\n            fireChangeEvent();\n          });\n        } else {\n          ct.setHEX(hex);\n        }\n\n        var top = input.offsetTop;\n        if (win.innerHeight - input.getBoundingClientRect().top > input.offsetHeight + options.margin + options.size) {\n          top += input.offsetHeight + options.margin; // below\n        } else {\n          top -= options.margin + options.size; // above\n        }\n\n        var el = ct.getElement();\n        el.style.position = 'absolute';\n        el.style.left = input.offsetLeft + 'px';\n        el.style.top = top + 'px';\n        el.style.zIndex = '1338'; // above everything\n\n        ct.inject(input.parentNode);\n      };\n\n      var closeColorTriangle = function closeColorTriangle() {\n        if (ct) {\n          ct.dispose();\n        }\n      };\n\n      var fireChangeEvent = function fireChangeEvent() {\n        var evt = doc.createEvent('HTMLEvents');\n        evt.initEvent('input', true, false); // bubbles = true, cancable = false\n        input.dispatchEvent(evt); // fire event\n      };\n\n      input.addEventListener('focus', openColorTriangle, false);\n      input.addEventListener('blur', closeColorTriangle, false);\n      input.addEventListener('keyup', function () {\n        var val = input.value;\n        if (val.match(/^#((?:[0-9A-Fa-f]{3})|(?:[0-9A-Fa-f]{6}))$/)) {\n          openColorTriangle();\n          fireChangeEvent();\n        } else {\n          closeColorTriangle();\n        }\n      }, false);\n    }\n  }]);\n\n  return ColorTriangle;\n}(EventEmitter);\n\n/***/ })\n/******/ ]);\n\n\n// WEBPACK FOOTER //\n// app.4a032ee-en.js"," \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, {\n \t\t\t\tconfigurable: false,\n \t\t\t\tenumerable: true,\n \t\t\t\tget: getter\n \t\t\t});\n \t\t}\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 9);\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap 5f19c49887263bc447b9","/** Make a node */\nexports.mk = function mk (e) {\n  return document.createElement(e)\n}\n\n/** Find one by query */\nexports.qs = function qs (s) {\n  return document.querySelector(s)\n}\n\n/** Find all by query */\nexports.qsa = function qsa (s) {\n  return document.querySelectorAll(s)\n}\n\n/**\n * Filter 'spacebar' and 'return' from keypress handler,\n * and when they're pressed, fire the callback.\n * use $(...).on('keypress', cr(handler))\n */\nexports.cr = function cr (hdl) {\n  return function (e) {\n    if (e.which === 10 || e.which === 13 || e.which === 32) {\n      hdl()\n    }\n  }\n}\n\n/** Decode number from 2B encoding */\nexports.parse2B = function parse2B (s, i = 0) {\n  return (s.charCodeAt(i++) - 1) + (s.charCodeAt(i) - 1) * 127\n}\n\n/** Decode number from 3B encoding */\nexports.parse3B = function parse3B (s, i = 0) {\n  return (s.charCodeAt(i) - 1) + (s.charCodeAt(i + 1) - 1) * 127 + (s.charCodeAt(i + 2) - 1) * 127 * 127\n}\n\n/** Encode using 2B encoding, returns string. */\nexports.encode2B = function encode2B (n) {\n  let lsb, msb\n  lsb = (n % 127)\n  n = ((n - lsb) / 127)\n  lsb += 1\n  msb = (n + 1)\n  return String.fromCharCode(lsb) + String.fromCharCode(msb)\n}\n\n/** Encode using 3B encoding, returns string. */\nexports.encode3B = function encode3B (n) {\n  let lsb, msb, xsb\n  lsb = (n % 127)\n  n = (n - lsb) / 127\n  lsb += 1\n  msb = (n % 127)\n  n = (n - msb) / 127\n  msb += 1\n  xsb = (n + 1)\n  return String.fromCharCode(lsb) + String.fromCharCode(msb) + String.fromCharCode(xsb)\n}\n\n\n\n// WEBPACK FOOTER //\n// ./js/utils.js","/*!chibi 3.0.7, Copyright 2012-2016 Kyle Barrow, released under MIT license */\n\n// MODIFIED VERSION.\n(function () {\n\t'use strict';\n\n\tvar readyfn = [],\n\t\tloadedfn = [],\n\t\tdomready = false,\n\t\tpageloaded = false,\n\t\td = document,\n\t\tw = window;\n\n\t// Fire any function calls on ready event\n\tfunction fireReady() {\n\t\tvar i;\n\t\tdomready = true;\n\t\tfor (i = 0; i < readyfn.length; i += 1) {\n\t\t\treadyfn[i]();\n\t\t}\n\t\treadyfn = [];\n\t}\n\n\t// Fire any function calls on loaded event\n\tfunction fireLoaded() {\n\t\tvar i;\n\t\tpageloaded = true;\n\t\t// For browsers with no DOM loaded support\n\t\tif (!domready) {\n\t\t\tfireReady();\n\t\t}\n\t\tfor (i = 0; i < loadedfn.length; i += 1) {\n\t\t\tloadedfn[i]();\n\t\t}\n\t\tloadedfn = [];\n\t}\n\n\t// Check DOM ready, page loaded\n\tif (d.addEventListener) {\n\t\t// Standards\n\t\td.addEventListener('DOMContentLoaded', fireReady, false);\n\t\tw.addEventListener('load', fireLoaded, false);\n\t} else if (d.attachEvent) {\n\t\t// IE\n\t\td.attachEvent('onreadystatechange', fireReady);\n\t\t// IE < 9\n\t\tw.attachEvent('onload', fireLoaded);\n\t} else {\n\t\t// Anything else\n\t\tw.onload = fireLoaded;\n\t}\n\n\t// Utility functions\n\n\t// Loop through node array\n\tfunction nodeLoop(fn, nodes) {\n\t\tvar i;\n\t\t// Good idea to walk up the DOM\n\t\tfor (i = nodes.length - 1; i >= 0; i -= 1) {\n\t\t\tfn(nodes[i]);\n\t\t}\n\t}\n\n\t// Convert to camel case\n\tfunction cssCamel(property) {\n\t\treturn property.replace(/-\\w/g, function (result) {\n\t\t\treturn result.charAt(1).toUpperCase();\n\t\t});\n\t}\n\n\t// Get computed style\n\tfunction computeStyle(elm, property) {\n\t\t// IE, everything else or null\n\t\treturn (elm.currentStyle) ? elm.currentStyle[cssCamel(property)] : (w.getComputedStyle) ? w.getComputedStyle(elm, null).getPropertyValue(property) : null;\n\n\t}\n\n\t// Returns URI encoded query string pair\n\tfunction queryPair(name, value) {\n\t\treturn encodeURIComponent(name).replace(/%20/g, '+') + '=' + encodeURIComponent(value).replace(/%20/g, '+');\n\t}\n\n\t// Set CSS, important to wrap in try to prevent error thown on unsupported property\n\tfunction setCss(elm, property, value) {\n\t\ttry {\n\t\t\telm.style[cssCamel(property)] = value;\n\t\t} catch (e) {\n\t\t}\n\t}\n\n\t// Show CSS\n\tfunction showCss(elm) {\n\t\telm.style.display = '';\n\t\t// For elements still hidden by style block\n\t\tif (computeStyle(elm, 'display') === 'none') {\n\t\t\telm.style.display = 'block';\n\t\t}\n\t}\n\n\t// Serialize form & JSON values\n\tfunction serializeData(nodes) {\n\t\tvar querystring = '', subelm, i, j;\n\t\tif (nodes.constructor === Object) { // Serialize JSON data\n\t\t\tfor (subelm in nodes) {\n\t\t\t\tif (nodes.hasOwnProperty(subelm)) {\n\t\t\t\t\tif (nodes[subelm].constructor === Array) {\n\t\t\t\t\t\tfor (i = 0; i < nodes[subelm].length; i += 1) {\n\t\t\t\t\t\t\tquerystring += '&' + queryPair(subelm, nodes[subelm][i]);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tquerystring += '&' + queryPair(subelm, nodes[subelm]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} else { // Serialize node data\n\t\t\tnodeLoop(function (elm) {\n\t\t\t\tif (elm.nodeName === 'FORM') {\n\t\t\t\t\tfor (i = 0; i < elm.elements.length; i += 1) {\n\t\t\t\t\t\tsubelm = elm.elements[i];\n\n\t\t\t\t\t\tif (!subelm.disabled) {\n\t\t\t\t\t\t\tswitch (subelm.type) {\n\t\t\t\t\t\t\t\t// Ignore buttons, unsupported XHR 1 form fields\n\t\t\t\t\t\t\t\tcase 'button':\n\t\t\t\t\t\t\t\tcase 'image':\n\t\t\t\t\t\t\t\tcase 'file':\n\t\t\t\t\t\t\t\tcase 'submit':\n\t\t\t\t\t\t\t\tcase 'reset':\n\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\tcase 'select-one':\n\t\t\t\t\t\t\t\t\tif (subelm.length > 0) {\n\t\t\t\t\t\t\t\t\t\tquerystring += '&' + queryPair(subelm.name, subelm.value);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\tcase 'select-multiple':\n\t\t\t\t\t\t\t\t\tfor (j = 0; j < subelm.length; j += 1) {\n\t\t\t\t\t\t\t\t\t\tif (subelm[j].selected) {\n\t\t\t\t\t\t\t\t\t\t\tquerystring += '&' + queryPair(subelm.name, subelm[j].value);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\tcase 'checkbox':\n\t\t\t\t\t\t\t\tcase 'radio':\n\t\t\t\t\t\t\t\t\tif (subelm.checked) {\n\t\t\t\t\t\t\t\t\t\tquerystring += '&' + queryPair(subelm.name, subelm.value);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\t// Everything else including shinny new HTML5 input types\n\t\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\t\tquerystring += '&' + queryPair(subelm.name, subelm.value);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}, nodes);\n\t\t}\n\t\t// Tidy up first &\n\t\treturn (querystring.length > 0) ? querystring.substring(1) : '';\n\t}\n\n\t// Class helper\n\tfunction classHelper(classes, action, nodes) {\n\t\tvar classarray, search, i, replace, has = false;\n\t\tif (classes) {\n\t\t\t// Trim any whitespace\n\t\t\tclassarray = classes.split(/\\s+/);\n\t\t\tnodeLoop(function (elm) {\n\t\t\t\tfor (i = 0; i < classarray.length; i += 1) {\n\t\t\t\t\tvar clz = classarray[i];\n\t\t\t\t\tif (action === 'remove') {\n\t\t\t\t\t\telm.classList.remove(clz);\n\t\t\t\t\t}\n\t\t\t\t\telse if (action === 'add') {\n\t\t\t\t\t\telm.classList.add(clz);\n\t\t\t\t\t}\n\t\t\t\t\telse if (action === 'toggle') {\n\t\t\t\t\t\telm.classList.toggle(clz);\n\t\t\t\t\t}\n\t\t\t\t\telse if (action === 'has') {\n\t\t\t\t\t\tif (elm.classList.contains(clz)) {\n\t\t\t\t\t\t\thas = true;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// search = new RegExp('\\\\b' + classarray[i] + '\\\\b', 'g');\n\t\t\t\t\t// replace = new RegExp(' *' + classarray[i] + '\\\\b', 'g');\n\t\t\t\t\t// if (action === 'remove') {\n\t\t\t\t\t// \telm.className = elm.className.replace(search, '');\n\t\t\t\t\t// } else if (action === 'toggle') {\n\t\t\t\t\t// \telm.className = (elm.className.match(search)) ? elm.className.replace(replace, '') : elm.className + ' ' + classarray[i];\n\t\t\t\t\t// } else if (action === 'has') {\n\t\t\t\t\t// \tif (elm.className.match(search)) {\n\t\t\t\t\t// \t\thas = true;\n\t\t\t\t\t// \t\tbreak;\n\t\t\t\t\t// \t}\n\t\t\t\t\t// }\n\t\t\t\t}\n\t\t\t}, nodes);\n\t\t}\n\t\treturn has;\n\t}\n\n\t// HTML insertion helper\n\tfunction insertHtml(value, position, nodes) {\n\t\tvar tmpnodes, tmpnode;\n\t\tif (value) {\n\t\t\tnodeLoop(function (elm) {\n\t\t\t\t// No insertAdjacentHTML support for FF < 8 and IE doesn't allow insertAdjacentHTML table manipulation, so use this instead\n\t\t\t\t// Convert string to node. We can't innerHTML on a document fragment\n\t\t\t\ttmpnodes = d.createElement('div');\n\t\t\t\ttmpnodes.innerHTML = value;\n\t\t\t\twhile ((tmpnode = tmpnodes.lastChild) !== null) {\n\t\t\t\t\t// Catch error in unlikely case elm has been removed\n\t\t\t\t\ttry {\n\t\t\t\t\t\tif (position === 'before') {\n\t\t\t\t\t\t\telm.parentNode.insertBefore(tmpnode, elm);\n\t\t\t\t\t\t} else if (position === 'after') {\n\t\t\t\t\t\t\telm.parentNode.insertBefore(tmpnode, elm.nextSibling);\n\t\t\t\t\t\t} else if (position === 'append') {\n\t\t\t\t\t\t\telm.appendChild(tmpnode);\n\t\t\t\t\t\t} else if (position === 'prepend') {\n\t\t\t\t\t\t\telm.insertBefore(tmpnode, elm.firstChild);\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}, nodes);\n\t\t}\n\t}\n\n\t// Get nodes and return chibi\n\tfunction chibi(selector) {\n\t\tvar cb, nodes = [], json = false, nodelist, i;\n\n\t\tif (selector) {\n\n\t\t\t// Element node, would prefer to use (selector instanceof HTMLElement) but no IE support\n\t\t\tif (selector.nodeType && selector.nodeType === 1) {\n\t\t\t\tnodes = [selector]; // return element as node list\n\t\t\t} else if (typeof selector === 'object') {\n\t\t\t\t// JSON, document object or node list, would prefer to use (selector instanceof NodeList) but no IE support\n\t\t\t\tjson = (typeof selector.length !== 'number');\n\t\t\t\tnodes = selector;\n\t\t\t} else if (typeof selector === 'string') {\n\t\t\t\tnodelist = d.querySelectorAll(selector);\n\n\t\t\t\t// Convert node list to array so results have full access to array methods\n\t\t\t\t// Array.prototype.slice.call not supported in IE < 9 and often slower than loop anyway\n\t\t\t\tfor (i = 0; i < nodelist.length; i += 1) {\n\t\t\t\t\tnodes[i] = nodelist[i];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Only attach nodes if not JSON\n\t\tcb = json ? {} : nodes;\n\n\t\t// Public functions\n\n\t\t// Executes a function on nodes\n\t\tcb.each = function (fn) {\n\t\t\tif (typeof fn === 'function') {\n\t\t\t\tnodeLoop(function (elm) {\n\t\t\t\t\t// <= IE 8 loses scope so need to apply\n\t\t\t\t\treturn fn.apply(elm, arguments);\n\t\t\t\t}, nodes);\n\t\t\t}\n\t\t\treturn cb;\n\t\t};\n\t\t// Find first\n\t\tcb.first = function () {\n\t\t\treturn chibi(nodes.shift());\n\t\t};\n\t\t// Find last\n\t\tcb.last = function () {\n\t\t\treturn chibi(nodes.pop());\n\t\t};\n\t\t// Find odd\n\t\tcb.odd = function () {\n\t\t\tvar odds = [], i;\n\t\t\tfor (i = 0; i < nodes.length; i += 2) {\n\t\t\t\todds.push(nodes[i]);\n\t\t\t}\n\t\t\treturn chibi(odds);\n\t\t};\n\t\t// Find even\n\t\tcb.even = function () {\n\t\t\tvar evens = [], i;\n\t\t\tfor (i = 1; i < nodes.length; i += 2) {\n\t\t\t\tevens.push(nodes[i]);\n\t\t\t}\n\t\t\treturn chibi(evens);\n\t\t};\n\t\t// Hide node\n\t\tcb.hide = function () {\n\t\t\tnodeLoop(function (elm) {\n\t\t\t\telm.style.display = 'none';\n\t\t\t}, nodes);\n\t\t\treturn cb;\n\t\t};\n\t\t// Show node\n\t\tcb.show = function () {\n\t\t\tnodeLoop(function (elm) {\n\t\t\t\tshowCss(elm);\n\t\t\t}, nodes);\n\t\t\treturn cb;\n\t\t};\n\t\t// Toggle node display\n\t\tcb.toggle = function (state) {\n\t\t\tif (typeof state != 'undefined') { // ADDED\n\t\t\t\tif (state)\n\t\t\t\t\tcb.show();\n\t\t\t\telse\n\t\t\t\t\tcb.hide();\n\t\t\t} else {\n\t\t\t\tnodeLoop(function (elm) {\n\t\t\t\t\t// computeStyle instead of style.display == 'none' catches elements that are hidden via style block\n\t\t\t\t\tif (computeStyle(elm, 'display') === 'none') {\n\t\t\t\t\t\tshowCss(elm);\n\t\t\t\t\t} else {\n\t\t\t\t\t\telm.style.display = 'none';\n\t\t\t\t\t}\n\n\t\t\t\t}, nodes);\n\t\t\t}\n\t\t\treturn cb;\n\t\t};\n\t\t// Remove node\n\t\tcb.remove = function () {\n\t\t\tnodeLoop(function (elm) {\n\t\t\t\t// Catch error in unlikely case elm has been removed\n\t\t\t\ttry {\n\t\t\t\t\telm.parentNode.removeChild(elm);\n\t\t\t\t} catch (e) {\n\t\t\t\t}\n\t\t\t}, nodes);\n\t\t\treturn chibi();\n\t\t};\n\t\t// Get/Set CSS\n\t\tcb.css = function (property, value) {\n\t\t\tif (property) {\n\t\t\t\tif (value || value === '') {\n\t\t\t\t\tnodeLoop(function (elm) {\n\t\t\t\t\t\tsetCss(elm, property, value);\n\t\t\t\t\t}, nodes);\n\t\t\t\t\treturn cb;\n\t\t\t\t}\n\t\t\t\tif (nodes[0]) {\n\t\t\t\t\tif (nodes[0].style[cssCamel(property)]) {\n\t\t\t\t\t\treturn nodes[0].style[cssCamel(property)];\n\t\t\t\t\t}\n\t\t\t\t\tif (computeStyle(nodes[0], property)) {\n\t\t\t\t\t\treturn computeStyle(nodes[0], property);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t\t// Get class(es)\n\t\tcb.getClass = function () {\n\t\t\tif (nodes[0] && nodes[0].className.length > 0) {\n\t\t\t\t// Weak IE trim support\n\t\t\t\treturn nodes[0].className.replace(/^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g, '').replace(/\\s+/, ' ');\n\t\t\t}\n\t\t};\n\t\t// Set (replaces) classes\n\t\tcb.setClass = function (classes) {\n\t\t\tif (classes || classes === '') {\n\t\t\t\tnodeLoop(function (elm) {\n\t\t\t\t\telm.className = classes;\n\t\t\t\t}, nodes);\n\t\t\t}\n\t\t\treturn cb;\n\t\t};\n\t\t// Add class\n\t\tcb.addClass = function (classes) {\n\t\t\tclassHelper(classes, 'add', nodes);\n\t\t\t// if (classes) {\n\t\t\t// \tnodeLoop(function (elm) {\n\t\t\t// \t\telm.className += ' ' + classes;\n\t\t\t// \t}, nodes);\n\t\t\t// }\n\t\t\treturn cb;\n\t\t};\n\t\t// Remove class\n\t\tcb.removeClass = function (classes) {\n\t\t\tclassHelper(classes, 'remove', nodes);\n\t\t\treturn cb;\n\t\t};\n\t\t// Toggle class\n\t\tcb.toggleClass = function (classes, set) {\n\t\t\tvar method = ((typeof set === 'undefined') ? 'toggle' : (+set ? 'add' : 'remove'));\n\t\t\tclassHelper(classes, method, nodes);\n\t\t\treturn cb;\n\t\t};\n\t\t// Has class\n\t\tcb.hasClass = function (classes) {\n\t\t\treturn classHelper(classes, 'has', nodes);\n\t\t};\n\t\t// Get/set HTML\n\t\tcb.html = function (value) {\n\t\t\tif (value || value === '') {\n\t\t\t\tnodeLoop(function (elm) {\n\t\t\t\t\telm.innerHTML = value;\n\t\t\t\t}, nodes);\n\t\t\t\treturn cb;\n\t\t\t}\n\t\t\tif (nodes[0]) {\n\t\t\t\treturn nodes[0].innerHTML;\n\t\t\t}\n\t\t};\n\t\t// Insert HTML before selector\n\t\tcb.htmlBefore = function (value) {\n\t\t\tinsertHtml(value, 'before', nodes);\n\t\t\treturn cb;\n\t\t};\n\t\t// Insert HTML after selector\n\t\tcb.htmlAfter = function (value) {\n\t\t\tinsertHtml(value, 'after', nodes);\n\t\t\treturn cb;\n\t\t};\n\t\t// Insert HTML after selector innerHTML\n\t\tcb.htmlAppend = function (value) {\n\t\t\tinsertHtml(value, 'append', nodes);\n\t\t\treturn cb;\n\t\t};\n\t\t// Insert HTML before selector innerHTML\n\t\tcb.htmlPrepend = function (value) {\n\t\t\tinsertHtml(value, 'prepend', nodes);\n\t\t\treturn cb;\n\t\t};\n\t\t// Get/Set HTML attributes\n\t\tcb.attr = function (property, value) {\n\t\t\tif (property) {\n\t\t\t\tproperty = property.toLowerCase();\n\t\t\t\t// IE < 9 doesn't allow style or class via get/setAttribute so switch. cssText returns prettier CSS anyway\n\t\t\t\tif (typeof value !== 'undefined') {//FIXED BUG HERE\n\t\t\t\t\tnodeLoop(function (elm) {\n\t\t\t\t\t\tif (property === 'style') {\n\t\t\t\t\t\t\telm.style.cssText = value;\n\t\t\t\t\t\t} else if (property === 'class') {\n\t\t\t\t\t\t\telm.className = value;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\telm.setAttribute(property, value);\n\t\t\t\t\t\t}\n\t\t\t\t\t}, nodes);\n\t\t\t\t\treturn cb;\n\t\t\t\t}\n\t\t\t\tif (nodes[0]) {\n\t\t\t\t\tif (property === 'style') {\n\t\t\t\t\t\tif (nodes[0].style.cssText) {\n\t\t\t\t\t\t\treturn nodes[0].style.cssText;\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (property === 'class') {\n\t\t\t\t\t\tif (nodes[0].className) {\n\t\t\t\t\t\t\treturn nodes[0].className;\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif (nodes[0].getAttribute(property)) {\n\t\t\t\t\t\t\treturn nodes[0].getAttribute(property);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t\t// Get/Set HTML data property\n\t\tcb.data = function (key, value) {\n\t\t\tif (key) {\n\t\t\t\treturn cb.attr('data-' + key, value);\n\t\t\t}\n\t\t};\n\t\t// Get/Set form element values\n\t\tcb.val = function (value) {\n\t\t\tvar values, i, j;\n\t\t\tif (typeof value != 'undefined') { // FIXED A BUG HERE\n\t\t\t\tnodeLoop(function (elm) {\n\t\t\t\t\tswitch (elm.nodeName) {\n\t\t\t\t\t\tcase 'SELECT':\n\t\t\t\t\t\t\tif (typeof value === 'string' || typeof value === 'number') {\n\t\t\t\t\t\t\t\tvalue = [value];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tfor (i = 0; i < elm.length; i += 1) {\n\t\t\t\t\t\t\t\t// Multiple select\n\t\t\t\t\t\t\t\tfor (j = 0; j < value.length; j += 1) {\n\t\t\t\t\t\t\t\t\telm[i].selected = '';\n\t\t\t\t\t\t\t\t\tif (elm[i].value === \"\"+value[j]) {\n\t\t\t\t\t\t\t\t\t\telm[i].selected = 'selected';\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'INPUT':\n\t\t\t\t\t\tcase 'TEXTAREA':\n\t\t\t\t\t\tcase 'BUTTON':\n\t\t\t\t\t\t\telm.value = value;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}, nodes);\n\n\t\t\t\treturn cb;\n\t\t\t}\n\t\t\tif (nodes[0]) {\n\t\t\t\tswitch (nodes[0].nodeName) {\n\t\t\t\t\tcase 'SELECT':\n\t\t\t\t\t\tvalues = [];\n\t\t\t\t\t\tfor (i = 0; i < nodes[0].length; i += 1) {\n\t\t\t\t\t\t\tif (nodes[0][i].selected) {\n\t\t\t\t\t\t\t\tvalues.push(nodes[0][i].value);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn (values.length > 1) ? values : values[0];\n\t\t\t\t\tcase 'INPUT':\n\t\t\t\t\tcase 'TEXTAREA':\n\t\t\t\t\tcase 'BUTTON':\n\t\t\t\t\t\treturn nodes[0].value;\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t\t// Return matching checked checkbox or radios\n\t\tcb.checked = function (check) {\n\t\t\tif (typeof check === 'boolean') {\n\t\t\t\tnodeLoop(function (elm) {\n\t\t\t\t\tif (elm.nodeName === 'INPUT' && (elm.type === 'checkbox' || elm.type === 'radio')) {\n\t\t\t\t\t\telm.checked = check;\n\t\t\t\t\t}\n\t\t\t\t}, nodes);\n\t\t\t\treturn cb;\n\t\t\t}\n\t\t\tif (nodes[0] && nodes[0].nodeName === 'INPUT' && (nodes[0].type === 'checkbox' || nodes[0].type === 'radio')) {\n\t\t\t\treturn (!!nodes[0].checked);\n\t\t\t}\n\t\t};\n\t\t// Add event handler\n\t\tcb.on = function (event, fn) {\n\t\t\tif (selector === w || selector === d) {\n\t\t\t\tnodes = [selector];\n\t\t\t}\n\t\t\tnodeLoop(function (elm) {\n\t\t\t\tif (d.addEventListener) {\n\t\t\t\t\telm.addEventListener(event, fn, false);\n\t\t\t\t} else if (d.attachEvent) {\n\t\t\t\t\t// <= IE 8 loses scope so need to apply, we add this to object so we can detach later (can't detach anonymous functions)\n\t\t\t\t\telm[event + fn] = function () {\n\t\t\t\t\t\treturn fn.apply(elm, arguments);\n\t\t\t\t\t};\n\t\t\t\t\telm.attachEvent('on' + event, elm[event + fn]);\n\t\t\t\t}\n\t\t\t}, nodes);\n\t\t\treturn cb;\n\t\t};\n\t\t// Remove event handler\n\t\tcb.off = function (event, fn) {\n\t\t\tif (selector === w || selector === d) {\n\t\t\t\tnodes = [selector];\n\t\t\t}\n\t\t\tnodeLoop(function (elm) {\n\t\t\t\tif (d.addEventListener) {\n\t\t\t\t\telm.removeEventListener(event, fn, false);\n\t\t\t\t} else if (d.attachEvent) {\n\t\t\t\t\telm.detachEvent('on' + event, elm[event + fn]);\n\t\t\t\t\t// Tidy up\n\t\t\t\t\telm[event + fn] = null;\n\t\t\t\t}\n\t\t\t}, nodes);\n\t\t\treturn cb;\n\t\t};\n\t\treturn cb;\n\t}\n\n\t// Basic XHR\n\tchibi.ajax = function (options) { // if options is a number, it's timeout in ms\n\t\tvar opts = Object.assign({\n\t\t\tmethod: 'GET',\n\t\t\tnocache: true,\n\t\t\ttimeout: 5000,\n\t\t\tloader: true,\n\t\t\tcallback: null\n\t\t}, options);\n\t\topts.method = opts.method.toUpperCase();\n\n\t\tvar loaderFn = opts.loader ? chibi._loader : function(){};\n\t\tvar url = opts.url;\n\t\tvar method = opts.method;\n\t\tvar query = null;\n\n\t\tif (opts.data) {\n\t\t\tquery = serializeData(opts.data);\n\t\t}\n\n\t\tif (query && (method === 'GET')) {\n\t\t\turl += (url.indexOf('?') === -1) ? '?' + query : '&' + query;\n\t\t\tquery = null;\n\t\t}\n\n\t\tvar xhr = new XMLHttpRequest();\n\n\t\t// prevent caching\n\t\tif (opts.nocache) {\n\t\t\tvar ts = (+(new Date())).toString(36);\n\t\t\turl += ((url.indexOf('?') === -1) ? '?' : '&') + '_=' + ts;\n\t\t}\n\n\t\tloaderFn(true);\n\n\t\txhr.open(method, url, true);\n\t\txhr.timeout = opts.timeout;\n\n\t\t// Abort after given timeout\n\t\tvar abortTmeo = setTimeout(function () {\n\t\t\tconsole.error(\"XHR timed out.\");\n\t\t\txhr.abort();\n\t\t\tloaderFn(false);\n\t\t}, opts.timeout + 10);\n\n\t\txhr.onreadystatechange = function () {\n\t\t\tif (xhr.readyState === 4) {\n\t\t\t\tloaderFn(false);\n\n\t\t\t\topts.callback && opts.callback(xhr.responseText, xhr.status);\n\n\t\t\t\tclearTimeout(abortTmeo);\n\t\t\t}\n\t\t};\n\n\t\txhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');\n\t\tif (method === 'POST') {\n\t\t\txhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');\n\t\t}\n\n\t\txhr.send(query);\n\t\treturn xhr;\n\t};\n\n\tchibi._loader = function(){};\n\n\t// Alias to cb.ajax(url, 'get', callback)\n\tchibi.get = function (url, callback, opts) {\n\t\topts = opts || {};\n\t\topts.url = url;\n\t\topts.callback = callback;\n\t\topts.method = 'GET';\n\t\treturn chibi.ajax(opts);\n\t};\n\n\t// Alias to cb.ajax(url, 'post', callback)\n\tchibi.post = function (url, callback, opts) {\n\t\topts = opts || {};\n\t\topts.url = url;\n\t\topts.callback = callback;\n\t\topts.method = 'POST';\n\t\treturn chibi.ajax(opts);\n\t};\n\n\t// Fire on DOM ready\n\tchibi.ready = function (fn) {\n\t\tif (fn) {\n\t\t\tif (domready) {\n\t\t\t\tfn();\n\t\t\t\treturn chibi;\n\t\t\t} else {\n\t\t\t\treadyfn.push(fn);\n\t\t\t}\n\t\t}\n\t};\n\n\t// Fire on page loaded\n\tchibi.loaded = function (fn) {\n\t\tif (fn) {\n\t\t\tif (pageloaded) {\n\t\t\t\tfn();\n\t\t\t\treturn chibi;\n\t\t\t} else {\n\t\t\t\tloadedfn.push(fn);\n\t\t\t}\n\t\t}\n\t};\n\n\tvar entityMap = {\n\t\t'&': '&amp;',\n\t\t'<': '&lt;',\n\t\t'>': '&gt;',\n\t\t'\"': '&quot;',\n\t\t\"'\": '&#39;',\n\t\t'/': '&#x2F;',\n\t\t'`': '&#x60;',\n\t\t'=': '&#x3D;'\n\t};\n\n\tchibi.htmlEscape = function(string) {\n\t\treturn String(string).replace(/[&<>\"'`=\\/]/g, function (s) {\n\t\t\treturn entityMap[s];\n\t\t});\n\t};\n\n\t// Set Chibi's global namespace here ($)\n\tmodule.exports = chibi;\n}());\n\n\n\n// WEBPACK FOOTER //\n// ./js/lib/chibi.js","const $ = require('./lib/chibi')\n\n/** Module for toggling a modal overlay */\nlet modal = {}\nlet curCloseCb = null\n\nmodal.show = function (sel, closeCb) {\n  let $m = $(sel)\n  $m.removeClass('hidden visible')\n  setTimeout(function () {\n    $m.addClass('visible')\n  }, 1)\n  curCloseCb = closeCb\n}\n\nmodal.hide = function (sel) {\n  let $m = $(sel)\n  $m.removeClass('visible')\n  setTimeout(function () {\n    $m.addClass('hidden')\n    if (curCloseCb) curCloseCb()\n  }, 500) // transition time\n}\n\nmodal.init = function () {\n  // close modal by click outside the dialog\n  $('.Modal').on('click', function () {\n    if ($(this).hasClass('no-close')) return // this is a no-close modal\n    modal.hide(this)\n  })\n\n  $('.Dialog').on('click', function (e) {\n    e.stopImmediatePropagation()\n  })\n\n  // Hide all modals on esc\n  $(window).on('keydown', function (e) {\n    if (e.which === 27) {\n      modal.hide('.Modal')\n    }\n  })\n}\n\nmodule.exports = modal\n\n\n\n// WEBPACK FOOTER //\n// ./js/modal.js","const $ = require('./lib/chibi')\nconst modal = require('./modal')\n\nlet nt = {}\nconst sel = '#notif'\nlet $balloon\n\nlet timerHideBegin // timeout to start hiding (transition)\nlet timerHideEnd // timeout to add the hidden class\nlet canCancel = false\n\nlet stopTimeouts = function () {\n  clearTimeout(timerHideBegin)\n  clearTimeout(timerHideEnd)\n}\n\nnt.show = function (message, timeout, isError) {\n  $balloon.toggleClass('error', isError === true)\n  $balloon.html(message)\n  modal.show($balloon)\n  stopTimeouts()\n\n  if (!timeout || timeout <= 0) {\n    timeout = 2500\n  }\n\n  timerHideBegin = setTimeout(nt.hide, timeout)\n\n  canCancel = false\n  setTimeout(() => {\n    canCancel = true\n  }, 500)\n}\n\nnt.hide = function () {\n  let $m = $(sel)\n  $m.removeClass('visible')\n  timerHideEnd = setTimeout(function () {\n    $m.addClass('hidden')\n  }, 250) // transition time\n}\n\nnt.init = function () {\n  $balloon = $(sel)\n\n  // close by click outside\n  $(document).on('click', function () {\n    if (!canCancel) return\n    nt.hide(this)\n  })\n\n  // click caused by selecting, prevent it from bubbling\n  $balloon.on('click', function (e) {\n    e.stopImmediatePropagation()\n    return false\n  })\n\n  // stop fading if moused\n  $balloon.on('mouseenter', function () {\n    stopTimeouts()\n    $balloon.removeClass('hidden').addClass('visible')\n  })\n}\n\nmodule.exports = nt\n\n\n\n// WEBPACK FOOTER //\n// ./js/notif.js","// Copyright Joyent, Inc. and other Node contributors.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a\n// copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to permit\n// persons to whom the Software is furnished to do so, subject to the\n// following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n// USE OR OTHER DEALINGS IN THE SOFTWARE.\n\nfunction EventEmitter() {\n  this._events = this._events || {};\n  this._maxListeners = this._maxListeners || undefined;\n}\nmodule.exports = EventEmitter;\n\n// Backwards-compat with node 0.10.x\nEventEmitter.EventEmitter = EventEmitter;\n\nEventEmitter.prototype._events = undefined;\nEventEmitter.prototype._maxListeners = undefined;\n\n// By default EventEmitters will print a warning if more than 10 listeners are\n// added to it. This is a useful default which helps finding memory leaks.\nEventEmitter.defaultMaxListeners = 10;\n\n// Obviously not all Emitters should be limited to 10. This function allows\n// that to be increased. Set to zero for unlimited.\nEventEmitter.prototype.setMaxListeners = function(n) {\n  if (!isNumber(n) || n < 0 || isNaN(n))\n    throw TypeError('n must be a positive number');\n  this._maxListeners = n;\n  return this;\n};\n\nEventEmitter.prototype.emit = function(type) {\n  var er, handler, len, args, i, listeners;\n\n  if (!this._events)\n    this._events = {};\n\n  // If there is no 'error' event listener then throw.\n  if (type === 'error') {\n    if (!this._events.error ||\n        (isObject(this._events.error) && !this._events.error.length)) {\n      er = arguments[1];\n      if (er instanceof Error) {\n        throw er; // Unhandled 'error' event\n      } else {\n        // At least give some kind of context to the user\n        var err = new Error('Uncaught, unspecified \"error\" event. (' + er + ')');\n        err.context = er;\n        throw err;\n      }\n    }\n  }\n\n  handler = this._events[type];\n\n  if (isUndefined(handler))\n    return false;\n\n  if (isFunction(handler)) {\n    switch (arguments.length) {\n      // fast cases\n      case 1:\n        handler.call(this);\n        break;\n      case 2:\n        handler.call(this, arguments[1]);\n        break;\n      case 3:\n        handler.call(this, arguments[1], arguments[2]);\n        break;\n      // slower\n      default:\n        args = Array.prototype.slice.call(arguments, 1);\n        handler.apply(this, args);\n    }\n  } else if (isObject(handler)) {\n    args = Array.prototype.slice.call(arguments, 1);\n    listeners = handler.slice();\n    len = listeners.length;\n    for (i = 0; i < len; i++)\n      listeners[i].apply(this, args);\n  }\n\n  return true;\n};\n\nEventEmitter.prototype.addListener = function(type, listener) {\n  var m;\n\n  if (!isFunction(listener))\n    throw TypeError('listener must be a function');\n\n  if (!this._events)\n    this._events = {};\n\n  // To avoid recursion in the case that type === \"newListener\"! Before\n  // adding it to the listeners, first emit \"newListener\".\n  if (this._events.newListener)\n    this.emit('newListener', type,\n              isFunction(listener.listener) ?\n              listener.listener : listener);\n\n  if (!this._events[type])\n    // Optimize the case of one listener. Don't need the extra array object.\n    this._events[type] = listener;\n  else if (isObject(this._events[type]))\n    // If we've already got an array, just append.\n    this._events[type].push(listener);\n  else\n    // Adding the second element, need to change to array.\n    this._events[type] = [this._events[type], listener];\n\n  // Check for listener leak\n  if (isObject(this._events[type]) && !this._events[type].warned) {\n    if (!isUndefined(this._maxListeners)) {\n      m = this._maxListeners;\n    } else {\n      m = EventEmitter.defaultMaxListeners;\n    }\n\n    if (m && m > 0 && this._events[type].length > m) {\n      this._events[type].warned = true;\n      console.error('(node) warning: possible EventEmitter memory ' +\n                    'leak detected. %d listeners added. ' +\n                    'Use emitter.setMaxListeners() to increase limit.',\n                    this._events[type].length);\n      if (typeof console.trace === 'function') {\n        // not supported in IE 10\n        console.trace();\n      }\n    }\n  }\n\n  return this;\n};\n\nEventEmitter.prototype.on = EventEmitter.prototype.addListener;\n\nEventEmitter.prototype.once = function(type, listener) {\n  if (!isFunction(listener))\n    throw TypeError('listener must be a function');\n\n  var fired = false;\n\n  function g() {\n    this.removeListener(type, g);\n\n    if (!fired) {\n      fired = true;\n      listener.apply(this, arguments);\n    }\n  }\n\n  g.listener = listener;\n  this.on(type, g);\n\n  return this;\n};\n\n// emits a 'removeListener' event iff the listener was removed\nEventEmitter.prototype.removeListener = function(type, listener) {\n  var list, position, length, i;\n\n  if (!isFunction(listener))\n    throw TypeError('listener must be a function');\n\n  if (!this._events || !this._events[type])\n    return this;\n\n  list = this._events[type];\n  length = list.length;\n  position = -1;\n\n  if (list === listener ||\n      (isFunction(list.listener) && list.listener === listener)) {\n    delete this._events[type];\n    if (this._events.removeListener)\n      this.emit('removeListener', type, listener);\n\n  } else if (isObject(list)) {\n    for (i = length; i-- > 0;) {\n      if (list[i] === listener ||\n          (list[i].listener && list[i].listener === listener)) {\n        position = i;\n        break;\n      }\n    }\n\n    if (position < 0)\n      return this;\n\n    if (list.length === 1) {\n      list.length = 0;\n      delete this._events[type];\n    } else {\n      list.splice(position, 1);\n    }\n\n    if (this._events.removeListener)\n      this.emit('removeListener', type, listener);\n  }\n\n  return this;\n};\n\nEventEmitter.prototype.removeAllListeners = function(type) {\n  var key, listeners;\n\n  if (!this._events)\n    return this;\n\n  // not listening for removeListener, no need to emit\n  if (!this._events.removeListener) {\n    if (arguments.length === 0)\n      this._events = {};\n    else if (this._events[type])\n      delete this._events[type];\n    return this;\n  }\n\n  // emit removeListener for all listeners on all events\n  if (arguments.length === 0) {\n    for (key in this._events) {\n      if (key === 'removeListener') continue;\n      this.removeAllListeners(key);\n    }\n    this.removeAllListeners('removeListener');\n    this._events = {};\n    return this;\n  }\n\n  listeners = this._events[type];\n\n  if (isFunction(listeners)) {\n    this.removeListener(type, listeners);\n  } else if (listeners) {\n    // LIFO order\n    while (listeners.length)\n      this.removeListener(type, listeners[listeners.length - 1]);\n  }\n  delete this._events[type];\n\n  return this;\n};\n\nEventEmitter.prototype.listeners = function(type) {\n  var ret;\n  if (!this._events || !this._events[type])\n    ret = [];\n  else if (isFunction(this._events[type]))\n    ret = [this._events[type]];\n  else\n    ret = this._events[type].slice();\n  return ret;\n};\n\nEventEmitter.prototype.listenerCount = function(type) {\n  if (this._events) {\n    var evlistener = this._events[type];\n\n    if (isFunction(evlistener))\n      return 1;\n    else if (evlistener)\n      return evlistener.length;\n  }\n  return 0;\n};\n\nEventEmitter.listenerCount = function(emitter, type) {\n  return emitter.listenerCount(type);\n};\n\nfunction isFunction(arg) {\n  return typeof arg === 'function';\n}\n\nfunction isNumber(arg) {\n  return typeof arg === 'number';\n}\n\nfunction isObject(arg) {\n  return typeof arg === 'object' && arg !== null;\n}\n\nfunction isUndefined(arg) {\n  return arg === void 0;\n}\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./node_modules/events/events.js\n// module id = 4\n// module chunks = 0","const $ = require('../lib/chibi')\nconst { rgb255ToHex } = require('../lib/color_utils')\n\nconst themes = exports.themes = [\n  [ // 0 - Tango - terminator\n    '#111213', '#CC0000', '#4E9A06', '#C4A000', '#3465A4', '#75507B', '#06989A', '#D3D7CF',\n    '#555753', '#EF2929', '#8AE234', '#FCE94F', '#729FCF', '#AD7FA8', '#34E2E2', '#EEEEEC'\n  ],\n  [ // 1 - Linux (CGA) - terminator\n    '#000000', '#aa0000', '#00aa00', '#aa5500', '#0000aa', '#aa00aa', '#00aaaa', '#aaaaaa',\n    '#555555', '#ff5555', '#55ff55', '#ffff55', '#5555ff', '#ff55ff', '#55ffff', '#ffffff'\n  ],\n  [ // 2 - xterm - terminator\n    '#000000', '#cd0000', '#00cd00', '#cdcd00', '#0000ee', '#cd00cd', '#00cdcd', '#e5e5e5',\n    '#7f7f7f', '#ff0000', '#00ff00', '#ffff00', '#5c5cff', '#ff00ff', '#00ffff', '#ffffff'\n  ],\n  [ // 3 - rxvt - terminator\n    '#000000', '#cd0000', '#00cd00', '#cdcd00', '#0000cd', '#cd00cd', '#00cdcd', '#faebd7',\n    '#404040', '#ff0000', '#00ff00', '#ffff00', '#0000ff', '#ff00ff', '#00ffff', '#ffffff'\n  ],\n  [ // 4 - Ambience - terminator\n    '#2e3436', '#cc0000', '#4e9a06', '#c4a000', '#3465a4', '#75507b', '#06989a', '#d3d7cf',\n    '#555753', '#ef2929', '#8ae234', '#fce94f', '#729fcf', '#ad7fa8', '#34e2e2', '#eeeeec'\n  ],\n  [ // 5 - Solarized Dark - terminator\n    '#073642', '#dc322f', '#859900', '#b58900', '#268bd2', '#d33682', '#2aa198', '#eee8d5',\n    '#002b36', '#cb4b16', '#586e75', '#657b83', '#839496', '#6c71c4', '#93a1a1', '#fdf6e3'\n  ],\n  [ // 6 - CGA NTSC - wikipedia\n    '#000000', '#69001A', '#117800', '#769100', '#1A00A6', '#8019AB', '#289E76', '#A4A4A4',\n    '#484848', '#C54E76', '#6DD441', '#D2ED46', '#765BFF', '#DC75FF', '#84FAD2', '#FFFFFF'\n  ],\n  [ // 7 - ZX Spectrum - wikipedia\n    '#000000', '#aa0000', '#00aa00', '#aaaa00', '#0000aa', '#aa00aa', '#00aaaa', '#aaaaaa',\n    '#000000', '#ff0000', '#00FF00', '#ffff00', '#0000ff', '#ff00ff', '#00ffff', '#ffffff'\n  ],\n  [ // 8 - Apple II - wikipedia\n    '#000000', '#722640', '#0E5940', '#808080', '#40337F', '#E434FE', '#1B9AFE', '#BFB3FF',\n    '#404C00', '#E46501', '#1BCB01', '#BFCC80', '#808080', '#F1A6BF', '#8DD9BF', '#ffffff'\n  ],\n  [ // 9 - Commodore - wikipedia\n    '#000000', '#8D3E37', '#55A049', '#AAB95D', '#40318D', '#80348B', '#72C1C8', '#D59F74',\n    '#8B5429', '#B86962', '#94E089', '#FFFFB2', '#8071CC', '#AA5FB6', '#87D6DD', '#ffffff'\n  ],\n  [ // 10 - Solarized Light - https://github.com/sgerrand/xfce4-terminal-colors-solarized\n    '#eee8d5', '#dc322f', '#859900', '#b58900', '#268bd2', '#d33682', '#2aa198', '#073642',\n    '#fdf6e3', '#cb4b16', '#93a1a1', '#839496', '#657b83', '#6c71c4', '#586e75', '#002b36'\n  ],\n  [ // 11 - Solarized Dark High contrast - https://github.com/sgerrand/xfce4-terminal-colors-solarized\n    '#073642', '#dc322f', '#859900', '#b58900', '#268bd2', '#d33682', '#2aa198', '#fdf6e3',\n    '#002b36', '#cb4b16', '#657b83', '#839496', '#93a1a1', '#6c71c4', '#eee8d5', '#fdf6e3'\n  ]\n]\n\nexports.fgbgThemes = [\n  ['#AAAAAA', '#000000', 'Lnx', 'Linux'],\n  ['#FFFFFF', '#000000', 'W+K', 'White on Black'],\n  ['#00FF00', '#000000', 'Lim', 'Lime'],\n  ['#E53C00', '#000000', 'Nix', 'Nixie'],\n  ['#EFF0F1', '#31363B', 'Brz', 'Breeze'],\n  ['#FFFFFF', '#300A24', 'Amb', 'Ambiance'],\n  ['#839496', '#002B36', 'SoD', 'Solarized Dark'],\n  ['#93a1a1', '#002b36', 'SoH', 'Solarized Dark (High Contrast)'],\n  ['#657B83', '#FDF6E3', 'SoL', 'Solarized Light'],\n  ['#000000', '#FFD75F', 'Wsp', 'Wasp'],\n  ['#000000', '#FFFFDD', 'K+Y', 'Black on Yellow'],\n  ['#000000', '#FFFFFF', 'K+W', 'Black on White']\n]\n\nlet colorTable256 = null\n\nexports.buildColorTable = function () {\n  if (colorTable256 !== null) return colorTable256\n\n  // 256color lookup table\n  // should not be used to look up 0-15 (will return transparent)\n  colorTable256 = new Array(16).fill('#000000')\n\n  // fill color table\n  // colors 16-231 are a 6x6x6 color cube\n  for (let red = 0; red < 6; red++) {\n    for (let green = 0; green < 6; green++) {\n      for (let blue = 0; blue < 6; blue++) {\n        let redValue = red * 40 + (red ? 55 : 0)\n        let greenValue = green * 40 + (green ? 55 : 0)\n        let blueValue = blue * 40 + (blue ? 55 : 0)\n        colorTable256.push(rgb255ToHex(redValue, greenValue, blueValue))\n      }\n    }\n  }\n  // colors 232-255 are a grayscale ramp, sans black and white\n  for (let gray = 0; gray < 24; gray++) {\n    let value = gray * 10 + 8\n    colorTable256.push(rgb255ToHex(value, value, value))\n  }\n\n  return colorTable256\n}\n\nexports.SELECTION_FG = '#333'\nexports.SELECTION_BG = '#b2d7fe'\n\nexports.themePreview = function (themeN) {\n  $('[data-fg]').forEach((elem) => {\n    let shade = elem.dataset.fg\n    if (/^\\d+$/.test(shade)) shade = exports.toHex(shade, themeN)\n    elem.style.color = shade\n  })\n  $('[data-bg]').forEach((elem) => {\n    let shade = elem.dataset.bg\n    if (/^\\d+$/.test(shade)) shade = exports.toHex(shade, themeN)\n    elem.style.backgroundColor = shade\n  })\n}\n\nexports.toHex = function (shade, themeN) {\n  if (/^\\d+$/.test(shade)) {\n    shade = +shade\n    if (shade < 16) shade = themes[themeN][shade]\n    else {\n      shade = exports.buildColorTable()[shade]\n    }\n  }\n  return shade\n}\n\n\n\n// WEBPACK FOOTER //\n// ./js/term/themes.js","const EventEmitter = require('events')\nconst { parse2B } = require('../utils')\nconst { themes } = require('./themes')\n\nconst encodeAsCodePoint = i => String.fromCodePoint(i + (i >= 0xD800 ? 0x801 : 1))\n\nclass ANSIParser {\n  constructor (handler) {\n    this.reset()\n    this.handler = handler\n    this.joinChunks = true\n  }\n  reset () {\n    this.currentSequence = 0\n    this.sequence = ''\n  }\n  parseSequence (sequence) {\n    if (sequence[0] === '[') {\n      let type = sequence[sequence.length - 1]\n      let content = sequence.substring(1, sequence.length - 1)\n\n      let numbers = content ? content.split(';').map(i => +i.replace(/\\D/g, '')) : []\n      let numOr1 = numbers.length ? numbers[0] : 1\n      if (type === 'H') {\n        this.handler('set-cursor', (numbers[0] | 0) - 1, (numbers[1] | 0) - 1)\n      } else if (type >= 'A' && type <= 'D') {\n        this.handler(`move-cursor-${type <= 'B' ? 'y' : 'x'}`, ((type === 'B' || type === 'C') ? 1 : -1) * numOr1)\n      } else if (type === 'E' || type === 'F') {\n        this.handler('move-cursor-line', (type === 'E' ? 1 : -1) * numOr1)\n      } else if (type === 'G') {\n        this.handler('set-cursor-x', numOr1 - 1)\n      } else if (type === 'J') {\n        let number = numbers.length ? numbers[0] : 2\n        if (number === 2) this.handler('clear')\n      } else if (type === 'P') {\n        this.handler('delete', numOr1)\n      } else if (type === '@') {\n        this.handler('insert-blanks', numOr1)\n      } else if (type === 'q') this.handler('set-cursor-style', numOr1)\n      else if (type === 'm') {\n        if (!numbers.length) {\n          this.handler('reset-style')\n          return\n        }\n        let type\n        while ((type = numbers.shift())) {\n          if (type === 0) this.handler('reset-style')\n          else if (type === 1) this.handler('add-attrs', 1 << 2) // bold\n          else if (type === 2) this.handler('add-attrs', 1 << 9) // faint\n          else if (type === 3) this.handler('add-attrs', 1 << 6) // italic\n          else if (type === 4) this.handler('add-attrs', 1 << 3) // underline\n          else if (type === 5 || type === 6) this.handler('add-attrs', 1 << 5) // blink\n          else if (type === 7) this.handler('add-attrs', 1 << 4) // invert\n          else if (type === 9) this.handler('add-attrs', 1 << 7) // strike\n          else if (type === 20) this.handler('add-attrs', 1 << 10) // fraktur\n          else if (type >= 30 && type <= 37) this.handler('set-color-fg', type % 10)\n          else if (type >= 40 && type <= 47) this.handler('set-color-bg', type % 10)\n          else if (type === 39) this.handler('reset-color-fg')\n          else if (type === 49) this.handler('reset-color-bg')\n          else if (type >= 90 && type <= 98) this.handler('set-color-fg', (type % 10) + 8)\n          else if (type >= 100 && type <= 108) this.handler('set-color-bg', (type % 10) + 8)\n          else if (type === 38 || type === 48) {\n            let mode = numbers.shift()\n            if (mode === 2) {\n              let r = numbers.shift()\n              let g = numbers.shift()\n              let b = numbers.shift()\n              let color = (r << 16 | g << 8 | b) + 256\n              if (type === 38) this.handler('set-color-fg', color)\n              if (type === 48) this.handler('set-color-bg', color)\n            } else if (mode === 5) {\n              let color = (numbers.shift() | 0) & 0xFF\n              if (type === 38) this.handler('set-color-fg', color)\n              if (type === 48) this.handler('set-color-bg', color)\n            }\n          }\n        }\n      } else if (type === 'h' || type === 'l') {\n        if (content === '?25') {\n          if (type === 'h') this.handler('show-cursor')\n          else if (type === 'l') this.handler('hide-cursor')\n        }\n      }\n    }\n  }\n  write (text) {\n    for (let character of text.toString()) {\n      let code = character.codePointAt(0)\n      if (code === 0x1b) this.currentSequence = 1\n      else if (this.currentSequence === 1 && character === '[') {\n        this.currentSequence = 2\n        this.sequence += '['\n      } else if (this.currentSequence && character.match(/[\\x40-\\x7e]/)) {\n        this.parseSequence(this.sequence + character)\n        this.currentSequence = 0\n        this.sequence = ''\n      } else if (this.currentSequence > 1) this.sequence += character\n      else if (this.currentSequence === 1) {\n        // something something nothing\n        this.currentSequence = 0\n        this.handler('write', character)\n      } else if (code < 0x03) this.handler('_null')\n      else if (code === 0x03) this.handler('sigint')\n      else if (code <= 0x06) this.handler('_null')\n      else if (code === 0x07) this.handler('bell')\n      else if (code === 0x08) this.handler('back')\n      else if (code === 0x09) this.handler('tab')\n      else if (code === 0x0a) this.handler('new-line')\n      else if (code === 0x0d) this.handler('return')\n      else if (code === 0x15) this.handler('delete-line')\n      else if (code === 0x17) this.handler('delete-word')\n      else this.handler('write', character)\n    }\n    if (!this.joinChunks) this.reset()\n  }\n}\nconst TERM_DEFAULT_STYLE = [0, 0, 0]\n\nlet getRainbowColor = t => {\n  let r = Math.floor(Math.sin(t) * 2.5 + 2.5)\n  let g = Math.floor(Math.sin(t + 2 / 3 * Math.PI) * 2.5 + 2.5)\n  let b = Math.floor(Math.sin(t + 4 / 3 * Math.PI) * 2.5 + 2.5)\n  return 16 + 36 * r + 6 * g + b\n}\n\nclass ScrollingTerminal {\n  constructor (screen) {\n    this.width = 80\n    this.height = 25\n    this.termScreen = screen\n    this.parser = new ANSIParser((...args) => this.handleParsed(...args))\n    this.buttonLabels = []\n\n    this.reset()\n\n    this._lastLoad = Date.now()\n    this.loadTimer()\n\n    window.showPage()\n  }\n  reset () {\n    this.style = TERM_DEFAULT_STYLE.slice()\n    this.cursor = { x: 0, y: 0, style: 1, visible: true }\n    this.trackMouse = false\n    this.theme = 0\n    this.rainbow = this.superRainbow = false\n    this.parser.reset()\n    this.clear()\n  }\n  clear () {\n    this.screen = []\n    for (let i = 0; i < this.width * this.height; i++) {\n      this.screen.push([' ', this.style.slice()])\n    }\n  }\n  scroll () {\n    this.screen.splice(0, this.width)\n    for (let i = 0; i < this.width; i++) {\n      this.screen.push([' ', TERM_DEFAULT_STYLE.slice()])\n    }\n    this.cursor.y--\n  }\n  newLine () {\n    this.cursor.y++\n    if (this.cursor.y >= this.height) this.scroll()\n  }\n  writeChar (character) {\n    this.screen[this.cursor.y * this.width + this.cursor.x] = [character, this.style.slice()]\n    this.cursor.x++\n    if (this.cursor.x >= this.width) {\n      this.cursor.x = 0\n      this.newLine()\n    }\n  }\n  moveBack (n = 1) {\n    for (let i = 0; i < n; i++) {\n      this.cursor.x--\n      if (this.cursor.x < 0) {\n        if (this.cursor.y > 0) this.cursor.x = this.width - 1\n        else this.cursor.x = 0\n        this.cursor.y = Math.max(0, this.cursor.y - 1)\n      }\n    }\n  }\n  moveForward (n = 1) {\n    for (let i = 0; i < n; i++) {\n      this.cursor.x++\n      if (this.cursor.x >= this.width) {\n        this.cursor.x = 0\n        this.cursor.y++\n        if (this.cursor.y >= this.height) this.scroll()\n      }\n    }\n  }\n  deleteChar () {  // FIXME unused?\n    this.moveBack()\n    this.screen.splice((this.cursor.y + 1) * this.width, 0, [' ', TERM_DEFAULT_STYLE.slice()])\n    this.screen.splice(this.cursor.y * this.width + this.cursor.x, 1)\n  }\n  deleteForward (n) {\n    n = Math.min(this.width, n)\n    for (let i = 0; i < n; i++) this.screen.splice((this.cursor.y + 1) * this.width, 0, [' ', TERM_DEFAULT_STYLE.slice()])\n    this.screen.splice(this.cursor.y * this.width + this.cursor.x, n)\n  }\n  clampCursor () {\n    if (this.cursor.x < 0) this.cursor.x = 0\n    if (this.cursor.y < 0) this.cursor.y = 0\n    if (this.cursor.x > this.width - 1) this.cursor.x = this.width - 1\n    if (this.cursor.y > this.height - 1) this.cursor.y = this.height - 1\n  }\n  handleParsed (action, ...args) {\n    if (action === 'write') {\n      this.writeChar(args[0])\n    } else if (action === 'delete') {\n      this.deleteForward(args[0])\n    } else if (action === 'insert-blanks') {\n      this.insertBlanks(args[0]) // FIXME undefined?\n    } else if (action === 'clear') {\n      this.clear()\n    } else if (action === 'bell') {\n      this.termScreen.load('U\\x01B')\n    } else if (action === 'back') {\n      this.moveBack()\n    } else if (action === 'new-line') {\n      this.newLine()\n      this.cursor.x = 0\n    } else if (action === 'return') {\n      this.cursor.x = 0\n    } else if (action === 'set-cursor') {\n      this.cursor.x = args[1]\n      this.cursor.y = args[0]\n      this.clampCursor()\n    } else if (action === 'move-cursor-y') {\n      this.cursor.y += args[0]\n      this.clampCursor()\n    } else if (action === 'move-cursor-x') {\n      this.cursor.x += args[0]\n      this.clampCursor()\n    } else if (action === 'move-cursor-line') {\n      this.cursor.x = 0\n      this.cursor.y += args[0]\n      this.clampCursor()\n    } else if (action === 'set-cursor-x') {\n      this.cursor.x = args[0]\n    } else if (action === 'set-cursor-style') {\n      this.cursor.style = Math.max(0, Math.min(6, args[0]))\n    } else if (action === 'reset-style') {\n      this.style = TERM_DEFAULT_STYLE.slice()\n    } else if (action === 'add-attrs') {\n      this.style[2] |= args[0]\n    } else if (action === 'set-color-fg') {\n      this.style[0] = args[0]\n      this.style[2] |= 1\n    } else if (action === 'set-color-bg') {\n      this.style[1] = args[0]\n      this.style[2] |= 1 << 1\n    } else if (action === 'reset-color-fg') {\n      this.style[0] = 0\n      if (this.style[2] & 1) this.style[2] ^= 1\n    } else if (action === 'reset-color-bg') {\n      this.style[1] = 0\n      if (this.style[2] & (1 << 1)) this.style[2] ^= (1 << 1)\n    } else if (action === 'hide-cursor') {\n      this.cursor.visible = false\n    } else if (action === 'show-cursor') {\n      this.cursor.visible = true\n    }\n  }\n  write (text) {\n    this.parser.write(text)\n  }\n  getScreenOpts () {\n    let data = 'O'\n    data += encodeAsCodePoint(25)\n    data += encodeAsCodePoint(80)\n    data += encodeAsCodePoint(this.theme)\n    data += encodeAsCodePoint(7)\n    data += encodeAsCodePoint(0)\n    data += encodeAsCodePoint(0)\n    data += encodeAsCodePoint(0)\n    let attributes = +this.cursor.visible\n    attributes |= (3 << 5) * +this.trackMouse // track mouse controls both\n    attributes |= 3 << 7 // buttons/links always visible\n    attributes |= (this.cursor.style << 9)\n    data += encodeAsCodePoint(attributes)\n    return data\n  }\n  getButtons () {\n    let data = 'B'\n    data += encodeAsCodePoint(this.buttonLabels.length)\n    data += this.buttonLabels.map(x => x + '\\x01').join('')\n    return data\n  }\n  getTitle () {\n    return 'TESPTerm Web UI Demo\\x01'\n  }\n  getCursor () {\n    let data = 'C'\n    data += encodeAsCodePoint(this.cursor.y)\n    data += encodeAsCodePoint(this.cursor.x)\n    data += encodeAsCodePoint(0)\n    return data\n  }\n  encodeColor (color) {\n    if (color < 256) {\n      return encodeAsCodePoint(color)\n    } else {\n      color -= 256\n      return encodeAsCodePoint((color & 0xFFF) | 0x10000) + encodeAsCodePoint(color >> 12)\n    }\n  }\n  serializeScreen () {\n    let serialized = 'S'\n    serialized += encodeAsCodePoint(0) + encodeAsCodePoint(0)\n    serialized += encodeAsCodePoint(this.height) + encodeAsCodePoint(this.width)\n\n    let lastStyle = [null, null, null]\n    let index = 0\n    for (let cell of this.screen) {\n      let style = cell[1].slice()\n      if (this.rainbow) {\n        let x = index % this.width\n        let y = Math.floor(index / this.width)\n        // C instead of F in mask and 1 << 8 in attrs to change attr bits 1 and 2\n        let t = (x + y) / 10 + Date.now() / 1000\n        if (this.superRainbow) {\n          t = (x * y + Date.now()) / 100 + Date.now() / 1000\n        }\n        style[0] = getRainbowColor(t)\n        style[1] = 0\n        if (this.superRainbow) style[1] = getRainbowColor(t / 10)\n        style[2] = style[2] | 1\n        if (!this.superRainbow && style[2] & (1 << 1)) style[2] ^= (1 << 1)\n        index++\n      }\n\n      let foreground = style[0]\n      let background = style[1]\n      let attributes = style[2]\n      let setForeground = foreground !== lastStyle[0]\n      let setBackground = background !== lastStyle[1]\n      let setAttributes = attributes !== lastStyle[2]\n\n      if (setForeground && setBackground) {\n        if (foreground < 256 && background < 256) {\n          serialized += '\\x03' + encodeAsCodePoint((background << 8) | foreground)\n        } else {\n          serialized += '\\x05' + this.encodeColor(foreground)\n          serialized += '\\x06' + this.encodeColor(background)\n        }\n      } else if (setForeground) serialized += '\\x05' + this.encodeColor(foreground)\n      else if (setBackground) serialized += '\\x06' + this.encodeColor(background)\n      if (setAttributes) serialized += '\\x04' + encodeAsCodePoint(attributes)\n      lastStyle = style\n\n      serialized += cell[0]\n    }\n    return serialized\n  }\n  getUpdate () {\n    let topics = 0\n    let topicData = []\n    let screenOpts = this.getScreenOpts()\n    let title = this.getTitle()\n    let buttons = this.getButtons()\n    let cursor = this.getCursor()\n    let screen = this.serializeScreen()\n    if (this._screenOpts !== screenOpts) {\n      this._screenOpts = screenOpts\n      topicData.push(screenOpts)\n    }\n    if (this._title !== title) {\n      this._title = title\n      topicData.push(title)\n    }\n    if (this._buttons !== buttons) {\n      this._buttons = buttons\n      topicData.push(buttons)\n    }\n    if (this._cursor !== cursor) {\n      this._cursor = cursor\n      topicData.push(cursor)\n    }\n    if (this._screen !== screen) {\n      this._screen = screen\n      topicData.push(screen)\n    }\n    if (!topicData.length) return ''\n    return 'U' + encodeAsCodePoint(topics) + topicData.join('')\n  }\n  loadTimer () {\n    clearInterval(this._loadTimer)\n    this._loadTimer = setInterval(() => {\n      let update = this.getUpdate()\n      if (update) this.termScreen.load(update)\n    }, 30)\n  }\n}\n\nclass Process extends EventEmitter {\n  write (data) {\n    this.emit('in', data)\n  }\n  destroy () {\n    // death.\n    this.emit('exit', 0)\n  }\n  run () {\n    // noop\n  }\n}\n\nlet demoData = {\n  buttons: [],\n  mouseReceiver: null\n}\n\nlet demoshIndex = {\n  clear: class Clear extends Process {\n    run () {\n      this.emit('write', '\\x1b[2J\\x1b[1;1H')\n      this.destroy()\n    }\n  },\n  screenfetch: class Screenfetch extends Process {\n    run () {\n      let image = `\n ###.                          ESPTerm Demo\n   '###.                       Hostname: ${window.location.hostname}\n     '###.                     Shell: ESPTerm Demo Shell\n       '###.                   Resolution: 80x25@${window.devicePixelRatio}x\n         :###-\n       .###'\n     .###'\n   .###'      ###############\n ###'         ###############\n      `.split('\\n').filter(line => line.trim())\n\n      let chars = ''\n      for (let y = 0; y < image.length; y++) {\n        for (let x = 0; x < 80; x++) {\n          if (image[y][x]) {\n            chars += `\\x1b[38;5;${getRainbowColor((x + y) / 10)}m${image[y][x]}`\n          } else chars += ' '\n        }\n      }\n\n      this.emit('write', '\\r\\n\\x1b[?25l')\n      let loop = () => {\n        this.emit('write', chars.substr(0, 80))\n        chars = chars.substr(80)\n        if (chars.length) setTimeout(loop, 50)\n        else {\n          this.emit('write', '\\r\\n\\x1b[?25h')\n          this.destroy()\n        }\n      }\n      loop()\n    }\n  },\n  'local-echo': class LocalEcho extends Process {\n    run (...args) {\n      if (!args.includes('--suppress-note')) {\n        this.emit('write', '\\x1b[38;5;239mNote: not all terminal features are supported or and may not work as expected in this demo\\x1b[0m\\r\\n')\n      }\n    }\n    write (data) {\n      this.emit('write', data)\n    }\n  },\n  'info': class Info extends Process {\n    run (...args) {\n      let fast = args.includes('--fast')\n      this.showSplash().then(() => {\n        this.printText(fast)\n      })\n    }\n    showSplash () {\n      let splash = `\n              -#####- -###*..#####- ######-\n              -#*    -#-    .## .##.  *#-\n              -##### .-###*..#####-   *#-  -*##*- #*-#--#**#-*##-\n              -#*        -#-.##.      *#-  *##@#* ##.  -#* *# .#*\n              -#####--####- .##.      *#-  -*#@@- ##.  -#* *# .#*\n      `.split('\\n').filter(line => line.trim())\n      let levels = {\n        ' ': -231,\n        '.': 4,\n        '-': 8,\n        '*': 17,\n        '#': 24\n      }\n      let characters = {\n        ' ': ' ',\n        '.': '░',\n        '-': '▒',\n        '*': '▓',\n        '#': '█'\n      }\n      for (let i in splash) {\n        if (splash[i].length < 79) splash[i] += ' '.repeat(79 - splash[i].length)\n      }\n      this.emit('write', '\\r\\n'.repeat(splash.length + 1))\n      this.emit('write', '\\x1b[A'.repeat(splash.length))\n      this.emit('write', '\\x1b[?25l')\n\n      let cursorX = 0\n      let cursorY = 0\n      let moveTo = (x, y) => {\n        let moveX = x - cursorX\n        let moveY = y - cursorY\n        this.emit('write', `\\x1b[${Math.abs(moveX)}${moveX > 0 ? 'C' : 'D'}`)\n        this.emit('write', `\\x1b[${Math.abs(moveY)}${moveY > 0 ? 'B' : 'A'}`)\n        cursorX = x\n        cursorY = y\n      }\n      let drawCell = (x, y) => {\n        moveTo(x, y)\n        if (splash[y][x] === '@') {\n          this.emit('write', '\\x1b[48;5;238m\\x1b[38;5;255m▄\\b')\n        } else {\n          let level = 231 + levels[splash[y][x]]\n          let character = characters[splash[y][x]]\n          this.emit('write', `\\x1b[48;5;${level}m\\x1b[38;5;${level}m${character}\\b`)\n        }\n      }\n      return new Promise((resolve, reject) => {\n        const self = this\n        let x = 13\n        let cycles = 0\n        let loop = function () {\n          for (let y = 0; y < splash.length; y++) {\n            let dx = x - y\n            if (dx > 0) drawCell(dx, y)\n          }\n\n          if (++x < 70) {\n            if (++cycles >= 3) {\n              setTimeout(loop, 50)\n              cycles = 0\n            } else loop()\n          } else {\n            moveTo(0, splash.length)\n            self.emit('write', '\\x1b[m\\x1b[?25h')\n            resolve()\n          }\n        }\n        loop()\n      })\n    }\n    printText (fast = false) {\n      // lots of printing\n      let parts = [\n        '',\n        '  ESPTerm is a VT100-like terminal emulator running on the ESP8266 WiFi chip.',\n        '',\n        '  \\x1b[93mThis is an online demo of the web user interface, simulating a simple ',\n        '  terminal in your browser.\\x1b[m',\n        '',\n        '  Type \\x1b[92mls\\x1b[m to list available commands.',\n        '  Use the \\x1b[94mlinks\\x1b[m below this screen for a demo of the options and more info.',\n        ''\n      ]\n\n      if (fast) {\n        this.emit('write', parts.join('\\r\\n') + '\\r\\n')\n        this.destroy()\n      } else {\n        const self = this\n        let loop = function () {\n          self.emit('write', parts.shift() + '\\r\\n')\n          if (parts.length) setTimeout(loop, 17)\n          else self.destroy()\n        }\n        loop()\n      }\n    }\n  },\n  colors: class PrintColors extends Process {\n    run () {\n      this.emit('write', '\\r\\n')\n      let fgtext = 'foreground-color'\n      this.emit('write', '    ')\n      for (let i = 0; i < 16; i++) {\n        this.emit('write', '\\x1b[' + (i < 8 ? `3${i}` : `9${i - 8}`) + 'm')\n        this.emit('write', fgtext[i] + ' ')\n      }\n      this.emit('write', '\\r\\n    ')\n      for (let i = 0; i < 16; i++) {\n        this.emit('write', '\\x1b[' + (i < 8 ? `4${i}` : `10${i - 8}`) + 'm  ')\n      }\n      this.emit('write', '\\x1b[m\\r\\n')\n      for (let r = 0; r < 6; r++) {\n        this.emit('write', '    ')\n        for (let g = 0; g < 6; g++) {\n          for (let b = 0; b < 6; b++) {\n            this.emit('write', `\\x1b[48;5;${16 + r * 36 + g * 6 + b}m  `)\n          }\n          this.emit('write', '\\x1b[m')\n        }\n        this.emit('write', '\\r\\n')\n      }\n      this.emit('write', '    ')\n      for (let g = 0; g < 24; g++) {\n        this.emit('write', `\\x1b[48;5;${232 + g}m  `)\n      }\n      this.emit('write', '\\x1b[m\\r\\n\\n')\n      this.destroy()\n    }\n  },\n  ls: class ListCommands extends Process {\n    run () {\n      this.emit('write', '\\x1b[92mList of demo commands\\x1b[m\\r\\n')\n      for (let i in demoshIndex) {\n        if (typeof demoshIndex[i] === 'string') continue\n        this.emit('write', i + '\\r\\n')\n      }\n      this.destroy()\n    }\n  },\n  theme: class SetTheme extends Process {\n    constructor (shell) {\n      super()\n      this.shell = shell\n    }\n    run (...args) {\n      let theme = +args[0] | 0\n      const maxnum = themes.length\n      if (!args.length || !Number.isFinite(theme) || theme < 0 || theme >= maxnum) {\n        this.emit('write', `\\x1b[31mUsage: theme [0–${maxnum - 1}]\\n`)\n        this.destroy()\n        return\n      }\n      this.shell.terminal.theme = theme\n      // HACK: reset drawn screen to prevent only partly redrawn screen\n      this.shell.terminal.termScreen.drawnScreenFG = []\n      this.emit('write', '')\n      this.destroy()\n    }\n  },\n  themes: class ShowThemes extends Process {\n    color (hex) {\n      hex = parseInt(hex.substr(1), 16)\n      let r = hex >> 16\n      let g = (hex >> 8) & 0xFF\n      let b = hex & 0xFF\n      this.emit('write', `\\x1b[48;2;${r};${g};${b}m`)\n      if (((r + g + b) / 3) > 127) {\n        this.emit('write', '\\x1b[38;5;16m')\n      } else {\n        this.emit('write', '\\x1b[38;5;255m')\n      }\n    }\n    run (...args) {\n      for (let i in themes) {\n        let theme = themes[i]\n\n        let name = `  ${i}`.substr(-2)\n\n        this.emit('write', `Theme ${name}: `)\n\n        for (let col = 0; col < 16; col++) {\n          let text = `  ${col}`.substr(-2)\n          this.color(theme[col])\n          this.emit('write', text)\n          this.emit('write', '\\x1b[m ')\n        }\n\n        this.emit('write', '\\n')\n      }\n\n      this.destroy()\n    }\n  },\n  cursor: class SetCursor extends Process {\n    run (...args) {\n      let steady = args.includes('--steady')\n      if (args.includes('block')) {\n        this.emit('write', `\\x1b[${2 * steady} q`)\n      } else if (args.includes('line')) {\n        this.emit('write', `\\x1b[${3 + steady} q`)\n      } else if (args.includes('bar') || args.includes('beam')) {\n        this.emit('write', `\\x1b[${5 + steady} q`)\n      } else {\n        this.emit('write', '\\x1b[31mUsage: cursor [block|line|bar] [--steady]\\r\\n')\n      }\n      this.destroy()\n    }\n  },\n  rainbow: class ToggleRainbow extends Process {\n    constructor (shell, options = {}) {\n      super()\n      this.shell = shell\n      this.su = options.su\n      this.abort = false\n    }\n    write (data, newLine = true) {\n      if (data === 'y') {\n        this.shell.terminal.rainbow = !this.shell.terminal.rainbow\n        this.shell.terminal.superRainbow = true\n        demoData._didWarnRainbow = true\n      } else {\n        this.emit('write', data)\n      }\n      if (newLine) this.emit('write', '\\x1b[0;32m\\x1b[G\\x1b[79PRainbow!\\n')\n      this.destroy()\n    }\n    run () {\n      if (this.su && !this.shell.terminal.rainbow) {\n        if (!demoData._didWarnRainbow) {\n          this.emit('write', '\\x1b[31;1mWarning: flashy colors. Continue? [y/N] ')\n        } else {\n          this.write('y', false)\n        }\n      } else {\n        this.shell.terminal.rainbow = !this.shell.terminal.rainbow\n        this.shell.terminal.superRainbow = false\n        this.destroy()\n      }\n    }\n    destroy () {\n      this.abort = true\n      super.destroy()\n    }\n  },\n  mouse: class ShowMouse extends Process {\n    constructor (shell) {\n      super()\n      this.shell = shell\n    }\n    run () {\n      this.emit('buttons', [\n        {\n          label: 'Exit',\n          action (shell) {\n            shell.write('\\x03')\n          }\n        }\n      ])\n\n      this.shell.terminal.trackMouse = true\n      demoData.mouseReceiver = this\n      this.randomData = []\n      this.highlighted = {}\n      let characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'\n      for (let i = 0; i < 23; i++) {\n        let line = ''\n        for (let j = 0; j < 79; j++) {\n          line += characters[Math.floor(characters.length * Math.random())]\n        }\n        this.randomData.push(line)\n      }\n      this.scrollOffset = 0\n      this.render()\n    }\n    render () {\n      this.emit('write', '\\x1b[m\\x1b[2J\\x1b[1;1H')\n      this.emit('write', '\\x1b[97m\\x1b[1mMouse Demo\\r\\n\\x1b[mMouse movement, clicking, and scrolling!')\n\n      // render random data for scrolling\n      for (let y = 0; y < 23; y++) {\n        let index = y + this.scrollOffset\n        // proper modulo:\n        index = ((index % this.randomData.length) + this.randomData.length) % this.randomData.length\n        let line = this.randomData[index]\n        let lineData = `\\x1b[${3 + y};1H\\x1b[38;5;239m`\n        for (let x in line) {\n          if (this.highlighted[(y + 2) * 80 + (+x)]) lineData += '\\x1b[97m'\n          lineData += line[x]\n          if (this.highlighted[(y + 2) * 80 + (+x)]) lineData += '\\x1b[38;5;239m'\n        }\n        this.emit('write', lineData)\n      }\n\n      // move cursor to mouse\n      if (this.mouse) {\n        this.emit('write', `\\x1b[${this.mouse.y + 1};${this.mouse.x + 1}H`)\n      }\n    }\n    mouseMove (x, y) {\n      this.mouse = { x, y }\n      this.render()\n    }\n    mouseDown (x, y, button) {\n      if (button === 4) this.scrollOffset--\n      else if (button === 5) this.scrollOffset++\n      else this.highlighted[y * 80 + x] = !this.highlighted[y * 80 + x]\n      this.render()\n    }\n    mouseUp (x, y, button) {}\n    destroy () {\n      this.shell.terminal.write('\\x1b[2J\\x1b[1;1H')\n      this.shell.terminal.trackMouse = false\n      if (demoData.mouseReceiver === this) demoData.mouseReceiver = null\n      super.destroy()\n    }\n  },\n  sudo: class Sudo extends Process {\n    constructor (shell) {\n      super()\n      this.shell = shell\n      this.didDestroy = false\n    }\n    run (...args) {\n      if (args.length === 0) {\n        this.emit('write', '\\x1b[31mUsage: sudo [command]\\x1b[m\\r\\n')\n        this.destroy()\n      } else {\n        let name = args.shift()\n        if (this.shell.index[name]) {\n          let Process = this.shell.index[name]\n          if (Process instanceof Function) {\n            let child = this.child = new Process(this.shell, { su: true })\n            this.on('in', data => child.write(data))\n            let write = data => this.emit('write', data)\n            let setButtons = buttons => this.emit('buttons', buttons)\n            child.on('write', write)\n            child.on('buttons', setButtons)\n            child.on('exit', code => {\n              child.removeListener('write', write)\n              child.removeListener('buttons', setButtons)\n              this.destroy()\n            })\n            child.run(...args)\n          } else {\n            this.emit('write', Process)\n            this.destroy()\n          }\n        } else {\n          this.emit('write', `sudo: ${name}: command not found\\r\\n`)\n          this.destroy()\n        }\n      }\n    }\n    destroy () {\n      if (this.didDestroy) return\n      this.didDestroy = true\n      if (this.child) this.child.destroy()\n      super.destroy()\n    }\n  },\n  make: class Make extends Process {\n    constructor (shell, options = {}) {\n      super()\n      this.su = options.su\n    }\n    run (...args) {\n      if (args.length === 0) this.emit('write', '\\x1b[31mmake: *** No targets specified.  Stop.\\x1b[0m\\r\\n')\n      else if (args.length === 3 && args.join(' ').toLowerCase() === 'me a sandwich') {\n        if (this.su) {\n          const b = '\\x1b[33m'\n          const r = '\\x1b[0m'\n          const l = '\\x1b[32m'\n          const c = '\\x1b[38;5;229m'\n          const h = '\\x1b[38;5;225m'\n          this.emit('write',\n            `                    ${b}_.---._\\r\\n` +\n            `                _.-~       ~-._\\r\\n` +\n            `            _.-~               ~-._\\r\\n` +\n            `        _.-~                       ~---._\\r\\n` +\n            `    _.-~                                 ~\\\\\\r\\n` +\n            ` .-~                                    _.;\\r\\n` +\n            ` :-._                               _.-~ ./\\r\\n` +\n            ` \\`-._~-._                   _..__.-~ _.-~\\r\\n` +\n            `  ${c}/  ${b}~-._~-._              / .__..--${c}~-${l}---._\\r\\n` +\n            `${c} \\\\_____(_${b};-._\\\\.        _.-~_/${c}       ~)${l}.. . \\\\\\r\\n` +\n            `${l}    /(_____  ${b}\\\\\\`--...--~_.-~${c}______..-+${l}_______)\\r\\n` +\n            `${l}  .(_________/${b}\\`--...--~/${l}    _/ ${h}          ${b}/\\\\\\r\\n` +\n            `${b} /-._${h}     \\\\_     ${l}(___./_..-~${h}__.....${b}__..-~./\\r\\n` +\n            `${b} \\`-._~-._${h}   ~\\\\--------~  .-~${b}_..__.-~ _.-~\\r\\n` +\n            `${b}     ~-._~-._ ${h}~---------\\`  ${b}/ .__..--~\\r\\n` +\n            `${b}         ~-._\\\\.        _.-~_/\\r\\n` +\n            `${b}             \\\\\\`--...--~_.-~\\r\\n` +\n            `${b}              \\`--...--~${r}\\r\\n`)\n        } else {\n          this.emit('write', '\\x1b[31mmake: me a sandwich : Permission denied\\x1b[0m\\r\\n')\n        }\n      } else {\n        this.emit('write', `\\x1b[31mmake: *** No rule to make target '${args.join(' ').toLowerCase()}'.  Stop.\\x1b[0m\\r\\n`)\n      }\n      this.destroy()\n    }\n  },\n  pwd: '/this/is/a/demo\\r\\n',\n  cd: '\\x1b[38;5;239mNo directories to change to\\r\\n',\n  whoami: `${window.navigator.userAgent}\\r\\n`,\n  hostname: `${window.location.hostname}`,\n  uname: 'ESPTerm Demo\\r\\n',\n  mkdir: '\\x1b[38;5;239mDid not create a directory because this is a demo.\\r\\n',\n  rm: '\\x1b[38;5;239mDid not delete anything because this is a demo.\\r\\n',\n  cp: '\\x1b[38;5;239mNothing to copy because this is a demo.\\r\\n',\n  mv: '\\x1b[38;5;239mNothing to move because this is a demo.\\r\\n',\n  ln: '\\x1b[38;5;239mNothing to link because this is a demo.\\r\\n',\n  touch: '\\x1b[38;5;239mNothing to touch\\r\\n',\n  exit: '\\x1b[38;5;239mNowhere to go\\r\\n',\n  github: class GoToGithub extends Process {\n    run () {\n      window.open('https://github.com/espterm/espterm-firmware')\n      this.destroy()\n    }\n  }\n}\nlet autocompleteIndex = {\n  'local-echo': 'local-echo [--suppress-note]',\n  theme: 'theme [n]',\n  cursor: 'cursor [block|line|bar] [--steady]',\n  sudo: 'sudo [command]'\n}\n\nclass DemoShell {\n  constructor (terminal, printInfo) {\n    this.terminal = terminal\n    this.terminal.reset()\n    this.parser = new ANSIParser((...args) => this.handleParsed(...args))\n    this.history = []\n    this.historyIndex = 0\n    this.cursorPos = 0\n    this.lastInputLength = 0\n    this.child = null\n    this.index = demoshIndex\n\n    if (printInfo) this.run('info')\n    else this.prompt()\n  }\n  write (text) {\n    if (this.child) {\n      if (text.codePointAt(0) === 3) this.child.destroy()\n      else this.child.write(text)\n    } else this.parser.write(text)\n  }\n  prompt (success = true) {\n    if (this.terminal.cursor.x !== 0) this.terminal.write('\\x1b[m\\x1b[38;5;238m⏎\\r\\n')\n    this.terminal.write('\\x1b[34;1mdemosh \\x1b[m')\n    if (!success) this.terminal.write('\\x1b[31m')\n    this.terminal.write('$ \\x1b[m')\n    this.history.unshift('')\n    this.cursorPos = 0\n\n    this.setButtons()\n  }\n  copyFromHistoryIndex () {\n    if (!this.historyIndex) return\n    let current = this.history[this.historyIndex]\n    this.history[0] = current\n    this.historyIndex = 0\n  }\n  getCompleted (visual = false) {\n    if (this.history[0]) {\n      let input = this.history[0]\n      let prefix = ''\n      if (input.startsWith('sudo ')) {\n        let newInput = input.replace(/^(sudo\\s+)+/, '')\n        prefix = input.substr(0, input.length - newInput.length)\n        input = newInput\n      }\n      for (let name in this.index) {\n        if (name.startsWith(input) && name !== input) {\n          if (visual && name in autocompleteIndex) return prefix + autocompleteIndex[name]\n          return prefix + name\n        }\n      }\n      return null\n    }\n    return null\n  }\n  handleParsed (action, ...args) {\n    this.terminal.write(`\\x1b[${this.lastInputLength - this.cursorPos}P`)\n    this.terminal.write('\\b\\x1b[P'.repeat(this.cursorPos))\n\n    if (action === 'write') {\n      this.copyFromHistoryIndex()\n      this.history[0] = this.history[0].substr(0, this.cursorPos) + args[0] + this.history[0].substr(this.cursorPos)\n      this.cursorPos++\n    } else if (action === 'back') {\n      this.copyFromHistoryIndex()\n      this.history[0] = this.history[0].substr(0, this.cursorPos - 1) + this.history[0].substr(this.cursorPos)\n      this.cursorPos--\n      if (this.cursorPos < 0) this.cursorPos = 0\n    } else if (action === 'tab') {\n      let completed = this.getCompleted()\n      if (completed) {\n        this.history[0] = completed\n        this.cursorPos = this.history[0].length\n      }\n    } else if (action === 'move-cursor-x') {\n      this.cursorPos = Math.max(0, Math.min(this.history[this.historyIndex].length, this.cursorPos + args[0]))\n    } else if (action === 'delete-line') {\n      this.copyFromHistoryIndex()\n      this.history[0] = ''\n      this.cursorPos = 0\n    } else if (action === 'delete-word') {\n      this.copyFromHistoryIndex()\n      let words = this.history[0].substr(0, this.cursorPos).split(' ')\n      words.pop()\n      this.history[0] = words.join(' ') + this.history[0].substr(this.cursorPos)\n      this.cursorPos = words.join(' ').length\n    } else if (action === 'move-cursor-y') {\n      this.historyIndex -= args[0]\n      if (this.historyIndex < 0) this.historyIndex = 0\n      if (this.historyIndex >= this.history.length) this.historyIndex = this.history.length - 1\n      this.cursorPos = this.history[this.historyIndex].length\n    }\n\n    this.terminal.write(this.history[this.historyIndex])\n    this.terminal.write('\\b'.repeat(this.history[this.historyIndex].length))\n    this.terminal.moveForward(this.cursorPos)\n\n    this.lastInputLength = this.cursorPos\n\n    let completed = this.getCompleted(true)\n    if (this.historyIndex === 0 && completed && action !== 'return') {\n      // show closest match faintly\n      let rest = completed.substr(this.history[0].length)\n      this.terminal.write(`\\x1b[2m${rest}\\x1b[m${'\\b'.repeat(rest.length)}`)\n      this.lastInputLength += rest.length\n    }\n\n    if (action === 'return') {\n      this.terminal.write('\\n')\n      this.parse(this.history[this.historyIndex])\n    }\n  }\n  parse (input) {\n    if (input === 'help') input = 'info'\n    // TODO: basic chaining (i.e. semicolon)\n    if (input) this.run(input)\n    else this.prompt()\n  }\n  run (command) {\n    let parts = ['']\n\n    let inQuote = false\n    for (let character of command.trim()) {\n      if (inQuote && character !== inQuote) {\n        parts[parts.length - 1] += character\n      } else if (inQuote) {\n        inQuote = false\n      } else if (character === '\"' || character === \"'\") {\n        inQuote = character\n      } else if (character.match(/\\s/)) {\n        if (parts[parts.length - 1]) parts.push('')\n      } else parts[parts.length - 1] += character\n    }\n\n    let name = parts.shift()\n\n    if (name in this.index) {\n      this.spawn(name, parts)\n    } else {\n      this.terminal.write(`demosh: Unknown command: ${name}\\r\\n`)\n      this.prompt(false)\n    }\n  }\n  spawn (name, args = []) {\n    let Process = this.index[name]\n    if (Process instanceof Function) {\n      this.setButtons([])\n      this.child = new Process(this)\n      let write = data => this.terminal.write(data)\n      let setButtons = buttons => this.setButtons(buttons)\n      this.child.on('write', write)\n      this.child.on('buttons', setButtons)\n      this.child.on('exit', code => {\n        if (this.child) {\n          this.child.removeListener('write', write)\n          this.child.removeListener('buttons', setButtons)\n        }\n        this.child = null\n        this.prompt(!code)\n      })\n      this.child.run(...args)\n    } else {\n      this.terminal.write(Process)\n      this.prompt()\n    }\n  }\n\n  setButtons (buttons) {\n    if (!buttons) {\n      const shell = this\n      let writeChars = chars => {\n        let loop = () => {\n          shell.write(chars[0])\n          chars = chars.substr(1)\n          if (chars) setTimeout(loop, 100)\n        }\n        setTimeout(loop, 200)\n      }\n\n      buttons = [\n        {\n          label: 'Open GitHub',\n          action (shell) {\n            if (shell.child) shell.child.destroy()\n            writeChars('github\\r')\n          }\n        },\n        {\n          label: 'Help',\n          action (shell) {\n            if (shell.child) shell.child.destroy()\n            writeChars('info\\r')\n          }\n        }\n      ]\n    }\n    if (!buttons.length) buttons.push({ label: '', action () {} })\n    this.buttons = buttons\n    this.terminal.buttonLabels = buttons.map(x => x.label)\n  }\n\n  onButtonPress (index) {\n    let button = this.buttons[index]\n    if (!button) return\n    button.action(this, this.terminal)\n  }\n}\n\nwindow.demoInterface = module.exports = {\n  input (data) {\n    let type = data[0]\n    let content = data.substr(1)\n\n    if (type === 's') {\n      this.shell.write(content)\n    } else if (type === 'b') {\n      let button = content.charCodeAt(0)\n      this.shell.onButtonPress(button - 1)\n    } else if (type === 'm' || type === 'p' || type === 'r') {\n      let row = parse2B(content, 0)\n      let column = parse2B(content, 2)\n      let button = parse2B(content, 4)\n      let modifiers = parse2B(content, 6)\n\n      if (demoData.mouseReceiver) {\n        if (type === 'm') demoData.mouseReceiver.mouseMove(column, row, button, modifiers)\n        else if (type === 'p') demoData.mouseReceiver.mouseDown(column, row, button, modifiers)\n        else if (type === 'r') demoData.mouseReceiver.mouseUp(column, row, button, modifiers)\n      }\n    }\n  },\n  didInit: false,\n  init (screen) {\n    if (this.didInit) return\n    this.didInit = true\n    this.terminal = new ScrollingTerminal(screen)\n    this.shell = new DemoShell(this.terminal, true)\n  }\n}\n\n\n\n// WEBPACK FOOTER //\n// ./js/term/demo.js","/*\n * Copyright (c) 2010 Tim Baumann\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n// NOTE:\n// Extracted from ColorTriangle and\n// Converted to ES6 by MightyPork (2017)\n\n/*******************\n * Color conversion *\n *******************/\n\nconst M = Math\nconst TAU = 2 * M.PI\n\nexports.hue2rgb = function (v1, v2, h) {\n  if (h < 0) h += 1\n  if (h > 1) h -= 1\n\n  if ((6 * h) < 1) return v1 + (v2 - v1) * 6 * h\n  if ((2 * h) < 1) return v2\n  if ((3 * h) < 2) return v1 + (v2 - v1) * ((2 / 3) - h) * 6\n  return v1\n}\n\nexports.hsl2rgb = function (h, s, l) {\n  h /= TAU\n  let r, g, b\n\n  if (s === 0) {\n    r = g = b = l\n  } else {\n    let var_1, var_2\n\n    if (l < 0.5) var_2 = l * (1 + s)\n    else var_2 = (l + s) - (s * l)\n\n    var_1 = 2 * l - var_2\n\n    r = exports.hue2rgb(var_1, var_2, h + (1 / 3))\n    g = exports.hue2rgb(var_1, var_2, h)\n    b = exports.hue2rgb(var_1, var_2, h - (1 / 3))\n  }\n  return [r, g, b]\n}\n\nexports.rgb2hsl = function (r, g, b) {\n  const min = M.min(r, g, b)\n  const max = M.max(r, g, b)\n  const d = max - min // delta\n\n  let h, s, l\n\n  l = (max + min) / 2\n\n  if (d === 0) {\n    // gray\n    h = s = 0 // HSL results from 0 to 1\n  } else {\n    // chroma\n    if (l < 0.5) s = d / (max + min)\n    else s = d / (2 - max - min)\n\n    const d_r = (((max - r) / 6) + (d / 2)) / d\n    const d_g = (((max - g) / 6) + (d / 2)) / d\n    const d_b = (((max - b) / 6) + (d / 2)) / d // deltas\n\n    if (r === max) h = d_b - d_g\n    else if (g === max) h = (1 / 3) + d_r - d_b\n    else if (b === max) h = (2 / 3) + d_g - d_r\n\n    if (h < 0) h += 1\n    else if (h > 1) h -= 1\n  }\n  h *= TAU\n  return [h, s, l]\n}\n\nexports.hex2rgb = function (hex) {\n  const groups = hex.match(/^#([\\da-f]{3,6})$/i)\n  if (groups) {\n    hex = groups[1]\n    const bytes = hex.length / 3\n    const max = (16 ** bytes) - 1\n    return [0, 1, 2].map(x => parseInt(hex.slice(x * bytes, (x + 1) * bytes), 16) / max)\n  }\n  return [0, 0, 0]\n}\n\nfunction pad (n) {\n  return `00${n}`.substr(-2)\n}\n\nexports.rgb255ToHex = function (r, g, b) {\n  return '#' + [r, g, b].map(x => pad(x.toString(16))).join('')\n}\n\nexports.rgb2hex = function (r, g, b) {\n  return '#' + [r, g, b].map(x => pad(Math.round(x * 255).toString(16))).join('')\n}\n\n\n\n// WEBPACK FOOTER //\n// ./js/lib/color_utils.js","let data = require('locale-data')\n\nmodule.exports = function localize (key) {\n  return data[key] || `?${key}?`\n}\n\n\n\n// WEBPACK FOOTER //\n// ./js/lang.js","require('./lib/polyfills')\nrequire('./modal')\nrequire('./notif')\nrequire('./appcommon')\ntry { require('./term/demo') } catch (err) {}\nrequire('./wifi')\n\nconst $ = require('./lib/chibi')\nconst { qs } = require('./utils')\n\n/* Export stuff to the global scope for inline scripts */\nwindow.termInit = require('./term')\nwindow.$ = $\nwindow.qs = qs\n\nwindow.themes = require('./term/themes')\n\nwindow.TermConf = require('./term_conf')\n\n\n\n// WEBPACK FOOTER //\n// ./js/index.js","/*! http://mths.be/fromcodepoint v0.1.0 by @mathias */\nif (!String.fromCodePoint) {\n  (function () {\n    var defineProperty = (function () {\n      // IE 8 only supports `Object.defineProperty` on DOM elements\n      try {\n        var object = {};\n        var $defineProperty = Object.defineProperty;\n        var result = $defineProperty(object, object, object) && $defineProperty;\n      } catch (error) {\n      }\n      return result;\n    }());\n    var stringFromCharCode = String.fromCharCode;\n    var floor = Math.floor;\n    var fromCodePoint = function () {\n      var MAX_SIZE = 0x4000;\n      var codeUnits = [];\n      var highSurrogate;\n      var lowSurrogate;\n      var index = -1;\n      var length = arguments.length;\n      if (!length) {\n        return '';\n      }\n      var result = '';\n      while (++index < length) {\n        var codePoint = Number(arguments[index]);\n        if (\n          !isFinite(codePoint) ||       // `NaN`, `+Infinity`, or `-Infinity`\n          codePoint < 0 ||              // not a valid Unicode code point\n          codePoint > 0x10FFFF ||       // not a valid Unicode code point\n          floor(codePoint) != codePoint // not an integer\n        ) {\n          throw RangeError('Invalid code point: ' + codePoint);\n        }\n        if (codePoint <= 0xFFFF) { // BMP code point\n          codeUnits.push(codePoint);\n        } else { // Astral code point; split in surrogate halves\n          // http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae\n          codePoint -= 0x10000;\n          highSurrogate = (codePoint >> 10) + 0xD800;\n          lowSurrogate = (codePoint % 0x400) + 0xDC00;\n          codeUnits.push(highSurrogate, lowSurrogate);\n        }\n        if (index + 1 == length || codeUnits.length > MAX_SIZE) {\n          result += stringFromCharCode.apply(null, codeUnits);\n          codeUnits.length = 0;\n        }\n      }\n      return result;\n    };\n    if (defineProperty) {\n      defineProperty(String, 'fromCodePoint', {\n        'value': fromCodePoint,\n        'configurable': true,\n        'writable': true\n      });\n    } else {\n      String.fromCodePoint = fromCodePoint;\n    }\n  }());\n}\n\n\n\n// WEBPACK FOOTER //\n// ./js/lib/polyfills.js","const $ = require('./lib/chibi')\nconst { mk, qs, qsa, cr } = require('./utils')\nconst modal = require('./modal')\nconst notify = require('./notif')\n\n/** Global generic init */\n$.ready(function () {\n  // Opening menu on mobile / narrow screen\n  function menuOpen () {\n    $('#menu').toggleClass('expanded')\n  }\n  $('#brand')\n    .on('click', menuOpen)\n    .on('keypress', cr(menuOpen))\n\n  // Checkbox UI (checkbox CSS and hidden input with int value)\n  $('.Row.checkbox').forEach(function (x) {\n    let inp = x.querySelector('input')\n    let box = x.querySelector('.box')\n\n    $(box).toggleClass('checked', inp.value)\n\n    let hdl = function () {\n      inp.value = 1 - inp.value\n      $(box).toggleClass('checked', inp.value)\n    }\n\n    $(x).on('click', hdl).on('keypress', cr(hdl))\n  })\n\n  // Expanding boxes on mobile\n  $('.Box.mobcol,.Box.fold').forEach(function (x) {\n    let h = x.querySelector('h2')\n\n    let hdl = function () {\n      if ($(x).hasClass('d-expanded')) {\n        $(x).removeClass('d-expanded')\n      } else {\n        $(x).toggleClass('expanded')\n      }\n    }\n    $(h).on('click', hdl).on('keypress', cr(hdl))\n  })\n\n  $('form').forEach(function (x) {\n    $(x).on('keypress', function (e) {\n      if ((e.keyCode === 10 || e.keyCode === 13) && e.ctrlKey) {\n        x.submit()\n      }\n    })\n  })\n\n  // loader dots...\n  setInterval(function () {\n    $('.anim-dots').each(function (x) {\n      let $x = $(x)\n      let dots = $x.html() + '.'\n      if (dots.length === 5) dots = '.'\n      $x.html(dots)\n    })\n  }, 1000)\n\n  // flipping number boxes with the mouse wheel\n  $('input[type=number]').on('wheel', function (e) {\n    let $this = $(this)\n    let val = +$this.val()\n    if (isNaN(val)) val = 1\n\n    const step = +($this.attr('step') || 1)\n    const min = +$this.attr('min')\n    const max = +$this.attr('max')\n    if (e.deltaY > 0) {\n      val += step\n    } else {\n      val -= step\n    }\n\n    if (Number.isFinite(min)) val = Math.max(val, +min)\n    if (Number.isFinite(max)) val = Math.min(val, +max)\n    $this.val(val)\n\n    if ('createEvent' in document) {\n      let evt = document.createEvent('HTMLEvents')\n      evt.initEvent('change', false, true)\n      $this[0].dispatchEvent(evt)\n    } else {\n      $this[0].fireEvent('onchange')\n    }\n\n    e.preventDefault()\n  })\n\n  // populate the form errors box from GET arg ?err=...\n  // (a way to pass errors back from server via redirect)\n  let errAt = window.location.search.indexOf('err=')\n  if (errAt !== -1 && qs('.Box.errors')) {\n    let errs = decodeURIComponent(window.location.search.substr(errAt + 4)).split(',')\n    let humanReadableErrors = []\n    errs.forEach(function (er) {\n      let lbls = qsa('label[for=\"' + er + '\"]')\n      if (lbls) {\n        for (let i = 0; i < lbls.length; i++) {\n          let lbl = lbls[i]\n          lbl.classList.add('error')\n          if (i === 0) humanReadableErrors.push(lbl.childNodes[0].textContent.trim().replace(/: ?$/, ''))\n        }\n      } else {\n        humanReadableErrors.push(er)\n      }\n    })\n\n    qs('.Box.errors .list').innerHTML = humanReadableErrors.join(', ')\n    qs('.Box.errors').classList.remove('hidden')\n  }\n\n  let msgAt = window.location.search.indexOf('msg=')\n  if (msgAt !== -1 && qs('.Box.message')) {\n    let msg = decodeURIComponent(window.location.search.substr(msgAt + 4))\n    let box = qs('.Box.message')\n    box.innerHTML = msg\n    box.classList.remove('hidden')\n    setTimeout(() => {\n      box.classList.add('hiding')\n      setTimeout(() => {\n        box.classList.add('hidden')\n      }, 1000)\n    }, 2000)\n  }\n\n  modal.init()\n  notify.init()\n\n  // remove tabindices from h2 if wide\n  if (window.innerWidth > 550) {\n    $('.Box h2').forEach(function (x) {\n      x.removeAttribute('tabindex')\n    })\n\n    // brand works as a link back to term in widescreen mode\n    let br = qs('#brand')\n    br && br.addEventListener('click', function () {\n      window.location.href = '/' // go to terminal\n    })\n  }\n})\n\n// setup the ajax loader\n$._loader = function (vis) {\n  $('#loader').toggleClass('show', vis)\n}\n\nlet pageShown = false\n// reveal content on load\nfunction showPage () {\n  pageShown = true\n  $('#content').addClass('load')\n}\n// HACKITY HACK: fix this later\nwindow.showPage = showPage\n\n// Auto reveal pages other than the terminal (sets window.noAutoShow)\n$.ready(function () {\n  if (window.noAutoShow === true) {\n    setTimeout(function () {\n      if (!pageShown) {\n        let bnr = mk('P')\n        bnr.id = 'load-failed'\n        bnr.innerHTML =\n          'Server connection failed! Trying again' +\n          '<span class=\"anim-dots\" style=\"width:1.5em;text-align:left;display:inline-block\">.</span>'\n        qs('#screen').appendChild(bnr)\n        showPage()\n      }\n    }, 2000)\n  } else {\n    setTimeout(function () {\n      showPage()\n    }, 1)\n  }\n})\n\n\n\n// WEBPACK FOOTER //\n// ./js/appcommon.js","const $ = require('./lib/chibi')\nconst { mk } = require('./utils')\nconst tr = require('./lang')\n\n{\n  const w = window.WiFi = {}\n\n  const authTypes = ['Open', 'WEP', 'WPA', 'WPA2', 'WPA/WPA2']\n  let curSSID\n\n  // Get XX % for a slider input\n  function calc_dBm (inp) {\n    return `+${(inp.value * 0.25).toFixed(2)} dBm`\n  }\n\n  // Display selected STA SSID etc\n  function selectSta (name, password, ip) {\n    $('#sta_ssid').val(name)\n    $('#sta_password').val(password)\n\n    $('#sta-nw').toggleClass('hidden', name.length === 0)\n    $('#sta-nw-nil').toggleClass('hidden', name.length > 0)\n\n    $('#sta-nw .essid').html($.htmlEscape(name))\n    const hasPassword = !!password\n\n    // (the following is kind of confusing with the double-double negations,\n    // but it works)\n    $('#sta-nw .passwd').toggleClass('hidden', !hasPassword)\n    $('#sta-nw .nopasswd').toggleClass('hidden', hasPassword)\n\n    $('#sta-nw .ip').html(ip.length > 0 ? tr('wifi.connected_ip_is') + ip : tr('wifi.not_conn'))\n  }\n\n  /** Update display for received response */\n  function onScan (resp, status) {\n    // var ap_json = {\n    //  \"result\": {\n    //    \"inProgress\": \"0\",\n    //    \"APs\": [\n    //      {\"essid\": \"Chlivek\", \"bssid\": \"88:f7:c7:52:b3:99\", \"rssi\": \"204\", \"enc\": \"4\", \"channel\": \"1\"},\n    //      {\"essid\": \"TyNikdy\", \"bssid\": \"5c:f4:ab:0d:f1:1b\", \"rssi\": \"164\", \"enc\": \"3\", \"channel\": \"1\"},\n    //    ]\n    //  }\n    // };\n\n    if (status !== 200) {\n      // bad response\n      rescan(5000) // wait 5s then retry\n      return\n    }\n\n    try {\n      resp = JSON.parse(resp)\n    } catch (e) {\n      console.log(e)\n      rescan(5000)\n      return\n    }\n\n    const done = !resp.result.inProgress && resp.result.APs.length > 0\n    rescan(done ? 15000 : 1000)\n    if (!done) return // no redraw yet\n\n    // clear the AP list\n    let $list = $('#ap-list')\n    // remove old APs\n    $('#ap-list .AP').remove()\n\n    $list.toggleClass('hidden', !done)\n    $('#ap-loader').toggleClass('hidden', done)\n\n    // scan done\n    resp.result.APs.sort((a, b) => b.rssi - a.rssi).forEach(function (ap) {\n      ap.enc = parseInt(ap.enc)\n\n      if (ap.enc > 4) return // hide unsupported auths\n\n      let item = mk('div')\n\n      let $item = $(item)\n        .data('ssid', ap.essid)\n        .data('pwd', ap.enc)\n        .attr('tabindex', 0)\n        .addClass('AP')\n\n      // mark current SSID\n      if (ap.essid === curSSID) {\n        $item.addClass('selected')\n      }\n\n      let inner = mk('div')\n      let escapedSSID = $.htmlEscape(ap.essid)\n      $(inner).addClass('inner')\n        .htmlAppend(`<div class=\"rssi\">${ap.rssi_perc}</div>`)\n        .htmlAppend(`<div class=\"essid\" title=\"${escapedSSID}\">${escapedSSID}</div>`)\n        .htmlAppend(`<div class=\"auth\">${authTypes[ap.enc]}</div>`)\n\n      $item.on('click', function () {\n        let $th = $(this)\n\n        const conn_ssid = $th.data('ssid')\n        let conn_pass = ''\n\n        if (+$th.data('pwd')) {\n          // this AP needs a password\n          conn_pass = window.prompt(tr('wifi.enter_passwd').replace(':ssid:', conn_ssid))\n          if (!conn_pass) return\n        }\n\n        $('#sta_password').val(conn_pass)\n        $('#sta_ssid').val(conn_ssid)\n        selectSta(conn_ssid, conn_pass, '')\n      })\n\n      item.appendChild(inner)\n      $list[0].appendChild(item)\n    })\n  }\n\n  function startScanning () {\n    $('#ap-loader').removeClass('hidden')\n    $('#ap-scan').addClass('hidden')\n    $('#ap-loader .anim-dots').html('.')\n\n    scanAPs()\n  }\n\n  /** Ask the CGI what APs are visible (async) */\n  function scanAPs () {\n    if (window._demo) {\n      onScan(window._demo_aps, 200)\n    } else {\n      $.get('http://' + window._root + '/cfg/wifi/scan', onScan)\n    }\n  }\n\n  function rescan (time) {\n    setTimeout(scanAPs, time)\n  }\n\n  /** Set up the WiFi page */\n  function wifiInit (cfg) {\n    // Update slider value displays\n    $('.Row.range').forEach(function (x) {\n      let inp = x.querySelector('input')\n      let disp1 = x.querySelector('.x-disp1')\n      let disp2 = x.querySelector('.x-disp2')\n      let t = calc_dBm(inp)\n      $(disp1).html(t)\n      $(disp2).html(t)\n      $(inp).on('input', function () {\n        t = calc_dBm(inp)\n        $(disp1).html(t)\n        $(disp2).html(t)\n      })\n    })\n\n    // Forget STA credentials\n    $('#forget-sta').on('click', () => {\n      selectSta('', '', '')\n      return false\n    })\n\n    selectSta(cfg.sta_ssid, cfg.sta_password, cfg.sta_active_ip)\n    curSSID = cfg.sta_active_ssid\n  }\n\n  w.init = wifiInit\n  w.startScanning = startScanning\n}\n\n\n\n// WEBPACK FOOTER //\n// ./js/wifi.js","<?php\n\nreturn [\n\t'menu.cfg_wifi' => 'WiFi Settings',\n\t'menu.cfg_network' => 'Network Settings',\n\t'menu.cfg_term' => 'Terminal Settings',\n\t'menu.about' => 'About ESPTerm',\n\t'menu.help' => 'Quick Reference',\n\t'menu.term' => 'Back to Terminal',\n\t'menu.cfg_system' => 'System Settings',\n\t'menu.cfg_wifi_conn' => 'Connecting to Network',\n\t'menu.settings' => 'Settings',\n\n\t// Terminal page\n\n\t'title.term' => 'Terminal', // page title of the terminal page\n\n\t'term_nav.fullscreen' => 'Fullscreen',\n\t'term_nav.config' => 'Config',\n\t'term_nav.wifi' => 'WiFi',\n\t'term_nav.help' => 'Help',\n\t'term_nav.about' => 'About',\n\t'term_nav.paste' => 'Paste',\n\t'term_nav.upload' => 'Upload',\n\t'term_nav.keybd' => 'Keyboard',\n\t'term_nav.paste_prompt' => 'Paste text to send:',\n\n\t'term_conn.connecting' => 'Connecting',\n\t'term_conn.waiting_content' => 'Waiting for content',\n\t'term_conn.disconnected' => 'Disconnected',\n\t'term_conn.waiting_server' => 'Waiting for server',\n\t'term_conn.reconnecting' => 'Reconnecting',\n\n\t// Terminal settings page\n\n\t'term.defaults' => 'Initial Settings',\n\t'term.expert' => 'Expert Options',\n\t'term.explain_initials' => '\n\t\tThose are the initial settings used after ESPTerm powers on, \n\t\tor when the screen reset command is received (<code>\\ec</code>).\n\t\tThey can be changed by the terminal application using escape sequences.\n\t\t',\n\t'term.explain_expert' => '\n\t\tThose are advanced config options that usually don\\'t need to be changed.\n\t\tEdit them only if you know what you\\'re doing.',\n\n\t'term.example' => 'Default colors preview',\n\n\t'term.explain_scheme' => '\n\t\tTo select default text and background color, click on the\n\t\tpreview palette. Alternatively, use numbers 0-15 for theme colors,\n\t\t16-255 for standard colors and hex (#FFFFFF) for True Color (24-bit).\n\t\t',\n\n\t'term.fgbg_presets' => 'Defaults Presets',\n\t'term.color_scheme' => 'Color Scheme',\n\t'term.reset_screen' => 'Reset screen & parser',\n\t'term.term_title' => 'Header Text',\n\t'term.term_width' => 'Width',\n\t'term.term_height' => 'Height',\n\t'term.buttons' => 'Button Labels',\n\t'term.theme' => 'Color Palette',\n\t'term.cursor_shape' => 'Cursor Style',\n\t'term.parser_tout_ms' => 'Parser Timeout',\n\t'term.display_tout_ms' => 'Redraw Delay',\n\t'term.display_cooldown_ms' => 'Redraw Cooldown',\n\t'term.allow_decopt_12' => 'Allow \\e?12h/l',\n\t'term.fn_alt_mode' => 'SS3 Fn keys',\n\t'term.show_config_links' => 'Show nav links',\n\t'term.show_buttons' => 'Show buttons',\n\t'term.loopback' => 'Local Echo (<span style=\"text-decoration:overline\">SRM</span>)',\n\t'term.crlf_mode' => 'Enter = CR+LF (LNM)',\n\t'term.want_all_fn' => 'Capture F5, F11, F12',\n\t'term.button_msgs' => 'Button codes<br>(ASCII, dec, CSV)',\n\t'term.color_fg' => 'Default Fg.',\n\t'term.color_bg' => 'Default Bg.',\n\t'term.color_fg_prev' => 'Foreground',\n\t'term.color_bg_prev' => 'Background',\n\t'term.colors_preview' => '',\n\t'term.debugbar' => 'Debug internal state',\n\t'term.ascii_debug' => 'Display control codes',\n\n\t'cursor.block_blink' => 'Block, blinking',\n    'cursor.block_steady' => 'Block, steady',\n    'cursor.underline_blink' => 'Underline, blinking',\n    'cursor.underline_steady' => 'Underline, steady',\n    'cursor.bar_blink' => 'I-bar, blinking',\n    'cursor.bar_steady' => 'I-bar, steady',\n\n\t// Text upload dialog\n\n\t'upload.title' => 'Text Upload',\n\t'upload.prompt' => 'Load a text file:',\n\t'upload.endings' => 'Line endings:',\n\t'upload.endings.cr' => 'CR (Enter key)',\n\t'upload.endings.crlf' => 'CR LF (Windows)',\n\t'upload.endings.lf' => 'LF (Linux)',\n\t'upload.chunk_delay' => 'Chunk delay (ms):',\n\t'upload.chunk_size' => 'Chunk size (0=line):',\n\t'upload.progress' => 'Upload:',\n\n\t// Network config page\n\n\t'net.explain_sta' => '\n\t\tSwitch off Dynamic IP to configure the static IP address.',\n\n\t'net.explain_ap' => '\n\t\tThose settings affect the built-in DHCP server in AP mode.',\n\n\t'net.ap_dhcp_time' => 'Lease time',\n\t'net.ap_dhcp_start' => 'Pool start IP',\n\t'net.ap_dhcp_end' => 'Pool end IP',\n\t'net.ap_addr_ip' => 'Own IP address',\n\t'net.ap_addr_mask' => 'Subnet mask',\n\n\t'net.sta_dhcp_enable' => 'Use dynamic IP',\n\t'net.sta_addr_ip' => 'ESPTerm static IP',\n\t'net.sta_addr_mask' => 'Subnet mask',\n\t'net.sta_addr_gw' => 'Gateway IP',\n\n\t'net.ap' => 'DHCP Server (AP)',\n\t'net.sta' => 'DHCP Client (Station)',\n\t'net.sta_mac' => 'Station MAC',\n\t'net.ap_mac' => 'AP MAC',\n\t'net.details' => 'MAC addresses',\n\n\t// Wifi config page\n\n\t'wifi.ap' => 'Built-in Access Point',\n\t'wifi.sta' => 'Join Existing Network',\n\n\t'wifi.enable' => 'Enabled',\n\t'wifi.tpw' => 'Transmit power',\n\t'wifi.ap_channel' => 'Channel',\n\t'wifi.ap_ssid' => 'AP SSID',\n\t'wifi.ap_password' => 'Password',\n\t'wifi.ap_hidden' => 'Hide SSID',\n\t'wifi.sta_info' => 'Selected',\n\n\t'wifi.not_conn' => 'Not connected.',\n\t'wifi.sta_none' => 'None',\n\t'wifi.sta_active_pw' => '🔒 Password saved',\n\t'wifi.sta_active_nopw' => '🔓 Open access',\n\t'wifi.connected_ip_is' => 'Connected, IP is ',\n\t'wifi.sta_password' => 'Password:',\n\n\t'wifi.scanning' => 'Scanning',\n\t'wifi.scan_now' => 'Click here to start scanning!',\n\t'wifi.cant_scan_no_sta' => 'Click here to enable client mode and start scanning!',\n\t'wifi.select_ssid' => 'Available networks:',\n\t'wifi.enter_passwd' => 'Enter password for \":ssid:\"',\n\t'wifi.sta_explain' => 'After selecting a network, press Apply to connect.',\n\n\t// Wifi connecting status page\n\n\t'wificonn.status' => 'Status:',\n\t'wificonn.back_to_config' => 'Back to WiFi config',\n\t'wificonn.telemetry_lost' => 'Telemetry lost; something went wrong, or your device disconnected.',\n\t'wificonn.explain_android_sucks' => '\n\t\tIf you\\'re configuring ESPTerm via a smartphone, or were connected \n\t\tfrom another external network, your device may lose connection and \n\t\tthis progress indicator won\\'t work. Please wait a while (~ 15 seconds), \n\t\tthen check if the connection succeeded.',\n\n\t'wificonn.explain_reset' => '\n\t\tTo force enable the built-in AP, hold the BOOT button until the blue LED \n\t\tstarts flashing. Hold the button longer (until the LED flashes rapidly) \n\t\tfor a \"factory reset\".',\n\n\t'wificonn.disabled' =>\"Station mode is disabled.\",\n\t'wificonn.idle' =>\"Idle, not connected and has no IP.\",\n\t'wificonn.success' => \"Connected! Received IP \",\n\t'wificonn.working' => \"Connecting to selected AP\",\n\t'wificonn.fail' => \"Connection failed, check settings & try again. Cause: \",\n\n\t// Access restrictions form\n\n\t'pwlock.title' => 'Access Restrictions',\n\t'pwlock.explain' => '\n\t\tSome parts, or all of the web interface can be protected by a password prompt.\n\t\tLeave the new password fields empty if you do not wish to change it.<br>\n\t\tThe default password is \"%def_access_pw%\".\n\t',\n\t'pwlock.region' => 'Protected pages',\n\t'pwlock.region.none' => 'None, all open',\n\t'pwlock.region.settings_noterm' => 'WiFi, Net & System settings',\n\t'pwlock.region.settings' => 'All settings pages',\n\t'pwlock.region.menus' => 'This entire menu section',\n\t'pwlock.region.all' => 'Everything, even terminal',\n\t'pwlock.new_access_pw' => 'New password',\n\t'pwlock.new_access_pw2' => 'Repeat',\n\t'pwlock.admin_pw' => 'Admin password',\n\t'pwlock.access_name' => 'Username',\n\n\t// Setting admin password\n\n\t'adminpw.title' => 'Change Admin Password',\n\t'adminpw.explain' =>\n\t\t'\n\t\tThe \"admin password\" is used to manipulate the stored default settings \n\t\tand to change access restrictions. This password is not saved as part \n\t\tof the main config, i.e. using save / restore does not affect this \n\t\tpassword. When the admin password is forgotten, the easiest way to \n\t\tre-gain access is to wipe and re-flash the chip.<br>\n\t\tThe default admin password is \"%def_admin_pw%\".\n\t\t',\n\t'adminpw.new_admin_pw' => 'New admin password',\n\t'adminpw.new_admin_pw2' => 'Repeat',\n\t'adminpw.old_admin_pw' => 'Old admin password',\n\n\t// Persist form\n\n\t'persist.title' => 'Save & Restore',\n\t'persist.explain' => '\n\t\tESPTerm saves all settings in Flash. The active settings can be copied to\n\t\tthe \"defaults area\" and restored later using the blue button below.\n\t\t',\n\t'persist.confirm_restore' => 'Restore all settings to their default values?',\n\t'persist.confirm_restore_hard' =>\n\t\t'Restore to firmware default settings? This will reset ' .\n\t\t'all active settings and switch to AP mode with the default SSID.',\n\t'persist.confirm_store_defaults' =>\n\t\t'Enter admin password to confirm you want to overwrite the default settings.',\n\t'persist.password' => 'Admin password:',\n\t'persist.restore_defaults' => 'Reset to saved defaults',\n\t'persist.write_defaults' => 'Save active settings as defaults',\n\t'persist.restore_hard' => 'Reset active settings to factory defaults',\n\t'persist.restore_hard_explain' =>\n\t\t'(This clears the WiFi config! Does not affect saved defaults or admin password.)',\n\n\t// UART settings form\n\n\t'uart.title' => 'Serial Port Parameters',\n\t'uart.explain' => '\n\t\tThis form controls the communication UART. The debug UART is fixed\n\t\tat 115.200 baud, one stop-bit and no parity.\n\t\t',\n\t'uart.baud' => 'Baud rate',\n\t'uart.parity' => 'Parity',\n\t'uart.parity.none' => 'None',\n\t'uart.parity.odd' => 'Odd',\n\t'uart.parity.even' => 'Even',\n\t'uart.stop_bits' => 'Stop-bits',\n\t'uart.stop_bits.one' => 'One',\n\t'uart.stop_bits.one_and_half' => 'One and half',\n\t'uart.stop_bits.two' => 'Two',\n\n\t// HW tuning form\n\n\t'hwtuning.title' => 'Hardware Tuning',\n\t'hwtuning.explain' => '\n\t\tESP8266 can be overclocked from 80&nbsp;MHz to 160&nbsp;MHz. This will make \n\t\tit more responsive and allow faster screen updates at the expense of slightly \n\t\thigher power consumption. This can also make it more susceptible to interference.\n\t\tUse with care.\n\t\t',\n\t'hwtuning.overclock' => 'Overclock to 160MHz',\n\n\t// Generic button / dialog labels\n\n\t'apply' => 'Apply!',\n\t'start' => 'Start',\n\t'cancel' => 'Cancel',\n\t'enabled' => 'Enabled',\n\t'disabled' => 'Disabled',\n\t'yes' => 'Yes',\n\t'no' => 'No',\n\t'confirm' => 'OK',\n\t'copy' => 'Copy',\n\t'form_errors' => 'Validation errors for:',\n];\n\n\n\n// WEBPACK FOOTER //\n// ./lang/en.php","const { qs, mk } = require('../utils')\nconst localize = require('../lang')\nconst Notify = require('../notif')\nconst TermScreen = require('./screen')\nconst TermConnection = require('./connection')\nconst TermInput = require('./input')\nconst TermUpload = require('./upload')\nconst initSoftKeyboard = require('./soft_keyboard')\nconst attachDebugScreen = require('./debug_screen')\nconst initButtons = require('./buttons')\n\n/** Init the terminal sub-module - called from HTML */\nmodule.exports = function (opts) {\n  const screen = new TermScreen()\n  const conn = new TermConnection(screen)\n  const input = TermInput(conn, screen)\n  const termUpload = TermUpload(conn, input, screen)\n  screen.input = input\n  screen.conn = conn\n  input.termUpload = termUpload\n\n  const buttons = initButtons(input)\n  screen.on('button-labels', labels => {\n    // TODO: don't use pointers for this\n    buttons.labels.splice(0, buttons.labels.length, ...labels)\n    buttons.update()\n  })\n\n  let showSplashTimeout = null\n  let showSplash = (obj, delay = 250) => {\n    clearTimeout(showSplashTimeout)\n    showSplashTimeout = setTimeout(() => {\n      screen.window.statusScreen = obj\n    }, delay)\n  }\n\n  conn.on('open', () => {\n    // console.log('*open')\n    showSplash({ title: localize('term_conn.connecting'), loading: true })\n  })\n  conn.on('connect', () => {\n    // console.log('*connect')\n    showSplash({ title: localize('term_conn.waiting_content'), loading: true })\n  })\n  conn.on('load', () => {\n    // console.log('*load')\n    clearTimeout(showSplashTimeout)\n    if (screen.window.statusScreen) screen.window.statusScreen = null\n  })\n  conn.on('disconnect', () => {\n    // console.log('*disconnect')\n    showSplash({ title: localize('term_conn.disconnected') }, 500)\n    screen.screen = []\n    screen.screenFG = []\n    screen.screenBG = []\n    screen.screenAttrs = []\n  })\n  conn.on('silence', () => {\n    // console.log('*silence')\n    showSplash({ title: localize('term_conn.waiting_server'), loading: true }, 0)\n  })\n  // conn.on('ping-fail', () => { screen.window.statusScreen = { title: 'Disconnected' } })\n  conn.on('ping-success', () => {\n    // console.log('*ping-success')\n    showSplash({ title: localize('term_conn.reconnecting'), loading: true }, 0)\n  })\n\n  conn.init()\n  input.init(opts)\n  termUpload.init()\n  Notify.init()\n\n  window.onerror = function (errorMsg, file, line, col) {\n    Notify.show(`<b>JS ERROR!</b><br>${errorMsg}<br>at ${file}:${line}:${col}`, 10000, true)\n    return false\n  }\n\n  qs('#screen').appendChild(screen.canvas)\n\n  initSoftKeyboard(screen, input)\n  if (attachDebugScreen) attachDebugScreen(screen)\n\n  let fullscreenIcon = {} // dummy\n  let isFullscreen = false\n  let properFullscreen = false\n  let fitScreen = false\n  let screenPadding = screen.window.padding\n  let fitScreenIfNeeded = function fitScreenIfNeeded () {\n    if (isFullscreen) {\n      fullscreenIcon.className = 'icn-resize-small'\n      if (properFullscreen) {\n        screen.window.fitIntoWidth = window.screen.width\n        screen.window.fitIntoHeight = window.screen.height\n        screen.window.padding = 0\n      } else {\n        screen.window.fitIntoWidth = window.innerWidth\n        if (qs('#term-nav').classList.contains('hidden')) {\n          screen.window.fitIntoHeight = window.innerHeight\n        } else {\n          screen.window.fitIntoHeight = window.innerHeight - 24\n        }\n        screen.window.padding = 0\n      }\n    } else {\n      fullscreenIcon.className = 'icn-resize-full'\n      screen.window.fitIntoWidth = fitScreen ? window.innerWidth - 4 : 0\n      screen.window.fitIntoHeight = fitScreen ? window.innerHeight : 0\n      screen.window.padding = screenPadding\n    }\n  }\n  fitScreenIfNeeded()\n  window.addEventListener('resize', fitScreenIfNeeded)\n\n  let toggleFitScreen = function () {\n    fitScreen = !fitScreen\n    const resizeButtonIcon = qs('#resize-button-icon')\n    if (fitScreen) {\n      resizeButtonIcon.classList.remove('icn-resize-small')\n      resizeButtonIcon.classList.add('icn-resize-full')\n    } else {\n      resizeButtonIcon.classList.remove('icn-resize-full')\n      resizeButtonIcon.classList.add('icn-resize-small')\n    }\n    fitScreenIfNeeded()\n  }\n\n  qs('#term-fit-screen').addEventListener('click', function () {\n    toggleFitScreen()\n    return false\n  })\n\n  // add fullscreen mode & button\n  if (window.Element.prototype.requestFullscreen || window.Element.prototype.webkitRequestFullscreen) {\n    properFullscreen = true\n\n    let checkForFullscreen = function () {\n      // document.fullscreenElement is not really supported yet, so here's a hack\n      if (isFullscreen && (window.innerWidth !== window.screen.width || window.innerHeight !== window.screen.height)) {\n        isFullscreen = false\n        fitScreenIfNeeded()\n      }\n    }\n    setInterval(checkForFullscreen, 500)\n  }\n\n  // (why are the buttons anchors?)\n  let button = mk('a')\n  button.id = 'fullscreen-button'\n  button.href = '#'\n  button.addEventListener('click', e => {\n    e.preventDefault()\n\n    if (document.body.classList.contains('pseudo-fullscreen')) {\n      document.body.classList.remove('pseudo-fullscreen')\n      isFullscreen = false\n      fitScreenIfNeeded()\n      return\n    }\n\n    isFullscreen = true\n    fitScreenIfNeeded()\n    screen.updateSize()\n\n    if (properFullscreen) {\n      if (screen.canvas.requestFullscreen) screen.canvas.requestFullscreen()\n      else screen.canvas.webkitRequestFullscreen()\n    } else {\n      document.body.classList.add('pseudo-fullscreen')\n    }\n  })\n  fullscreenIcon = mk('i')\n  fullscreenIcon.className = 'icn-resize-full'\n  button.appendChild(fullscreenIcon)\n  let span = mk('span')\n  span.textContent = localize('term_nav.fullscreen')\n  button.appendChild(span)\n  qs('#term-nav').insertBefore(button, qs('#term-nav').firstChild)\n\n  // for debugging\n  window.termScreen = screen\n  window.conn = conn\n  window.input = input\n  window.termUpl = termUpload\n}\n\n\n\n// WEBPACK FOOTER //\n// ./js/term/index.js","const EventEmitter = require('events')\nconst $ = require('../lib/chibi')\nconst { mk, qs } = require('../utils')\nconst notify = require('../notif')\nconst ScreenParser = require('./screen_parser')\nconst ScreenRenderer = require('./screen_renderer')\n\nmodule.exports = class TermScreen extends EventEmitter {\n  constructor () {\n    super()\n\n    this.canvas = mk('canvas')\n    this.ctx = this.canvas.getContext('2d')\n\n    this.parser = new ScreenParser(this)\n    this.renderer = new ScreenRenderer(this)\n\n    // debug screen handle\n    this._debug = null\n\n    if ('AudioContext' in window || 'webkitAudioContext' in window) {\n      this.audioCtx = new (window.AudioContext || window.webkitAudioContext)()\n    } else {\n      console.warn('No AudioContext!')\n    }\n\n    // dummy. Handle for Input\n    this.input = new Proxy({}, {\n      get () {\n        return () => console.warn('TermScreen#input not set!')\n      }\n    })\n    // dummy. Handle for Conn\n    this.conn = new Proxy({}, {\n      get () {\n        return () => console.warn('TermScreen#conn not set!')\n      },\n      set (a, b) {\n        return () => console.warn('TermScreen#conn not set!')\n      }\n    })\n\n    this.cursor = {\n      x: 0,\n      y: 0,\n      blinking: true,\n      visible: true,\n      hanging: false,\n      style: 'block'\n    }\n\n    this._window = {\n      width: 0,\n      height: 0,\n      devicePixelRatio: 1,\n      fontFamily: '\"DejaVu Sans Mono\", \"Liberation Mono\", \"Inconsolata\", \"Menlo\", monospace',\n      fontSize: 20,\n      padding: 6,\n      gridScaleX: 1.0,\n      gridScaleY: 1.2,\n      fitIntoWidth: 0,\n      fitIntoHeight: 0,\n      debug: false,\n      graphics: 0,\n      statusScreen: null\n    }\n\n    // scaling caused by fitIntoWidth/fitIntoHeight\n    this._windowScale = 1\n\n    // actual padding, as it may be disabled by fullscreen mode etc.\n    this._padding = 0\n\n    // properties of this.window that require updating size and redrawing\n    this.windowState = {\n      width: 0,\n      height: 0,\n      devicePixelRatio: 0,\n      padding: 0,\n      gridScaleX: 0,\n      gridScaleY: 0,\n      fontFamily: '',\n      fontSize: 0,\n      fitIntoWidth: 0,\n      fitIntoHeight: 0\n    }\n\n    // current selection\n    this.selection = {\n      // when false, this will prevent selection in favor of mouse events,\n      // though alt can be held to override it\n      selectable: true,\n\n      // selection start and end (x, y) tuples\n      start: [0, 0],\n      end: [0, 0]\n    }\n\n    // mouse features\n    this.mouseMode = { clicks: false, movement: false }\n\n    // make writing to window update size and draw\n    const self = this\n    this.window = new Proxy(this._window, {\n      set (target, key, value, receiver) {\n        if (target[key] !== value) {\n          target[key] = value\n          self.scheduleSizeUpdate()\n          self.renderer.scheduleDraw(`window:${key}=${value}`)\n          self.emit(`update-window:${key}`, value)\n        }\n        return true\n      }\n    })\n\n    this.bracketedPaste = false\n    this.blinkingCellCount = 0\n    this.reverseVideo = false\n\n    this.screen = []\n    this.screenFG = []\n    this.screenBG = []\n    this.screenAttrs = []\n\n    let selecting = false\n\n    let selectStart = (x, y) => {\n      if (selecting) return\n      selecting = true\n      this.selection.start = this.selection.end = this.screenToGrid(x, y, true)\n      this.renderer.scheduleDraw('select-start')\n    }\n\n    let selectMove = (x, y) => {\n      if (!selecting) return\n      this.selection.end = this.screenToGrid(x, y, true)\n      this.renderer.scheduleDraw('select-move')\n    }\n\n    let selectEnd = (x, y) => {\n      if (!selecting) return\n      selecting = false\n      this.selection.end = this.screenToGrid(x, y, true)\n      this.renderer.scheduleDraw('select-end')\n      Object.assign(this.selection, this.getNormalizedSelection())\n    }\n\n    // bind event listeners\n\n    this.canvas.addEventListener('mousedown', e => {\n      if ((this.selection.selectable || e.altKey) && e.button === 0) {\n        selectStart(e.offsetX, e.offsetY)\n      } else {\n        this.input.onMouseDown(...this.screenToGrid(e.offsetX, e.offsetY),\n          e.button + 1)\n      }\n    })\n\n    window.addEventListener('mousemove', e => {\n      selectMove(e.offsetX, e.offsetY)\n    })\n\n    window.addEventListener('mouseup', e => {\n      selectEnd(e.offsetX, e.offsetY)\n    })\n\n    // touch event listeners\n\n    let touchPosition = null\n    let touchDownTime = 0\n    let touchSelectMinTime = 500\n    let touchDidMove = false\n\n    let getTouchPositionOffset = touch => {\n      let rect = this.canvas.getBoundingClientRect()\n      return [touch.clientX - rect.left, touch.clientY - rect.top]\n    }\n\n    this.canvas.addEventListener('touchstart', e => {\n      touchPosition = getTouchPositionOffset(e.touches[0])\n      touchDidMove = false\n      touchDownTime = Date.now()\n    }, { passive: true })\n\n    this.canvas.addEventListener('touchmove', e => {\n      touchPosition = getTouchPositionOffset(e.touches[0])\n\n      if (!selecting && touchDidMove === false) {\n        if (touchDownTime < Date.now() - touchSelectMinTime) {\n          selectStart(...touchPosition)\n        }\n      } else if (selecting) {\n        e.preventDefault()\n        selectMove(...touchPosition)\n      }\n\n      touchDidMove = true\n    })\n\n    this.canvas.addEventListener('touchend', e => {\n      if (e.touches[0]) {\n        touchPosition = getTouchPositionOffset(e.touches[0])\n      }\n\n      if (selecting) {\n        e.preventDefault()\n        selectEnd(...touchPosition)\n\n        // selection ended; show touch select menu\n        let touchSelectMenu = qs('#touch-select-menu')\n        touchSelectMenu.classList.add('open')\n        let rect = touchSelectMenu.getBoundingClientRect()\n\n        // use middle position for x and one line above for y\n        let selectionPos = this.gridToScreen(\n          (this.selection.start[0] + this.selection.end[0]) / 2,\n          this.selection.start[1] - 1\n        )\n        selectionPos[0] -= rect.width / 2\n        selectionPos[1] -= rect.height / 2\n        touchSelectMenu.style.transform = `translate(${selectionPos[0]}px, ${\n          selectionPos[1]}px)`\n      }\n\n      if (!touchDidMove && !this.mouseMode.clicks) {\n        this.emit('tap', Object.assign(e, {\n          x: touchPosition[0],\n          y: touchPosition[1]\n        }))\n      }\n\n      touchPosition = null\n    })\n\n    this.on('tap', e => {\n      if (this.selection.start[0] !== this.selection.end[0] ||\n        this.selection.start[1] !== this.selection.end[1]) {\n        // selection is not empty\n        // reset selection\n        this.selection.start = this.selection.end = [0, 0]\n        qs('#touch-select-menu').classList.remove('open')\n        this.renderer.scheduleDraw('select-reset')\n      } else {\n        e.preventDefault()\n        this.emit('open-soft-keyboard')\n      }\n    })\n\n    $.ready(() => {\n      let copyButton = qs('#touch-select-copy-btn')\n      if (copyButton) {\n        copyButton.addEventListener('click', () => {\n          this.copySelectionToClipboard()\n        })\n      }\n    })\n\n    this.canvas.addEventListener('mousemove', e => {\n      if (!selecting) {\n        this.input.onMouseMove(...this.screenToGrid(e.offsetX, e.offsetY))\n      }\n    })\n\n    this.canvas.addEventListener('mouseup', e => {\n      if (!selecting) {\n        this.input.onMouseUp(...this.screenToGrid(e.offsetX, e.offsetY),\n          e.button + 1)\n      }\n    })\n\n    let aggregateWheelDelta = 0\n    this.canvas.addEventListener('wheel', e => {\n      if (this.mouseMode.clicks) {\n        if (Math.abs(e.wheelDeltaY) === 120) {\n          // mouse wheel scrolling\n          this.input.onMouseWheel(...this.screenToGrid(e.offsetX, e.offsetY), e.deltaY > 0 ? 1 : -1)\n        } else {\n          // smooth scrolling\n          aggregateWheelDelta -= e.wheelDeltaY\n          if (Math.abs(aggregateWheelDelta) >= 40) {\n            this.input.onMouseWheel(...this.screenToGrid(e.offsetX, e.offsetY), aggregateWheelDelta > 0 ? 1 : -1)\n            aggregateWheelDelta = 0\n          }\n        }\n\n        // prevent page scrolling\n        e.preventDefault()\n      }\n    })\n\n    this.canvas.addEventListener('contextmenu', e => {\n      if (this.mouseMode.clicks) {\n        // prevent mouse keys getting stuck\n        e.preventDefault()\n      }\n      selectEnd(e.offsetX, e.offsetY)\n    })\n  }\n\n  /**\n   * Schedule a size update in the next millisecond\n   */\n  scheduleSizeUpdate () {\n    clearTimeout(this._scheduledSizeUpdate)\n    this._scheduledSizeUpdate = setTimeout(() => this.updateSize(), 1)\n  }\n\n  /**\n   * Returns a CSS font string with this TermScreen's font settings and the\n   * font modifiers.\n   * @param {Object} modifiers\n   * @param {string} [modifiers.style] - the font style\n   * @param {string} [modifiers.weight] - the font weight\n   * @returns {string} a CSS font string\n   */\n  getFont (modifiers = {}) {\n    let fontStyle = modifiers.style || 'normal'\n    let fontWeight = modifiers.weight || 'normal'\n    return `${fontStyle} normal ${fontWeight} ${this.window.fontSize}px ${this.window.fontFamily}`\n  }\n\n  /**\n   * Converts screen coordinates to grid coordinates.\n   * @param {number} x - x in pixels\n   * @param {number} y - y in pixels\n   * @param {boolean} rounded - whether to round the coord, used for select highlighting\n   * @returns {number[]} a tuple of (x, y) in cells\n   */\n  screenToGrid (x, y, rounded = false) {\n    let cellSize = this.getCellSize()\n\n    x = x / this._windowScale - this._padding\n    y = y / this._windowScale - this._padding\n    x = Math.floor((x + (rounded ? cellSize.width / 2 : 0)) / cellSize.width)\n    y = Math.floor(y / cellSize.height)\n    x = Math.max(0, Math.min(this.window.width - 1, x))\n    y = Math.max(0, Math.min(this.window.height - 1, y))\n\n    return [x, y]\n  }\n\n  /**\n   * Converts grid coordinates to screen coordinates.\n   * @param {number} x - x in cells\n   * @param {number} y - y in cells\n   * @param {boolean} [withScale] - when true, will apply window scale\n   * @returns {number[]} a tuple of (x, y) in pixels\n   */\n  gridToScreen (x, y, withScale = false) {\n    let cellSize = this.getCellSize()\n\n    return [x * cellSize.width, y * cellSize.height].map(v => this._padding + (withScale ? v * this._windowScale : v))\n  }\n\n  /**\n   * The character size, used for calculating the cell size. The space character\n   * is used for measuring.\n   * @returns {Object} the character size with `width` and `height` in pixels\n   */\n  getCharSize () {\n    this.ctx.font = this.getFont()\n\n    return {\n      width: Math.floor(this.ctx.measureText(' ').width),\n      height: this.window.fontSize\n    }\n  }\n\n  /**\n   * The cell size, which is the character size multiplied by the grid scale.\n   * @returns {Object} the cell size with `width` and `height` in pixels\n   */\n  getCellSize () {\n    let charSize = this.getCharSize()\n\n    return {\n      width: Math.ceil(charSize.width * this.window.gridScaleX),\n      height: Math.ceil(charSize.height * this.window.gridScaleY)\n    }\n  }\n\n  /**\n   * Updates the canvas size if it changed\n   */\n  updateSize () {\n    // see below (this is just updating it)\n    this._window.devicePixelRatio = Math.ceil(this._windowScale * (window.devicePixelRatio || 1))\n\n    let didChange = false\n    for (let key in this.windowState) {\n      if (this.windowState.hasOwnProperty(key) && this.windowState[key] !== this.window[key]) {\n        didChange = true\n        this.windowState[key] = this.window[key]\n      }\n    }\n\n    if (didChange) {\n      const {\n        width,\n        height,\n        fitIntoWidth,\n        fitIntoHeight,\n        padding\n      } = this.window\n      const cellSize = this.getCellSize()\n\n      // real height of the canvas element in pixels\n      let realWidth = width * cellSize.width\n      let realHeight = height * cellSize.height\n      let originalWidth = realWidth\n\n      if (fitIntoWidth && fitIntoHeight) {\n        let terminalAspect = realWidth / realHeight\n        let fitAspect = fitIntoWidth / fitIntoHeight\n\n        if (terminalAspect < fitAspect) {\n          // align heights\n          realHeight = fitIntoHeight - 2 * padding\n          realWidth = realHeight * terminalAspect\n        } else {\n          // align widths\n          realWidth = fitIntoWidth - 2 * padding\n          realHeight = realWidth / terminalAspect\n        }\n      }\n\n      // store new window scale\n      this._windowScale = realWidth / originalWidth\n\n      realWidth += 2 * padding\n      realHeight += 2 * padding\n\n      // store padding\n      this._padding = padding * (originalWidth / realWidth)\n\n      // the DPR must be rounded to a very nice value to prevent gaps between cells\n      let devicePixelRatio = this._window.devicePixelRatio = Math.ceil(this._windowScale * (window.devicePixelRatio || 1))\n\n      this.canvas.width = (width * cellSize.width + 2 * Math.round(this._padding)) * devicePixelRatio\n      this.canvas.style.width = `${realWidth}px`\n      this.canvas.height = (height * cellSize.height + 2 * Math.round(this._padding)) * devicePixelRatio\n      this.canvas.style.height = `${realHeight}px`\n\n      // the screen has been cleared (by changing canvas width)\n      this.renderer.resetDrawn()\n\n      // draw immediately; the canvas shouldn't flash\n      this.renderer.draw('update-size')\n    }\n  }\n\n  /**\n   * Returns a normalized version of the current selection, such that `start`\n   * is always before `end`.\n   * @returns {Object} the normalized selection, with `start` and `end`\n   */\n  getNormalizedSelection () {\n    let { start, end } = this.selection\n    // if the start line is after the end line, or if they're both on the same\n    // line but the start column comes after the end column, swap\n    if (start[1] > end[1] || (start[1] === end[1] && start[0] > end[0])) {\n      [start, end] = [end, start]\n    }\n    return { start, end }\n  }\n\n  /**\n   * Returns whether or not a given cell is in the current selection.\n   * @param {number} col - the column (x)\n   * @param {number} line - the line (y)\n   * @returns {boolean}\n   */\n  isInSelection (col, line) {\n    let { start, end } = this.getNormalizedSelection()\n    let colAfterStart = start[0] <= col\n    let colBeforeEnd = col < end[0]\n    let onStartLine = line === start[1]\n    let onEndLine = line === end[1]\n\n    if (onStartLine && onEndLine) return colAfterStart && colBeforeEnd\n    else if (onStartLine) return colAfterStart\n    else if (onEndLine) return colBeforeEnd\n    else return start[1] < line && line < end[1]\n  }\n\n  /**\n   * Sweeps for selected cells and joins them in a multiline string.\n   * @returns {string} the selection\n   */\n  getSelectedText () {\n    const screenLength = this.window.width * this.window.height\n    let lines = []\n    let previousLineIndex = -1\n\n    for (let cell = 0; cell < screenLength; cell++) {\n      let x = cell % this.window.width\n      let y = Math.floor(cell / this.window.width)\n\n      if (this.isInSelection(x, y)) {\n        if (previousLineIndex !== y) {\n          previousLineIndex = y\n          lines.push('')\n        }\n        lines[lines.length - 1] += this.screen[cell]\n      }\n    }\n\n    return lines.join('\\n')\n  }\n\n  /**\n   * Copies the selection to clipboard and creates a notification balloon.\n   */\n  copySelectionToClipboard () {\n    let selectedText = this.getSelectedText()\n    // don't copy anything if nothing is selected\n    if (!selectedText) return\n    let textarea = mk('textarea')\n    document.body.appendChild(textarea)\n    textarea.value = selectedText\n    textarea.select()\n    if (document.execCommand('copy')) {\n      notify.show('Copied to clipboard')\n    } else {\n      notify.show('Failed to copy')\n    }\n    document.body.removeChild(textarea)\n  }\n\n  /**\n   * Shows an actual notification (if possible) or a notification balloon.\n   * @param {string} text - the notification content\n   */\n  showNotification (text) {\n    console.info(`Notification: ${text}`)\n    if (window.Notification && window.Notification.permission === 'granted') {\n      let notification = new window.Notification('ESPTerm', {\n        body: text\n      })\n      notification.addEventListener('click', () => window.focus())\n    } else {\n      if (window.Notification && window.Notification.permission !== 'denied') {\n        window.Notification.requestPermission()\n      } else {\n        // Fallback using the built-in notification balloon\n        notify.show(text)\n      }\n    }\n  }\n\n  /**\n   * Creates a beep sound.\n   */\n  beep () {\n    const audioCtx = this.audioCtx\n    if (!audioCtx) return\n\n    // prevent screeching\n    if (this._lastBeep && this._lastBeep > Date.now() - 50) return\n    this._lastBeep = Date.now()\n\n    if (!this._convolver) {\n      this._convolver = audioCtx.createConvolver()\n      let impulseLength = audioCtx.sampleRate * 0.8\n      let impulse = audioCtx.createBuffer(2, impulseLength, audioCtx.sampleRate)\n      for (let i = 0; i < impulseLength; i++) {\n        impulse.getChannelData(0)[i] = (1 - i / impulseLength) ** (7 + Math.random())\n        impulse.getChannelData(1)[i] = (1 - i / impulseLength) ** (7 + Math.random())\n      }\n      this._convolver.buffer = impulse\n      this._convolver.connect(audioCtx.destination)\n    }\n\n    // main beep\n    const mainOsc = audioCtx.createOscillator()\n    const mainGain = audioCtx.createGain()\n    mainOsc.connect(mainGain)\n    mainGain.gain.value = 4\n    mainOsc.frequency.value = 750\n    mainOsc.type = 'sine'\n\n    // surrogate beep (making it sound like 'oops')\n    const surrOsc = audioCtx.createOscillator()\n    const surrGain = audioCtx.createGain()\n    surrOsc.connect(surrGain)\n    surrGain.gain.value = 2\n    surrOsc.frequency.value = 400\n    surrOsc.type = 'sine'\n\n    mainGain.connect(this._convolver)\n    surrGain.connect(this._convolver)\n\n    let startTime = audioCtx.currentTime\n    mainOsc.start()\n    mainOsc.stop(startTime + 0.5)\n    surrOsc.start(startTime + 0.05)\n    surrOsc.stop(startTime + 0.8)\n\n    let loop = function () {\n      if (audioCtx.currentTime < startTime + 0.8) window.requestAnimationFrame(loop)\n      mainGain.gain.value *= 0.8\n      surrGain.gain.value *= 0.8\n    }\n    loop()\n  }\n\n  load (...args) {\n    this.parser.load(...args)\n  }\n}\n\n\n\n// WEBPACK FOOTER //\n// ./js/term/screen.js","const $ = require('../lib/chibi')\nconst { qs } = require('../utils')\n\n// constants for decoding the update blob\nconst SEQ_SKIP = 1\nconst SEQ_REPEAT = 2\nconst SEQ_SET_COLORS = 3\nconst SEQ_SET_ATTRS = 4\nconst SEQ_SET_FG = 5\nconst SEQ_SET_BG = 6\nconst SEQ_SET_ATTR_0 = 7\n\nfunction du (str) {\n  let num = str.codePointAt(0)\n  if (num > 0xDFFF) num -= 0x800\n  return num - 1\n}\n\n/* eslint-disable no-multi-spaces */\nconst TOPIC_SCREEN_OPTS  = 'O'\nconst TOPIC_CONTENT      = 'S'\nconst TOPIC_TITLE        = 'T'\nconst TOPIC_BUTTONS      = 'B'\nconst TOPIC_CURSOR       = 'C'\nconst TOPIC_INTERNAL     = 'D'\nconst TOPIC_BELL         = '!'\n\nconst OPT_CURSOR_VISIBLE   = (1 << 0)\nconst OPT_DEBUGBAR         = (1 << 1)\nconst OPT_CURSORS_ALT_MODE = (1 << 2)\nconst OPT_NUMPAD_ALT_MODE  = (1 << 3)\nconst OPT_FN_ALT_MODE      = (1 << 4)\nconst OPT_CLICK_TRACKING   = (1 << 5)\nconst OPT_MOVE_TRACKING    = (1 << 6)\nconst OPT_SHOW_BUTTONS     = (1 << 7)\nconst OPT_SHOW_CONFIG_LINKS = (1 << 8)\n// const OPT_CURSOR_SHAPE   = (7 << 9)\nconst OPT_CRLF_MODE        = (1 << 12)\nconst OPT_BRACKETED_PASTE  = (1 << 13)\nconst OPT_REVERSE_VIDEO    = (1 << 14)\n\nconst ATTR_FG        = (1 << 0)  // 1 if not using default background color (ignore cell bg) - color extension bit\nconst ATTR_BG        = (1 << 1)  // 1 if not using default foreground color (ignore cell fg) - color extension bit\nconst ATTR_BOLD      = (1 << 2)  // Bold font\nconst ATTR_UNDERLINE = (1 << 3)  // Underline decoration\nconst ATTR_INVERSE   = (1 << 4)  // Invert colors - this is useful so we can clear then with SGR manipulation commands\nconst ATTR_BLINK     = (1 << 5)  // Blinking\nconst ATTR_ITALIC    = (1 << 6)  // Italic font\nconst ATTR_STRIKE    = (1 << 7)  // Strike-through decoration\nconst ATTR_OVERLINE  = (1 << 8)  // Over-line decoration\nconst ATTR_FAINT     = (1 << 9)  // Faint foreground color (reduced alpha)\nconst ATTR_FRAKTUR   = (1 << 10) // Fraktur font (unicode substitution)\n/* eslint-enable no-multi-spaces */\n\nmodule.exports = class ScreenParser {\n  constructor (screen) {\n    this.screen = screen\n\n    // true if TermScreen#load was called at least once\n    this.contentLoaded = false\n  }\n\n  /**\n   * Hide the warning message about failed data load\n   */\n  hideLoadFailedMsg () {\n    if (!this.contentLoaded) {\n      let errmsg = qs('#load-failed')\n      if (errmsg) errmsg.parentNode.removeChild(errmsg)\n      this.contentLoaded = true\n    }\n  }\n\n  loadUpdate (str) {\n    // console.log(`update ${str}`)\n    // current index\n    let ci = 0\n    let strArray = Array.from ? Array.from(str) : str.split('')\n\n    let text\n    let resized = false\n    const topics = du(strArray[ci++])\n    // this.screen.cursor.hanging = !!(attributes & (1 << 1))\n\n    while (ci < strArray.length) {\n      const topic = strArray[ci++]\n\n      if (topic === TOPIC_SCREEN_OPTS) {\n        const newHeight = du(strArray[ci++])\n        const newWidth = du(strArray[ci++])\n        const theme = du(strArray[ci++])\n        const defFg = (du(strArray[ci++]) & 0xFFFF) | ((du(strArray[ci++]) & 0xFFFF) << 16)\n        const defBg = (du(strArray[ci++]) & 0xFFFF) | ((du(strArray[ci++]) & 0xFFFF) << 16)\n        const attributes = du(strArray[ci++])\n\n        // theming\n        this.screen.renderer.loadTheme(theme)\n        this.screen.renderer.setDefaultColors(defFg, defBg)\n\n        // apply size\n        resized = (this.screen.window.height !== newHeight) || (this.screen.window.width !== newWidth)\n        this.screen.window.height = newHeight\n        this.screen.window.width = newWidth\n\n        // process attributes\n        this.screen.cursor.visible = !!(attributes & OPT_CURSOR_VISIBLE)\n\n        this.screen.input.setAlts(\n          !!(attributes & OPT_CURSORS_ALT_MODE),\n          !!(attributes & OPT_NUMPAD_ALT_MODE),\n          !!(attributes & OPT_FN_ALT_MODE),\n          !!(attributes & OPT_CRLF_MODE)\n        )\n\n        const trackMouseClicks = !!(attributes & OPT_CLICK_TRACKING)\n        const trackMouseMovement = !!(attributes & OPT_MOVE_TRACKING)\n\n        // 0 - Block blink     2 - Block steady (1 is unused)\n        // 3 - Underline blink 4 - Underline steady\n        // 5 - I-bar blink     6 - I-bar steady\n        let cursorShape = (attributes >> 9) & 0x07\n        // if it's not zero, decrement such that the two most significant bits\n        // are the type and the least significant bit is the blink state\n        if (cursorShape > 0) cursorShape--\n        const cursorStyle = cursorShape >> 1\n        const cursorBlinking = !(cursorShape & 1)\n        if (cursorStyle === 0) this.screen.cursor.style = 'block'\n        else if (cursorStyle === 1) this.screen.cursor.style = 'line'\n        else if (cursorStyle === 2) this.screen.cursor.style = 'bar'\n        if (this.screen.cursor.blinking !== cursorBlinking) {\n          this.screen.cursor.blinking = cursorBlinking\n          this.screen.renderer.resetCursorBlink()\n        }\n\n        this.screen.input.setMouseMode(trackMouseClicks, trackMouseMovement)\n        this.screen.selection.selectable = !trackMouseClicks && !trackMouseMovement\n        $(this.screen.canvas).toggleClass('selectable', this.screen.selection.selectable)\n        this.screen.mouseMode = {\n          clicks: trackMouseClicks,\n          movement: trackMouseMovement\n        }\n\n        const showButtons = !!(attributes & OPT_SHOW_BUTTONS)\n        const showConfigLinks = !!(attributes & OPT_SHOW_CONFIG_LINKS)\n\n        $('.x-term-conf-btn').toggleClass('hidden', !showConfigLinks)\n        $('#action-buttons').toggleClass('hidden', !showButtons)\n\n        this.screen.bracketedPaste = !!(attributes & OPT_BRACKETED_PASTE)\n        this.screen.reverseVideo = !!(attributes & OPT_REVERSE_VIDEO)\n\n        const debugbar = !!(attributes & OPT_DEBUGBAR)\n        // TODO do something with debugbar\n\n      } else if (topic === TOPIC_CURSOR) {\n\n        // cursor position\n        const cursorY = du(strArray[ci++])\n        const cursorX = du(strArray[ci++])\n        const hanging = du(strArray[ci++])\n\n        const cursorMoved = (\n          hanging !== this.screen.cursor.hanging ||\n          cursorX !== this.screen.cursor.x ||\n          cursorY !== this.screen.cursor.y)\n\n        this.screen.cursor.x = cursorX\n        this.screen.cursor.y = cursorY\n\n        this.screen.cursor.hanging = !!hanging\n\n        if (cursorMoved) {\n          this.screen.renderer.resetCursorBlink()\n          this.screen.emit('cursor-moved')\n        }\n\n        this.screen.renderer.scheduleDraw('cursor-moved')\n      } else if (topic === TOPIC_TITLE) {\n\n        // TODO optimize this\n        text = ''\n        while (ci < strArray.length) {\n          let c = strArray[ci++]\n          if (c !== '\\x01') {\n            text += c\n          } else {\n            break\n          }\n        }\n\n        qs('#screen-title').textContent = text\n        if (text.length === 0) text = 'Terminal'\n        qs('title').textContent = `${text} :: ESPTerm`\n\n      } else if (topic === TOPIC_BUTTONS) {\n        const count = du(strArray[ci++])\n\n        let labels = []\n        for (let j = 0; j < count; j++) {\n          text = ''\n          while (ci < strArray.length) {\n            let c = strArray[ci++]\n            if (c === '\\x01') break\n            text += c\n          }\n          labels.push(text)\n        }\n\n        this.screen.emit('button-labels', labels)\n      } else if (topic === TOPIC_BELL) {\n\n        this.screen.beep()\n\n      } else if (topic === TOPIC_INTERNAL) {\n        // debug info\n\n        const flags = du(strArray[ci++])\n        const cursorAttrs = du(strArray[ci++])\n        const regionStart = du(strArray[ci++])\n        const regionEnd = du(strArray[ci++])\n        const charsetGx = du(strArray[ci++])\n        const charsetG0 = strArray[ci++]\n        const charsetG1 = strArray[ci++]\n        const freeHeap = du(strArray[ci++])\n        const clientCount = du(strArray[ci++])\n\n        this.screen.emit('internal', {\n          flags,\n          cursorAttrs,\n          regionStart,\n          regionEnd,\n          charsetGx,\n          charsetG0,\n          charsetG1,\n          freeHeap,\n          clientCount\n        })\n      } else if (topic === TOPIC_CONTENT) {\n        // set screen content\n\n        const frameY = du(strArray[ci++])\n        const frameX = du(strArray[ci++])\n        const frameHeight = du(strArray[ci++])\n        const frameWidth = du(strArray[ci++])\n\n        if (this.screen._debug && this.screen.window.debug) {\n          this.screen._debug.pushFrame([frameX, frameY, frameWidth, frameHeight])\n        }\n\n        // content\n        let fg = 7\n        let bg = 0\n        let attrs = 0\n        let cell = 0 // cell index\n        let lastChar = ' '\n        let frameLength = frameWidth * frameHeight\n        let screenLength = this.screen.window.width * this.screen.window.height\n\n        if (resized) {\n          this.screen.updateSize()\n          this.screen.blinkingCellCount = 0\n          this.screen.screen = new Array(screenLength).fill(' ')\n          this.screen.screenFG = new Array(screenLength).fill(' ')\n          this.screen.screenBG = new Array(screenLength).fill(' ')\n          this.screen.screenAttrs = new Array(screenLength).fill(0)\n        }\n\n        const MASK_LINE_ATTR = ATTR_UNDERLINE | ATTR_OVERLINE | ATTR_STRIKE\n        const MASK_BLINK = ATTR_BLINK\n\n        let pushCell = () => {\n          // Remove blink attribute if it wouldn't have any effect\n          let myAttrs = attrs\n          let hasFG = attrs & ATTR_FG\n          let hasBG = attrs & ATTR_BG\n          let cellFG = fg\n          let cellBG = bg\n\n          // use 0,0 if no fg/bg. this is to match back-end implementation\n          // and allow leaving out fg/bg setting for cells with none\n          if (!hasFG) cellFG = 0\n          if (!hasBG) cellBG = 0\n\n          if ((myAttrs & MASK_BLINK) !== 0 &&\n            ((lastChar === ' ' && ((myAttrs & MASK_LINE_ATTR) === 0)) || // no line styles\n              (fg === bg && hasFG && hasBG) // invisible text\n            )\n          ) {\n            myAttrs ^= MASK_BLINK\n          }\n          // update blinking cells counter if blink state changed\n          if ((this.screen.screenAttrs[cell] & MASK_BLINK) !== (myAttrs & MASK_BLINK)) {\n            if (myAttrs & MASK_BLINK) this.screen.blinkingCellCount++\n            else this.screen.blinkingCellCount--\n          }\n\n          let cellXInFrame = cell % frameWidth\n          let cellYInFrame = Math.floor(cell / frameWidth)\n          let index = (frameY + cellYInFrame) * this.screen.window.width + frameX + cellXInFrame\n\n          // 8 dark system colors turn bright when bold\n          if ((myAttrs & ATTR_BOLD) && !(myAttrs & ATTR_FAINT) && hasFG && cellFG < 8) {\n            cellFG += 8\n          }\n\n          this.screen.screen[index] = lastChar\n          this.screen.screenFG[index] = cellFG\n          this.screen.screenBG[index] = cellBG\n          this.screen.screenAttrs[index] = myAttrs\n        }\n\n        while (ci < strArray.length && cell < frameLength) {\n          let character = strArray[ci++]\n          let charCode = character.codePointAt(0)\n\n          let data, count\n          switch (charCode) {\n            case SEQ_REPEAT:\n              count = du(strArray[ci++])\n              for (let j = 0; j < count; j++) {\n                pushCell()\n                if (++cell > frameLength) break\n              }\n              break\n\n            case SEQ_SKIP:\n              cell += du(strArray[ci++])\n              break\n\n            case SEQ_SET_COLORS:\n              data = du(strArray[ci++])\n              fg = data & 0xFF\n              bg = (data >> 8) & 0xFF\n              break\n\n            case SEQ_SET_ATTRS:\n              data = du(strArray[ci++])\n              attrs = data & 0xFFFF\n              break\n\n            case SEQ_SET_ATTR_0:\n              attrs = 0\n              break\n\n            case SEQ_SET_FG:\n              data = du(strArray[ci++])\n              if (data & 0x10000) {\n                data &= 0xFFF\n                data |= (du(strArray[ci++]) & 0xFFF) << 12\n                data += 256\n              }\n              fg = data\n              break\n\n            case SEQ_SET_BG:\n              data = du(strArray[ci++])\n              if (data & 0x10000) {\n                data &= 0xFFF\n                data |= (du(strArray[ci++]) & 0xFFF) << 12\n                data += 256\n              }\n              bg = data\n              break\n\n            default:\n              if (charCode < 32) character = '\\ufffd'\n              lastChar = character\n              pushCell()\n              cell++\n          }\n        }\n\n        if (this.screen.window.debug) console.log(`Blinky cells: ${this.screen.blinkingCellCount}`)\n\n        this.screen.renderer.scheduleDraw('load', 16)\n        this.screen.conn.emit('load')\n\n      }\n\n      if ((topics & 0x3B) !== 0) this.hideLoadFailedMsg()\n    }\n  }\n\n  /**\n   * Loads a message from the server, and optionally a theme.\n   * @param {string} str - the message\n   */\n  load (str) {\n    const content = str.substr(1)\n\n    // This is a good place for debugging the message\n    // console.log(str)\n\n    switch (str[0]) {\n      case 'U':\n        this.loadUpdate(content)\n        break\n\n      case 'G':\n        this.screen.showNotification(content)\n        break\n\n      default:\n        console.warn(`Bad data message type; ignoring.\\n${JSON.stringify(str)}`)\n    }\n  }\n}\n\n\n\n// WEBPACK FOOTER //\n// ./js/term/screen_parser.js","const { themes, buildColorTable, SELECTION_FG, SELECTION_BG } = require('./themes')\n\n// Some non-bold Fraktur symbols are outside the contiguous block\nconst frakturExceptions = {\n  'C': '\\u212d',\n  'H': '\\u210c',\n  'I': '\\u2111',\n  'R': '\\u211c',\n  'Z': '\\u2128'\n}\n\n// TODO do not repeat - this is also defined in screen_parser ...\n/* eslint-disable no-multi-spaces */\nconst ATTR_FG        = (1 << 0)  // 1 if not using default background color (ignore cell bg) - color extension bit\nconst ATTR_BG        = (1 << 1)  // 1 if not using default foreground color (ignore cell fg) - color extension bit\nconst ATTR_BOLD      = (1 << 2)  // Bold font\nconst ATTR_UNDERLINE = (1 << 3)  // Underline decoration\nconst ATTR_INVERSE   = (1 << 4)  // Invert colors - this is useful so we can clear then with SGR manipulation commands\nconst ATTR_BLINK     = (1 << 5)  // Blinking\nconst ATTR_ITALIC    = (1 << 6)  // Italic font\nconst ATTR_STRIKE    = (1 << 7)  // Strike-through decoration\nconst ATTR_OVERLINE  = (1 << 8)  // Over-line decoration\nconst ATTR_FAINT     = (1 << 9)  // Faint foreground color (reduced alpha)\nconst ATTR_FRAKTUR   = (1 << 10) // Fraktur font (unicode substitution)\n/* eslint-enable no-multi-spaces */\n\nmodule.exports = class ScreenRenderer {\n  constructor (screen) {\n    this.screen = screen\n    this.ctx = screen.ctx\n\n    this._palette = null    // colors 0-15\n    this.defaultBgNum = 0\n    this.defaultFgNum = 7\n\n    // 256color lookup table\n    // should not be used to look up 0-15 (will return transparent)\n    this.colorTable256 = buildColorTable()\n\n    this.resetDrawn()\n\n    this.blinkStyleOn = false\n    this.blinkInterval = null\n    this.cursorBlinkOn = false\n    this.cursorBlinkInterval = null\n\n    // start blink timers\n    this.resetBlink()\n    this.resetCursorBlink()\n  }\n\n  resetDrawn () {\n    // used to determine if a cell should be redrawn; storing the current state\n    // as it is on screen\n    if (this.screen.window && this.screen.window.debug) {\n      console.log('Resetting drawn screen')\n    }\n    this.drawnScreen = []\n    this.drawnScreenFG = []\n    this.drawnScreenBG = []\n    this.drawnScreenAttrs = []\n    this.drawnCursor = [-1, -1, '']\n  }\n\n  /**\n   * The color palette. Should define 16 colors in an array.\n   * @type {string[]}\n   */\n  get palette () {\n    return this._palette || themes[0]\n  }\n\n  /** @type {string[]} */\n  set palette (palette) {\n    if (this._palette !== palette) {\n      this._palette = palette\n      this.resetDrawn()\n      this.scheduleDraw('palette')\n    }\n  }\n\n  loadTheme (i) {\n    if (i in themes) this.palette = themes[i]\n  }\n\n  setDefaultColors (fg, bg) {\n    if (fg !== this.defaultFgNum || bg !== this.defaultBgNum) {\n      this.resetDrawn()\n      this.defaultFgNum = fg\n      this.defaultBgNum = bg\n      this.scheduleDraw('default-colors')\n    }\n  }\n\n  /**\n   * Schedule a draw in the next millisecond\n   * @param {string} why - the reason why the draw occured (for debugging)\n   * @param {number} [aggregateTime] - time to wait for more scheduleDraw calls\n   *   to occur. 1 ms by default.\n   */\n  scheduleDraw (why, aggregateTime = 1) {\n    clearTimeout(this._scheduledDraw)\n    this._scheduledDraw = setTimeout(() => this.draw(why), aggregateTime)\n  }\n\n  /**\n   * Returns the specified color. If `i` is in the palette, it will return the\n   * palette color. If `i` is between 16 and 255, it will return the 256color\n   * value. If `i` is larger than 255, it will return an RGB color value. If `i`\n   * is -1 (foreground) or -2 (background), it will return the selection colors.\n   * @param {number} i - the color\n   * @returns {string} the CSS color\n   */\n  getColor (i) {\n    // return palette color if it exists\n    if (i < 16 && i in this.palette) return this.palette[i]\n\n    // -1 for selection foreground, -2 for selection background\n    if (i === -1) return SELECTION_FG\n    if (i === -2) return SELECTION_BG\n\n    // 256 color\n    if (i > 15 && i < 256) return this.colorTable256[i]\n\n    // true color, encoded as (hex) + 256 (such that #000 == 256)\n    if (i > 255) {\n      i -= 256\n      let red = (i >> 16) & 0xFF\n      let green = (i >> 8) & 0xFF\n      let blue = i & 0xFF\n      return `rgb(${red}, ${green}, ${blue})`\n    }\n\n    // return error color\n    return (Date.now() / 1000) % 2 === 0 ? '#f0f' : '#0f0'\n  }\n\n  /**\n   * Resets the cursor blink to on and restarts the timer\n   */\n  resetCursorBlink () {\n    this.cursorBlinkOn = true\n    clearInterval(this.cursorBlinkInterval)\n    this.cursorBlinkInterval = setInterval(() => {\n      this.cursorBlinkOn = this.screen.cursor.blinking\n        ? !this.cursorBlinkOn\n        : true\n      if (this.screen.cursor.blinking) this.scheduleDraw('cursor-blink')\n    }, 500)\n  }\n\n  /**\n   * Resets the blink style to on and restarts the timer\n   */\n  resetBlink () {\n    this.blinkStyleOn = true\n    clearInterval(this.blinkInterval)\n    let intervals = 0\n    this.blinkInterval = setInterval(() => {\n      if (this.screen.blinkingCellCount <= 0) return\n\n      intervals++\n      if (intervals >= 4 && this.blinkStyleOn) {\n        this.blinkStyleOn = false\n        intervals = 0\n        this.scheduleDraw('blink-style')\n      } else if (intervals >= 1 && !this.blinkStyleOn) {\n        this.blinkStyleOn = true\n        intervals = 0\n        this.scheduleDraw('blink-style')\n      }\n    }, 200)\n  }\n\n  /**\n   * Draws a cell's background with the given parameters.\n   * @param {Object} options\n   * @param {number} options.x - x in cells\n   * @param {number} options.y - y in cells\n   * @param {number} options.cellWidth - cell width in pixels\n   * @param {number} options.cellHeight - cell height in pixels\n   * @param {number} options.bg - the background color\n   */\n  drawBackground ({ x, y, cellWidth, cellHeight, bg }) {\n    const ctx = this.ctx\n    const { width, height } = this.screen.window\n    const padding = Math.round(this.screen._padding)\n    ctx.fillStyle = this.getColor(bg)\n    let screenX = x * cellWidth + padding\n    let screenY = y * cellHeight + padding\n    let isBorderCell = x === 0 || y === 0 || x === width - 1 || y === height - 1\n    if (isBorderCell) {\n      let left = screenX\n      let top = screenY\n      let right = screenX + cellWidth\n      let bottom = screenY + cellHeight\n      if (x === 0) left -= padding\n      else if (x === width - 1) right += padding\n      if (y === 0) top -= padding\n      else if (y === height - 1) bottom += padding\n      ctx.clearRect(left, top, right - left, bottom - top)\n      ctx.fillRect(left, top, right - left, bottom - top)\n    } else {\n      ctx.clearRect(screenX, screenY, cellWidth, cellHeight)\n      ctx.fillRect(screenX, screenY, cellWidth, cellHeight)\n    }\n  }\n\n  /**\n   * Draws a cell's character with the given parameters. Won't do anything if\n   * text is an empty string.\n   * @param {Object} options\n   * @param {number} options.x - x in cells\n   * @param {number} options.y - y in cells\n   * @param {Object} options.charSize - the character size, an object with\n   *   `width` and `height` in pixels\n   * @param {number} options.cellWidth - cell width in pixels\n   * @param {number} options.cellHeight - cell height in pixels\n   * @param {string} options.text - the cell content\n   * @param {number} options.fg - the foreground color\n   * @param {number} options.attrs - the cell's attributes\n   */\n  drawCharacter ({ x, y, charSize, cellWidth, cellHeight, text, fg, attrs }) {\n    if (!text) return\n\n    const ctx = this.ctx\n    const padding = Math.round(this.screen._padding)\n\n    let underline = false\n    let strike = false\n    let overline = false\n    if (attrs & ATTR_FAINT) ctx.globalAlpha = 0.5\n    if (attrs & ATTR_UNDERLINE) underline = true\n    if (attrs & ATTR_FRAKTUR) text = ScreenRenderer.alphaToFraktur(text)\n    if (attrs & ATTR_STRIKE) strike = true\n    if (attrs & ATTR_OVERLINE) overline = true\n\n    ctx.fillStyle = this.getColor(fg)\n\n    let screenX = x * cellWidth + padding\n    let screenY = y * cellHeight + padding\n\n    let codePoint = text.codePointAt(0)\n    if (codePoint >= 0x2580 && codePoint <= 0x259F) {\n      // block elements\n      ctx.beginPath()\n      const left = screenX\n      const top = screenY\n      const cw = cellWidth\n      const ch = cellHeight\n      const c2w = cellWidth / 2\n      const c2h = cellHeight / 2\n\n      // http://www.fileformat.info/info/unicode/block/block_elements/utf8test.htm\n      //         0x00  0x01  0x02  0x03  0x04  0x05  0x06  0x07  0x08  0x09  0x0A  0x0B  0x0C  0x0D  0x0E  0x0F\n      // 0x2580     ▀     ▁     ▂     ▃     ▄     ▅     ▆     ▇     █     ▉     ▊     ▋     ▌     ▍     ▎     ▏\n      // 0x2590     ▐     ░     ▒     ▓     ▔     ▕     ▖     ▗     ▘     ▙     ▚     ▛     ▜     ▝     ▞     ▟\n\n      if (codePoint === 0x2580) {\n        // upper half block >▀<\n        ctx.rect(left, top, cw, c2h)\n      } else if (codePoint <= 0x2588) {\n        // lower n eighth block (increasing) >▁< to >█<\n        let offset = (1 - (codePoint - 0x2580) / 8) * ch\n        ctx.rect(left, top + offset, cw, ch - offset)\n      } else if (codePoint <= 0x258F) {\n        // left n eighth block (decreasing) >▉< to >▏<\n        let offset = (codePoint - 0x2588) / 8 * cw\n        ctx.rect(left, top, cw - offset, ch)\n      } else if (codePoint === 0x2590) {\n        // right half block >▐<\n        ctx.rect(left + c2w, top, c2w, ch)\n      } else if (codePoint <= 0x2593) {\n        // shading >░< >▒< >▓<\n\n        // dot spacing by dividing cell size by a constant. This could be\n        // reworked to always return a whole number, but that would require\n        // prime factorization, and doing that without a loop would let you\n        // take over the world, which is not within the scope of this project.\n        let dotSpacingX, dotSpacingY, dotSize\n        if (codePoint === 0x2591) {\n          dotSpacingX = cw / 4\n          dotSpacingY = ch / 10\n          dotSize = 1\n        } else if (codePoint === 0x2592) {\n          dotSpacingX = cw / 6\n          dotSpacingY = cw / 10\n          dotSize = 1\n        } else if (codePoint === 0x2593) {\n          dotSpacingX = cw / 4\n          dotSpacingY = cw / 7\n          dotSize = 2\n        }\n\n        let alignRight = false\n        for (let dy = 0; dy < ch; dy += dotSpacingY) {\n          for (let dx = 0; dx < cw; dx += dotSpacingX) {\n            // prevent overflow\n            let dotSizeY = Math.min(dotSize, ch - dy)\n            ctx.rect(left + (alignRight ? cw - dx - dotSize : dx), top + dy, dotSize, dotSizeY)\n          }\n          alignRight = !alignRight\n        }\n      } else if (codePoint === 0x2594) {\n        // upper one eighth block >▔<\n        ctx.rect(left, top, cw, ch / 8)\n      } else if (codePoint === 0x2595) {\n        // right one eighth block >▕<\n        ctx.rect(left + (7 / 8) * cw, top, cw / 8, ch)\n      } else if (codePoint === 0x2596) {\n        // left bottom quadrant >▖<\n        ctx.rect(left, top + c2h, c2w, c2h)\n      } else if (codePoint === 0x2597) {\n        // right bottom quadrant >▗<\n        ctx.rect(left + c2w, top + c2h, c2w, c2h)\n      } else if (codePoint === 0x2598) {\n        // left top quadrant >▘<\n        ctx.rect(left, top, c2w, c2h)\n      } else if (codePoint === 0x2599) {\n        // left chair >▙<\n        ctx.rect(left, top, c2w, ch)\n        ctx.rect(left + c2w, top + c2h, c2w, c2h)\n      } else if (codePoint === 0x259A) {\n        // quadrants lt rb >▚<\n        ctx.rect(left, top, c2w, c2h)\n        ctx.rect(left + c2w, top + c2h, c2w, c2h)\n      } else if (codePoint === 0x259B) {\n        // left chair upside down >▛<\n        ctx.rect(left, top, c2w, ch)\n        ctx.rect(left + c2w, top, c2w, c2h)\n      } else if (codePoint === 0x259C) {\n        // right chair upside down >▜<\n        ctx.rect(left, top, cw, c2h)\n        ctx.rect(left + c2w, top + c2h, c2w, c2h)\n      } else if (codePoint === 0x259D) {\n        // right top quadrant >▝<\n        ctx.rect(left + c2w, top, c2w, c2h)\n      } else if (codePoint === 0x259E) {\n        // quadrants lb rt >▞<\n        ctx.rect(left, top + c2h, c2w, c2h)\n        ctx.rect(left + c2w, top, c2w, c2h)\n      } else if (codePoint === 0x259F) {\n        // right chair upside down >▟<\n        ctx.rect(left, top + c2h, c2w, c2h)\n        ctx.rect(left + c2w, top, c2w, ch)\n      }\n\n      ctx.fill()\n    } else if (codePoint >= 0xE0B0 && codePoint <= 0xE0B3) {\n      // powerline symbols, except branch, line, and lock. Basically, just the triangles\n      ctx.beginPath()\n\n      if (codePoint === 0xE0B0 || codePoint === 0xE0B1) {\n        // right-pointing triangle\n        ctx.moveTo(screenX, screenY)\n        ctx.lineTo(screenX + cellWidth, screenY + cellHeight / 2)\n        ctx.lineTo(screenX, screenY + cellHeight)\n      } else if (codePoint === 0xE0B2 || codePoint === 0xE0B3) {\n        // left-pointing triangle\n        ctx.moveTo(screenX + cellWidth, screenY)\n        ctx.lineTo(screenX, screenY + cellHeight / 2)\n        ctx.lineTo(screenX + cellWidth, screenY + cellHeight)\n      }\n\n      if (codePoint % 2 === 0) {\n        // triangle\n        ctx.fill()\n      } else {\n        // chevron\n        ctx.strokeStyle = ctx.fillStyle\n        ctx.stroke()\n      }\n    } else {\n      // Draw other characters using the text renderer\n      ctx.fillText(text, screenX + 0.5 * cellWidth, screenY + 0.5 * cellHeight)\n    }\n\n    // -- line drawing - a reference for a possible future rect/line implementation ---\n    // http://www.fileformat.info/info/unicode/block/box_drawing/utf8test.htm\n    //         0x00  0x01  0x02  0x03  0x04  0x05  0x06  0x07  0x08  0x09  0x0A  0x0B  0x0C  0x0D  0x0E  0x0F\n    // 0x2500     ─     ━     │     ┃     ┄     ┅     ┆     ┇     ┈     ┉     ┊     ┋     ┌     ┍     ┎     ┏\n    // 0x2510     ┐     ┑     ┒     ┓     └     ┕     ┖     ┗     ┘     ┙     ┚     ┛     ├     ┝     ┞     ┟\n    // 0x2520     ┠     ┡     ┢     ┣     ┤     ┥     ┦     ┧     ┨     ┩     ┪     ┫     ┬     ┭     ┮     ┯\n    // 0x2530     ┰     ┱     ┲     ┳     ┴     ┵     ┶     ┷     ┸     ┹     ┺     ┻     ┼     ┽     ┾     ┿\n    // 0x2540     ╀     ╁     ╂     ╃     ╄     ╅     ╆     ╇     ╈     ╉     ╊     ╋     ╌     ╍     ╎     ╏\n    // 0x2550     ═     ║     ╒     ╓     ╔     ╕     ╖     ╗     ╘     ╙     ╚     ╛     ╜     ╝     ╞     ╟\n    // 0x2560     ╠     ╡     ╢     ╣     ╤     ╥     ╦     ╧     ╨     ╩     ╪     ╫     ╬     ╭     ╮     ╯\n    // 0x2570     ╰     ╱     ╲     ╳     ╴     ╵     ╶     ╷     ╸     ╹     ╺     ╻     ╼     ╽     ╾     ╿\n\n    if (underline || strike || overline) {\n      ctx.strokeStyle = this.getColor(fg)\n      ctx.lineWidth = 1\n      ctx.lineCap = 'round'\n      ctx.beginPath()\n\n      if (underline) {\n        let lineY = Math.round(screenY + charSize.height) + 0.5\n        ctx.moveTo(screenX, lineY)\n        ctx.lineTo(screenX + cellWidth, lineY)\n      }\n\n      if (strike) {\n        let lineY = Math.round(screenY + 0.5 * cellHeight) + 0.5\n        ctx.moveTo(screenX, lineY)\n        ctx.lineTo(screenX + cellWidth, lineY)\n      }\n\n      if (overline) {\n        let lineY = Math.round(screenY) + 0.5\n        ctx.moveTo(screenX, lineY)\n        ctx.lineTo(screenX + cellWidth, lineY)\n      }\n\n      ctx.stroke()\n    }\n\n    ctx.globalAlpha = 1\n  }\n\n  /**\n   * Returns all adjacent cell indices given a radius.\n   * @param {number} cell - the center cell index\n   * @param {number} [radius] - the radius. 1 by default\n   * @returns {number[]} an array of cell indices\n   */\n  getAdjacentCells (cell, radius = 1) {\n    const { width, height } = this.screen.window\n    const screenLength = width * height\n\n    let cells = []\n\n    for (let x = -radius; x <= radius; x++) {\n      for (let y = -radius; y <= radius; y++) {\n        if (x === 0 && y === 0) continue\n        cells.push(cell + x + y * width)\n      }\n    }\n\n    return cells.filter(cell => cell >= 0 && cell < screenLength)\n  }\n\n  /**\n   * Updates the screen.\n   * @param {string} why - the draw reason (for debugging)\n   */\n  draw (why) {\n    const ctx = this.ctx\n    const {\n      width,\n      height,\n      devicePixelRatio,\n      statusScreen\n    } = this.screen.window\n\n    if (statusScreen) {\n      // draw status screen instead\n      this.drawStatus(statusScreen)\n      this.startDrawLoop()\n      return\n    } else this.stopDrawLoop()\n\n    const charSize = this.screen.getCharSize()\n    const { width: cellWidth, height: cellHeight } = this.screen.getCellSize()\n    const screenLength = width * height\n\n    ctx.setTransform(devicePixelRatio, 0, 0, devicePixelRatio, 0, 0)\n\n    if (this.screen.window.debug && this.screen._debug) this.screen._debug.drawStart(why)\n\n    ctx.font = this.screen.getFont()\n    ctx.textAlign = 'center'\n    ctx.textBaseline = 'middle'\n\n    // bits in the attr value that affect the font\n    const FONT_MASK = ATTR_BOLD | ATTR_ITALIC\n\n    // Map of (attrs & FONT_MASK) -> Array of cell indices\n    let fontGroups = new Map()\n\n    // Map of (cell index) -> boolean, whether or not a cell has updated\n    let updateMap = new Map()\n\n    for (let cell = 0; cell < screenLength; cell++) {\n      let x = cell % width\n      let y = Math.floor(cell / width)\n      let isCursor = this.cursorBlinkOn &&\n        this.screen.cursor.x === x &&\n        this.screen.cursor.y === y &&\n        this.screen.cursor.visible\n\n      let wasCursor = x === this.drawnCursor[0] && y === this.drawnCursor[1]\n\n      let inSelection = this.screen.isInSelection(x, y)\n\n      let text = this.screen.screen[cell]\n      let fg = this.screen.screenFG[cell] | 0\n      let bg = this.screen.screenBG[cell] | 0\n      let attrs = this.screen.screenAttrs[cell] | 0\n\n      if (!(attrs & ATTR_FG)) fg = this.defaultFgNum\n      if (!(attrs & ATTR_BG)) bg = this.defaultBgNum\n\n      if (attrs & ATTR_INVERSE) [fg, bg] = [bg, fg] // swap - reversed character colors\n      if (this.screen.reverseVideo) [fg, bg] = [bg, fg] // swap - reversed all screen\n\n      if (attrs & ATTR_BLINK && !this.blinkStyleOn) {\n        // blinking is enabled and blink style is off\n        // set text to nothing so drawCharacter doesn't draw anything\n        text = ''\n      }\n\n      if (inSelection) {\n        fg = -1\n        bg = -2\n      }\n\n      let didUpdate = text !== this.drawnScreen[cell] || // text updated\n        fg !== this.drawnScreenFG[cell] || // foreground updated, and this cell has text\n        bg !== this.drawnScreenBG[cell] || // background updated\n        attrs !== this.drawnScreenAttrs[cell] || // attributes updated\n        isCursor !== wasCursor || // cursor blink/position updated\n        (isCursor && this.screen.cursor.style !== this.drawnCursor[2]) || // cursor style updated\n        (isCursor && this.screen.cursor.hanging !== this.drawnCursor[3]) // cursor hanging updated\n\n      let font = attrs & FONT_MASK\n      if (!fontGroups.has(font)) fontGroups.set(font, [])\n\n      fontGroups.get(font).push({ cell, x, y, text, fg, bg, attrs, isCursor, inSelection })\n      updateMap.set(cell, didUpdate)\n    }\n\n    // Map of (cell index) -> boolean, whether or not a cell should be redrawn\n    const redrawMap = new Map()\n\n    let isTextWide = text =>\n      text !== ' ' && ctx.measureText(text).width >= (cellWidth + 0.05)\n\n    // decide for each cell if it should be redrawn\n    let updateRedrawMapAt = cell => {\n      let shouldUpdate = updateMap.get(cell) || redrawMap.get(cell) || false\n\n      // TODO: fonts (necessary?)\n      let text = this.screen.screen[cell]\n      let isWideCell = isTextWide(text)\n      let checkRadius = isWideCell ? 2 : 1\n\n      if (!shouldUpdate) {\n        // check adjacent cells\n        let adjacentDidUpdate = false\n\n        for (let adjacentCell of this.getAdjacentCells(cell, checkRadius)) {\n          // update this cell if:\n          // - the adjacent cell updated (For now, this'll always be true because characters can be slightly larger than they say they are)\n          // - the adjacent cell updated and this cell or the adjacent cell is wide\n          if (updateMap.get(adjacentCell) && (this.screen.window.graphics < 2 || isWideCell || isTextWide(this.screen.screen[adjacentCell]))) {\n            adjacentDidUpdate = true\n            break\n          }\n        }\n\n        if (adjacentDidUpdate) shouldUpdate = true\n      }\n\n      redrawMap.set(cell, shouldUpdate)\n    }\n\n    for (let cell of updateMap.keys()) updateRedrawMapAt(cell)\n\n    // mask to redrawing regions only\n    if (this.screen.window.graphics >= 1) {\n      let debug = this.screen.window.debug && this.screen._debug\n      let padding = Math.round(this.screen._padding)\n      ctx.save()\n      ctx.beginPath()\n      for (let y = 0; y < height; y++) {\n        let regionStart = null\n        for (let x = 0; x < width; x++) {\n          let cell = y * width + x\n          let redrawing = redrawMap.get(cell)\n          if (redrawing && regionStart === null) regionStart = x\n          if (!redrawing && regionStart !== null) {\n            ctx.rect(padding + regionStart * cellWidth, padding + y * cellHeight, (x - regionStart) * cellWidth, cellHeight)\n            if (debug) this.screen._debug.clipRect(regionStart * cellWidth, y * cellHeight, (x - regionStart) * cellWidth, cellHeight)\n            regionStart = null\n          }\n        }\n        if (regionStart !== null) {\n          ctx.rect(padding + regionStart * cellWidth, padding + y * cellHeight, (width - regionStart) * cellWidth, cellHeight)\n          if (debug) this.screen._debug.clipRect(regionStart * cellWidth, y * cellHeight, (width - regionStart) * cellWidth, cellHeight)\n        }\n      }\n      ctx.clip()\n    }\n\n    // pass 1: backgrounds\n    for (let font of fontGroups.keys()) {\n      for (let data of fontGroups.get(font)) {\n        let { cell, x, y, text, bg } = data\n\n        if (redrawMap.get(cell)) {\n          this.drawBackground({ x, y, cellWidth, cellHeight, bg })\n\n          if (this.screen.window.debug && this.screen._debug) {\n            // set cell flags\n            let flags = (+redrawMap.get(cell))\n            flags |= (+updateMap.get(cell)) << 1\n            flags |= (+isTextWide(text)) << 2\n            this.screen._debug.setCell(cell, flags)\n          }\n        }\n      }\n    }\n\n    // reset drawn cursor\n    this.drawnCursor = [-1, -1, -1]\n\n    // pass 2: characters\n    for (let font of fontGroups.keys()) {\n      // set font once because in Firefox, this is a really slow action for some\n      // reason\n      let modifiers = {}\n      if (font & ATTR_BOLD) modifiers.weight = 'bold'\n      if (font & ATTR_ITALIC) modifiers.style = 'italic'\n      ctx.font = this.screen.getFont(modifiers)\n\n      for (let data of fontGroups.get(font)) {\n        let { cell, x, y, text, fg, bg, attrs, isCursor, inSelection } = data\n\n        if (redrawMap.get(cell)) {\n          this.drawCharacter({\n            x, y, charSize, cellWidth, cellHeight, text, fg, attrs\n          })\n\n          this.drawnScreen[cell] = text\n          this.drawnScreenFG[cell] = fg\n          this.drawnScreenBG[cell] = bg\n          this.drawnScreenAttrs[cell] = attrs\n\n          if (isCursor) this.drawnCursor = [x, y, this.screen.cursor.style, this.screen.cursor.hanging]\n\n          // draw cursor\n          if (isCursor && !inSelection) {\n            ctx.save()\n            ctx.beginPath()\n\n            let cursorX = x\n            let cursorY = y\n\n            if (this.screen.cursor.hanging) {\n              // draw hanging cursor in the margin\n              cursorX += 1\n            }\n\n            let screenX = cursorX * cellWidth + this.screen._padding\n            let screenY = cursorY * cellHeight + this.screen._padding\n            if (this.screen.cursor.style === 'block') {\n              // block\n              ctx.rect(screenX, screenY, cellWidth, cellHeight)\n            } else if (this.screen.cursor.style === 'bar') {\n              // vertical bar\n              let barWidth = 2\n              ctx.rect(screenX, screenY, barWidth, cellHeight)\n            } else if (this.screen.cursor.style === 'line') {\n              // underline\n              let lineHeight = 2\n              ctx.rect(screenX, screenY + charSize.height, cellWidth, lineHeight)\n            }\n            ctx.clip()\n\n            // swap foreground/background\n            ;[fg, bg] = [bg, fg]\n\n            // HACK: ensure cursor is visible\n            if (fg === bg) bg = fg === 0 ? 7 : 0\n\n            this.drawBackground({ x: cursorX, y: cursorY, cellWidth, cellHeight, bg })\n            this.drawCharacter({\n              x: cursorX, y: cursorY, charSize, cellWidth, cellHeight, text, fg, attrs\n            })\n            ctx.restore()\n          }\n        }\n      }\n    }\n\n    if (this.screen.window.graphics >= 1) ctx.restore()\n\n    if (this.screen.window.debug && this.screen._debug) this.screen._debug.drawEnd()\n\n    this.screen.emit('draw', why)\n  }\n\n  drawStatus (statusScreen) {\n    const ctx = this.ctx\n    const {\n      fontFamily,\n      width,\n      height,\n      devicePixelRatio\n    } = this.screen.window\n\n    // reset drawnScreen to force redraw when statusScreen is disabled\n    this.drawnScreen = []\n\n    const cellSize = this.screen.getCellSize()\n    const screenWidth = width * cellSize.width + 2 * this.screen._padding\n    const screenHeight = height * cellSize.height + 2 * this.screen._padding\n\n    ctx.setTransform(devicePixelRatio, 0, 0, devicePixelRatio, 0, 0)\n    ctx.fillStyle = this.getColor(this.defaultBgNum)\n    ctx.fillRect(0, 0, screenWidth, screenHeight)\n\n    ctx.font = `24px ${fontFamily}`\n    ctx.fillStyle = this.getColor(this.defaultFgNum)\n    ctx.textAlign = 'center'\n    ctx.textBaseline = 'middle'\n    ctx.fillText(statusScreen.title || '', screenWidth / 2, screenHeight / 2 - 50)\n\n    if (statusScreen.loading) {\n      // show loading spinner\n      ctx.save()\n      ctx.translate(screenWidth / 2, screenHeight / 2 + 20)\n\n      ctx.strokeStyle = this.getColor(this.defaultFgNum)\n      ctx.lineWidth = 5\n      ctx.lineCap = 'round'\n\n      let t = Date.now() / 1000\n\n      for (let i = 0; i < 12; i++) {\n        ctx.rotate(Math.PI / 6)\n        let offset = ((t * 12) - i) % 12\n        ctx.globalAlpha = Math.max(0.2, 1 - offset / 3)\n        ctx.beginPath()\n        ctx.moveTo(0, 15)\n        ctx.lineTo(0, 30)\n        ctx.stroke()\n      }\n\n      ctx.restore()\n    }\n  }\n\n  startDrawLoop () {\n    if (this._drawTimerThread) return\n    let threadID = Math.random().toString(36)\n    this._drawTimerThread = threadID\n    this.drawTimerLoop(threadID)\n  }\n\n  stopDrawLoop () {\n    this._drawTimerThread = null\n  }\n\n  drawTimerLoop (threadID) {\n    if (!threadID || threadID !== this._drawTimerThread) return\n    window.requestAnimationFrame(() => this.drawTimerLoop(threadID))\n    this.draw('draw-loop')\n  }\n\n  /**\n   * Converts an alphabetic character to its fraktur variant.\n   * @param {string} character - the character\n   * @returns {string} the converted character\n   */\n  static alphaToFraktur (character) {\n    if (character >= 'a' && character <= 'z') {\n      character = String.fromCodePoint(0x1d51e - 0x61 + character.charCodeAt(0))\n    } else if (character >= 'A' && character <= 'Z') {\n      character = frakturExceptions[character] || String.fromCodePoint(0x1d504 - 0x41 + character.charCodeAt(0))\n    }\n    return character\n  }\n}\n\n\n\n// WEBPACK FOOTER //\n// ./js/term/screen_renderer.js","const EventEmitter = require('events')\nconst $ = require('../lib/chibi')\nlet demo\ntry { demo = require('./demo') } catch (err) {}\n\nconst RECONN_DELAY = 2000\nconst HEARTBEAT_TIME = 3000\n\n/** Handle connections */\nmodule.exports = class TermConnection extends EventEmitter {\n  constructor (screen) {\n    super()\n\n    this.screen = screen\n    this.ws = null\n    this.heartbeatTimeout = null\n    this.pingInterval = null\n    this.xoff = false\n    this.autoXoffTimeout = null\n    this.reconnTimeout = null\n    this.forceClosing = false\n\n    try {\n      this.blobReader = new FileReader()\n      this.blobReader.onload = (evt) => {\n        this.onDecodedWSMessage(this.blobReader.result)\n      }\n      this.blobReader.onerror = (evt) => {\n        console.error(evt)\n      }\n    } catch (e) {\n      this.blobReader = null\n    }\n\n    this.pageShown = false\n\n    this.disconnectTimeout = null\n\n    document.addEventListener('visibilitychange', () => {\n      if (document.hidden === true) {\n        console.info('Window lost focus, freeing socket')\n        // Delayed, avoid disconnecting if the background time is short\n        this.disconnectTimeout = setTimeout(() => {\n          this.closeSocket()\n          clearTimeout(this.heartbeatTimeout)\n        }, 1000)\n      } else {\n        clearTimeout(this.disconnectTimeout)\n        console.info('Window got focus, re-connecting')\n        this.init()\n      }\n    }, false)\n  }\n\n  onWSOpen (evt) {\n    console.log('CONNECTED')\n    this.heartbeat()\n    this.send('i')\n    this.forceClosing = false\n\n    this.emit('connect')\n  }\n\n  onWSClose (evt) {\n    if (this.forceClosing) {\n      this.forceClosing = false\n      return\n    }\n    console.warn('SOCKET CLOSED, code ' + evt.code + '. Reconnecting...')\n    if (evt.code < 1000) {\n      console.error('Bad code from socket!')\n      // this sometimes happens for unknown reasons, code < 1000 is invalid\n      // location.reload()\n    }\n\n    clearTimeout(this.reconnTimeout)\n    this.reconnTimeout = setTimeout(() => this.init(), RECONN_DELAY)\n\n    this.emit('disconnect', evt.code)\n  }\n\n  onDecodedWSMessage (str) {\n    switch (str.charAt(0)) {\n      case '.':\n        console.log(str)\n        // heartbeat, no-op message\n        break\n\n      case '-':\n        // console.log('xoff');\n        this.xoff = true\n        this.autoXoffTimeout = setTimeout(() => {\n          this.xoff = false\n        }, 250)\n        break\n\n      case '+':\n        // console.log('xon');\n        this.xoff = false\n        clearTimeout(this.autoXoffTimeout)\n        break\n\n      default:\n        this.screen.load(str)\n        if (!this.pageShown) {\n          window.showPage()\n          this.pageShown = true\n        }\n        break\n    }\n    this.heartbeat()\n  }\n\n  onWSMessage (evt) {\n    if (typeof evt.data === 'string') this.onDecodedWSMessage(evt.data)\n    else {\n      if (!this.blobReader) {\n        console.error('No FileReader!')\n        return\n      }\n\n      if (this.blobReader.readyState !== 1) {\n        this.blobReader.readAsText(evt.data)\n      } else {\n        setTimeout(() => {\n          this.onWSMessage(evt)\n        }, 1)\n      }\n    }\n  }\n\n  canSend () {\n    return !this.xoff\n  }\n\n  send (message) {\n    if (window._demo) {\n      if (typeof window.demoInterface !== 'undefined') {\n        demo.input(message)\n      } else {\n        console.log(`TX: ${JSON.stringify(message)}`)\n      }\n      return true // Simulate success\n    }\n    if (this.xoff) {\n      // TODO queue\n      console.log(\"Can't send, flood control.\")\n      return false\n    }\n\n    if (!this.ws) return false // for dry testing\n    if (this.ws.readyState !== 1) {\n      console.error('Socket not ready')\n      return false\n    }\n    if (typeof message !== 'string') {\n      message = JSON.stringify(message)\n    }\n    this.ws.send(message)\n    return true\n  }\n\n  /** Safely close the socket */\n  closeSocket () {\n    if (this.ws) {\n      this.forceClosing = true\n      if (this.ws.readyState === 1) this.ws.close()\n      this.ws = null\n    }\n  }\n\n  init () {\n    if (window._demo) {\n      if (typeof window.demoInterface === 'undefined') {\n        window.alert('Demoing non-demo build!') // this will catch mistakes when deploying to the website\n      } else {\n        demo.init(this.screen)\n      }\n      return\n    }\n\n    clearTimeout(this.reconnTimeout)\n    clearTimeout(this.heartbeatTimeout)\n\n    this.closeSocket()\n\n    this.ws = new window.WebSocket('ws://' + window._root + '/term/update.ws')\n    this.ws.addEventListener('open', (...args) => this.onWSOpen(...args))\n    this.ws.addEventListener('close', (...args) => this.onWSClose(...args))\n    this.ws.addEventListener('message', (...args) => this.onWSMessage(...args))\n    console.log('Opening socket.')\n    this.heartbeat()\n\n    this.emit('open')\n  }\n\n  heartbeat () {\n    clearTimeout(this.heartbeatTimeout)\n    this.heartbeatTimeout = setTimeout(() => this.onHeartbeatFail(), HEARTBEAT_TIME)\n  }\n\n  sendPing () {\n    console.log('> ping')\n    this.emit('ping')\n    $.get('http://' + window._root + '/api/v1/ping', (resp, status) => {\n      if (status === 200) {\n        clearInterval(this.pingInterval)\n        console.info('Server ready, opening socket…')\n        this.emit('ping-success')\n        this.init()\n        // location.reload()\n      } else this.emit('ping-fail', status)\n    }, {\n      timeout: 100,\n      loader: false // we have loader on-screen\n    })\n  }\n\n  onHeartbeatFail () {\n    this.closeSocket()\n    this.emit('silence')\n    console.error('Heartbeat lost, probing server...')\n    clearInterval(this.pingInterval)\n    this.pingInterval = setInterval(() => { this.sendPing() }, 1000)\n\n    // first ping, if this gets through, it'll will reduce delay\n    setTimeout(() => { this.sendPing() }, 200)\n  }\n}\n\n\n\n// WEBPACK FOOTER //\n// ./js/term/connection.js","const $ = require('../lib/chibi')\nconst { encode2B } = require('../utils')\n\n/**\n * User input\n *\n * --- Rx messages: ---\n * S - screen content (binary encoding of the entire screen with simple compression)\n * T - text labels - Title and buttons, \\0x01-separated\n * B - beep\n * . - heartbeat\n *\n * --- Tx messages ---\n * s - string\n * b - action button\n * p - mb press\n * r - mb release\n * m - mouse move\n */\nmodule.exports = function (conn, screen) {\n  // handle for input object\n  let input\n\n  const KEY_NAMES = {\n    0x03: 'Cancel',\n    0x06: 'Help',\n    0x08: 'Backspace',\n    0x09: 'Tab',\n    0x0C: 'Clear',\n    0x0D: 'Enter',\n    0x10: 'Shift',\n    0x11: 'Control',\n    0x12: 'Alt',\n    0x13: 'Pause',\n    0x14: 'CapsLock',\n    0x1B: 'Escape',\n    0x20: ' ',\n    0x21: 'PageUp',\n    0x22: 'PageDown',\n    0x23: 'End',\n    0x24: 'Home',\n    0x25: 'ArrowLeft',\n    0x26: 'ArrowUp',\n    0x27: 'ArrowRight',\n    0x28: 'ArrowDown',\n    0x29: 'Select',\n    0x2A: 'Print',\n    0x2B: 'Execute',\n    0x2C: 'PrintScreen',\n    0x2D: 'Insert',\n    0x2E: 'Delete',\n    0x3A: ':',\n    0x3B: ';',\n    0x3C: '<',\n    0x3D: '=',\n    0x3E: '>',\n    0x3F: '?',\n    0x40: '@',\n    0x5B: 'Meta',\n    0x5C: 'Meta',\n    0x5D: 'ContextMenu',\n    0x6A: 'Numpad*',\n    0x6B: 'Numpad+',\n    0x6D: 'Numpad-',\n    0x6E: 'Numpad.',\n    0x6F: 'Numpad/',\n    0x90: 'NumLock',\n    0x91: 'ScrollLock',\n    0xA0: '^',\n    0xA1: '!',\n    0xA2: '\"',\n    0xA3: '#',\n    0xA4: '$',\n    0xA5: '%',\n    0xA6: '&',\n    0xA7: '_',\n    0xA8: '(',\n    0xA9: ')',\n    0xAA: '*',\n    0xAB: '+',\n    0xAC: '|',\n    0xAD: '-',\n    0xAE: '{',\n    0xAF: '}',\n    0xB0: '~',\n    0xBA: ';',\n    0xBB: '=',\n    0xBC: 'Numpad,',\n    0xBD: '-',\n    0xBE: 'Numpad,',\n    0xC0: '`',\n    0xC2: 'Numpad,',\n    0xDB: '[',\n    0xDC: '\\\\',\n    0xDD: ']',\n    0xDE: \"'\",\n    0xE0: 'Meta'\n  }\n  // numbers 0-9\n  for (let i = 0x30; i <= 0x39; i++) KEY_NAMES[i] = String.fromCharCode(i)\n  // characters A-Z\n  for (let i = 0x41; i <= 0x5A; i++) KEY_NAMES[i] = String.fromCharCode(i)\n  // function F1-F20\n  for (let i = 0x70; i <= 0x83; i++) KEY_NAMES[i] = `F${i - 0x70 + 1}`\n  // numpad 0-9\n  for (let i = 0x60; i <= 0x69; i++) KEY_NAMES[i] = `Numpad${i - 0x60}`\n\n  let cfg = {\n    np_alt: false,    // Application Numpad Mode\n    cu_alt: false,    // Application Cursors Mode\n    fn_alt: false,    // SS3 function keys mode\n    mt_click: false,  // Mouse click tracking\n    mt_move: false,   // Mouse move tracking\n    no_keys: false,   // Suppress any key / clipboard event intercepting\n    crlf_mode: false, // Enter sends CR LF\n    all_fn: false     // Capture also F5, F11 and F12\n  }\n\n  /** Fn alt choice for key message */\n  const fa = (alt, normal) => cfg.fn_alt ? alt : normal\n\n  /** Cursor alt choice for key message */\n  const ca = (alt, normal) => cfg.cu_alt ? alt : normal\n\n  /** Numpad alt choice for key message */\n  const na = (alt, normal) => cfg.np_alt ? alt : normal\n\n  const keymap = {\n    /* eslint-disable key-spacing */\n    'Backspace':     '\\x08',\n    'Tab':           '\\x09',\n    'Enter':         () => cfg.crlf_mode ? '\\x0d\\x0a' : '\\x0d',\n    'Control+Enter': '\\x0a',\n    'Escape':        '\\x1b',\n    'ArrowUp':       () => ca('\\x1bOA', '\\x1b[A'),\n    'ArrowDown':     () => ca('\\x1bOB', '\\x1b[B'),\n    'ArrowRight':    () => ca('\\x1bOC', '\\x1b[C'),\n    'ArrowLeft':     () => ca('\\x1bOD', '\\x1b[D'),\n    'Home':          () => ca('\\x1bOH', fa('\\x1b[H', '\\x1b[1~')),\n    'Insert':        '\\x1b[2~',\n    'Delete':        '\\x1b[3~',\n    'End':           () => ca('\\x1bOF', fa('\\x1b[F', '\\x1b[4~')),\n    'PageUp':        '\\x1b[5~',\n    'PageDown':      '\\x1b[6~',\n    'F1':            () => fa('\\x1bOP', '\\x1b[11~'),\n    'F2':            () => fa('\\x1bOQ', '\\x1b[12~'),\n    'F3':            () => fa('\\x1bOR', '\\x1b[13~'),\n    'F4':            () => fa('\\x1bOS', '\\x1b[14~'),\n    'F5':            '\\x1b[15~', // note the disconnect\n    'F6':            '\\x1b[17~',\n    'F7':            '\\x1b[18~',\n    'F8':            '\\x1b[19~',\n    'F9':            '\\x1b[20~',\n    'F10':           '\\x1b[21~', // note the disconnect\n    'F11':           '\\x1b[23~',\n    'F12':           '\\x1b[24~',\n    'Shift+F1':      () => fa('\\x1bO1;2P', '\\x1b[25~'),\n    'Shift+F2':      () => fa('\\x1bO1;2Q', '\\x1b[26~'), // note the disconnect\n    'Shift+F3':      () => fa('\\x1bO1;2R', '\\x1b[28~'),\n    'Shift+F4':      () => fa('\\x1bO1;2S', '\\x1b[29~'), // note the disconnect\n    'Shift+F5':      () => fa('\\x1b[15;2~', '\\x1b[31~'),\n    'Shift+F6':      () => fa('\\x1b[17;2~', '\\x1b[32~'),\n    'Shift+F7':      () => fa('\\x1b[18;2~', '\\x1b[33~'),\n    'Shift+F8':      () => fa('\\x1b[19;2~', '\\x1b[34~'),\n    'Shift+F9':      () => fa('\\x1b[20;2~', '\\x1b[35~'), // 35-38 are not standard - but what is?\n    'Shift+F10':     () => fa('\\x1b[21;2~', '\\x1b[36~'),\n    'Shift+F11':     () => fa('\\x1b[22;2~', '\\x1b[37~'),\n    'Shift+F12':     () => fa('\\x1b[23;2~', '\\x1b[38~'),\n    'Numpad0':       () => na('\\x1bOp', '0'),\n    'Numpad1':       () => na('\\x1bOq', '1'),\n    'Numpad2':       () => na('\\x1bOr', '2'),\n    'Numpad3':       () => na('\\x1bOs', '3'),\n    'Numpad4':       () => na('\\x1bOt', '4'),\n    'Numpad5':       () => na('\\x1bOu', '5'),\n    'Numpad6':       () => na('\\x1bOv', '6'),\n    'Numpad7':       () => na('\\x1bOw', '7'),\n    'Numpad8':       () => na('\\x1bOx', '8'),\n    'Numpad9':       () => na('\\x1bOy', '9'),\n    'Numpad*':       () => na('\\x1bOR', '*'),\n    'Numpad+':       () => na('\\x1bOl', '+'),\n    'Numpad-':       () => na('\\x1bOS', '-'),\n    'Numpad.':       () => na('\\x1bOn', '.'),\n    'Numpad/':       () => na('\\x1bOQ', '/'),\n    // we don't implement numlock key (should change in numpad_alt mode,\n    // but it's even more useless than the rest and also has the side\n    // effect of changing the user's numlock state)\n\n    // shortcuts\n    'Control+]':  '\\x1b', // alternate way to enter ESC\n    'Control+\\\\': '\\x1c',\n    'Control+[':  '\\x1d',\n    'Control+^':  '\\x1e',\n    'Control+_':  '\\x1f',\n\n    // extra controls\n    'Control+ArrowLeft':  '\\x1f[1;5D',\n    'Control+ArrowRight': '\\x1f[1;5C',\n    'Control+ArrowUp':    '\\x1f[1;5A',\n    'Control+ArrowDown':  '\\x1f[1;5B',\n    'Control+Home':       '\\x1f[1;5H',\n    'Control+End':        '\\x1f[1;5F',\n\n    // extra shift controls\n    'Shift+ArrowLeft':    '\\x1f[1;2D',\n    'Shift+ArrowRight':   '\\x1f[1;2C',\n    'Shift+ArrowUp':      '\\x1f[1;2A',\n    'Shift+ArrowDown':    '\\x1f[1;2B',\n    'Shift+Home':         '\\x1f[1;2H',\n    'Shift+End':          '\\x1f[1;2F',\n\n    // macOS text editing commands\n    'Alt+ArrowLeft':      '\\x1bb',  // ⌥← to go back a word (^[b)\n    'Alt+ArrowRight':     '\\x1bf',  // ⌥→ to go forward one word (^[f)\n    'Meta+ArrowLeft':     '\\x01',   // ⌘← to go to the beginning of a line (^A)\n    'Meta+ArrowRight':    '\\x05',   // ⌘→ to go to the end of a line (^E)\n    'Alt+Backspace':      '\\x17',   // ⌥⌫ to delete a word (^W)\n    'Meta+Backspace':     '\\x15',   // ⌘⌫ to delete to the beginning of a line (^U)\n\n    // copy to clipboard\n    'Control+Shift+C' () {\n      screen.copySelectionToClipboard()\n    },\n    'Control+Insert' () {\n      screen.copySelectionToClipboard()\n    },\n\n    // toggle debug mode\n    'Control+F12' () {\n      screen.window.debug ^= 1\n    }\n    /* eslint-enable key-spacing */\n  }\n\n  // ctrl+[A-Z] sent as simple low ASCII codes\n  for (let i = 1; i <= 26; i++) {\n    keymap[`Control+${String.fromCharCode(0x40 + i)}`] = String.fromCharCode(i)\n  }\n\n  /** Send a literal message */\n  function sendString (str) {\n    return conn.send('s' + str)\n  }\n\n  /** Send a button event */\n  function sendButton (index) {\n    conn.send('b' + String.fromCharCode(index + 1))\n  }\n\n  const shouldAcceptEvent = function () {\n    if (cfg.no_keys) return false\n    if (document.activeElement instanceof window.HTMLTextAreaElement) return false\n    return true\n  }\n\n  const keyBlacklist = [\n    'F5', 'F11', 'F12', 'Shift+F5'\n  ]\n\n  let softModifiers = {\n    alt: false,\n    ctrl: false,\n    meta: false,\n    shift: false\n  }\n\n  const handleKeyDown = function (e) {\n    if (!shouldAcceptEvent()) return\n\n    let modifiers = []\n    // sorted alphabetically\n    if (e.altKey || softModifiers.alt) modifiers.push('Alt')\n    if (e.ctrlKey || softModifiers.ctrl) modifiers.push('Control')\n    if (e.metaKey || softModifiers.meta) modifiers.push('Meta')\n    if (e.shiftKey || softModifiers.shift) modifiers.push('Shift')\n\n    let key = KEY_NAMES[e.which] || e.key\n\n    // ignore clipboard events\n    if ((e.ctrlKey || e.metaKey) && key === 'V') return\n\n    let binding = null\n\n    for (let name in keymap) {\n      let itemModifiers = name.split('+')\n      let itemKey = itemModifiers.pop()\n\n      if (itemKey === key && itemModifiers.sort().join() === modifiers.join()) {\n        if (keyBlacklist.includes(name) && !cfg.all_fn) continue\n        binding = keymap[name]\n        break\n      }\n    }\n\n    if (binding) {\n      if (binding instanceof Function) binding = binding()\n      e.preventDefault()\n      if (typeof binding === 'string') {\n        sendString(binding)\n      }\n    }\n  }\n\n  /** Bind/rebind key messages */\n  function initKeys ({ allFn }) {\n    // This takes care of text characters typed\n    window.addEventListener('keypress', function (evt) {\n      if (!shouldAcceptEvent()) return\n      if (evt.ctrlKey || evt.metaKey) return\n\n      let str = ''\n      if (evt.key && evt.key.length === 1) str = evt.key\n      else if (evt.which && evt.which !== 229) str = String.fromCodePoint(evt.which)\n\n      if (str.length > 0 && str.charCodeAt(0) >= 32) {\n        // prevent space from scrolling\n        if (evt.which === 32) evt.preventDefault()\n        sendString(str)\n      }\n    })\n\n    window.addEventListener('keydown', handleKeyDown)\n    window.addEventListener('copy', e => {\n      if (!shouldAcceptEvent()) return\n      let selectedText = screen.getSelectedText()\n      if (selectedText) {\n        e.preventDefault()\n        e.clipboardData.setData('text/plain', selectedText)\n      }\n    })\n    window.addEventListener('paste', e => {\n      if (!shouldAcceptEvent()) return\n      e.preventDefault()\n      let string = e.clipboardData.getData('text/plain')\n      if (string.includes('\\n') || string.length > 90) {\n        if (!input.termUpload) console.error('input.termUpload is undefined')\n        input.termUpload.setContent(string)\n        input.termUpload.open()\n      } else {\n        // simple string, just paste it\n        if (screen.bracketedPaste) string = `\\x1b[200~${string}\\x1b[201~`\n        sendString(string)\n      }\n    })\n\n    cfg.all_fn = allFn\n  }\n\n  // mouse button states\n  let mb1 = 0\n  let mb2 = 0\n  let mb3 = 0\n\n  /** Init the Input module */\n  function init (opts) {\n    initKeys(opts)\n\n    // global mouse state tracking - for motion reporting\n    window.addEventListener('mousedown', evt => {\n      if (evt.button === 0) mb1 = 1\n      if (evt.button === 1) mb2 = 1\n      if (evt.button === 2) mb3 = 1\n    })\n\n    window.addEventListener('mouseup', evt => {\n      if (evt.button === 0) mb1 = 0\n      if (evt.button === 1) mb2 = 0\n      if (evt.button === 2) mb3 = 0\n    })\n  }\n\n  // record modifier keys\n  // bits: Meta, Alt, Shift, Ctrl\n  let modifiers = 0b0000\n\n  window.addEventListener('keydown', e => {\n    if (e.ctrlKey) modifiers |= 1\n    if (e.shiftKey) modifiers |= 2\n    if (e.altKey) modifiers |= 4\n    if (e.metaKey) modifiers |= 8\n  })\n  window.addEventListener('keyup', e => {\n    modifiers = 0\n    if (e.ctrlKey) modifiers |= 1\n    if (e.shiftKey) modifiers |= 2\n    if (e.altKey) modifiers |= 4\n    if (e.metaKey) modifiers |= 8\n  })\n\n  /** Prepare modifiers byte for mouse message */\n  function packModifiersForMouse () {\n    return modifiers\n  }\n\n  input = {\n    /** Init the Input module */\n    init,\n\n    /** Send a literal string message */\n    sendString,\n    sendButton,\n\n    /** Enable alternate key modes (cursors, numpad, fn) */\n    setAlts: function (cu, np, fn, crlf) {\n      if (cfg.cu_alt !== cu || cfg.np_alt !== np || cfg.fn_alt !== fn || cfg.crlf_mode !== crlf) {\n        cfg.cu_alt = cu\n        cfg.np_alt = np\n        cfg.fn_alt = fn\n        cfg.crlf_mode = crlf\n      }\n    },\n\n    setMouseMode (click, move) {\n      cfg.mt_click = click\n      cfg.mt_move = move\n    },\n\n    // Mouse events\n    onMouseMove (x, y) {\n      if (!cfg.mt_move) return\n      const b = mb1 ? 1 : mb2 ? 2 : mb3 ? 3 : 0\n      const m = packModifiersForMouse()\n      conn.send('m' + encode2B(y) + encode2B(x) + encode2B(b) + encode2B(m))\n    },\n\n    onMouseDown (x, y, b) {\n      if (!cfg.mt_click) return\n      if (b > 3 || b < 1) return\n      const m = packModifiersForMouse()\n      conn.send('p' + encode2B(y) + encode2B(x) + encode2B(b) + encode2B(m))\n    },\n\n    onMouseUp (x, y, b) {\n      if (!cfg.mt_click) return\n      if (b > 3 || b < 1) return\n      const m = packModifiersForMouse()\n      conn.send('r' + encode2B(y) + encode2B(x) + encode2B(b) + encode2B(m))\n      // console.log(\"B \",b,\" M \",m);\n    },\n\n    onMouseWheel (x, y, dir) {\n      if (!cfg.mt_click) return\n      // -1 ... btn 4 (away from user)\n      // +1 ... btn 5 (towards user)\n      const m = packModifiersForMouse()\n      const b = (dir < 0 ? 4 : 5)\n      conn.send('p' + encode2B(y) + encode2B(x) + encode2B(b) + encode2B(m))\n      // console.log(\"B \",b,\" M \",m);\n    },\n\n    /**\n     * Prevent capturing keys. This is used for text input\n     * modals on the terminal screen\n     */\n    blockKeys (yes) {\n      cfg.no_keys = yes\n    },\n\n    handleKeyDown,\n    softModifiers\n  }\n  return input\n}\n\n\n\n// WEBPACK FOOTER //\n// ./js/term/input.js","const $ = require('../lib/chibi')\nconst { qs } = require('../utils')\nconst modal = require('../modal')\n\n/** File upload utility */\nmodule.exports = function (conn, input, screen) {\n  let lines, // array of lines without newlines\n    line_i, // current line index\n    fuTout, // timeout handle for line sending\n    send_delay_ms, // delay between lines (ms)\n    nl_str, // newline string to use\n    curLine, // current line (when using fuOil)\n    inline_pos // Offset in line (for long lines)\n\n  // lines longer than this are split to chunks\n  // sending a super-ling string through the socket is not a good idea\n  const MAX_LINE_LEN = 128\n\n  function openUploadDialog () {\n    updateStatus('Ready...')\n    modal.show('#fu_modal', onDialogClose)\n    $('#fu_form').toggleClass('busy', false)\n    input.blockKeys(true)\n  }\n\n  function onDialogClose () {\n    console.log('Upload modal closed.')\n    clearTimeout(fuTout)\n    line_i = 0\n    input.blockKeys(false)\n  }\n\n  function updateStatus (msg) {\n    qs('#fu_prog').textContent = msg\n  }\n\n  function startUpload () {\n    let v = qs('#fu_text').value\n    if (!v.length) {\n      fuClose()\n      return\n    }\n\n    lines = v.split('\\n')\n    line_i = 0\n    inline_pos = 0 // offset in line\n    send_delay_ms = +qs('#fu_delay').value\n\n    // sanitize - 0 causes overflows\n    if (send_delay_ms < 0) {\n      send_delay_ms = 0\n      qs('#fu_delay').value = send_delay_ms\n    }\n\n    nl_str = {\n      'CR': '\\r',\n      'LF': '\\n',\n      'CRLF': '\\r\\n'\n    }[qs('#fu_crlf').value]\n\n    $('#fu_form').toggleClass('busy', true)\n    updateStatus('Starting...')\n    uploadLine()\n  }\n\n  function uploadLine () {\n    if (!$('#fu_modal').hasClass('visible')) {\n      // Modal is closed, cancel\n      return\n    }\n\n    if (!conn.canSend()) {\n      // postpone\n      fuTout = setTimeout(uploadLine, 1)\n      return\n    }\n\n    if (inline_pos === 0) {\n      curLine = ''\n      if (line_i === 0) {\n        if (screen.bracketedPaste) {\n          curLine = '\\x1b[200~'\n        }\n      }\n\n      curLine += lines[line_i++] + nl_str\n\n      if (line_i === lines.length) {\n        if (screen.bracketedPaste) {\n          curLine += '\\x1b[201~'\n        }\n      }\n    }\n\n    let maxChunk = +qs('#fu_chunk').value\n    if (maxChunk === 0 || maxChunk > MAX_LINE_LEN) {\n      maxChunk = MAX_LINE_LEN\n    }\n\n    let chunk\n    if ((curLine.length - inline_pos) <= maxChunk) {\n      chunk = curLine.substr(inline_pos, maxChunk)\n      inline_pos = 0\n    } else {\n      chunk = curLine.substr(inline_pos, maxChunk)\n      inline_pos += maxChunk\n    }\n\n    if (!input.sendString(chunk)) {\n      updateStatus('FAILED!')\n      return\n    }\n\n    let pt = Math.round((line_i / lines.length) * 1000) / 10\n    updateStatus(`${line_i} / ${lines.length} (${pt}%)`)\n\n    if (lines.length > line_i || inline_pos > 0) {\n      fuTout = setTimeout(uploadLine, send_delay_ms)\n    } else {\n      closeWhenReady()\n    }\n  }\n\n  function closeWhenReady () {\n    if (!conn.canSend()) {\n      // stuck in XOFF still, wait to process...\n      updateStatus('Waiting for Tx buffer...')\n      setTimeout(closeWhenReady, 100)\n    } else {\n      updateStatus('Done.')\n      // delay to show it\n      fuClose()\n    }\n  }\n\n  function fuClose () {\n    modal.hide('#fu_modal')\n  }\n\n  return {\n    init: function () {\n      qs('#fu_file').addEventListener('change', function (evt) {\n        let reader = new window.FileReader()\n        let file = evt.target.files[0]\n        let ftype = file.type || 'application/octet-stream'\n        console.log('Selected file type: ' + ftype)\n        if (!ftype.match(/text\\/.*|application\\/(json|csv|.*xml.*|.*script.*|x-php)/)) {\n          // Deny load of blobs like img - can crash browser and will get corrupted anyway\n          if (!window.confirm(`This does not look like a text file: ${ftype}\\nReally load?`)) {\n            qs('#fu_file').value = ''\n            return\n          }\n        }\n        reader.onload = function (e) {\n          const txt = e.target.result.replace(/[\\r\\n]+/, '\\n')\n          qs('#fu_text').value = txt\n        }\n        console.log('Loading file...')\n        reader.readAsText(file)\n      }, false)\n\n      qs('#term-fu-open').addEventListener('click', e => {\n        e.preventDefault()\n        openUploadDialog()\n      })\n\n      qs('#term-fu-start').addEventListener('click', e => {\n        e.preventDefault()\n        startUpload()\n      })\n\n      qs('#term-fu-close').addEventListener('click', e => {\n        e.preventDefault()\n        fuClose()\n      })\n    },\n    open: openUploadDialog,\n    setContent (content) {\n      qs('#fu_text').value = content\n    }\n  }\n}\n\n\n\n// WEBPACK FOOTER //\n// ./js/term/upload.js","const { qs } = require('../utils')\n\nmodule.exports = function (screen, input) {\n  const keyInput = qs('#softkb-input')\n  if (!keyInput) return // abort, we're not on the terminal page\n\n  const shortcutBar = document.createElement('div')\n  shortcutBar.id = 'keyboard-shortcut-bar'\n  if (navigator.userAgent.match(/iPad|iPhone|iPod/)) {\n    qs('#screen').appendChild(shortcutBar)\n  }\n\n  let keyboardOpen = false\n\n  // moves the input to where the cursor is on the canvas.\n  // this is because most browsers will always scroll to wherever the focused\n  // input is\n  let updateInputPosition = function () {\n    if (!keyboardOpen) return\n\n    let [x, y] = screen.gridToScreen(screen.cursor.x, screen.cursor.y, true)\n    keyInput.style.transform = `translate(${x}px, ${y}px)`\n  }\n\n  keyInput.addEventListener('focus', () => {\n    keyboardOpen = true\n    updateInputPosition()\n    shortcutBar.classList.add('open')\n  })\n\n  keyInput.addEventListener('blur', () => {\n    keyboardOpen = false\n    shortcutBar.classList.remove('open')\n  })\n\n  screen.on('cursor-moved', updateInputPosition)\n\n  qs('#term-kb-open').addEventListener('click', e => {\n    e.preventDefault()\n    keyInput.focus()\n  })\n\n  // Chrome for Android doesn't send proper keydown/keypress events with\n  // real key values instead of 229 “Unidentified,” so here's a workaround\n  // that deals with the input composition events.\n\n  let lastCompositionString = ''\n\n  // sends the difference between the last and the new composition string\n  let sendInputDelta = function (newValue) {\n    if (newValue === null) newValue = '' // this sometimes happens, why?\n    let resend = false\n    if (newValue.length > lastCompositionString.length) {\n      if (newValue.startsWith(lastCompositionString)) {\n        // characters have been added at the end\n        input.sendString(newValue.substr(lastCompositionString.length))\n      } else resend = true\n    } else if (newValue.length < lastCompositionString.length) {\n      if (lastCompositionString.startsWith(newValue)) {\n        // characters have been removed at the end\n        input.sendString('\\b'.repeat(lastCompositionString.length -\n          newValue.length))\n      } else resend = true\n    } else if (newValue !== lastCompositionString) resend = true\n\n    if (resend) {\n      // the entire string changed; resend everything\n      input.sendString('\\b'.repeat(lastCompositionString.length) +\n        newValue)\n    }\n    lastCompositionString = newValue\n  }\n\n  keyInput.addEventListener('keydown', e => {\n    if (e.key === 'Unidentified') return\n\n    keyInput.value = ''\n\n    e.stopPropagation()\n    input.handleKeyDown(e)\n  })\n\n  keyInput.addEventListener('keypress', e => {\n    // prevent key duplication on iOS (because Safari *does* send proper events)\n    e.stopPropagation()\n  })\n\n  keyInput.addEventListener('input', e => {\n    e.stopPropagation()\n\n    if (e.isComposing && 'data' in e) {\n      sendInputDelta(e.data)\n    } else if (e.isComposing) {\n      // Firefox Mobile doesn't support InputEvent#data, so here's a hack\n      // that just takes the input value and uses that\n      sendInputDelta(keyInput.value)\n    } else {\n      if (e.inputType === 'insertCompositionText') input.sendString(e.data)\n      else if (e.inputType === 'deleteContentBackward') {\n        lastCompositionString = ''\n        sendInputDelta('')\n      } else if (e.inputType === 'insertText') {\n        input.sendString(e.data)\n      }\n    }\n  })\n\n  keyInput.addEventListener('compositionstart', e => {\n    lastCompositionString = ''\n  })\n\n  keyInput.addEventListener('compositionend', e => {\n    lastCompositionString = ''\n    keyInput.value = ''\n  })\n\n  screen.on('open-soft-keyboard', () => keyInput.focus())\n\n  // shortcut bar\n  const shortcuts = {\n    Control: 'ctrl',\n    Esc: 0x1b,\n    Tab: 0x09,\n    '←': 0x25,\n    '↓': 0x28,\n    '↑': 0x26,\n    '→': 0x27\n  }\n\n  let touchMoved = false\n\n  for (const shortcut in shortcuts) {\n    const button = document.createElement('button')\n    button.classList.add('shortcut-button')\n    button.textContent = shortcut\n    shortcutBar.appendChild(button)\n\n    const key = shortcuts[shortcut]\n    if (typeof key === 'string') button.classList.add('modifier')\n    button.addEventListener('touchstart', e => {\n      touchMoved = false\n      if (typeof key === 'string') {\n        // modifier button\n        input.softModifiers[key] = true\n        button.classList.add('enabled')\n\n        // prevent default. This prevents scrolling, but also prevents the\n        // selection popup\n        e.preventDefault()\n      }\n    })\n    window.addEventListener('touchmove', e => {\n      touchMoved = true\n    })\n    button.addEventListener('touchend', e => {\n      e.preventDefault()\n      if (typeof key === 'number') {\n        if (touchMoved) return\n        let fakeEvent = { which: key, preventDefault: () => {} }\n        input.handleKeyDown(fakeEvent)\n      } else if (typeof key === 'string') {\n        button.classList.remove('enabled')\n        input.softModifiers[key] = false\n      }\n    })\n  }\n}\n\n\n\n// WEBPACK FOOTER //\n// ./js/term/soft_keyboard.js","const { mk } = require('../utils')\n\nmodule.exports = function attachDebugScreen (screen) {\n  const debugCanvas = mk('canvas')\n  const ctx = debugCanvas.getContext('2d')\n\n  debugCanvas.classList.add('debug-canvas')\n\n  let mouseHoverCell = null\n  let updateToolbar\n\n  let onMouseMove = e => {\n    mouseHoverCell = screen.screenToGrid(e.offsetX, e.offsetY)\n    startDrawing()\n    updateToolbar()\n  }\n  let onMouseOut = () => (mouseHoverCell = null)\n\n  let addCanvas = function () {\n    if (!debugCanvas.parentNode) {\n      screen.canvas.parentNode.appendChild(debugCanvas)\n      screen.canvas.addEventListener('mousemove', onMouseMove)\n      screen.canvas.addEventListener('mouseout', onMouseOut)\n    }\n  }\n  let removeCanvas = function () {\n    if (debugCanvas.parentNode) {\n      debugCanvas.parentNode.removeChild(debugCanvas)\n      screen.canvas.removeEventListener('mousemove', onMouseMove)\n      screen.canvas.removeEventListener('mouseout', onMouseOut)\n      onMouseOut()\n    }\n  }\n  let updateCanvasSize = function () {\n    let { width, height, devicePixelRatio } = screen.window\n    let cellSize = screen.getCellSize()\n    debugCanvas.width = width * cellSize.width * devicePixelRatio\n    debugCanvas.height = height * cellSize.height * devicePixelRatio\n    debugCanvas.style.width = `${width * cellSize.width}px`\n    debugCanvas.style.height = `${height * cellSize.height}px`\n  }\n\n  let drawInfo = mk('div')\n  drawInfo.classList.add('draw-info')\n\n  let startTime, endTime, lastReason\n  let cells = new Map()\n  let clippedRects = []\n  let updateFrames = []\n\n  let startDrawing\n\n  screen._debug = {\n    drawStart (reason) {\n      lastReason = reason\n      startTime = Date.now()\n      clippedRects = []\n    },\n    drawEnd () {\n      endTime = Date.now()\n      console.log(drawInfo.textContent = `Draw: ${lastReason} (${(endTime - startTime)} ms) with graphics=${screen.window.graphics}`)\n      startDrawing()\n    },\n    setCell (cell, flags) {\n      cells.set(cell, [flags, Date.now()])\n    },\n    clipRect (...args) {\n      clippedRects.push(args)\n    },\n    pushFrame (frame) {\n      frame.push(Date.now())\n      updateFrames.push(frame)\n      startDrawing()\n    }\n  }\n\n  let clipPattern\n  {\n    let patternCanvas = document.createElement('canvas')\n    patternCanvas.width = patternCanvas.height = 12\n    let pctx = patternCanvas.getContext('2d')\n    pctx.lineWidth = 1\n    pctx.strokeStyle = '#00f'\n    pctx.beginPath()\n    pctx.moveTo(0, 0)\n    pctx.lineTo(0 - 4, 12)\n    pctx.moveTo(4, 0)\n    pctx.lineTo(4 - 4, 12)\n    pctx.moveTo(8, 0)\n    pctx.lineTo(8 - 4, 12)\n    pctx.moveTo(12, 0)\n    pctx.lineTo(12 - 4, 12)\n    pctx.moveTo(16, 0)\n    pctx.lineTo(16 - 4, 12)\n    pctx.stroke()\n    clipPattern = ctx.createPattern(patternCanvas, 'repeat')\n  }\n\n  let isDrawing = false\n  let lastDrawTime = 0\n  let t = 0\n\n  let drawLoop = function () {\n    if (isDrawing) window.requestAnimationFrame(drawLoop)\n\n    let dt = (Date.now() - lastDrawTime) / 1000\n    lastDrawTime = Date.now()\n    t += dt\n\n    let { devicePixelRatio, width, height } = screen.window\n    let { width: cellWidth, height: cellHeight } = screen.getCellSize()\n    let screenLength = width * height\n    let now = Date.now()\n\n    ctx.setTransform(devicePixelRatio, 0, 0, devicePixelRatio, 0, 0)\n    ctx.clearRect(0, 0, width * cellWidth, height * cellHeight)\n\n    let activeCells = 0\n    for (let cell = 0; cell < screenLength; cell++) {\n      if (!cells.has(cell) || cells.get(cell)[0] === 0) continue\n\n      let [flags, timestamp] = cells.get(cell)\n      let elapsedTime = (now - timestamp) / 1000\n\n      if (elapsedTime > 1) continue\n\n      activeCells++\n      ctx.globalAlpha = 0.5 * Math.max(0, 1 - elapsedTime)\n\n      let x = cell % width\n      let y = Math.floor(cell / width)\n\n      if (flags & 1) {\n        // redrawn\n        ctx.fillStyle = '#f0f'\n      }\n      if (flags & 2) {\n        // updated\n        ctx.fillStyle = '#0f0'\n      }\n\n      ctx.fillRect(x * cellWidth, y * cellHeight, cellWidth, cellHeight)\n\n      if (flags & 4) {\n        // wide cell\n        ctx.lineWidth = 2\n        ctx.strokeStyle = '#f00'\n        ctx.strokeRect(x * cellWidth, y * cellHeight, cellWidth, cellHeight)\n      }\n    }\n\n    if (clippedRects.length) {\n      ctx.globalAlpha = 0.5\n      ctx.beginPath()\n\n      for (let rect of clippedRects) {\n        ctx.rect(...rect)\n      }\n\n      ctx.fillStyle = clipPattern\n      ctx.fill()\n    }\n\n    let didDrawUpdateFrames = false\n    if (updateFrames.length) {\n      let framesToDelete = []\n      for (let frame of updateFrames) {\n        let time = frame[4]\n        let elapsed = Date.now() - time\n        if (elapsed > 1000) framesToDelete.push(frame)\n        else {\n          didDrawUpdateFrames = true\n          ctx.globalAlpha = 1 - elapsed / 1000\n          ctx.strokeStyle = '#ff0'\n          ctx.lineWidth = 2\n          ctx.strokeRect(frame[0] * cellWidth, frame[1] * cellHeight, frame[2] * cellWidth, frame[3] * cellHeight)\n        }\n      }\n      for (let frame of framesToDelete) {\n        updateFrames.splice(updateFrames.indexOf(frame), 1)\n      }\n    }\n\n    if (mouseHoverCell) {\n      ctx.save()\n      ctx.globalAlpha = 1\n      ctx.lineWidth = 1 + 0.5 * Math.sin(t * 10)\n      ctx.strokeStyle = '#fff'\n      ctx.lineJoin = 'round'\n      ctx.setLineDash([2, 2])\n      ctx.lineDashOffset = t * 10\n      ctx.strokeRect(mouseHoverCell[0] * cellWidth, mouseHoverCell[1] * cellHeight, cellWidth, cellHeight)\n      ctx.lineDashOffset += 2\n      ctx.strokeStyle = '#000'\n      ctx.strokeRect(mouseHoverCell[0] * cellWidth, mouseHoverCell[1] * cellHeight, cellWidth, cellHeight)\n      ctx.restore()\n    }\n\n    if (activeCells === 0 && !mouseHoverCell && !didDrawUpdateFrames) {\n      isDrawing = false\n      removeCanvas()\n    }\n  }\n\n  startDrawing = function () {\n    if (isDrawing) return\n    addCanvas()\n    updateCanvasSize()\n    isDrawing = true\n    lastDrawTime = Date.now()\n    drawLoop()\n  }\n\n  // debug toolbar\n  const toolbar = mk('div')\n  toolbar.classList.add('debug-toolbar')\n  let toolbarAttached = false\n  const dataDisplay = mk('div')\n  dataDisplay.classList.add('data-display')\n  toolbar.appendChild(dataDisplay)\n  const internalDisplay = mk('div')\n  internalDisplay.classList.add('internal-display')\n  toolbar.appendChild(internalDisplay)\n  toolbar.appendChild(drawInfo)\n  const buttons = mk('div')\n  buttons.classList.add('toolbar-buttons')\n  toolbar.appendChild(buttons)\n\n  {\n    const redraw = mk('button')\n    redraw.textContent = 'Redraw'\n    redraw.addEventListener('click', e => {\n      screen.renderer.resetDrawn()\n      screen.renderer.draw('debug-redraw')\n    })\n    buttons.appendChild(redraw)\n\n    const fancyGraphics = mk('button')\n    fancyGraphics.textContent = 'Toggle Graphics'\n    fancyGraphics.addEventListener('click', e => {\n      screen.window.graphics = +!screen.window.graphics\n    })\n    buttons.appendChild(fancyGraphics)\n  }\n\n  const attachToolbar = function () {\n    screen.canvas.parentNode.appendChild(toolbar)\n  }\n  const detachToolbar = function () {\n    toolbar.parentNode.removeChild(toolbar)\n  }\n\n  screen.on('update-window:debug', debug => {\n    if (debug !== toolbarAttached) {\n      toolbarAttached = debug\n      if (debug) attachToolbar()\n      else {\n        detachToolbar()\n        removeCanvas()\n      }\n    }\n  })\n\n  const displayCellAttrs = attrs => {\n    let result = attrs.toString(16)\n    if (attrs & 1 || attrs & 2) {\n      result += ':has('\n      if (attrs & 1) result += 'fg'\n      if (attrs & 2) result += (attrs & 1 ? ',' : '') + 'bg'\n      result += ')'\n    }\n    let attributes = []\n    if (attrs & (1 << 2)) attributes.push('\\\\[bold]bold\\\\()')\n    if (attrs & (1 << 3)) attributes.push('\\\\[underline]underln\\\\()')\n    if (attrs & (1 << 4)) attributes.push('\\\\[invert]invert\\\\()')\n    if (attrs & (1 << 5)) attributes.push('blink')\n    if (attrs & (1 << 6)) attributes.push('\\\\[italic]italic\\\\()')\n    if (attrs & (1 << 7)) attributes.push('\\\\[strike]strike\\\\()')\n    if (attrs & (1 << 8)) attributes.push('\\\\[overline]overln\\\\()')\n    if (attrs & (1 << 9)) attributes.push('\\\\[faint]faint\\\\()')\n    if (attrs & (1 << 10)) attributes.push('fraktur')\n    if (attributes.length) result += ':' + attributes.join()\n    return result.trim()\n  }\n\n  const formatColor = color => color < 256 ? color : `#${`000000${(color - 256).toString(16)}`.substr(-6)}`\n  const getCellData = cell => {\n    if (cell < 0 || cell > screen.screen.length) return '(-)'\n    let cellAttrs = screen.renderer.drawnScreenAttrs[cell] | 0\n    let cellFG = screen.renderer.drawnScreenFG[cell] | 0\n    let cellBG = screen.renderer.drawnScreenBG[cell] | 0\n    let fgText = formatColor(cellFG)\n    let bgText = formatColor(cellBG)\n    fgText += `\\\\[color=${screen.renderer.getColor(cellFG).replace(/ /g, '')}]●\\\\[]`\n    bgText += `\\\\[color=${screen.renderer.getColor(cellBG).replace(/ /g, '')}]●\\\\[]`\n    let cellCode = (screen.renderer.drawnScreen[cell] || '').codePointAt(0) | 0\n    let hexcode = cellCode.toString(16).toUpperCase()\n    if (hexcode.length < 4) hexcode = `0000${hexcode}`.substr(-4)\n    hexcode = `U+${hexcode}`\n    let x = cell % screen.window.width\n    let y = Math.floor(cell / screen.window.width)\n    return `((${y},${x})=${cell}:\\\\[bold]${hexcode}\\\\[]:F${fgText}:B${bgText}:A(${displayCellAttrs(cellAttrs)}))`\n  }\n\n  const setFormattedText = (node, text) => {\n    node.innerHTML = ''\n\n    let match\n    let attrs = {}\n\n    let pushSpan = content => {\n      let span = mk('span')\n      node.appendChild(span)\n      span.textContent = content\n      for (let key in attrs) span[key] = attrs[key]\n    }\n\n    while ((match = text.match(/\\\\\\[(.*?)\\]/))) {\n      if (match.index > 0) pushSpan(text.substr(0, match.index))\n\n      attrs = { style: '' }\n      let data = match[1].split(' ')\n      for (let attr of data) {\n        if (!attr) continue\n        let key, value\n        if (attr.indexOf('=') > -1) {\n          key = attr.substr(0, attr.indexOf('='))\n          value = attr.substr(attr.indexOf('=') + 1)\n        } else {\n          key = attr\n          value = true\n        }\n\n        if (key === 'color') console.log(value)\n\n        if (key === 'bold') attrs.style += 'font-weight:bold;'\n        if (key === 'italic') attrs.style += 'font-style:italic;'\n        if (key === 'underline') attrs.style += 'text-decoration:underline;'\n        if (key === 'invert') attrs.style += 'background:#000;filter:invert(1);'\n        if (key === 'strike') attrs.style += 'text-decoration:line-through;'\n        if (key === 'overline') attrs.style += 'text-decoration:overline;'\n        if (key === 'faint') attrs.style += 'opacity:0.5;'\n        else if (key === 'color') attrs.style += `color:${value};`\n        else attrs[key] = value\n      }\n\n      text = text.substr(match.index + match[0].length)\n    }\n\n    if (text) pushSpan(text)\n  }\n\n  let internalInfo = {}\n\n  updateToolbar = () => {\n    if (!toolbarAttached) return\n    let text = `C((${screen.cursor.y},${screen.cursor.x}),hang:${screen.cursor.hanging},vis:${screen.cursor.visible})`\n    if (mouseHoverCell) {\n      text += ' m' + getCellData(mouseHoverCell[1] * screen.window.width + mouseHoverCell[0])\n    }\n    setFormattedText(dataDisplay, text)\n\n    if ('flags' in internalInfo) {\n      // we got ourselves some internal data\n      let text = ' '\n      text += ` flags:${internalInfo.flags.toString(2)}`\n      text += ` curAttrs:${internalInfo.cursorAttrs.toString(2)}`\n      text += ` Region:${internalInfo.regionStart}->${internalInfo.regionEnd}`\n      text += ` Charset:${internalInfo.charsetGx} (0:${internalInfo.charsetG0},1:${internalInfo.charsetG1})`\n      text += ` Heap:${internalInfo.freeHeap}`\n      text += ` Clients:${internalInfo.clientCount}`\n      setFormattedText(internalDisplay, text)\n    }\n  }\n\n  screen.on('draw', updateToolbar)\n  screen.on('internal', data => {\n    internalInfo = data\n    updateToolbar()\n  })\n}\n\n\n\n// WEBPACK FOOTER //\n// ./js/term/debug_screen.js","const { qs } = require('../utils')\n\nmodule.exports = function initButtons (input) {\n  let container = qs('#action-buttons')\n\n  // button labels\n  let labels = []\n\n  // button elements\n  let buttons = []\n\n  // add a button element\n  let pushButton = function pushButton () {\n    let button = document.createElement('button')\n    button.classList.add('action-button')\n    button.setAttribute('data-n', buttons.length)\n    buttons.push(button)\n    container.appendChild(button)\n\n    button.addEventListener('click', e => {\n      // might as well use the attribute ¯\\_(ツ)_/¯\n      let index = +button.getAttribute('data-n')\n      input.sendButton(index)\n    })\n\n    return button\n  }\n\n  // remove a button element\n  let popButton = function popButton () {\n    let button = buttons.pop()\n    button.parentNode.removeChild(button)\n  }\n\n  // sync with DOM\n  let update = function updateButtons () {\n    if (labels.length > buttons.length) {\n      for (let i = buttons.length; i < labels.length; i++) {\n        pushButton()\n      }\n    } else if (buttons.length > labels.length) {\n      for (let i = labels.length; i <= buttons.length; i++) {\n        popButton()\n      }\n    }\n\n    for (let i = 0; i < labels.length; i++) {\n      let label = labels[i].trim()\n      let button = buttons[i]\n      button.textContent = label || '\\u00a0' // label or nbsp\n      if (!label) button.classList.add('inactive')\n      else button.classList.remove('inactive')\n    }\n  }\n\n  return { update, labels }\n}\n\n\n\n// WEBPACK FOOTER //\n// ./js/term/buttons.js","const ColorTriangle = require('./lib/colortriangle')\nconst $ = require('./lib/chibi')\nconst themes = require('./term/themes')\nconst { qs } = require('./utils')\n\nfunction selectedTheme () {\n  return +$('#theme').val()\n}\n\nexports.init = function () {\n  $('#theme').on('change', showColor)\n\n  $('#default_fg').on('input', showColor)\n  $('#default_bg').on('input', showColor)\n\n  let opts = {\n    padding: 10,\n    event: 'drag',\n    uppercase: true,\n    trianglePointerSize: 20,\n    // wheelPointerSize: 12,\n    size: 200,\n    parseColor: (color) => {\n      return themes.toHex(color, selectedTheme())\n    }\n  }\n\n  ColorTriangle.initInput(qs('#default_fg'), opts)\n  ColorTriangle.initInput(qs('#default_bg'), opts)\n\n  $('.colorprev.bg span').on('click', function () {\n    const bg = this.dataset.bg\n    if (typeof bg != 'undefined') $('#default_bg').val(bg)\n    showColor()\n  })\n\n  $('.colorprev.fg span').on('click', function () {\n    const fg = this.dataset.fg\n    if (typeof fg != 'undefined') $('#default_fg').val(fg)\n    showColor()\n  })\n\n  let $presets = $('#fgbg_presets')\n  for (let i = 0; i < themes.fgbgThemes.length; i++) {\n    const thm = themes.fgbgThemes[i]\n    const fg = thm[0]\n    const bg = thm[1]\n    const lbl = thm[2]\n    const tit = thm[3]\n    $presets.htmlAppend(\n        '<span class=\"preset\" ' +\n        'data-xfg=\"' + fg + '\" data-xbg=\"' + bg + '\" ' +\n        'style=\"color:' + fg + ';background:' + bg + '\" title=\"' + tit + '\">&nbsp;' + lbl + '&nbsp;</span>')\n\n    if ((i + 1) % 5 === 0) $presets.htmlAppend('<br>')\n  }\n\n  $('.preset').on('click', function () {\n    $('#default_fg').val(this.dataset.xfg)\n    $('#default_bg').val(this.dataset.xbg)\n    showColor()\n  })\n\n  showColor()\n}\n\nfunction showColor () {\n  let ex = qs('.color-example')\n  let fg = $('#default_fg').val()\n  let bg = $('#default_bg').val()\n\n  if (/^\\d+$/.test(fg)) {\n    fg = +fg\n  } else if (!/^#[\\da-f]{6}$/i.test(fg)) {\n    fg = 'black'\n  }\n\n  if (/^\\d+$/.test(bg)) {\n    bg = +bg\n  } else if (!/^#[\\da-f]{6}$/i.test(bg)) {\n    bg = 'black'\n  }\n\n  const themeN = selectedTheme()\n  ex.dataset.fg = fg\n  ex.dataset.bg = bg\n\n  themes.themePreview(themeN)\n\n  $('.colorprev.fg span').css('background', themes.toHex(bg, themeN))\n}\n\nexports.nextTheme = () => {\n  let sel = qs('#theme')\n  let i = sel.selectedIndex\n  sel.options[++i % sel.options.length].selected = true\n  showColor()\n}\n\nexports.prevTheme = () => {\n  let sel = qs('#theme')\n  let i = sel.selectedIndex\n  sel.options[(sel.options.length + (--i)) % sel.options.length].selected = true\n  showColor()\n}\n\n\n\n// WEBPACK FOOTER //\n// ./js/term_conf.js","/*\n * Copyright (c) 2010 Tim Baumann\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n// NOTE: Converted to ES6 by MightyPork (2017)\n// Modified for ESPTerm\n\nconst EventEmitter = require('events')\nconst {\n  rgb2hex,\n  hex2rgb,\n  hsl2rgb,\n  rgb2hsl\n} = require('./color_utils')\n\nconst win = window\nconst doc = document\nconst M = Math\nconst TAU = 2 * M.PI\n\nfunction times (i, fn) {\n  for (let j = 0; j < i; j++) {\n    fn(j)\n  }\n}\n\nfunction each (obj, fn) {\n  if (obj.length) {\n    times(obj.length, function (i) {\n      fn(obj[i], i)\n    })\n  } else {\n    for (let key in obj) {\n      if (obj.hasOwnProperty(key)) {\n        fn(obj[key], key)\n      }\n    }\n  }\n}\n\nmodule.exports = class ColorTriangle extends EventEmitter {\n  /****************\n   * ColorTriangle *\n   ****************/\n\n  // Constructor function:\n  constructor (color, options) {\n    super()\n\n    this.options = {\n      size: 150,\n      padding: 8,\n      triangleSize: 0.8,\n      wheelPointerColor1: '#444',\n      wheelPointerColor2: '#eee',\n      trianglePointerSize: 16,\n      // wheelPointerSize: 16,\n      trianglePointerColor1: '#eee',\n      trianglePointerColor2: '#444',\n      background: 'transparent'\n    }\n\n    this.pixelRatio = window.devicePixelRatio\n\n    this.setOptions(options)\n    this.calculateProperties()\n\n    this.createContainer()\n    this.createTriangle()\n    this.createWheel()\n    this.createWheelPointer()\n    this.createTrianglePointer()\n    this.attachEvents()\n\n    color = color || '#f00'\n    if (typeof color == 'string') {\n      this.setHEX(color)\n    }\n  }\n\n  calculateProperties () {\n    let opts = this.options\n\n    this.padding = opts.padding\n    this.innerSize = opts.size - opts.padding * 2\n    this.triangleSize = opts.triangleSize * this.innerSize\n    this.wheelThickness = (this.innerSize - this.triangleSize) / 2\n    this.wheelPointerSize = opts.wheelPointerSize || this.wheelThickness\n\n    this.wheelRadius = (this.innerSize) / 2\n    this.triangleRadius = (this.triangleSize) / 2\n    this.triangleSideLength = M.sqrt(3) * this.triangleRadius\n  }\n\n  calculatePositions () {\n    const r = this.triangleRadius\n    const hue = this.hue\n    const third = TAU / 3\n    const s = this.saturation\n    const l = this.lightness\n\n    // Colored point\n    const hx = this.hx = M.cos(hue) * r\n    const hy = this.hy = -M.sin(hue) * r\n    // Black point\n    const sx = this.sx = M.cos(hue - third) * r\n    const sy = this.sy = -M.sin(hue - third) * r\n    // White point\n    const vx = this.vx = M.cos(hue + third) * r\n    const vy = this.vy = -M.sin(hue + third) * r\n    // Current point\n    const mx = (sx + vx) / 2\n    const my = (sy + vy) / 2\n    const a = (1 - 2 * M.abs(l - 0.5)) * s\n    this.x = sx + (vx - sx) * l + (hx - mx) * a\n    this.y = sy + (vy - sy) * l + (hy - my) * a\n  }\n\n  createContainer () {\n    let c = this.container = doc.createElement('div')\n    c.className = 'color-triangle'\n\n    c.style.display = 'block'\n    c.style.padding = `${this.padding}px`\n    c.style.position = 'relative'\n    c.style.boxShadow = '0 1px 10px black'\n    c.style.borderRadius = '5px'\n    c.style.width = c.style.height = `${this.innerSize + 2 * this.padding}px`\n    c.style.background = this.options.background\n  }\n\n  createWheel () {\n    let c = this.wheel = doc.createElement('canvas')\n    c.width = c.height = this.innerSize * this.pixelRatio\n    c.style.width = c.style.height = `${this.innerSize}px`\n    c.style.position = 'absolute'\n    c.style.margin = c.style.padding = '0'\n    c.style.left = c.style.top = `${this.padding}px`\n\n    this.drawWheel(c.getContext('2d'))\n    this.container.appendChild(c)\n  }\n\n  drawWheel (ctx) {\n    let s, i\n\n    ctx.save()\n    ctx.setTransform(this.pixelRatio, 0, 0, this.pixelRatio, 0, 0)\n    ctx.translate(this.wheelRadius, this.wheelRadius)\n    s = this.wheelRadius - this.triangleRadius\n    // Draw a circle for every color\n    for (i = 0; i < 360; i++) {\n      ctx.rotate(TAU / -360) // rotate one degree\n      ctx.beginPath()\n      ctx.fillStyle = 'hsl(' + i + ', 100%, 50%)'\n      ctx.arc(this.wheelRadius - (s / 2), 0, s / 2, 0, TAU, true)\n      ctx.fill()\n    }\n    ctx.restore()\n  }\n\n  createTriangle () {\n    let c = this.triangle = doc.createElement('canvas')\n\n    c.width = c.height = this.innerSize * this.pixelRatio\n    c.style.width = c.style.height = `${this.innerSize}px`\n    c.style.position = 'absolute'\n    c.style.margin = c.style.padding = '0'\n    c.style.left = c.style.top = this.padding + 'px'\n\n    this.triangleCtx = c.getContext('2d')\n\n    this.container.appendChild(c)\n  }\n\n  drawTriangle () {\n    const hx = this.hx\n    const hy = this.hy\n    const sx = this.sx\n    const sy = this.sy\n    const vx = this.vx\n    const vy = this.vy\n    const size = this.innerSize\n\n    let ctx = this.triangleCtx\n\n    // clear\n    ctx.clearRect(0, 0, size * this.pixelRatio, size * this.pixelRatio)\n\n    ctx.save()\n    ctx.setTransform(this.pixelRatio, 0, 0, this.pixelRatio, 0, 0)\n    ctx.translate(this.wheelRadius, this.wheelRadius)\n\n    // make a triangle\n    ctx.beginPath()\n    ctx.moveTo(hx, hy)\n    ctx.lineTo(sx, sy)\n    ctx.lineTo(vx, vy)\n    ctx.closePath()\n    ctx.clip()\n\n    ctx.fillStyle = '#000'\n    ctx.fillRect(-this.wheelRadius, -this.wheelRadius, size, size)\n    // => black triangle\n\n    // create gradient from hsl(hue, 1, 1) to transparent\n    let grad0 = ctx.createLinearGradient(hx, hy, (sx + vx) / 2, (sy + vy) / 2)\n    const hsla = 'hsla(' + M.round(this.hue * (360 / TAU)) + ', 100%, 50%, '\n    grad0.addColorStop(0, hsla + '1)')\n    grad0.addColorStop(1, hsla + '0)')\n    ctx.fillStyle = grad0\n    ctx.fillRect(-this.wheelRadius, -this.wheelRadius, size, size)\n    // => gradient: one side of the triangle is black, the opponent angle is $color\n\n    // create color gradient from white to transparent\n    let grad1 = ctx.createLinearGradient(vx, vy, (hx + sx) / 2, (hy + sy) / 2)\n    grad1.addColorStop(0, '#fff')\n    grad1.addColorStop(1, 'rgba(255, 255, 255, 0)')\n    ctx.globalCompositeOperation = 'lighter'\n    ctx.fillStyle = grad1\n    ctx.fillRect(-this.wheelRadius, -this.wheelRadius, size, size)\n    // => white angle\n\n    ctx.restore()\n  }\n\n  // The two pointers\n  createWheelPointer () {\n    let c = this.wheelPointer = doc.createElement('canvas')\n    const size = this.wheelPointerSize\n    c.width = c.height = size * this.pixelRatio\n    c.style.width = c.style.height = `${size}px`\n    c.style.position = 'absolute'\n    c.style.margin = c.style.padding = '0'\n    this.drawPointer(c.getContext('2d'), size / 2, this.options.wheelPointerColor1, this.options.wheelPointerColor2)\n    this.container.appendChild(c)\n  }\n\n  moveWheelPointer () {\n    const r = this.wheelPointerSize / 2\n    const s = this.wheelPointer.style\n    s.top = this.padding + this.wheelRadius - M.sin(this.hue) * (this.triangleRadius + this.wheelThickness / 2) - r + 'px'\n    s.left = this.padding + this.wheelRadius + M.cos(this.hue) * (this.triangleRadius + this.wheelThickness / 2) - r + 'px'\n  }\n\n  createTrianglePointer () { // create pointer in the triangle\n    let c = this.trianglePointer = doc.createElement('canvas')\n    const size = this.options.trianglePointerSize\n\n    c.width = c.height = size * this.pixelRatio\n    c.style.width = c.style.height = `${size}px`\n    c.style.position = 'absolute'\n    c.style.margin = c.style.padding = '0'\n    this.drawPointer(c.getContext('2d'), size / 2, this.options.trianglePointerColor1, this.options.trianglePointerColor2)\n    this.container.appendChild(c)\n  }\n\n  moveTrianglePointer (x, y) {\n    const s = this.trianglePointer.style\n    const r = this.options.trianglePointerSize / 2\n    s.top = (this.y + this.wheelRadius + this.padding - r) + 'px'\n    s.left = (this.x + this.wheelRadius + this.padding - r) + 'px'\n  }\n\n  drawPointer (ctx, r, color1, color2) {\n    ctx.setTransform(this.pixelRatio, 0, 0, this.pixelRatio, 0, 0)\n    ctx.fillStyle = color2\n    ctx.beginPath()\n    ctx.arc(r, r, r, 0, TAU, true)\n    ctx.fill() // => black circle\n    ctx.fillStyle = color1\n    ctx.beginPath()\n    ctx.arc(r, r, r - 2, 0, TAU, true)\n    ctx.fill() // => white circle with 1px black border\n    ctx.fillStyle = color2\n    ctx.beginPath()\n    ctx.arc(r, r, r / 4 + 2, 0, TAU, true)\n    ctx.fill() // => black circle with big white border and a small black border\n    ctx.globalCompositeOperation = 'destination-out'\n    ctx.beginPath()\n    ctx.arc(r, r, r / 4, 0, TAU, true)\n    ctx.fill() // => transparent center\n  }\n\n  // The Element and the DOM\n  inject (parent) {\n    parent.appendChild(this.container)\n  }\n\n  getRelativeCoordinates (evt) {\n    let elem = this.triangle\n    let rect = elem.getBoundingClientRect()\n\n    return {\n      x: evt.clientX - rect.x,\n      y: evt.clientY - rect.y\n    }\n  }\n\n  dispose () {\n    let parent = this.container.parentNode\n    if (parent) {\n      parent.removeChild(this.container)\n    }\n  }\n\n  getElement () {\n    return this.container\n  }\n\n  // Color accessors\n  getCSS () {\n    const h = Math.round(this.hue * (360 / TAU))\n    const s = Math.round(this.saturation * 100)\n    const l = Math.round(this.lightness * 100)\n\n    return `hsl(${h}, ${s}%, ${l}%)`\n  }\n\n  getHEX () {\n    return rgb2hex(...this.getRGB())\n  }\n\n  setHEX (hex) {\n    this.setRGB(...hex2rgb(hex))\n  }\n\n  getRGB () {\n    return hsl2rgb(...this.getHSL())\n  }\n\n  setRGB (r, g, b) {\n    this.setHSL(...rgb2hsl(r, g, b))\n  }\n\n  getHSL () {\n    return [this.hue, this.saturation, this.lightness]\n  }\n\n  setHSL (h, s, l) {\n    this.hue = h\n    this.saturation = s\n    this.lightness = l\n\n    this.initColor()\n  }\n\n  initColor () {\n    this.calculatePositions()\n    this.moveWheelPointer()\n    this.drawTriangle()\n    this.moveTrianglePointer()\n  }\n\n  // Mouse event handling\n  attachEvents () {\n    this.down = null\n\n    let mousedown = (evt) => {\n      evt.stopPropagation()\n      evt.preventDefault()\n\n      doc.body.addEventListener('mousemove', mousemove, false)\n      doc.body.addEventListener('mouseup', mouseup, false)\n\n      let xy = this.getRelativeCoordinates(evt)\n      this.map(xy.x, xy.y)\n    }\n\n    let mousemove = (evt) => {\n      let xy = this.getRelativeCoordinates(evt)\n      this.move(xy.x, xy.y)\n    }\n\n    let mouseup = (evt) => {\n      if (this.down) {\n        this.down = null\n        this.emit('dragend')\n      }\n      doc.body.removeEventListener('mousemove', mousemove, false)\n      doc.body.removeEventListener('mouseup', mouseup, false)\n    }\n\n    this.container.addEventListener('mousedown', mousedown, false)\n    this.container.addEventListener('mousemove', mousemove, false)\n  }\n\n  map (x, y) {\n    let x0 = x\n    let y0 = y\n    x -= this.wheelRadius\n    y -= this.wheelRadius\n\n    const r = M.sqrt(x * x + y * y) // Pythagoras\n    if (r > this.triangleRadius && r < this.wheelRadius) {\n      // Wheel\n      this.down = 'wheel'\n      this.emit('dragstart')\n      this.move(x0, y0)\n    } else if (r < this.triangleRadius) {\n      // Inner circle\n      this.down = 'triangle'\n      this.emit('dragstart')\n      this.move(x0, y0)\n    }\n  }\n\n  move (x, y) {\n    if (!this.down) {\n      return\n    }\n\n    x -= this.wheelRadius\n    y -= this.wheelRadius\n\n    let rad = M.atan2(-y, x)\n    if (rad < 0) {\n      rad += TAU\n    }\n\n    if (this.down === 'wheel') {\n      this.hue = rad\n      this.initColor()\n      this.emit('drag')\n    } else if (this.down === 'triangle') {\n      // get radius and max radius\n      let rad0 = (rad + TAU - this.hue) % TAU\n      let rad1 = rad0 % (TAU / 3) - (TAU / 6)\n      let a = 0.5 * this.triangleRadius\n      let b = M.tan(rad1) * a\n      let r = M.sqrt(x * x + y * y) // Pythagoras\n      let maxR = M.sqrt(a * a + b * b) // Pythagoras\n\n      if (r > maxR) {\n        const dx = M.tan(rad1) * r\n        let rad2 = M.atan(dx / maxR)\n        if (rad2 > TAU / 6) {\n          rad2 = TAU / 6\n        } else if (rad2 < -TAU / 6) {\n          rad2 = -TAU / 6\n        }\n        rad += rad2 - rad1\n\n        rad0 = (rad + TAU - this.hue) % TAU\n        rad1 = rad0 % (TAU / 3) - (TAU / 6)\n        b = M.tan(rad1) * a\n        r = maxR = M.sqrt(a * a + b * b) // Pythagoras\n      }\n\n      x = M.round(M.cos(rad) * r)\n      y = M.round(-M.sin(rad) * r)\n\n      const l = this.lightness = ((M.sin(rad0) * r) / this.triangleSideLength) + 0.5\n\n      const widthShare = 1 - (M.abs(l - 0.5) * 2)\n      let s = this.saturation = (((M.cos(rad0) * r) + (this.triangleRadius / 2)) / (1.5 * this.triangleRadius)) / widthShare\n      s = M.max(0, s) // cannot be lower than 0\n      s = M.min(1, s) // cannot be greater than 1\n\n      this.lightness = l\n      this.saturation = s\n\n      this.x = x\n      this.y = y\n      this.moveTrianglePointer()\n\n      this.emit('drag')\n    }\n  }\n\n  /***************\n   * Init helpers *\n   ***************/\n\n  static initInput (input, options) {\n    options = options || {}\n\n    let ct\n    let openColorTriangle = function () {\n      let hex = input.value\n      if (options.parseColor) hex = options.parseColor(hex)\n      if (!ct) {\n        options.size = options.size || input.offsetWidth\n        options.background = win.getComputedStyle(input, null).backgroundColor\n        options.margin = options.margin || 10\n        options.event = options.event || 'dragend'\n\n        ct = new ColorTriangle(hex, options)\n        ct.on(options.event, () => {\n          const hex = ct.getHEX()\n          input.value = options.uppercase ? hex.toUpperCase() : hex\n          fireChangeEvent()\n        })\n      } else {\n        ct.setHEX(hex)\n      }\n\n      let top = input.offsetTop\n      if (win.innerHeight - input.getBoundingClientRect().top > input.offsetHeight + options.margin + options.size) {\n        top += input.offsetHeight + options.margin // below\n      } else {\n        top -= options.margin + options.size // above\n      }\n\n      let el = ct.getElement()\n      el.style.position = 'absolute'\n      el.style.left = input.offsetLeft + 'px'\n      el.style.top = top + 'px'\n      el.style.zIndex = '1338' // above everything\n\n      ct.inject(input.parentNode)\n    }\n\n    let closeColorTriangle = () => {\n      if (ct) {\n        ct.dispose()\n      }\n    }\n\n    let fireChangeEvent = () => {\n      let evt = doc.createEvent('HTMLEvents')\n      evt.initEvent('input', true, false) // bubbles = true, cancable = false\n      input.dispatchEvent(evt) // fire event\n    }\n\n    input.addEventListener('focus', openColorTriangle, false)\n    input.addEventListener('blur', closeColorTriangle, false)\n    input.addEventListener('keyup', () => {\n      const val = input.value\n      if (val.match(/^#((?:[0-9A-Fa-f]{3})|(?:[0-9A-Fa-f]{6}))$/)) {\n        openColorTriangle()\n        fireChangeEvent()\n      } else {\n        closeColorTriangle()\n      }\n    }, false)\n  }\n\n  /*******************\n   * Helper functions *\n   *******************/\n\n  setOptions (opts) {\n    opts = opts || {}\n    let dflt = this.options\n    let options = this.options = {}\n\n    each(dflt, function (val, key) {\n      options[key] = (opts.hasOwnProperty(key))\n        ? opts[key]\n        : val\n    })\n  }\n}\n\n\n\n// WEBPACK FOOTER //\n// ./js/lib/colortriangle.js"],"sourceRoot":""}
\ No newline at end of file
diff --git a/term.html b/term.html
index 687b779..9efbfe9 100644
--- a/term.html
+++ b/term.html
@@ -5,8 +5,8 @@
 	<meta http-equiv="X-UA-Compatible" content="IE=edge">
 	<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, maximum-scale=1">
 	<title>Terminal :: ESPTerm</title>
-	<link href="/css/app.69e5b77.css" rel="stylesheet">
-	<script src="/js/app.69e5b77.js"></script>
+	<link href="/css/app.4a032ee-en.css" rel="stylesheet">
+	<script src="/js/app.4a032ee-en.js"></script>
 	<script>
 		var _root = location.host;
 		var _demo = 1;
@@ -61,7 +61,7 @@
 	</div>
 </div>
 
-<h1 id="screen-title"><!-- Screen title is loaded here by JS --></h1>
+<h1 id="screen-title"><!-- JS, title --></h1>
 <a href="#" id="term-fit-screen" class="mq-tablet-max"><i id="resize-button-icon" class="icn-resize-small"></i></a>
 
 <div id="term-wrap">
@@ -76,7 +76,7 @@
 		<div class="screen-margin bottom"></div>
 	</div>
 
-	<div id="action-buttons"></div>
+	<div id="action-buttons"><!-- JS, buttons --></div>
 </div>
 
 <nav id="term-nav">