* Copied current state of dash.html to default index.html.
authorUrban Wallasch <urban.wallasch@freenet.de>
Fri, 9 Aug 2019 07:51:29 +0000 (09:51 +0200)
committerUrban Wallasch <urban.wallasch@freenet.de>
Fri, 9 Aug 2019 07:51:29 +0000 (09:51 +0200)
index.html

index 4d7e61a810619fd5818a63aedccd94d999b25b47..3b8a81e345d41fbd525a648f17c634687b63060e 100644 (file)
@@ -12,31 +12,514 @@ html, body {
   background-color: black;
   color: white;
 }
+x-page {
+  display: block;
+  width: 100%;
+}
+
+x-boxleft, x-boxright {
+  display: block;
+  border: none;
+}
+x-boxleft { float:left; }
+x-boxright { float:right; }
+
+.clear {
+  clear:both;
+}
+.cont {
+  min-width:14.5em;
+  padding: 2px;
+  border: solid 1px grey;
+}
+.bar {
+  min-width:14.5em;
+}
+
+table, caption, tbody, tfoot, thead, tr, th, td {
+  width: auto;
+  height: auto;
+  margin: 0;
+  padding: 0;
+  border: 0;
+  border-collapse: collapse;
+  outline: 0;
+  vertical-align: baseline;
+  background: transparent;
+}
+table { width: 100%; }
+
+.aright { text-align: right; }
+.aleft { text-align: left; }
+.acenter { text-align: center; }
+.ajust { text-align: justify; }
 
