Index: trunk/src/cptms/cms_messages.json
===================================================================
--- trunk/src/cptms/cms_messages.json	(revision 314)
+++ 	(revision )
@@ -1,1 +1,0 @@
-{"data":[{"cms":{"index":"1200022","message":{"displayTime":"","phase1":{"Line1":"   Near Vista","Line2":"    Hermosa","Line3":"        "},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1200023","message":{"displayTime":"","phase1":{"Line1":"","Line2":"","Line3":""},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1200024","message":{"displayTime":"","phase1":{"Line1":"bottom of fifth","Line2":"dodgers up by 2","Line3":"        "},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1200025","message":{"displayTime":"","phase1":{"Line1":"","Line2":"","Line3":""},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1200026","message":{"displayTime":"","phase1":{"Line1":"","Line2":"","Line3":""},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1200027","message":{"displayTime":"","phase1":{"Line1":"","Line2":"","Line3":""},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1200028","message":{"displayTime":"","phase1":{"Line1":"","Line2":"","Line3":""},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1200029","message":{"displayTime":"","phase1":{"Line1":"","Line2":"","Line3":""},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1200030","message":{"displayTime":"","phase1":{"Line1":"","Line2":"","Line3":""},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1200031","message":{"displayTime":"","phase1":{"Line1":"","Line2":"","Line3":""},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1200032","message":{"displayTime":"","phase1":{"Line1":"","Line2":"","Line3":""},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1200033","message":{"displayTime":"","phase1":{"Line1":"","Line2":"","Line3":""},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1200034","message":{"displayTime":"","phase1":{"Line1":"","Line2":"","Line3":""},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1200035","message":{"displayTime":"","phase1":{"Line1":"","Line2":"","Line3":""},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1200036","message":{"displayTime":"","phase1":{"Line1":"","Line2":"","Line3":""},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1200037","message":{"displayTime":"","phase1":{"Line1":"","Line2":"","Line3":""},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1200038","message":{"displayTime":"","phase1":{"Line1":"","Line2":"","Line3":""},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1200039","message":{"displayTime":"","phase1":{"Line1":"","Line2":"","Line3":""},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1200040","message":{"displayTime":"","phase1":{"Line1":"","Line2":"","Line3":""},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1200041","message":{"displayTime":"","phase1":{"Line1":"","Line2":"","Line3":""},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1200042","message":{"displayTime":"","phase1":{"Line1":"","Line2":"","Line3":""},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1200043","message":{"displayTime":"","phase1":{"Line1":"","Line2":"","Line3":""},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1200044","message":{"displayTime":"","phase1":{"Line1":"","Line2":"","Line3":""},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1200045","message":{"displayTime":"","phase1":{"Line1":"","Line2":"","Line3":""},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1200046","message":{"displayTime":"","phase1":{"Line1":"","Line2":"","Line3":""},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1200047","message":{"displayTime":"","phase1":{"Line1":"","Line2":"","Line3":""},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1200048","message":{"displayTime":"","phase1":{"Line1":"","Line2":"","Line3":""},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1200049","message":{"displayTime":"","phase1":{"Line1":"","Line2":"","Line3":""},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1200050","message":{"displayTime":"","phase1":{"Line1":"","Line2":"","Line3":""},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1200051","message":{"displayTime":"","phase1":{"Line1":"","Line2":"","Line3":""},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1200052","message":{"displayTime":"","phase1":{"Line1":"","Line2":"","Line3":""},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1200053","message":{"displayTime":"","phase1":{"Line1":"  slow for the","Line2":"   cone zone","Line3":"        "},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1200055","message":{"displayTime":"","phase1":{"Line1":"","Line2":"","Line3":""},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1200056","message":{"displayTime":"","phase1":{"Line1":"    caution","Line2":"  slow traffic","Line3":"     ahead"},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1200057","message":{"displayTime":"","phase1":{"Line1":"","Line2":"","Line3":""},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1200058","message":{"displayTime":"","phase1":{"Line1":"","Line2":"","Line3":""},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1208488","message":{"displayTime":"","phase1":{"Line1":"","Line2":"","Line3":""},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1211184","message":{"displayTime":"","phase1":{"Line1":"","Line2":"","Line3":""},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1211185","message":{"displayTime":"","phase1":{"Line1":"","Line2":"","Line3":""},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1211967","message":{"displayTime":"","phase1":{"Line1":"","Line2":"","Line3":""},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1211978","message":{"displayTime":"","phase1":{"Line1":"","Line2":"","Line3":""},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1212138","message":{"displayTime":"","phase1":{"Line1":"","Line2":"","Line3":""},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1212822","message":{"displayTime":"","phase1":{"Line1":"","Line2":"","Line3":""},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1212823","message":{"displayTime":"","phase1":{"Line1":"","Line2":"","Line3":""},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1214503","message":{"displayTime":"","phase1":{"Line1":" You're heading","Line2":"     south.","Line3":"        "},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1214504","message":{"displayTime":"","phase1":{"Line1":"","Line2":"","Line3":""},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1214505","message":{"displayTime":"","phase1":{"Line1":"","Line2":"","Line3":""},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1214506","message":{"displayTime":"","phase1":{"Line1":"","Line2":"","Line3":""},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1214507","message":{"displayTime":"","phase1":{"Line1":"","Line2":"","Line3":""},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1214508","message":{"displayTime":"","phase1":{"Line1":"","Line2":"","Line3":""},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1214509","message":{"displayTime":"","phase1":{"Line1":"","Line2":"","Line3":""},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1214510","message":{"displayTime":"","phase1":{"Line1":"","Line2":"","Line3":""},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1214511","message":{"displayTime":"","phase1":{"Line1":"","Line2":"","Line3":""},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1214512","message":{"displayTime":"","phase1":{"Line1":"","Line2":"","Line3":""},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1214513","message":{"displayTime":"","phase1":{"Line1":"","Line2":"","Line3":""},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1214514","message":{"displayTime":"","phase1":{"Line1":"","Line2":"","Line3":""},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1214956","message":{"displayTime":"","phase1":{"Line1":"","Line2":"","Line3":""},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1217542","message":{"displayTime":"","phase1":{"Line1":"","Line2":"","Line3":""},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1218442","message":{"displayTime":"","phase1":{"Line1":"","Line2":"","Line3":""},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1218482","message":{"displayTime":"","phase1":{"Line1":"  San Clemente","Line2":"   Next Exit","Line3":"        "},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1218483","message":{"displayTime":"","phase1":{"Line1":"","Line2":"","Line3":""},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1218484","message":{"displayTime":"","phase1":{"Line1":"","Line2":"","Line3":""},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1218485","message":{"displayTime":"","phase1":{"Line1":"","Line2":"","Line3":""},"phase2":{"Line1":"","Line2":"","Line3":""}}}},{"cms":{"index":"1218486","message":{"displayTime":"","phase1":{"Line1":"","Line2":"","Line3":""},"phase2":{"Line1":"","Line2":"","Line3":""}}}}]}
Index: trunk/src/cptms/cms_demo.html
===================================================================
--- trunk/src/cptms/cms_demo.html	(revision 301)
+++ 	(revision )
@@ -1,389 +1,0 @@
-<!DOCTYPE html>
-<html>
-  <head>
-<!-- Launch with  python -m CGIHTTPServer 8080  -->
-    <meta name="viewport" content="initial-scale=1.0, user-scalable=no">
-    <meta charset="utf-8">
-    <title>CMS Manager Demo</title>
-    <style>
-        @font-face {
-          font-family: Scoreboard;
-          src: url('scoreboard.ttf');
-        }
-      html, body {
-            height: 370px;
-            padding: 0;
-            margin: 0;
-        }
-        textarea {
-           height: 33px;
-           width: 272px;
-           resize: none;
-           font-family: Scoreboard;
-           font-size: xx-large;
-           background-color: #2F4F4F;
-           color: yellow;
-        }
-       input {
-           border: thin solid #333;
-           padding: 2px;
-           font-family: monospace;
-           font-size: large;
-        }
-      #map {
-           height: 550px;
-           width: 100%;
-           overflow: hidden;
-           border: thin solid #333;
-       }
-      #cms-info-label {
-           height: 20px;
-           width: 540px;
-           overflow: hidden;
-           background-color: #A8C5FF;  /*#ECECFB; */
-           border: thin solid #BDBDBD;
-           padding: 5px;
-       }
-      #message-display {
-           height: 172px;
-           width: 300px;
-           overflow: hidden;
-           float: left;
-           /* border: thin solid #333;*/
-           /* border-left: none;*/
-       }
-      #message-input {
-           height: 122px;
-           width: 135px;
-           background-color: #729FFF;
-           float: left;
-           
-       }
-       #buttonPanel {
-           height: 122px;
-           width: 100px;
-           background-color: #729FFF;
-           border-left: none;
-           float: left;
-           padding: 20px;
-        }
-       .wrapper {
-           position: relative;\
-        }
-       #dialog {
-          position: absolute;
-          top: 10%;
-          right: 20%;
-          background-color: #729FFF; /* #ECECFB; */
-          margin: auto;
-          padding: 20px;
-          border: 1px solid #888;
-          width: 52%;
-          display: none;           
-        }
-      .unstyled-button {
-        border: 0 none;
-        padding: 0;
-        background: none;
-        cursor: pointer;
-      }    
-
-
-    /* The Close Button */
-    .close {
-      color: orange;
-      float: right;
-      font-size: 20px;
-      font-weight: bold;
-    }
-
-    .close:hover,
-    .close:focus {
-      color: red;
-      text-decoration: none;
-      cursor: pointer;
-    }
-</style>
-  </head>
-  <body>
-    <div id="map"></div>
-    <!--The div element where the show/hide button appears -->
-    <!-- div id="hideButton">&#128065;</div -->
-    <button id="cmsButton" class="unstyled-button"><img id="cmsBtnImg" src="images/btnDepressed_CMS.png"></button>
-    <button id="vdsButton" class="unstyled-button"><img id="vdsBtnImg" src="images/btnDepressed_VDS.png"></button>
-    <div id="map" class = "wrapper"></div>
-    <!-- The div element for the popup dialog -->
-    <div id="dialog" style="display:none;">
-        <span class="close">&times;</span>
-        <br>
-        <div id="cms-info-label" style="font-family:monospace">CMS ID: xxx LOCATION: </div>
-        <br>
-        <div><pre>Proposed:                              Current:</pre></div>
-        <input id='cmsID' value="" type='hidden'/>
-        <div id="message-input">
-        <input id="msgcontent1" size="16" maxlength="16" type="text"/><br><br>
-        <input id="msgcontent2" size="16" maxlength="16"/><br><br>
-        <input id="msgcontent3" size="16" maxlength="16"/>
-        </div>        
-        <div id="buttonPanel"    style="display: block;">
-        <button onclick="handleSubmit();">Send >></button><br>
-        <button onclick="handleClear();">Clear >></button><br>
-        <button onclick="handleClose();">Close </button>
-        </div>
-        <div id="message-display"  style="display: block;">
-         <textarea readonly id="msgdisplay1" maxlength="16" rows="1" cols="16"></textarea>
-         <textarea readonly id="msgdisplay2" maxlength="16" rows="1" cols="16"></textarea>
-         <textarea readonly id="msgdisplay3" maxlength="16" rows="1" cols="16"></textarea>
-        </div>
-    </div>
-
-    <script>
-var centerPoint = {
-    lat: 33.693385,
-    lng: -117.798937
-};
-var map;
-var kMapStartupFile = "cmsStatusD12.json";
-var blueFlag = "images/icon_cmsBlue.png";
-var yellowFlag = "images/icon_cmsYellow.png";
-var messageList;
-var cms_info;
-var markerList = [];
-var cms_showing = true;
-var vds_showing = true;
-
-function initMap()
-{
-    map = new google.maps.Map(document.getElementById('map'),
-    {
-        center: centerPoint,
-        zoom: 11,
-        mapTypeControl: false,
-        streetViewControl: false
-    });
-    initButton();
-    getMessage(1); // load the current message file
-    setMarkers();
-}
-// Initialize the view/hide buttons 
-function initButton()
-{
-    var cmsBtnDiv = document.getElementById('cmsButton');
-    map.controls[google.maps.ControlPosition.LEFT_BOTTOM].push(cmsBtnDiv)
-    cmsBtnDiv.title = 'Click to toggle cms view';
-
-    // Setup the click event listeners to toggle icon display
-    cmsBtnDiv.addEventListener('click', function() {
-            cms_showing = !cms_showing;
-            // reveal or hide all the icons
-            for (var i = 0; i < markerList.length; i++)
-            {
-                markerList[i].setVisible(cms_showing);
-            }
-            // Determine which button image to show
-            if (cms_showing)
-            {
-                pic = "images/btnDepressed_CMS.png"
-            }
-            else
-            {
-                pic = "images/btnReady_CMS.png"
-            }
-            document.getElementById('cmsBtnImg').src=pic;
-    });
-    var vdsBtnDiv = document.getElementById('vdsButton');
-    map.controls[google.maps.ControlPosition.LEFT_BOTTOM].push(vdsBtnDiv)
-    vdsBtnDiv.title = 'Click to toggle vds view';
-
-    // Setup the click event listeners to toggle icon display
-    vdsBtnDiv.addEventListener('click', function() {
-            vds_showing = !vds_showing;
-            // reveal or hide all the icons
-            alert("Not implemented yet")
-            // Determine which button image to show
-            if (vds_showing)
-            {
-                pic = "btnDepressed_VDS.png"
-            }
-            else
-            {
-                pic = "btnReady_VDS.png"
-            }
-            document.getElementById('vdsBtnImg').src=pic;
-    });
-}
-function setMarkers()
-{
-    var simpleImage = "";
-    loadcmsJSON(function(response)
-    {
-        // Parse JSON string into object
-        cms_info = JSON.parse(response);
-        console.log(cms_info.data[0].cms);
-        // Process each new marker 
-        for (var i = 0; i < cms_info.data.length; i++)
-        {
-            var cms = cms_info.data[i].cms;
-            var currLat = Number(cms.location.latitude);
-            var currLong = Number(cms.location.longitude);
-            // load a yellow flag if there's currently no message
-            if (messageList[i] == "||")
-                simpleImage = yellowFlag;
-            else
-                simpleImage = blueFlag;
-            var directionCode = cms.location.direction.charAt(0);
-            var locationInfo = directionCode + " " + cms.location
-                .route + " " + cms.location.postmile + " " + cms
-                .location.locationName
-            markerList[i] = new google.maps.Marker(
-            {
-                position:
-                {
-                    lat: currLat,
-                    lng: currLong
-                },
-                map: map,
-                icon: simpleImage,
-                title: "#"+i+" " +locationInfo,
-                cmsid: "" + i,
-                location: locationInfo
-            });
-            google.maps.event.addListener(markerList[i], 'click',
-                function()
-                {
-                    var dialog = document.getElementById('dialog');
-                    dialog.style.display = 'block';
-                    // fetch the sequential msg #
-                    cmsID = Number(this.cmsid);
-                    // Assign to the hidden field
-                    document.getElementById('cmsID').value = cmsID;
-                    getMessage(cmsID); // note: this is async
-                    document.getElementById('cms-info-label').innerHTML = "CMS ID: " +
-                        cmsID + "&nbsp;&nbsp;&nbsp;LOCATION: " + this.location;
-                    // clear input fields
-                    document.getElementById('msgcontent1').value = "";
-                    document.getElementById('msgcontent2').value = "";
-                    document.getElementById('msgcontent3').value = "";
-                    document.getElementById('msgcontent1').focus();
-                    var span = document.getElementsByClassName("close")[0]
-                    // When the user clicks on <span> (x), close the modal
-                    span.onclick = function() {
-                      handleClose();
-                    }
-                });
-        }
-    });
-}
-
-function loadcmsJSON(callback)
-{
-    var xobj = new XMLHttpRequest();
-    xobj.overrideMimeType("application/json");
-    xobj.open('GET', kMapStartupFile, true);
-    xobj.onreadystatechange = function()
-    {
-        if (xobj.readyState == 4 && xobj.status == "200")
-        {
-            callback(xobj.responseText);
-        }
-    };
-    // We want ajax to ignore any cached responses
-    xobj.setRequestHeader('If-Modified-Since', 'Sat, 01 Jan 2000 01:01:01 GMT')
-    xobj.send(null);
-}
-
-function handleSubmit()
-{
-    // recover the user's response
-    var response1 = document.getElementById('msgcontent1').value;
-    var response2 = document.getElementById('msgcontent2').value;
-    var response3 = document.getElementById('msgcontent3').value;
-    var newMsg = response1+response2+response3;
-    if (newMsg.length == 0)
-    {
-        alert("Nothing to Send ... Proposed is empty.");
-    }
-    else
-    {
-        document.getElementById('msgdisplay1').value = response1;
-        document.getElementById('msgdisplay2').value = response2;
-        document.getElementById('msgdisplay3').value = response3;
-        saveMessage(response1 + "|" + response2 + "|" + response3);
-    }
-}
-
-function handleClose()
-{
-    // hide the display
-    document.getElementById('dialog').style.display = 'none'
-}
-
-function handleClear()
-{
-    document.getElementById('msgdisplay1').value = "";
-    document.getElementById('msgdisplay2').value = "";
-    document.getElementById('msgdisplay3').value = "";
-    saveMessage("||");
-}
-
-function loadJSON(inFile, callback)
-{
-    var xobj = new XMLHttpRequest();
-    xobj.overrideMimeType("application/json");
-    xobj.open('GET', inFile, true);
-    xobj.onreadystatechange = function()
-    {
-        if (xobj.readyState == 4 && xobj.status == "200")
-        {
-            callback(xobj.responseText);
-        }
-    };
-    // We want ajax to ignore any cached responses
-    xobj.setRequestHeader('If-Modified-Since', 'Sat, 01 Jan 2000 01:01:01 GMT')
-    xobj.send(null);
-}
-// retrieve the current cms message file
-function getMessage(cmsID)
-{
-    loadJSON("http://localhost:8080/messagefile.txt", function(response)
-    {
-        // Parse JSON string into object
-        messageList = JSON.parse(response);
-        // select a message from json for the given cmsID
-        console.log("get by cmsID=" + cmsID);
-        var cmsSign = document.getElementById('msgdisplay1');
-        messageparts = messageList[cmsID].split("|");
-        cmsSign.value = messageparts[0];
-        document.getElementById('msgdisplay2').value = messageparts[1];
-        document.getElementById('msgdisplay3').value = messageparts[2];
-    });
-}
-// Save an updated cms message to the file
-// NB: cms id's are one-based, json array is zero-based.
-function saveMessage(outMessage, cmsID)
-{
-    var cmsID = document.getElementById('cmsID').value;
-    console.log("Saving " + outMessage + " for cmsID " + cmsID)
-    messageList[cmsID] = outMessage;
-    // Change icon if something was saved
-    if (outMessage == "||")
-        markerList[cmsID].setIcon(yellowFlag);
-    else
-        markerList[cmsID].setIcon(blueFlag);
-
-    var xhttp = new XMLHttpRequest();
-    xhttp.open("GET", "http://localhost:8080/cgi-bin/saveMessage.py?msg=" + JSON
-        .stringify(messageList), true);
-    xhttp.send();
-    // Using POST might be a better idea ... haven't tried this yet
-    //      var xhr = new XMLHttpRequest();
-    //      xhr.open("POST", "/cgi-bin/saveMessage.py?", true);
-    //      xhr.setRequestHeader('Content-Type', 'application/json; charset=UTF-8');
-    // send the collected data as JSON
-    //      xhr.send(JSON.stringify(messageList));
-}    </script>
-    <script async defer
-    src="https://maps.googleapis.com/maps/api/js?key=AIzaSyD6iTyN0DjP-9OVkAgicyp4tkC10naE_B8&callback=initMap">
-    </script>
-  </body>
-</html>
Index: trunk/src/cptms/cptms.html
===================================================================
--- trunk/src/cptms/cptms.html	(revision 312)
+++ 	(revision )
@@ -1,908 +1,0 @@
-<!DOCTYPE html>
-<html>
-  <head>
-<!-- Launch with  python -m CGIHTTPServer 80  -->
-<!-- map center button icon from http://icons8.com/.  (Obligatory backlink, don't remove ) -->
-  <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
-    <title>CPTMS Map v0.6.2</title> 
-    <style>
-        @font-face {
-          font-family: Scoreboard;
-          src: url('scoreboard.ttf');
-        }
-      /* Set the size of the div element that contains the map */
-      #mapdiv {
-        height: 100%;
-        width: 100%;  
-       }
-        /* Makes the page fill the window. */
-      html, body {
-        height: 100%;
-        margin: 0;
-        padding: 0;
-      }
-        textarea {
-           height: 33px;
-           width: 272px;
-           resize: none;
-           font-family: Scoreboard;
-           font-size: xx-large;
-           background-color: #2F4F4F;
-           color: yellow;
-        }
-       input {
-           border: thin solid #333;
-           padding: 2px;
-           font-family: "Lucida Console", Monaco, monospace;
-           font-size: medium;
-        }
-      #search-input {
-        background-color: #17263c;  /* #CD853F;  /*#E6E6FA; /* lavender */
-        color: #E6E6FA;  /* #FFEFD5; */
-        font-family: Roboto;
-        font-size: 18px;
-        font-weight: 400;
-        margin-left: 12px;
-        padding: 0 11px 0 13px;
-        text-overflow: ellipsis;
-        border-color: #746855;   /* #4d90fe; */
-        width: 400px;
-      }
-
-      #search-input:focus {
-        border-color: #E6E6FA; 
-      }
-      #ctrButton {
-        cursor: pointer;
-        background-color: #fff;
-        margin-right: 7px;
-        border: thick solid white;
-      }
-      #cms-info-label {
-           height: 20px;
-           width: 590px;
-           overflow: hidden;
-           background-color: #A8C5FF;  /*#ECECFB; */
-           border: thin solid #BDBDBD;
-           padding: 5px;
-       }
-      #message-display {
-           height: 172px;
-           width: 300px;
-           overflow: hidden;
-           float: left;
-       }
-      #message-input {
-           height: 122px;
-           width: 165px;
-           background-color: #729FFF;
-           float: left;
-       }
-       #buttonPanel {
-           height: 122px;
-           width: 130px;
-           background-color: #729FFF;
-           border-left: none;
-           float: left;
-           padding: 20px;
-        }
-       .wrapper {
-           position: relative;\
-        }
-       #dialog {
-          position: absolute;
-          top: 10%;
-          right: 20%;
-          background-color: #729FFF; /* #ECECFB; */
-          margin: auto;
-          padding: 20px;
-          border: 1px solid #888;
-          width: 680px;
-          display: none;           
-        }
-      .unstyled-button {
-        border: 0 none;
-        padding: 0;
-        background: none;
-        cursor: pointer;
-      }    
-    /* The Close Button in the CMS Dialog */
-    .close {
-      color: #2E2E2E;
-      float: right;
-      font-size: 30px;
-      font-weight: bold;
-    }
-    .close:hover,
-    .close:focus {
-      color: black;
-      text-decoration: none;
-      cursor: pointer;
-    }
-
-    </style>
-  </head>
-  <body>
-    <!-- 
-         Version 6.2 puts cctv and cms and vds in separate data layers.   
-         Version 6.1 Puts cms messages in json formatted file.  Polls for updates.
-         Version 6.0 Adds speed-dependent images to infowindow for cctv icons
-         Version 5.8 Adds an infowindow with a static image for all cctv icons
-         Version 5.7 integrates CCTV icons and button (but empty click handler)
-         Version 5.6 integrates CMS features
-         Version 5.5 renames title to CPTMS, loads static data on startup and dynamic data
-         every ten seconds.  
-         Version 5.4 adds Search box and Center button
-         Version 5.3 fixed dot color update defect, increased refresh rate to 10 sec.
-         Version 5.2 places red dots overlapping yellow dots.
-         Version 5.1 removes the map and street view buttons and the H3 tag.
-         Version 5 uses precomputed perpendicular vector in dot adjustment function
-         Version 4 Adjust the spacing between dots when the map is zoomed.
-         Version 3 does loadGeoJson only once, and subsequently does an ajax load
-         of the highways file, and selectively updates only those placePins whose
-         color has changed. 
-         @author jdalbey  2019.2.17
-    -->
-    <!-- The text area input for the Search Box -->
-    <input id="search-input" class="controls" type="text" placeholder="Search Box">
-    <!--The div element where the map appears -->
-    <div id="mapdiv"></div>
-    <!-- The div element for the popup dialog -->
-    <div id="dialog" style="display:none;">
-        <span class="close">&#x2612;</span>  <!-- close button symbol -->
-        <br>
-        <div id="cms-info-label" style="font-family:'Courier New'">CMS ID: xxx LOCATION: </div>
-        <br>
-        <input id='cmsID' value="" type='hidden'/>
-        <div id="message-input">Proposed:
-        <input id="msgcontent1"  maxlength="16" type="text"/><br><br>
-        <input id="msgcontent2"  maxlength="16" type="text"/><br><br>
-        <input id="msgcontent3"  maxlength="16" type="text"/>
-        </div>        
-        <div id="buttonPanel"    style="display: block;">
-        <button onclick="handleCMSsubmit();">Send >></button><br>
-        <button onclick="handleCMSclear();">Clear >></button><br>
-        <button onclick="handleDialogClose();">Close </button>
-        </div>
-        <div id="message-display"  style="display: block;">Current:
-         <textarea readonly id="msgdisplay1" maxlength="16" rows="1" cols="16"></textarea>
-         <textarea readonly id="msgdisplay2" maxlength="16" rows="1" cols="16"></textarea>
-         <textarea readonly id="msgdisplay3" maxlength="16" rows="1" cols="16"></textarea>
-        </div>
-    </div>
-    <!--The div elements where the buttons appear  -->
-    <div id="ctrButton"><img width="30" src="images/CPTMSImages/btn_mapcenter.png"</div>
-    <button id="cctvButton" class="unstyled-button"><img id="cctvBtnImg" src="images/CPTMSImages/btnReady_CCTV.png"></button>
-    <button id="cmsButton" class="unstyled-button"><img id="cmsBtnImg" src="images/CPTMSImages/btnReady_CMS.png"></button>
-    <button id="vdsButton" class="unstyled-button"><img id="vdsBtnImg" src="images/CPTMSImages/btnDepressed_VDS.png"></button>
-
-    <script>
-//TODO:  
-// Add phase 2 to messages.
-// cms set visible gets undefined error after last icon is processed.
-
-    // a global variable for the google map
-    var map;
-    // a global dictionary to lookup a station's original coordinates
-    var vds_coords = {};
-    // a global variable to hold locations of marked search places
-    var placePins = [];
-    // Constant name of dynamic json data file created by CADserver
-    var kMapPointsFile = "highways.json";
-    // Constant name of initial (static) highways file used once at startup
-    var kMapStartupFile = "highways_startup.json";
-    // Constant for map center location: The John Wayne Airport
-    //var centerPoint = {lat: 33.687228, lng: -117.872148};
-    // Constant for map center location in District 12
-    var centerPoint = {
-        lat: 33.693385,
-        lng: -117.798937
-    };
-    // Initial map zoom
-    var initZoom = 11;
-    // Dot colors used in traffic model to indicate free-flowing, slowed, and stopped traffic
-    // and their associated zvalues so slower traffic dots are more visible.
-    // white means a disabled spot
-    var colorZvalues = {
-        "white": 5,
-        "lime": 10,
-        "yellow": 20,
-        "red": 30
-    };
-    var kCMSstartupFile = "cmsStatusD12.json";
-    var kCCTVfile = "cctv_locations_D12.json";
-    var blueFlag = "images/CPTMSImages/icon_cmsBlue.png";
-    var yellowFlag = "images/CPTMSImages/icon_cmsYellow.png";
-    var cctvIcon = "images/CPTMSImages/icon_cctvCyan.png";
-    var cctvIconWhite = "images/CPTMSImages/icon_cctvWhite.png";
-    var vdsIconGreen = "images/CPTMSImages/circle-green.png"
-    var vdsIconYellow = "images/CPTMSImages/circle-yellow.png"
-    var vdsIconRed = "images/CPTMSImages/circle-red.png"
-    var cms_info;
-    var messageDict = {};
-    var cms_showing = false;
-    var vds_showing = true;
-    var cctv_showing = false;
-    var cctv_infowindow; // We create just a single instance of info window.
-
-    // Build a solid colored icon to use instead of the classic pin
-    // Use a diamond on N and E directions, circle on S and W directions
-    function dotSymbol(color) //,direction)
-    {
-//        var circle = google.maps.SymbolPath.CIRCLE;
-//        var diamond = 'M -1,0 0,-1 1,0 0,1 z';
-//        var myShape = circle;
-        var iconPath = vdsIconGreen;
-        if (color == 'red')
-        {
-           iconPath = vdsIconRed;
-        }
-        else if (color == 'yellow')
-        {
-            iconPath = vdsIconYellow;
-        }
-        return {
-//            path: iconPath,
-//            icon: 
-//                    {
-                        url: iconPath, 
-                        anchor: new google.maps.Point(6, 6)
-//                    };
-//            anchor: new google.maps.Point(6, 6),
-//            scale: 5,
-//            strokeColor: "black", // the border color
-//            strokeWeight: 1, // the border thickness
-//            fillColor: color,
-//            fillOpacity: 1.0
-        };
-    }
-
-    // Load the map data from a json file and style all the points
-    function loadVDSlayer()
-    {
-        // Load the static map data and call saveCoords when done
-        map.data.loadGeoJson(kMapStartupFile, null, saveCoords)
-//        var d = new Date();
-//        var start = d.getTime();
-        // Style the map data by applying the desired properties to each feature (marker)
-        // The function will be called every time a feature's properties are updated.
-        map.data.setStyle(function(feature)
-        {
-            // Get the postmile id 
-            var name = feature.getId();
-            // Get the desired color value
-            var ptColor = feature.getProperty("color");
-            var street = feature.getProperty("street");
-            // Build the marker
-            var iconSymbol = dotSymbol(ptColor);
-            // return the StyleOptions
-            return {
-                icon: iconSymbol,
-/*                    icon: 
-                    {
-                        url: vdsIconGreen, 
-                        anchor: new google.maps.Point(6, 6)
-                    }, */
-                title: name + " @" + street, // set rollover text
-                // set zIndex for slowed traffic to a higher value so they overlap
-                zIndex: colorZvalues[ptColor]
-            };
-        });
-    }
-    // callback when load GeoJson completes
-    // save each feature's Point as the original coordinates for later reference
-    function saveCoords(features)
-    {
-        // Iterate over all the features in the map
-        features.forEach(function(feature)
-        {
-            var pt = feature.getGeometry().get();
-            vds_coords[feature.getId()] = pt; // save the Point in a dictionary
-        });
-        // update the dot colors from the dynamic json data 
-        updateVDSlayer();
-        // go adjust the marker coordinates so dots don't overlap
-        adjustCoords(calcDistanceFactor());
-    }
-
-    // magic formula controls distance between dots proportionate to zoom factor
-    function calcDistanceFactor()
-    {
-        // 15 is maximum zoom, the point at which no adjustment is needed
-        return (.0005 * (15 - map.getZoom()));
-    }
-
-    // Adjust the coordinates of dots so they appear side-by-side
-    // The perpendicular vector for each dot has been provided,
-    // so we just need to multiply by a scaling factor (adjAmount) 
-    // @param adjAmount amount by which to adjust coordinate 
-    function adjustCoords(adjAmount)
-    {
-        // Adjust the NB points a slight amount
-        map.data.forEach(function(feature)
-        {
-            // get the name of the current feature
-            var name = feature.getId();
-            // lookup the original coordinates for this feature
-            var coords = vds_coords[name];
-
-            //retrieve the perpendicular vector (precomputed)
-            var perpx = feature.getProperty("perpx")
-            var perpy = feature.getProperty("perpy")
-                // Make adjustment and save it
-            var myLat = coords.lat() + perpy * adjAmount
-            var myLong = coords.lng() + perpx * adjAmount
-            feature.setGeometry(
-            {
-                lat: myLat,
-                lng: myLong
-            });
-        });
-    }
-
-    // update the color (as needed) for a given marker
-    function updateMarker(marker)
-    {
-        target = marker.id;
-        newColor = marker.properties.color;
-        // see if new color is different than current color
-        currentFeature = map.data.getFeatureById(target);
-        currentColor = currentFeature.getProperty("color");
-        // if a new color is desired then assign it to the feature's color property
-        if (currentColor != newColor)
-        {
-            currentFeature.setProperty("color", newColor);
-            // set zIndex for slowed traffic to a higher value so they overlap
-            currentFeature.setProperty("zIndex", colorZvalues[newColor]);
-        }
-    }
-
-    // Load the dynamic json file for highways, etc.
-    // Ref: https://codepen.io/KryptoniteDove/post/load-json-file-locally-using-pure-javascript
-    function loadJSON(inFile, callback)
-    {
-        var xobj = new XMLHttpRequest();
-        xobj.overrideMimeType("application/json");
-        xobj.open('GET', inFile, true);
-        xobj.onreadystatechange = function()
-        {
-            if (xobj.readyState == 4 && xobj.status == "200")
-            {
-                callback(xobj.responseText);
-            }
-        };
-        // We want ajax to ignore any cached responses
-        xobj.setRequestHeader('If-Modified-Since', 'Sat, 01 Jan 2000 01:01:01 GMT')
-        xobj.send(null);
-    }
-    // Load the highways dynamic json file and update the map
-    function updateVDSlayer()
-    {
-        var parsed_JSON;
-        loadJSON(kMapPointsFile, function(response)
-        {
-            // Parse JSON string into object
-            parsed_JSON = JSON.parse(response);
-            // Process each new marker - lookup in current map
-            parsed_JSON.features.forEach(updateMarker);
-        });
-    }
-
-    // Initialize the center button (to re-center the map)
-    function initCenter()
-    {
-        var centerBtnDiv = document.getElementById('ctrButton');
-        map.controls[google.maps.ControlPosition.RIGHT_CENTER].push(centerBtnDiv)
-        centerBtnDiv.title = 'Click to recenter the map';
-
-        // Setup the click event listeners: reset center location and zoom factor
-        centerBtnDiv.addEventListener('click', function()
-        {
-            map.setCenter(centerPoint);
-            map.setZoom(initZoom);
-            clearPlacePins();
-        });
-    }
-
-    // Initialize the search box and listener 
-    function initSearch()
-    {
-        // Create the search box and link it to the UI element.
-        var input = document.getElementById('search-input');
-        var searchBox = new google.maps.places.SearchBox(input);
-        map.controls[google.maps.ControlPosition.TOP_LEFT].push(input);
-
-        // Bias the SearchBox results towards current map's viewport.
-        map.addListener('bounds_changed', function()
-        {
-            searchBox.setBounds(map.getBounds());
-        });
-
-        // Listen for the event fired when the user selects a prediction and retrieve
-        // more details for that place.
-        searchBox.addListener('places_changed', function()
-        {
-            var places = searchBox.getPlaces();
-
-            if (places.length == 0)
-            {
-                return;
-            }
-
-            clearPlacePins();
-
-            // Create a bounding region to include the search result places
-            var bounds = new google.maps.LatLngBounds();
-            // For each place, get the icon, name and location.
-            // There may be multiple search results
-            places.forEach(function(place)
-            {
-                if (!place.geometry)
-                {
-                    console.log("Returned place contains no geometry");
-                    return;
-                }
-
-                // Create a marker for each place.
-                placeMarker = new google.maps.Marker(
-                {
-                    map: map,
-                    title: place.name,
-                    position: place.geometry.location
-                })
-
-                // Click on the marker to remove it from the display
-                placeMarker.addListener('click', function()
-                {
-                    placeMarker.setMap(null);
-                });
-
-                // Add this marker to the collection of current markers 
-                placePins.push(placeMarker);
-
-                // Create a bounding region to include this place
-                if (place.geometry.viewport)
-                {
-                    // Only geocodes have viewport.
-                    bounds.union(place.geometry.viewport);
-                }
-                else
-                {
-                    bounds.extend(place.geometry.location);
-                }
-            });
-            // This will pan and zoom to the area around the marker
-            //map.fitBounds(bounds);
-            // This will center the map on the new marker(s) but not zoom
-            map.setCenter(bounds.getCenter());
-        });
-    }
-
-    // Remove any place pins from a previous search
-    function clearPlacePins()
-    {
-        placePins.forEach(function(marker)
-        {
-            marker.setMap(null);
-        });
-        placePins = [];
-    }
-    // Initialize the view/hide buttons 
-    function initLayerButtons()
-    {
-        var cctvBtnDiv = document.getElementById('cctvButton');
-        map.controls[google.maps.ControlPosition.LEFT_BOTTOM].push(cctvBtnDiv)
-        cctvBtnDiv.title = 'Click to toggle cctv view';
-        // Setup the click event listeners to toggle icon display
-        cctvBtnDiv.addEventListener('click', function()
-        {
-            cctv_showing = !cctv_showing;
-            // reveal or hide all the icons
-            cctvLayer.forEach(function(feature)
-            {
-                cctvLayer.overrideStyle(feature,
-                {
-                    visible: cctv_showing
-                });
-            });
-            // Determine which button image to show
-            if (cctv_showing)
-            {
-                pic = "images/CPTMSImages/btnDepressed_CCTV.png"
-            }
-            else
-            {
-                pic = "images/CPTMSImages/btnReady_CCTV.png"
-            }
-            document.getElementById('cctvBtnImg').src = pic;
-        });
-
-        var cmsBtnDiv = document.getElementById('cmsButton');
-        map.controls[google.maps.ControlPosition.LEFT_BOTTOM].push(cmsBtnDiv)
-        cmsBtnDiv.title = 'Click to toggle cms view';
-        // Setup the click event listeners to toggle icon display
-        cmsBtnDiv.addEventListener('click', function()
-        {
-            cms_showing = !cms_showing;
-            // Determine which button image to show
-            if (cms_showing)
-            {
-                pic = "images/CPTMSImages/btnDepressed_CMS.png"
-                // It's nice when icons become visible that the messages have been refreshed.
-                loadAllMessages();
-            }
-            else
-            {
-                pic = "images/CPTMSImages/btnReady_CMS.png"
-            }
-            document.getElementById('cmsBtnImg').src = pic;
-            // reveal or hide all the icons
-            cmsLayer.forEach(function(feature)
-            {
-                cmsLayer.overrideStyle(feature,
-                {
-                    visible: cms_showing
-                });
-            });
-        });
-
-        var vdsBtnDiv = document.getElementById('vdsButton');
-        map.controls[google.maps.ControlPosition.LEFT_BOTTOM].push(vdsBtnDiv)
-        vdsBtnDiv.title = 'Click to toggle vds view';
-
-        // Setup the click event listeners to toggle icon display
-        vdsBtnDiv.addEventListener('click', function()
-        {
-            vds_showing = !vds_showing;
-            // reveal or hide all the dots
-            map.data.forEach(function(feature)
-            {
-                map.data.overrideStyle(feature,
-                {
-                    visible: vds_showing
-                });
-            });
-            // Determine which button image to show
-            if (vds_showing)
-            {
-                pic = "images/CPTMSImages/btnDepressed_VDS.png"
-            }
-            else
-            {
-                pic = "images/CPTMSImages/btnReady_VDS.png"
-            }
-            document.getElementById('vdsBtnImg').src = pic;
-        });
-    }
-
-function loadCMSlayer()
-{
-    cmsLayer = new google.maps.Data();
-    cmsLayer.setMap(map);
-    cmsLayer.loadGeoJson("cms_locations_D12.gjson");
-    cmsLayer.setStyle(function(feature)
-    {
-        // return the StyleOptions
-        return {
-            icon: yellowFlag,
-            title: feature.getId()+ " " +feature.getProperty("location"),
-            visible: false
-        };
-    });
-    
-    cmsLayer.addListener('click', function(event)
-    {
-        var dialog = document.getElementById('dialog');
-        // Note: If the dialog is already being displayed when someone else
-        // updates the message, it won't be reflected in the dialog, until
-        // you close and reopen it.
-        dialog.style.display = 'block';
-        cmsID = event.feature.getId();
-        // Assign to the hidden field
-        document.getElementById('cmsID').value = cmsID;
-        showMessage(cmsID); // note: this is async
-        document.getElementById('cms-info-label').innerHTML = "CMS ID: " +
-            cmsID + "&nbsp;&nbsp;&nbsp;LOCATION: " + event.feature.getProperty("location");
-        // clear input fields
-        document.getElementById('msgcontent1').value = "";
-        document.getElementById('msgcontent2').value = "";
-        document.getElementById('msgcontent3').value = "";
-        document.getElementById('msgcontent1').focus();
-        var span = document.getElementsByClassName("close")[0]
-            // When the user clicks on <span> (x), close the modal
-        span.onclick = function()
-        {
-            handleDialogClose();
-        }
-    });
-}
-function makecctvIcon(nearVDS)
-{
-    var imgIcon = cctvIcon
-    if ((typeof map.data.getFeatureById(nearVDS)) == "undefined")
-    {
-        imgIcon = cctvIconWhite;
-    }
-    return imgIcon
-}
-function loadCCTVlayer()
-{
-    var imgTag = '<IMG WIDTH="700" SRC="images/CPTMSImages/';
-    cctv_infowindow = new google.maps.InfoWindow();
-    cctvLayer = new google.maps.Data();
-    cctvLayer.loadGeoJson("cctv_locations_D12.gjson");
-    cctvLayer.setStyle(function(feature)
-    {
-        // return the StyleOptions
-        return {
-            icon: makecctvIcon(feature.getProperty("nearVDS")),
-            title: feature.getId() + " " +feature.getProperty('locationName'),
-            visible: false  
-        };
-    });
-    cctvLayer.addListener('click', function(event)
-    {
-        //console.log("cctv layer was clicked at " + event.feature.getId());
-        cctvIndex = event.feature.getId();
-        //console.log(this.title + " is looking for " + this.nearVDS);
-        nearVDS = map.data.getFeatureById(event.feature.getProperty("nearVDS"));
-        currentColor = nearVDS.getProperty("color");
-        var imgDir = "CCTVFast/";
-        if (currentColor == "red" || currentColor == "yellow")
-        {
-            imgDir = "CCTVSlow/"
-        }
-
-        cctv_infowindow.setContent('<div style="font-weight:bold;font-family: monospace">' +  nearVDS.getId() + "&nbsp;" + currentColor + "<BR>" + imgTag + imgDir + cctvIndex + '.jpg">' + "</div>");
-        cctv_infowindow.setPosition(event.feature.getGeometry().get());
-        cctv_infowindow.open(map);
-
-    });
-    cctvLayer.setMap(map);
-}
-
-    // Center justify message text in a 16 column field
-    function justifyCMStext(message)
-    {
-        var kBlanks = "                ";
-        var padLen = (16 - message.length) / 2;
-        var padding = kBlanks.substring(0, padLen);
-        return padding + message;
-    }
-
-    function handleCMSsubmit()
-    {
-        // recover the user's response
-        var response1 = justifyCMStext(document.getElementById('msgcontent1').value.trim());
-        var response2 = justifyCMStext(document.getElementById('msgcontent2').value.trim());
-        var response3 = justifyCMStext(document.getElementById('msgcontent3').value.trim());
-        var newMsg = response1 + response2 + response3;
-        if (newMsg.length == 0)
-        {
-            alert("Nothing to Send ... Proposed is empty.");
-        }
-        else
-        {
-            document.getElementById('msgdisplay1').value = response1;
-            document.getElementById('msgdisplay2').value = response2;
-            document.getElementById('msgdisplay3').value = response3;
-            saveMessage(response1 + "|" + response2 + "|" + response3);
-        }
-    }
-
-    function handleDialogClose()
-    {
-        // hide the display
-        document.getElementById('dialog').style.display = 'none'
-    }
-
-    function handleCMSclear()
-    {
-        document.getElementById('msgdisplay1').value = "";
-        document.getElementById('msgdisplay2').value = "";
-        document.getElementById('msgdisplay3').value = "";
-        saveMessage("||");
-    }
-    // retrieve the current cms message file
-    function showMessage(cmsID)
-    {
-        loadAllMessages();  // because someone else may have made a recent update
-        // lookup the message for this cms ID
-        var message = messageDict[cmsID].cms.message;
-        // show the message in the display
-        document.getElementById('msgdisplay1').value = message.phase1.Line1;
-        document.getElementById('msgdisplay2').value = message.phase1.Line2;
-        document.getElementById('msgdisplay3').value = message.phase1.Line3;
-    }
-    function loadAllMessages()
-    {
-        loadJSON("cms_messages.json", function(response)
-        {
-            // Parse JSON string into object
-            messagejson = JSON.parse(response);
-            // Add each message to a lookup dictionary 
-            for (var i = 0; i < messagejson.data.length; i++)
-            {
-                var item = messagejson.data[i];
-                messageDict[item.cms.index] = item;
-                // Set the appropriate icon on the cms icon
-                // set a yellow flag if there's currently no message
-                if (item.cms.message.phase1.Line1 + 
-                    item.cms.message.phase1.Line2 +
-                    item.cms.message.phase1.Line3 == "")
-                {
-                    cmsLayer.overrideStyle(cmsLayer.getFeatureById(item.cms.index), {icon: yellowFlag})
-                }
-                else
-                {
-                    cmsLayer.overrideStyle(cmsLayer.getFeatureById(item.cms.index), {icon: blueFlag})
-                }
-            }
-        });
-    }
-
-    // Save an updated cms message to the file
-    function saveMessage(outMessage)
-    {
-        // Fetch cmsID from hidden field where it was put when dialog opened.
-        var cmsID = document.getElementById('cmsID').value;
-        //console.log("Saving " + outMessage + " for cmsID " + cmsID)
-        msgParts = outMessage.split("|");
-        messageDict[cmsID].cms.message.phase1.Line1 = msgParts[0];
-        messageDict[cmsID].cms.message.phase1.Line2 = msgParts[1];
-        messageDict[cmsID].cms.message.phase1.Line3 = msgParts[2];
-        // Set icon to reflect message state
-        if (outMessage == "||")
-        {
-            currentIcon = {icon: yellowFlag};
-        }
-        else
-        {
-            currentIcon = {icon: blueFlag};
-        }
-        cmsLayer.overrideStyle(cmsLayer.getFeatureById(cmsID), currentIcon)
-        outString = "{\n\t\"data\":\n\t\t" + JSON.stringify(Object.values(messageDict)) + "}";
-
-        var xhttp = new XMLHttpRequest();
-        xhttp.open("GET", "cgi-bin/saveMessage.py?msg=" + outString, true);
-        xhttp.send();
-        // Using POST might be a better idea ... haven't tried this yet
-        //      var xhr = new XMLHttpRequest();
-        //      xhr.open("POST", "/cgi-bin/saveMessage.py?", true);
-        //      xhr.setRequestHeader('Content-Type', 'application/json; charset=UTF-8');
-        // send the collected data as JSON
-        //      xhr.send(JSON.stringify(messageList));
-    }
-
-    // Initialize the map and load the points
-    function initMap()
-    {
-        // Declare the map and where it belongs on the page
-        map = new google.maps.Map(document.getElementById('mapdiv'),
-        {
-            zoom: initZoom,
-            center: centerPoint,
-            styles: night_mode,
-            mapTypeControl: false,
-            streetViewControl: false
-        });
-        loadVDSlayer(); // go load the map data
-        // setup the search box and center button
-        initSearch();
-        initCenter();
-
-loadCMSlayer();
-
-loadCCTVlayer();
-
-        initLayerButtons();
-
-        // Start a timer to refresh the vds dots every 10 seconds
-        var myTimer = setInterval(updateVDSlayer, 10000);
-        // start an interval timer to refresh the cms icons every 10 seconds
-        var cmsTimer = setInterval(loadAllMessages, 10000);
-        // Listen for zoom changes and move the placePins so as to keep a nice
-        // visual distance between them appropriate to the zoom factor
-        map.addListener('zoom_changed', function()
-        {
-            // fetch how much the map is currently zoomed
-            currentZoom = map.getZoom();
-            // only bother adjusting within this range
-            if ((currentZoom < 16) && (currentZoom > 10))
-            {
-                // magic formula controls distance between dots
-                adjustCoords(calcDistanceFactor());
-            }
-        });
-
-    }
-    // Styles array for Night Mode map
-    // Ref: https://developers.google.com/maps/documentation/javascript/styling
-    var night_mode = [
-                {elementType: 'geometry', stylers: [{color: '#242f3e'}]},
-                {elementType: 'labels.text.stroke', stylers: [{color: '#242f3e'}]},
-                {elementType: 'labels.text.fill', stylers: [{color: '#746855'}]},
-                {
-                  featureType: 'administrative.locality',
-                  elementType: 'labels.text.fill',
-                  stylers: [{color: '#d59563'}]
-                },
-                {
-                  featureType: 'poi',
-                  elementType: 'labels.text.fill',
-                  stylers: [{color: '#d59563'}]
-                },
-                {
-                  featureType: 'poi.park',
-                  elementType: 'geometry',
-                  stylers: [{color: '#263c3f'}]
-                },
-                {
-                  featureType: 'poi.park',
-                  elementType: 'labels.text.fill',
-                  stylers: [{color: '#6b9a76'}]
-                },
-                {
-                  featureType: 'road',
-                  elementType: 'geometry',
-                  stylers: [{color: '#38414e'}]
-                },
-                {
-                  featureType: 'road',
-                  elementType: 'geometry.stroke',
-                  stylers: [{color: '#212a37'}]
-                },
-                {
-                  featureType: 'road',
-                  elementType: 'labels.text.fill',
-                  stylers: [{color: '#9ca5b3'}]
-                },
-                {
-                  featureType: 'road.highway',
-                  elementType: 'geometry',
-                  stylers: [{color: '#746855'}]
-                },
-                {
-                  featureType: 'road.highway',
-                  elementType: 'geometry.stroke',
-                  stylers: [{color: '#1f2835'}]
-                },
-                {
-                  featureType: 'road.highway',
-                  elementType: 'labels.text.fill',
-                  stylers: [{color: '#f3d19c'}]
-                },
-                {
-                  featureType: 'transit',
-                  elementType: 'geometry',
-                  stylers: [{color: '#2f3948'}]
-                },
-                {
-                  featureType: 'transit.station',
-                  elementType: 'labels.text.fill',
-                  stylers: [{color: '#d59563'}]
-                },
-                {
-                  featureType: 'water',
-                  elementType: 'geometry',
-                  stylers: [{color: '#17263c'}]
-                },
-                {
-                  featureType: 'water',
-                  elementType: 'labels.text.fill',
-                  stylers: [{color: '#515c6d'}]
-                },
-                {
-                  featureType: 'water',
-                  elementType: 'labels.text.stroke',
-                  stylers: [{color: '#17263c'}]
-                }
-              ]
-
-    // Using John's API Key
-    </script>
-    <script async defer
-    src="https://maps.googleapis.com/maps/api/js?key=AIzaSyD6iTyN0DjP-9OVkAgicyp4tkC10naE_B8&libraries=places&callback=initMap">
-    </script>
-  </body>
-</html>
