~ merge
authorAlexandre Bertails <bertails@w3.org>
Mon, 22 Aug 2011 14:29:53 -0400
changeset 6 8aba95009ca5
parent 5 33c98cb357ea (current diff)
parent 4 500ec4cfbf0e (diff)
child 7 5ccfff98678e
child 8 a576ef67fea1
~ merge
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/scripts/tracker.js	Mon Aug 22 14:29:53 2011 -0400
@@ -0,0 +1,383 @@
+
+function buildMessage(data, boundary) {
+    var CRLF = "\r\n";
+    var parts = [];
+    var iter = 0;
+
+    while (iter < data.length) {
+        var part = "";
+        var type = "TEXT";
+
+        part = 'Content-Disposition: form-data; ';
+        part += 'name="' + data[iter][0] + '"' + CRLF + CRLF;
+
+        part += data[iter][1] + CRLF;
+
+        parts.push(part);
+        iter++;
+    }
+
+    var request = "--" + boundary + CRLF;
+        request+= parts.join("--" + boundary + CRLF);
+        request+= "--" + boundary + "--" + CRLF;
+
+    return request;
+}
+
+function send(user, data) {
+    var boundary = "AJAX-----------------------" + Date.now();
+    var xhr = new XMLHttpRequest;
+
+    if (!("withCredentials" in xhr)) {
+      return false;
+    }    
+
+    try {
+    xhr.open("POST", "http://teole.jfouffa.org/2011/07/html5track.php", true);
+    xhr.setRequestHeader('X-HTML5TRACK', 'true');
+    xhr.onreadystatechange = function() {
+        switch (xhr.readyState) {
+         case 4:
+            document.getElementById("log").textContent = "xhr done " + xhr.status + " " + xhr.statusText;
+            break;
+         case 0:
+            document.getElementById("log").textContent = "xhr unsent";
+            break;
+         case 1:
+            document.getElementById("log").textContent = "xhr opened";
+            break;
+         case 2:
+            document.getElementById("log").textContent = "xhr headers_received";
+            break;
+         case 3:
+            document.getElementById("log").textContent = "xhr loading";
+            break;
+        }
+    };
+    var contentType = "multipart/form-data; boundary=" + boundary;
+    xhr.setRequestHeader("Content-Type", contentType);
+
+    var data = buildMessage([ ["user", user], ["gps_coords", data] ], boundary);
+
+    xhr.sendAsBinary(data);
+
+    } catch (e) {
+      return false;
+    }
+   return true;
+}
+
+var storage = (function() {
+     try {
+       return !!window.localStorage.getItem;
+     } catch (e) {
+       return false;
+     }
+})();
+
+
+
+var watchId = 0;
+var running = false;
+
+var duration = 0;
+var start_time = 0;
+var intervalId = 0;
+
+// wait for at least 5 consecutive GPS data before declaring the GPS ready
+var MAX_ERRORS = 2;
+var got_error = MAX_ERRORS;
+
+var discarded = 0;
+var locations = 0;
+
+var coordinates = [];
+
+var dst_unit = 1;
+
+function formatNumber(n) {
+  return (n < 10)? "0" + n : n;
+}  
+
+function formatTime(time) {
+ t = parseInt(time);
+ hours = parseInt(t / 3600);
+ minutes = parseInt(t / 60);
+ seconds = t - ((hours * 3600) + (minutes * 60));
+ return ((hours > 0)?  formatNumber(hours) + ":": "") + formatNumber(minutes) + ":" + formatNumber(seconds);
+}
+
+
+
+
+function pushCoordinates(position) {
+   coordinates[coordinates.length] =
+    [ position.timestamp, position.coords.longitude, position.coords.latitude, position.coords.altitude, position.coords.speed ];
+//    [ position.timestamp, position.coords.longitude, position.coords.latitude, position.coords.altitude ];
+}
+
+function pause() {
+   coordinates[coordinates.length] = [ Date.now(), "pause", 0, 0, 0, 0 ];
+}
+
+function getLastCoordinates() {
+   return (coordinates.length > 0)? coordinates[coordinates.length - 1] : null;
+}
+
+function getCoordinates() {
+  if (coordinates.length > 0 && !running) {
+    var result = "";
+    var i = 0;
+    while (i < coordinates.length) {
+      var position = coordinates[i];
+      var j = 1;
+      result += position[0];
+      while (j < position.length) result += "," + position[j++];      
+      result += " ";
+      i++;
+    }
+    return result;
+  }
+  return null;
+}
+
+function calculateDistance(lat1, lon1, lat2, lon2) {
+ var R = 6371; // km
+ var dLat = (lat2-lat1) * Math.PI / 180;
+ var dLon = (lon2-lon1) * Math.PI / 180;
+ var lat1 = lat1  * Math.PI / 180;
+ var lat2 = lat2 * Math.PI / 180;
+ var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
+        Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(lat1) * Math.cos(lat2); 
+ var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); 
+ var d = R * c;
+ return d;
+}
+
+function calculateDistanceCoordinates() {
+  var result = 0;
+  if (coordinates.length > 0) {
+    var i = 1;
+    while (i < coordinates.length) {
+      var position1 = coordinates[i-1];
+      var position2 = coordinates[i];
+      result += calculateDistance(position1[2], position1[1], position2[2], position2[1]);
+      i++;
+    }
+  }
+  return result;
+}
+
+function calculateDurationCoordinates() {
+  var result = 0;
+  if (coordinates.length > 0) {
+    var i = 1;
+    while (i < coordinates.length) {
+      var position1 = coordinates[i-1];
+      var position2 = coordinates[i];
+      result += (position2[0]- position1[0]);
+      i++;
+    }
+  }
+  return result;
+}
+
+function repaint() {
+  if (document.visibilityState == true && running) {
+    document.getElementById("locations").textContent = String(locations);
+    var d = calculateDistanceCoordinates() * dst_unit;
+    var t = duration + (Date.now() - start_time);
+    document.getElementById("distance").textContent = String(Math.round(d*100)/100);
+    if (t != 0 && d != 0) {
+      document.getElementById("speed").textContent = String(Math.round( (d / (t / 3600000)) * 100) / 100);
+      document.getElementById("pace").textContent = String(Math.round( ((t / 60000)/d) * 100) / 100);
+    }
+    if (coordinates.length > 0) {
+      document.getElementById("gps_text").style.display = "none";
+      document.getElementById("gps_data").style.display = "inline";
+    }
+  }
+}
+
+function logGPS(position, startMsg) {
+    document.getElementById("log").textContent = 
+      startMsg + position.timestamp 
+       + ": " + position.coords.latitude
+       + ", " + position.coords.longitude
+       + ", " + position.coords.altitude
+       + ", " + position.coords.accuracy
+       + ", " + position.coords.altitudeAccuracy
+       + ", " + position.coords.heading
+       + ", " + position.coords.speed;
+}
+
+function handleSuccess(position) {
+  if (running) {
+   logGPS(position, "GPS: ");
+
+    // discard positions that have no altitude since they're likely inacurate
+    if (position.coords.altitude != null) {
+      pushCoordinates(position);
+      locations++;
+      repaint();
+    } else {
+      document.getElementById("discarded").textContent = String(discarded++);
+    }
+   } else {
+
+
+     if (position.coords.altitude == null) {
+       got_error++;
+       if (got_error > MAX_ERRORS) got_error = MAX_ERRORS;
+           logGPS(position, "[ERROR] GPS: ");
+     } else {
+       got_error--;
+       logGPS(position, "GPS: ");
+     }
+     if (got_error <= 0) {
+       got_error = 0;
+       document.getElementById("gps_text").textContent = "ready";       
+       document.getElementById("waves").style.display = "block";       
+     } else {
+       document.getElementById("gps_text").textContent = "not ready";
+       document.getElementById("waves").style.display = "none";       
+     }
+   }
+}
+
+function handleError(error) {
+  var code = "unknown";
+  switch(error.code) {
+    case error.TIMEOUT:
+      code = "timeout";
+      break;
+    case error.PERMISSION_DENIED:
+      code = "permission denied";
+      break;
+    case error.POSITION_UNAVAILABLE:
+      code = "position unavailable";
+      break;
+  }
+  if (running) {
+    document.getElementById("errors").textContent = String(++got_error);
+    document.getElementById("log").textContent = "[ERROR] GPS: " + code; 
+  } else {
+    document.getElementById("gps_text").textContent = code; 
+    // wait for 5 non-consecutive errors
+    got_error = MAX_ERRORS;
+  }
+}
+
+function timer() {
+  if (document.visibilityState == true) {
+    document.getElementById("realtime").textContent = 
+      formatTime(Math.round((duration+(Date.now()-start_time))/1000));
+  }
+}
+
+function start() {
+  if (!running) {
+   running = true;
+   start_time = Date.now();
+   intervalId = setInterval(timer, 1000);
+   document.getElementById("stop").disabled = false;
+   document.getElementById("start").textContent = "Pause";
+  } else {
+   running = false;
+   clearInterval(intervalId);
+   duration += (Date.now() - start_time);
+   document.getElementById("start").textContent = "Restart";
+   pause();
+   document.getElementById("gps_text").style.display = "inline";
+   document.getElementById("gps_data").style.display = "none";
+  }
+}
+
+function stop() {
+  //  navigator.geolocation.clearWatch(watchId);
+  running = false;
+  clearInterval(intervalId);
+  got_error = 0;
+  locations = 0;
+  discarded = 0;
+  duration  = 0;
+  document.getElementById("start").textContent = "Start";
+  document.getElementById("stop").disabled = true;
+  document.getElementById("log").textContent = "";
+  var coords = getCoordinates();
+  if (coords != null && storage) {
+    try {
+      window.localStorage.setItem("track_gps_app", coords);
+    } catch (e) {
+      document.getDocumentById("log").textContent = "[ERROR] Can't store the value " + e.code;
+    }
+  }
+  if (coords != null) {
+    if (!send("teole",coords)) {      
+      document.getElementById("gps_coords").value = coords;
+      document.getElementById("xhr_failed").style.display = "inline";
+      document.getElementById("xhr_failed").disabled = false;
+    }
+  }
+  coordinates = [];
+}
+
+function init() {  
+  if (!!document.visibilityState)
+    document.addEventListener("visibilitychange", repaint, false);
+  else
+    document.visibilityState = true;
+
+  // @@ in the future, make sure this is empty
+   if (storage) {
+    window.localStorage.setItem("track_gps_app", "");
+
+    if (window.localStorage.getItem("track_gps_app_dst_unit") === "mile") {
+      dst_unit = 0.621371192;    
+    }
+    setUnit();
+   } else {
+     document.getElementById("log").textContent = "[ERROR] no local storage";
+   }
+   if (!!navigator.geolocation) {
+     watchId = navigator.geolocation.watchPosition(handleSuccess, handleError, {enableHighAccuracy:true, maximumAge:0, timeout:1000});
+   } else {
+     document.getElementById("gps_text").textContent = "not supported";
+     document.getElementById("start").disabled = true;
+   }
+
+    var xhr = new XMLHttpRequest;
+    if (!!xhr && !("withCredentials" in xhr)) {
+      document.getElementById("xhr_failed").style.display = "inline";
+      document.getElementById("xhr_failed").disabled = true;
+    }        
+}
+
+window.addEventListener("load", init, false);
+
+function km() {
+  if (storage) {
+    window.localStorage.setItem("track_gps_app_dst_unit", "km");
+  }
+  dst_unit = 1;
+  setUnit();
+  repaint();
+}
+
+function mile() {
+  if (storage) {
+    window.localStorage.setItem("track_gps_app_dst_unit", "mile");
+  }
+  dst_unit = 0.621371192;    
+  setUnit();
+  repaint();
+}
+
+function setUnit() {  
+  var text = (dst_unit == 0.621371192)? "mile" : "km";
+  var nodes = document.getElementsByClassName("dst_unit");
+  i = 0;
+  do {
+    nodes[i].textContent = text;
+  } while (++i < nodes.length);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/styles/tracker.css	Mon Aug 22 14:29:53 2011 -0400
@@ -0,0 +1,44 @@
+body { background-color: #6699ff; }
+section table { margin: auto; }
+section p { text-align: center;}
+.text { font-size: 150%; }
+button {
+  font-size: 175%;
+  padding-left: 1ex;
+  padding-right: 1ex;
+  margin: 0;
+}
+#log { font-size: 75%; }
+#errors { color: red }
+#discarded { color: #f88 }
+table { border-collapse: collapse; }
+th { text-align: left; border-right: 1px solid #ccc; padding-right: 0.5ex;}
+td:nth-child(2) { text-align: right; width: 8ex; padding-right: 0.5ex;}
+h1 { text-align: right; padding-right: 1ex; font-family: cursive; margin: 0;}
+#gps_data { display: none }
+
+nav #atab0 { color: #ccc; cursor: default; }
+#vtab0:target ~ #tab0 { display: block }
+#vtab0:target ~ #tab1 { display: none }
+#vtab0:target ~ nav #atab1 { color: #6699ff; cursor: pointer; }
+#vtab0:target ~ nav #atab0 { color: #ccc; cursor: default; }
+
+#tab1 { display: none; }
+#vtab1:target ~ #tab0 { display: none }
+#vtab1:target ~ #tab1 { display: block }
+#vtab1:target ~ nav #atab0 { color: #6699ff; cursor: pointer; }
+#vtab1:target ~ nav #atab1 { color: #ccc; cursor: default; }
+
+section.tab_anchor { display: none; }
+
+nav {
+  border-bottom: 1px solid white;
+  padding-bottom: 2px;
+  margin-bottom: 5px;
+}
+nav a {
+  border: 1px solid white;
+  background: white;
+  color: #6699ff;
+  padding: 2px;
+}
--- a/src/main/resources/templates/geolocation.ssp	Mon Aug 22 14:28:09 2011 -0400
+++ b/src/main/resources/templates/geolocation.ssp	Mon Aug 22 14:29:53 2011 -0400
@@ -7,440 +7,9 @@
  <meta name="viewport" content="width=device-width,initial-scale=1.0" />
  <link rel='icon' type='image/png' href='geolocation-icon.png'/>
  <title>HTML5 Track</title>
- <script>
-<![CDATA[
-
-function buildMessage(data, boundary) {
-    var CRLF = "\r\n";
-    var parts = [];
-    var iter = 0;
-
-    while (iter < data.length) {
-        var part = "";
-        var type = "TEXT";
-
-        part = 'Content-Disposition: form-data; ';
-        part += 'name="' + data[iter][0] + '"' + CRLF + CRLF;
-
-        part += data[iter][1] + CRLF;
-
-        parts.push(part);
-        iter++;
-    }
-
-    var request = "--" + boundary + CRLF;
-        request+= parts.join("--" + boundary + CRLF);
-        request+= "--" + boundary + "--" + CRLF;
-
-    return request;
-}
-
-function send(user, data) {
-    var boundary = "AJAX-----------------------" + Date.now();
-    var xhr = new XMLHttpRequest;
-
-    if (!("withCredentials" in xhr)) {
-      return false;
-    }    
-
-    try {
-    xhr.open("POST", "http://teole.jfouffa.org/2011/07/html5track.php", true);
-    xhr.setRequestHeader('X-HTML5TRACK', 'true');
-    xhr.onreadystatechange = function() {
-        switch (xhr.readyState) {
-         case 4:
-            document.getElementById("log").textContent = "xhr done " + xhr.status + " " + xhr.statusText;
-            break;
-         case 0:
-            document.getElementById("log").textContent = "xhr unsent";
-            break;
-         case 1:
-            document.getElementById("log").textContent = "xhr opened";
-            break;
-         case 2:
-            document.getElementById("log").textContent = "xhr headers_received";
-            break;
-         case 3:
-            document.getElementById("log").textContent = "xhr loading";
-            break;
-        }
-    };
-    var contentType = "multipart/form-data; boundary=" + boundary;
-    xhr.setRequestHeader("Content-Type", contentType);
-
-    var data = buildMessage([ ["user", user], ["gps_coords", data] ], boundary);
-
-    xhr.sendAsBinary(data);
-
-    } catch (e) {
-      return false;
-    }
-   return true;
-}
-
-var storage = (function() {
-     try {
-       return !!window.localStorage.getItem;
-     } catch (e) {
-       return false;
-     }
-})();
-
-
-
-var watchId = 0;
-var running = false;
-
-var duration = 0;
-var start_time = 0;
-var intervalId = 0;
-
-// wait for at least 5 consecutive GPS data before declaring the GPS ready
-var MAX_ERRORS = 2;
-var got_error = MAX_ERRORS;
-
-var discarded = 0;
-var locations = 0;
-
-var coordinates = [];
-
-var dst_unit = 1;
-
-function formatNumber(n) {
-  return (n < 10)? "0" + n : n;
-}  
-
-function formatTime(time) {
- t = parseInt(time);
- hours = parseInt(t / 3600);
- minutes = parseInt(t / 60);
- seconds = t - ((hours * 3600) + (minutes * 60));
- return ((hours > 0)?  formatNumber(hours) + ":": "") + formatNumber(minutes) + ":" + formatNumber(seconds);
-}
-
-
-
-
-function pushCoordinates(position) {
-   coordinates[coordinates.length] =
-    [ position.timestamp, position.coords.longitude, position.coords.latitude, position.coords.altitude, position.coords.speed ];
-//    [ position.timestamp, position.coords.longitude, position.coords.latitude, position.coords.altitude ];
-}
-
-function pause() {
-   coordinates[coordinates.length] = [ Date.now(), "pause", 0, 0, 0, 0 ];
-}
-
-function getLastCoordinates() {
-   return (coordinates.length > 0)? coordinates[coordinates.length - 1] : null;
-}
-
-function getCoordinates() {
-  if (coordinates.length > 0 && !running) {
-    var result = "";
-    var i = 0;
-    while (i < coordinates.length) {
-      var position = coordinates[i];
-      var j = 1;
-      result += position[0];
-      while (j < position.length) result += "," + position[j++];      
-      result += " ";
-      i++;
-    }
-    return result;
-  }
-  return null;
-}
-
-function calculateDistance(lat1, lon1, lat2, lon2) {
- var R = 6371; // km
- var dLat = (lat2-lat1) * Math.PI / 180;
- var dLon = (lon2-lon1) * Math.PI / 180;
- var lat1 = lat1  * Math.PI / 180;
- var lat2 = lat2 * Math.PI / 180;
- var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
-        Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(lat1) * Math.cos(lat2); 
- var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); 
- var d = R * c;
- return d;
-}
-
-function calculateDistanceCoordinates() {
-  var result = 0;
-  if (coordinates.length > 0) {
-    var i = 1;
-    while (i < coordinates.length) {
-      var position1 = coordinates[i-1];
-      var position2 = coordinates[i];
-      result += calculateDistance(position1[2], position1[1], position2[2], position2[1]);
-      i++;
-    }
-  }
-  return result;
-}
-
-function calculateDurationCoordinates() {
-  var result = 0;
-  if (coordinates.length > 0) {
-    var i = 1;
-    while (i < coordinates.length) {
-      var position1 = coordinates[i-1];
-      var position2 = coordinates[i];
-      result += (position2[0]- position1[0]);
-      i++;
-    }
-  }
-  return result;
-}
-
-function repaint() {
-  if (document.visibilityState == true && running) {
-    document.getElementById("locations").textContent = String(locations);
-    var d = calculateDistanceCoordinates() * dst_unit;
-    var t = duration + (Date.now() - start_time);
-    document.getElementById("distance").textContent = String(Math.round(d*100)/100);
-    if (t != 0 && d != 0) {
-      document.getElementById("speed").textContent = String(Math.round( (d / (t / 3600000)) * 100) / 100);
-      document.getElementById("pace").textContent = String(Math.round( ((t / 60000)/d) * 100) / 100);
-    }
-    if (coordinates.length > 0) {
-      document.getElementById("gps_text").style.display = "none";
-      document.getElementById("gps_data").style.display = "inline";
-    }
-  }
-}
-
-function logGPS(position, startMsg) {
-    document.getElementById("log").textContent = 
-      startMsg + position.timestamp 
-       + ": " + position.coords.latitude
-       + ", " + position.coords.longitude
-       + ", " + position.coords.altitude
-       + ", " + position.coords.accuracy
-       + ", " + position.coords.altitudeAccuracy
-       + ", " + position.coords.heading
-       + ", " + position.coords.speed;
-}
-
-function handleSuccess(position) {
-  if (running) {
-   logGPS(position, "GPS: ");
-
-    // discard positions that have no altitude since they're likely inacurate
-    if (position.coords.altitude != null) {
-      pushCoordinates(position);
-      locations++;
-      repaint();
-    } else {
-      document.getElementById("discarded").textContent = String(discarded++);
-    }
-   } else {
-
-
-     if (position.coords.altitude == null) {
-       got_error++;
-       if (got_error > MAX_ERRORS) got_error = MAX_ERRORS;
-           logGPS(position, "[ERROR] GPS: ");
-     } else {
-       got_error--;
-       logGPS(position, "GPS: ");
-     }
-     if (got_error <= 0) {
-       got_error = 0;
-       document.getElementById("gps_text").textContent = "ready";       
-       document.getElementById("waves").style.display = "block";       
-     } else {
-       document.getElementById("gps_text").textContent = "not ready";
-       document.getElementById("waves").style.display = "none";       
-     }
-   }
-}
-
-function handleError(error) {
-  var code = "unknown";
-  switch(error.code) {
-    case error.TIMEOUT:
-      code = "timeout";
-      break;
-    case error.PERMISSION_DENIED:
-      code = "permission denied";
-      break;
-    case error.POSITION_UNAVAILABLE:
-      code = "position unavailable";
-      break;
-  }
-  if (running) {
-    document.getElementById("errors").textContent = String(++got_error);
-    document.getElementById("log").textContent = "[ERROR] GPS: " + code; 
-  } else {
-    document.getElementById("gps_text").textContent = code; 
-    // wait for 5 non-consecutive errors
-    got_error = MAX_ERRORS;
-  }
-}
-
-function timer() {
-  if (document.visibilityState == true) {
-    document.getElementById("realtime").textContent = 
-      formatTime(Math.round((duration+(Date.now()-start_time))/1000));
-  }
-}
-
-function start() {
-  if (!running) {
-   running = true;
-   start_time = Date.now();
-   intervalId = setInterval(timer, 1000);
-   document.getElementById("stop").disabled = false;
-   document.getElementById("start").textContent = "Pause";
-  } else {
-   running = false;
-   clearInterval(intervalId);
-   duration += (Date.now() - start_time);
-   document.getElementById("start").textContent = "Restart";
-   pause();
-   document.getElementById("gps_text").style.display = "inline";
-   document.getElementById("gps_data").style.display = "none";
-  }
-}
-
-function stop() {
-  //  navigator.geolocation.clearWatch(watchId);
-  running = false;
-  clearInterval(intervalId);
-  got_error = 0;
-  locations = 0;
-  discarded = 0;
-  duration  = 0;
-  document.getElementById("start").textContent = "Start";
-  document.getElementById("stop").disabled = true;
-  document.getElementById("log").textContent = "";
-  var coords = getCoordinates();
-  if (coords != null && storage) {
-    try {
-      window.localStorage.setItem("track_gps_app", coords);
-    } catch (e) {
-      document.getDocumentById("log").textContent = "[ERROR] Can't store the value " + e.code;
-    }
-  }
-  if (coords != null) {
-    if (!send("teole",coords)) {      
-      document.getElementById("gps_coords").value = coords;
-      document.getElementById("xhr_failed").style.display = "inline";
-      document.getElementById("xhr_failed").disabled = false;
-    }
-  }
-  coordinates = [];
-}
-
-function init() {  
-  if (!!document.visibilityState)
-    document.addEventListener("visibilitychange", repaint, false);
-  else
-    document.visibilityState = true;
-
-  // @@ in the future, make sure this is empty
-   if (storage) {
-    window.localStorage.setItem("track_gps_app", "");
-
-    if (window.localStorage.getItem("track_gps_app_dst_unit") === "mile") {
-      dst_unit = 0.621371192;    
-    }
-    setUnit();
-   } else {
-     document.getElementById("log").textContent = "[ERROR] no local storage";
-   }
-   if (!!navigator.geolocation) {
-     watchId = navigator.geolocation.watchPosition(handleSuccess, handleError, {enableHighAccuracy:true, maximumAge:0, timeout:1000});
-   } else {
-     document.getElementById("gps_text").textContent = "not supported";
-     document.getElementById("start").disabled = true;
-   }
-
-    var xhr = new XMLHttpRequest;
-    if (!!xhr && !("withCredentials" in xhr)) {
-      document.getElementById("xhr_failed").style.display = "inline";
-      document.getElementById("xhr_failed").disabled = true;
-    }        
-}
-
-window.addEventListener("load", init, false);
-
-function km() {
-  if (storage) {
-    window.localStorage.setItem("track_gps_app_dst_unit", "km");
-  }
-  dst_unit = 1;
-  setUnit();
-  repaint();
-}
-
-function mile() {
-  if (storage) {
-    window.localStorage.setItem("track_gps_app_dst_unit", "mile");
-  }
-  dst_unit = 0.621371192;    
-  setUnit();
-  repaint();
-}
-
-function setUnit() {  
-  var text = (dst_unit == 0.621371192)? "mile" : "km";
-  var nodes = document.getElementsByClassName("dst_unit");
-  i = 0;
-  do {
-    nodes[i].textContent = text;
-  } while (++i < nodes.length);
-}
-
-]]>
+ <script src='/scripts/tracker.js'>
  </script>
-<style>
-body { background-color: #6699ff; }
-section table { margin: auto; }
-section p { text-align: center;}
-.text { font-size: 150%; }
-button {
-  font-size: 175%;
-  padding-left: 1ex;
-  padding-right: 1ex;
-  margin: 0;
-}
-#log { font-size: 75%; }
-#errors { color: red }
-#discarded { color: #f88 }
-table { border-collapse: collapse; }
-th { text-align: left; border-right: 1px solid #ccc; padding-right: 0.5ex;}
-td:nth-child(2) { text-align: right; width: 8ex; padding-right: 0.5ex;}
-h1 { text-align: right; padding-right: 1ex; font-family: cursive; margin: 0;}
-#gps_data { display: none }
-
-nav #atab0 { color: #ccc; cursor: default; }
-#vtab0:target ~ #tab0 { display: block }
-#vtab0:target ~ #tab1 { display: none }
-#vtab0:target ~ nav #atab1 { color: #6699ff; cursor: pointer; }
-#vtab0:target ~ nav #atab0 { color: #ccc; cursor: default; }
-
-#tab1 { display: none; }
-#vtab1:target ~ #tab0 { display: none }
-#vtab1:target ~ #tab1 { display: block }
-#vtab1:target ~ nav #atab0 { color: #6699ff; cursor: pointer; }
-#vtab1:target ~ nav #atab1 { color: #ccc; cursor: default; }
-
-section.tab_anchor { display: none; }
-
-nav {
-  border-bottom: 1px solid white;
-  padding-bottom: 2px;
-  margin-bottom: 5px;
-}
-nav a {
-  border: 1px solid white;
-  background: white;
-  color: #6699ff;
-  padding: 2px;
-}
-</style>
+ <link rel="stylesheet" href="/styles/tracker.css" type="text/css" />
 </head>
 <body>
 <section id='vtab0' class='tab_anchor'></section>