-.speed {
-  font-size: 8em;
+.big { font-size: 8em; }
+.medium { font-size: 4em; }
+.small { font-size: 2.5em; }
+.smaller { font-size: 1.8em; }
+.tiny { font-size: 1em; }
+.tinyb { font-size: 1em; font-weight: bold; }
+
+.warn1 { color:#fd0; }
+.warn2 { color:#f20; }
+.setval { color:#0af; }
+.hilite { background-color: #ff0; }
+.special { font-size:50%; color:#088; }
+
+x-bar {
+  display: block;
+  clear: both;
+  width: 100%;
+  padding: 3px;
+  font-size: 150%;
+}
+.pause {
+  background-color:#fd0;
+  color: #000;
+  display: none;
+}
+.error {
+  background-color:#a00;
+  color: #fff;
+  display: none;
+}
+.nosleep {
+  background-color: #000;
+  color: #ff8;
+  font-size: 90%;
+}
+.nosleepon {
+  color: #af8;
 }
+
 </style>
 </head>
 <body>
-<div id="speed" class="speed">77</div>
-<div id="cctrl" class="speed">12</div>
-<script>
-function loadDoc() {
-  xhttp.onreadystatechange = function() {
-    if (this.readyState == 4 && this.status == 200) {
-      tele = JSON.parse(this.responseText);
-      document.getElementById("speed").innerHTML = Math.round(tele.speed * 3.6);
-      document.getElementById("cctrl").innerHTML = Math.round(tele.cctrl * 3.6);
+
+<x-page id="page">
+
+<x-boxleft id="speedo" class="cont">
+  <table>
+    <tr><td colspan="2" class="aright"><span class="big" id="speed">--</span></td><td><span class="tinyb"> km/h</span></td></tr>
+    <tr>
+      <td class="small"><svg width="50" height="50">
+        <circle cx="25" cy="25" r="22" stroke="red" stroke-width="6" fill="white" id="nav_slimitsign"/>
+        <text fill="#000" font-size="24" font-family="sans-serif" font-weight="normal" x="10" y="34" id="nav_slimit">&nbsp;–</text>
+      </svg>&nbsp;&nbsp;</td>
+      <td class="aright"><span class="medium setval" id="cctrl">-</span></td><td><span class="tinyb"> km/h</span></td>
+    </tr>
+    <tr><td><span class="small setval" id="gear">-</span></td>
+        <td class="aright"><span class="small" id="rpm">-</span></td><td><span class="tinyb"> rpm</span></td></tr>
+  </table>
+</x-boxleft>
+
+<x-boxleft id="range" class="cont">
+  <table>
+    <tr><td class="tiny">Fuel</td><td class="aright"><span class="small" id="fuel">-</span></td><td><span class="tinyb"> l</span></td></tr>
+    <tr><td class="tiny">Range</td><td class="aright"><span class="small" id="fuel_range">-</span></td><td><span class="tinyb"> km</span></td></tr>
+    <tr><td class="tiny">Current</td><td class="aright" colspan="2"><span class="smaller" id="fuel_cons">-</span><span class="tinyb"> l/100km</span></td></tr>
+    <tr><td class="tiny">Average</td><td class="aright" colspan="2"><span class="smaller" id="fuel_avg">-</span><span class="tinyb"> l/100km</span></td></tr>
+    <tr><td class="tiny">Mileage</td><td class="aright" colspan="2"><span class="smaller" id="odometer">-</span><span class="tinyb">km</span></td></tr>
+  </table>
+</x-boxleft>
+
+<x-boxleft id="nav" class="cont">
+  <table>
+    <tr><td class="tiny">Distance</td><td><span class="small" id="nav_dist">-</span><span class="tinyb"> km</span></td></tr>
+    <tr><td class="tiny">ETA</td><td><span class="small" id="nav_eta">-</span></td></tr>
+    <tr><td class="tiny">Next rest</td><td><span class="small" id="next_rest">-</span></td></tr>
+    <tr><td class="tiny">Deadline</td><td><span class="small" id="job_ttd">-</span></td></tr>
+  </table>
+</x-boxleft>
+
+<x-boxleft id="job" class="cont">
+  <table>
+    <tr><td class="tiny">Vehicle&nbsp;</td><td><span class="tinyb" id="vehicle">-</span></td></tr>
+    <tr><td class="tiny">Trailers&nbsp;</td><td><span class="tinyb" id="trailer">-</span></td></tr>
+    <tr><td class="tiny">Cargo&nbsp;</td><td><span class="tinyb" id="cargo">-</span></td></tr>
+    <tr><td class="tiny">Mass&nbsp;</td><td><span class="tinyb" id="cargomass">-</span></td></tr>
+    <tr><td class="tiny">From&nbsp;</td><td><span class="tinyb" id="source">-</span></td></tr>
+    <tr><td class="tiny">To&nbsp;</td><td><span class="tinyb" id="destination">-</span></td></tr>
+    <tr><td class="tiny">Reward&nbsp;</td><td><span class="tinyb" id="reward">-</span></td></tr>
+  </table>
+</x-boxleft>
+
+<x-boxleft id="range" class="bar clear">
+  <x-bar class="pause" id="pausebar">Paused</x-bar>
+  <x-bar class="error" id="errbar">&nbsp;</x-bar>
+  <x-bar class="nosleep" id="nsbar">&nbsp;</x-bar>
+</x-boxleft>
+
+</x-page>
+
+<script type="text/javascript">
+
+// Element references:
+var speed = document.getElementById("speed");
+var nav_slimitsign = document.getElementById("nav_slimitsign");
+var cctrl = document.getElementById("cctrl");
+var gear = document.getElementById("gear");
+var rpm = document.getElementById("rpm");
+//
+var fuel = document.getElementById("fuel");
+var fuel_range = document.getElementById("fuel_range");
+var fuel_cons = document.getElementById("fuel_cons");
+var fuel_avg = document.getElementById("fuel_avg");
+var odometer = document.getElementById("odometer");
+//
+var nav_dist = document.getElementById("nav_dist");
+var nav_eta = document.getElementById("nav_eta");
+var nav_slimit = document.getElementById("nav_slimit");
+var next_rest = document.getElementById("next_rest");
+var job_ttd = document.getElementById("job_ttd");
+//
+var vehicle = document.getElementById("vehicle");
+var trailer = document.getElementById("trailer");
+var cargo = document.getElementById("cargo");
+var cargomass = document.getElementById("cargomass");
+var source = document.getElementById("source");
+var destination = document.getElementById("destination");
+var reward = document.getElementById("reward");
+//
+var errbar = document.getElementById("errbar");
+var pausebar = document.getElementById("pausebar");
+var nsbar = document.getElementById("nsbar");
+
+// Helper functions:
+
+function pad2( x ) {
+  return x > 9 ? x : '0' + x;
+}
+
+function s2hms(s) {
+  var sgn = Math.sign(s);
+  s = Math.abs(s);
+  return ( sgn < 0 ? '-' : '' )
+       + pad2( Math.floor(s / 3600) ) + ':'
+       + pad2( Math.floor(s % 3600 / 60) ) + ':'
+       + pad2( Math.floor(s % 60 ) );
+}
+
+function s2hm(s) {
+  var sgn = Math.sign(s);
+  s = Math.abs(s);
+  return ( sgn < 0 ? '-' : '' )
+       + pad2( Math.floor(s / 3600) ) + ':'
+       + pad2( Math.floor(s % 3600 / 60) );
+}
+
+function m2hm(s) {
+  var sgn = Math.sign(s);
+  s = Math.abs(s);
+  return ( sgn < 0 ? '-' : '' )
+       + pad2( Math.floor(s / 60) ) + ':'
+       + pad2( Math.floor(s % 60) );
+}
+
+function warn(elem, lvl) {
+  if ( lvl == 0 ) {
+    elem.classList.remove("warn1");
+    elem.classList.remove("warn2");
+  }
+  else if ( lvl == 1 ) {
+    elem.classList.remove("warn2");
+    elem.classList.add("warn1");
+  }
+  else {
+    elem.classList.remove("warn1");
+    elem.classList.add("warn2");
+  }
+}
+
+// We try to deduce the correct forward gear number to display from
+// the number of gears available. This is likely just plain nonsense!
+function dgear(x, f, m) {
+  if ( x > 0 )
+    return ( m ? '' : 'A' ) + ( f==14 ? ( x<3 ? 'C'+x : x-2 ) : x );
+  if ( x < 0 )
+    return 'R' + -x;
+  return 'N';
+}
+
+// Return current time stamp in seconds:
+function tnow() {
+  return Math.floor(Date.now() / 1000);
+}
+
+// Timestamp of last activity, used for NoSleep timeout:
+var last_active = tnow();
+
+// Used to calculate current fuel consumption:
+var last_fuel = -1;
+var last_odometer = -1;
+
+// Display update callback:
+function update_cb() {
+  if (this.readyState == 4 && this.status == 200) {
+    var tele = JSON.parse(this.responseText);
+
+    //// pause and error bar status:
+
+    if ( !(tele.tele_flags & 1) ) {  // TELE_FLAG_ALIVE
+      if ( tnow() - last_active > 300 ) // 5 minutes NoSleep timeout
+        disableNoSleep();
+      pausebar.style.display = "none";
+      errbar.style.display = "block";
+      errbar.innerHTML = "Game offline";
+      return;
     }
-  };
+    else if ( tele.tele_version !== 1 ) {  // TELE_VERSION
+      errbar.style.display = "block";
+      errbar.innerHTML = "Version mismatch";
+    } else {
+      errbar.style.display = "none";
+    }
+
+    if ( tele.paused ) {
+      if ( tnow() - last_active > 600 ) // 10 minutes NoSleep timeout
+        disableNoSleep();
+      pausebar.style.display = "block";
+    }
+    else {
+      last_active = tnow();
+      pausebar.style.display = "none";
+    }
+
+    //// "speedo" box
+
+    // speedometer:
+    var aspeed = Math.abs( tele.speed );
+    speed.innerHTML = (aspeed * 3.6).toFixed(0);
+    if ( tele.nav_slimit > 0 && aspeed > tele.nav_slimit + 1.9 )
+      warn( speed, 2 );
+    else if ( tele.nav_slimit > 0 && aspeed > tele.nav_slimit + 0.3 )
+      warn( speed, 1 );
+    else
+      warn( speed, 0 );
+    // speed limit:
+    if ( tele.nav_slimit > 0 ) {
+      nav_slimit.innerHTML = (tele.nav_slimit * 3.6).toFixed(0);
+      nav_slimitsign.style.visibility = "visible";
+    }
+    else
+      nav_slimitsign.style.visibility = "hidden";
+    // cruise control:
+    cctrl.innerHTML = Math.round(tele.cctrl * 3.6);
+    // engine gear:
+    gear.innerHTML = dgear(tele.gear_disp, tele.gear_fwdcnt, tele.shifter);
+    if ( tele.clutch_eff > 0 )
+      gear.classList.add("hilite");
+    else
+      gear.classList.remove("hilite");
+    // engine rpm:
+    rpm.innerHTML = tele.rpm.toFixed(0);
+
+    //// "range" box
+
+    // fuel amount:
+    fuel.innerHTML = (tele.fuel - 0.5).toFixed(0);
+    warn( fuel, tele.fuel_warn ? 1 : 0 );
+
+    // estimated range remaining:
+    fuel_range.innerHTML = (tele.fuel_range - 0.5).toFixed(0);
+
+    // current fuel consumption:
+    if ( last_fuel != tele.fuel && last_odometer != tele.odometer ) {
+      if ( last_fuel > 0 && last_odometer > 0 ) {
+        var fc = (last_fuel-tele.fuel)*100 / (tele.odometer-last_odometer);
+        fuel_cons.innerHTML = fc > 999 ? '∞' : fc.toFixed(1);
+      }
+      last_fuel = tele.fuel;
+      last_odometer = tele.odometer;
+    }
+    else if ( tele.speed > 1 && tele.throttle_eff < 0.01 && tele.clutch_eff < 0.1 ) {
+      fuel_cons.innerHTML = '0';
+    }
+    else if ( tele.speed < 0.1 ) {
+      fuel_cons.innerHTML = tele.rpm < 0.1 ? '-' : '∞';
+    }
+    else {
+      // keep last displayed value
+    }
+
+    // average fuel consumption:
+    fuel_avg.innerHTML = (tele.fuel_avg * 100).toFixed(1);
+
+    // odometer:
+    odometer.innerHTML = tele.odometer.toFixed(1);
+
+    //// "nav" box
+
+    // remaining distance to destination:
+    nav_dist.innerHTML = (tele.nav_dist / 1000).toFixed(0);
+
+    // estimated time till arrival at destination:
+    nav_eta.innerHTML = s2hm(tele.nav_eta);
+
+    // time until next rest stop:
+    next_rest.innerHTML = m2hm(tele.next_rest);
+    warn( next_rest, tele.next_rest < 60 ? 2 : tele.next_rest < 99 ? 1 : 0 );
+
+    // remaining time until job delivery date:
+    job_ttd.innerHTML =
+      tele.job_isvalid
+      ? tele.job_deltime != 4294967295
+        ? m2hm(tele.job_deltime - tele.game_time)
+        : '<span class="special">[external]</span>'
+      : '-'
+
+    //// "job" box
+
+    // make and model of truck and number of trailers
+    vehicle.innerHTML = tele.truck_brand + ' ' + tele.truck_name;
+    trailer.innerHTML = tele.trailer_cnt;
+    cargo.innerHTML = tele.job_isvalid ? tele.job_cargo : '-';
+    cargomass.innerHTML = tele.job_isvalid ? (tele.job_cargo_mass / 1000).toFixed(0) + 't' : '-';
+    source.innerHTML = tele.job_isvalid ? tele.job_source_city : '-';
+    destination.innerHTML = tele.job_isvalid ? tele.job_destination_city : '-';
+    reward.innerHTML = tele.job_isvalid ? tele.job_income + '.-' : '-';
+  }
+  else if (this.readyState == 4) {
+    disableNoSleep();
+    // Show error status:
+    pausebar.style.display = "none";
+    errbar.style.display = "block";
+    if ( this.status )
+      errbar.innerHTML = "Status: " + this.status + "<br>" + this.responseText;
+    else
+      errbar.innerHTML = "Connection error";
+  }
+};
+
+function loadDoc() {
   xhttp.open("GET", "/json", true);
   xhttp.send();
 }
+
+// XHRequest:
 var xhttp = new XMLHttpRequest();
-loadDoc();
-window.setInterval(loadDoc, 500);
-</script>
+xhttp.onreadystatechange = update_cb;
+window.setInterval(loadDoc, 333);
+
+
+////////////////////////////////////////////////////////////////
+// Begin disable mobile sleep.
+//
+// See: https://github.com/richtr/NoSleep.js/blob/master/src
+////////////////////////////////////////////////////////////////
+
+const webm = 'data:video/webm;base64,GkXfo0AgQoaBAUL3gQFC8oEEQvOBCEKCQAR3ZWJtQoeBAkKFgQIYU4BnQI0VSalmQCgq17FAAw9CQE2AQAZ3aGFtbXlXQUAGd2hhbW15RIlACECPQAAAAAAAFlSua0AxrkAu14EBY8WBAZyBACK1nEADdW5khkAFVl9WUDglhohAA1ZQOIOBAeBABrCBCLqBCB9DtnVAIueBAKNAHIEAAIAwAQCdASoIAAgAAUAmJaQAA3AA/vz0AAA=';
+const mp4 = 'data:video/mp4;base64,AAAAIGZ0eXBtcDQyAAACAGlzb21pc28yYXZjMW1wNDEAAAAIZnJlZQAACKBtZGF0AAAC8wYF///v3EXpvebZSLeWLNgg2SPu73gyNjQgLSBjb3JlIDE0MiByMjQ3OSBkZDc5YTYxIC0gSC4yNjQvTVBFRy00IEFWQyBjb2RlYyAtIENvcHlsZWZ0IDIwMDMtMjAxNCAtIGh0dHA6Ly93d3cudmlkZW9sYW4ub3JnL3gyNjQuaHRtbCAtIG9wdGlvbnM6IGNhYmFjPTEgcmVmPTEgZGVibG9jaz0xOjA6MCBhbmFseXNlPTB4MToweDExMSBtZT1oZXggc3VibWU9MiBwc3k9MSBwc3lfcmQ9MS4wMDowLjAwIG1peGVkX3JlZj0wIG1lX3JhbmdlPTE2IGNocm9tYV9tZT0xIHRyZWxsaXM9MCA4eDhkY3Q9MCBjcW09MCBkZWFkem9uZT0yMSwxMSBmYXN0X3Bza2lwPTEgY2hyb21hX3FwX29mZnNldD0wIHRocmVhZHM9NiBsb29rYWhlYWRfdGhyZWFkcz0xIHNsaWNlZF90aHJlYWRzPTAgbnI9MCBkZWNpbWF0ZT0xIGludGVybGFjZWQ9MCBibHVyYXlfY29tcGF0PTAgY29uc3RyYWluZWRfaW50cmE9MCBiZnJhbWVzPTMgYl9weXJhbWlkPTIgYl9hZGFwdD0xIGJfYmlhcz0wIGRpcmVjdD0xIHdlaWdodGI9MSBvcGVuX2dvcD0wIHdlaWdodHA9MSBrZXlpbnQ9MzAwIGtleWludF9taW49MzAgc2NlbmVjdXQ9NDAgaW50cmFfcmVmcmVzaD0wIHJjX2xvb2thaGVhZD0xMCByYz1jcmYgbWJ0cmVlPTEgY3JmPTIwLjAgcWNvbXA9MC42MCBxcG1pbj0wIHFwbWF4PTY5IHFwc3RlcD00IHZidl9tYXhyYXRlPTIwMDAwIHZidl9idWZzaXplPTI1MDAwIGNyZl9tYXg9MC4wIG5hbF9ocmQ9bm9uZSBmaWxsZXI9MCBpcF9yYXRpbz0xLjQwIGFxPTE6MS4wMACAAAAAOWWIhAA3//p+C7v8tDDSTjf97w55i3SbRPO4ZY+hkjD5hbkAkL3zpJ6h/LR1CAABzgB1kqqzUorlhQAAAAxBmiQYhn/+qZYADLgAAAAJQZ5CQhX/AAj5IQADQGgcIQADQGgcAAAACQGeYUQn/wALKCEAA0BoHAAAAAkBnmNEJ/8ACykhAANAaBwhAANAaBwAAAANQZpoNExDP/6plgAMuSEAA0BoHAAAAAtBnoZFESwr/wAI+SEAA0BoHCEAA0BoHAAAAAkBnqVEJ/8ACykhAANAaBwAAAAJAZ6nRCf/AAsoIQADQGgcIQADQGgcAAAADUGarDRMQz/+qZYADLghAANAaBwAAAALQZ7KRRUsK/8ACPkhAANAaBwAAAAJAZ7pRCf/AAsoIQADQGgcIQADQGgcAAAACQGe60Qn/wALKCEAA0BoHAAAAA1BmvA0TEM//qmWAAy5IQADQGgcIQADQGgcAAAAC0GfDkUVLCv/AAj5IQADQGgcAAAACQGfLUQn/wALKSEAA0BoHCEAA0BoHAAAAAkBny9EJ/8ACyghAANAaBwAAAANQZs0NExDP/6plgAMuCEAA0BoHAAAAAtBn1JFFSwr/wAI+SEAA0BoHCEAA0BoHAAAAAkBn3FEJ/8ACyghAANAaBwAAAAJAZ9zRCf/AAsoIQADQGgcIQADQGgcAAAADUGbeDRMQz/+qZYADLkhAANAaBwAAAALQZ+WRRUsK/8ACPghAANAaBwhAANAaBwAAAAJAZ+1RCf/AAspIQADQGgcAAAACQGft0Qn/wALKSEAA0BoHCEAA0BoHAAAAA1Bm7w0TEM//qmWAAy4IQADQGgcAAAAC0Gf2kUVLCv/AAj5IQADQGgcAAAACQGf+UQn/wALKCEAA0BoHCEAA0BoHAAAAAkBn/tEJ/8ACykhAANAaBwAAAANQZvgNExDP/6plgAMuSEAA0BoHCEAA0BoHAAAAAtBnh5FFSwr/wAI+CEAA0BoHAAAAAkBnj1EJ/8ACyghAANAaBwhAANAaBwAAAAJAZ4/RCf/AAspIQADQGgcAAAADUGaJDRMQz/+qZYADLghAANAaBwAAAALQZ5CRRUsK/8ACPkhAANAaBwhAANAaBwAAAAJAZ5hRCf/AAsoIQADQGgcAAAACQGeY0Qn/wALKSEAA0BoHCEAA0BoHAAAAA1Bmmg0TEM//qmWAAy5IQADQGgcAAAAC0GehkUVLCv/AAj5IQADQGgcIQADQGgcAAAACQGepUQn/wALKSEAA0BoHAAAAAkBnqdEJ/8ACyghAANAaBwAAAANQZqsNExDP/6plgAMuCEAA0BoHCEAA0BoHAAAAAtBnspFFSwr/wAI+SEAA0BoHAAAAAkBnulEJ/8ACyghAANAaBwhAANAaBwAAAAJAZ7rRCf/AAsoIQADQGgcAAAADUGa8DRMQz/+qZYADLkhAANAaBwhAANAaBwAAAALQZ8ORRUsK/8ACPkhAANAaBwAAAAJAZ8tRCf/AAspIQADQGgcIQADQGgcAAAACQGfL0Qn/wALKCEAA0BoHAAAAA1BmzQ0TEM//qmWAAy4IQADQGgcAAAAC0GfUkUVLCv/AAj5IQADQGgcIQADQGgcAAAACQGfcUQn/wALKCEAA0BoHAAAAAkBn3NEJ/8ACyghAANAaBwhAANAaBwAAAANQZt4NExC//6plgAMuSEAA0BoHAAAAAtBn5ZFFSwr/wAI+CEAA0BoHCEAA0BoHAAAAAkBn7VEJ/8ACykhAANAaBwAAAAJAZ+3RCf/AAspIQADQGgcAAAADUGbuzRMQn/+nhAAYsAhAANAaBwhAANAaBwAAAAJQZ/aQhP/AAspIQADQGgcAAAACQGf+UQn/wALKCEAA0BoHCEAA0BoHCEAA0BoHCEAA0BoHCEAA0BoHCEAA0BoHAAACiFtb292AAAAbG12aGQAAAAA1YCCX9WAgl8AAAPoAAAH/AABAAABAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAGGlvZHMAAAAAEICAgAcAT////v7/AAAF+XRyYWsAAABcdGtoZAAAAAPVgIJf1YCCXwAAAAEAAAAAAAAH0AAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAygAAAMoAAAAAACRlZHRzAAAAHGVsc3QAAAAAAAAAAQAAB9AAABdwAAEAAAAABXFtZGlhAAAAIG1kaGQAAAAA1YCCX9WAgl8AAV+QAAK/IFXEAAAAAAAtaGRscgAAAAAAAAAAdmlkZQAAAAAAAAAAAAAAAFZpZGVvSGFuZGxlcgAAAAUcbWluZgAAABR2bWhkAAAAAQAAAAAAAAAAAAAAJGRpbmYAAAAcZHJlZgAAAAAAAAABAAAADHVybCAAAAABAAAE3HN0YmwAAACYc3RzZAAAAAAAAAABAAAAiGF2YzEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAygDKAEgAAABIAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY//8AAAAyYXZjQwFNQCj/4QAbZ01AKOyho3ySTUBAQFAAAAMAEAAr8gDxgxlgAQAEaO+G8gAAABhzdHRzAAAAAAAAAAEAAAA8AAALuAAAABRzdHNzAAAAAAAAAAEAAAABAAAB8GN0dHMAAAAAAAAAPAAAAAEAABdwAAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAAC7gAAAAAQAAF3AAAAABAAAAAAAAABxzdHNjAAAAAAAAAAEAAAABAAAAAQAAAAEAAAEEc3RzegAAAAAAAAAAAAAAPAAAAzQAAAAQAAAADQAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAANAAAADQAAAQBzdGNvAAAAAAAAADwAAAAwAAADZAAAA3QAAAONAAADoAAAA7kAAAPQAAAD6wAAA/4AAAQXAAAELgAABEMAAARcAAAEbwAABIwAAAShAAAEugAABM0AAATkAAAE/wAABRIAAAUrAAAFQgAABV0AAAVwAAAFiQAABaAAAAW1AAAFzgAABeEAAAX+AAAGEwAABiwAAAY/AAAGVgAABnEAAAaEAAAGnQAABrQAAAbPAAAG4gAABvUAAAcSAAAHJwAAB0AAAAdTAAAHcAAAB4UAAAeeAAAHsQAAB8gAAAfjAAAH9gAACA8AAAgmAAAIQQAACFQAAAhnAAAIhAAACJcAAAMsdHJhawAAAFx0a2hkAAAAA9WAgl/VgIJfAAAAAgAAAAAAAAf8AAAAAAAAAAAAAAABAQAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAACsm1kaWEAAAAgbWRoZAAAAADVgIJf1YCCXwAArEQAAWAAVcQAAAAAACdoZGxyAAAAAAAAAABzb3VuAAAAAAAAAAAAAAAAU3RlcmVvAAAAAmNtaW5mAAAAEHNtaGQAAAAAAAAAAAAAACRkaW5mAAAAHGRyZWYAAAAAAAAAAQAAAAx1cmwgAAAAAQAAAidzdGJsAAAAZ3N0c2QAAAAAAAAAAQAAAFdtcDRhAAAAAAAAAAEAAAAAAAAAAAACABAAAAAArEQAAAAAADNlc2RzAAAAAAOAgIAiAAIABICAgBRAFQAAAAADDUAAAAAABYCAgAISEAaAgIABAgAAABhzdHRzAAAAAAAAAAEAAABYAAAEAAAAABxzdHNjAAAAAAAAAAEAAAABAAAAAQAAAAEAAAAUc3RzegAAAAAAAAAGAAAAWAAAAXBzdGNvAAAAAAAAAFgAAAOBAAADhwAAA5oAAAOtAAADswAAA8oAAAPfAAAD5QAAA/gAAAQLAAAEEQAABCgAAAQ9AAAEUAAABFYAAARpAAAEgAAABIYAAASbAAAErgAABLQAAATHAAAE3gAABPMAAAT5AAAFDAAABR8AAAUlAAAFPAAABVEAAAVXAAAFagAABX0AAAWDAAAFmgAABa8AAAXCAAAFyAAABdsAAAXyAAAF+AAABg0AAAYgAAAGJgAABjkAAAZQAAAGZQAABmsAAAZ+AAAGkQAABpcAAAauAAAGwwAABskAAAbcAAAG7wAABwYAAAcMAAAHIQAABzQAAAc6AAAHTQAAB2QAAAdqAAAHfwAAB5IAAAeYAAAHqwAAB8IAAAfXAAAH3QAAB/AAAAgDAAAICQAACCAAAAg1AAAIOwAACE4AAAhhAAAIeAAACH4AAAiRAAAIpAAACKoAAAiwAAAItgAACLwAAAjCAAAAFnVkdGEAAAAObmFtZVN0ZXJlbwAAAHB1ZHRhAAAAaG1ldGEAAAAAAAAAIWhkbHIAAAAAAAAAAG1kaXJhcHBsAAAAAAAAAAAAAAAAO2lsc3QAAAAzqXRvbwAAACtkYXRhAAAAAQAAAABIYW5kQnJha2UgMC4xMC4yIDIwMTUwNjExMDA=';
+
+// Detect iOS browsers < version 10
+const oldIOS = typeof navigator !== 'undefined' && parseFloat(
+  ('' + (/CPU.*OS ([0-9_]{3,4})[0-9_]{0,1}|(CPU like).*AppleWebKit.*Mobile/i.exec(navigator.userAgent) || [0, ''])[1])
+    .replace('undefined', '3_2').replace('_', '.').replace('_', '')
+) < 10 && !window.MSStream
+
+class NoSleep {
+  constructor () {
+    if (oldIOS) {
+      this.noSleepTimer = null
+    } else {
+      // Set up no sleep video element
+      this.noSleepVideo = document.createElement('video')
+
+      this.noSleepVideo.setAttribute('muted', '')
+      this.noSleepVideo.setAttribute('title', 'No Sleep')
+      this.noSleepVideo.setAttribute('playsinline', '')
+
+      this._addSourceToVideo(this.noSleepVideo, 'webm', webm)
+      this._addSourceToVideo(this.noSleepVideo, 'mp4', mp4)
+
+      this.noSleepVideo.addEventListener('loadedmetadata', () => {
+        if (this.noSleepVideo.duration <= 1) { // webm source
+          this.noSleepVideo.setAttribute('loop', '')
+        } else { // mp4 source
+          this.noSleepVideo.addEventListener('timeupdate', () => {
+            if (this.noSleepVideo.currentTime > 0.5) {
+              this.noSleepVideo.currentTime = Math.random()
+            }
+          })
+        }
+      })
+    }
+  }
+
+  _addSourceToVideo (element, type, dataURI) {
+    var source = document.createElement('source')
+    source.src = dataURI
+    source.type = `video/${type}`
+    element.appendChild(source)
+  }
 
+  enable () {
+    if (oldIOS) {
+      this.disable()
+      console.warn(`
+        NoSleep enabled for older iOS devices. This can interrupt
+        active or long-running network requests from completing successfully.
+        See https://github.com/richtr/NoSleep.js/issues/15 for more details.
+      `)
+      this.noSleepTimer = window.setInterval(() => {
+        if (!document.hidden) {
+          window.location.href = window.location.href.split('#')[0]
+          window.setTimeout(window.stop, 0)
+        }
+      }, 15000)
+    } else {
+      this.noSleepVideo.play()
+    }
+  }
+
+  disable () {
+    if (oldIOS) {
+      if (this.noSleepTimer) {
+        console.warn(`
+          NoSleep now disabled for older iOS devices.
+        `)
+        window.clearInterval(this.noSleepTimer)
+        this.noSleepTimer = null
+      }
+    } else {
+      this.noSleepVideo.pause()
+    }
+  }
+};
+
+var noSleep = new NoSleep();
+
+// Enable wake lock.
+// (must be wrapped in a user input event handler e.g. a mouse or touch handler)
+function installNoSleepHandler() {
+  document.addEventListener(
+    'click',
+    function enableNoSleep() {
+      document.removeEventListener('click', enableNoSleep, false);
+      noSleep.enable();
+      nsbar.innerHTML = "NoSleep enabled.";
+      nsbar.classList.add("nosleepon");
+      last_active = tnow();
+    },
+    false
+  );
+}
+
+// Disable wake lock and reinstall wake lock handler.
+function disableNoSleep() {
+  noSleep.disable();
+  installNoSleepHandler();
+  nsbar.innerHTML = "Click page to enable NoSleep.";
+  nsbar.classList.remove("nosleepon");
+}
+
+disableNoSleep();
+
+////////////////////////////////////////////////////////////////
+// End disable mobile sleep.
+////////////////////////////////////////////////////////////////
+
+</script>
 </body>
 </html>