    //<![CDATA[

    // We store the link text as a variable so we can 
    // restore it later if needed.
    var directionsGoogleText = "Directions on Google";
    var directionsMapquestText = "Directions on Mapquest";
    var directionsYahooText = "Directions on Yahoo";
    var dLinkGoogle = document.getElementById("directionsLinkGoogle");
    dLinkGoogle.appendChild(document.createTextNode(directionsGoogleText));
    var dLinkMapquest = document.getElementById("directionsLinkMapquest");
    dLinkMapquest.appendChild(document.createTextNode(directionsMapquestText));
    var dLinkYahoo = document.getElementById("directionsLinkYahoo");
    dLinkYahoo.appendChild(document.createTextNode(directionsYahooText));

    function addTagToList(newTag) {
        if (tagToCountTable[newTag]) {
            tagToCountTable[newTag]++;
        } else {
            tagToCountTable[newTag] = 1;
        }
    }

    function sortByCount(a, b) {
        return tagToCountTable[b] - tagToCountTable[a];
    }

    function myEncodeURI(source) {
        // Do the javascript thing, but encode a space as a +
        var nextSpace = source.indexOf(' ');
        while (nextSpace != -1) {
            source = source.substring(0, nextSpace) + "+" + source.substring(nextSpace+1);
            nextSpace = source.indexOf(' ');
        }
        return encodeURI(source);
    }

    function calculateDistances(form) {
        // First, update the link to directions.
        var dLinkGoogle = document.getElementById("directionsLinkGoogle");
        var dLinkMapquest = document.getElementById("directionsLinkMapquest");
        var dLinkYahoo = document.getElementById("directionsLinkYahoo");
        var canDoGoogle = true;
        var canDoMapquest = true;
        var canDoYahoo = true;
        var ind1 = form.marker1.value;
        var ind2 = form.marker2.value;
        if (ind1 != '' && ind2 != '' && markerAddresses[ind1] != "null" && markerAddresses[ind2] != "null") {
            dLinkGoogle.childNodes[0].nodeValue = directionsGoogleText;
            dLinkGoogle.setAttribute("href", "http://maps.google.com/maps?saddr=" + myEncodeURI(markerAddresses[ind1] + " " + markerCityZips[ind1]) + "&daddr=" + myEncodeURI(markerAddresses[ind2] + " " + markerCityZips[ind2]) + "&hl=en");
            dLinkYahoo.childNodes[0].nodeValue = directionsYahooText;
            dLinkYahoo.setAttribute("href", "http://maps.yahoo.com/dd_result?newaddr=" + myEncodeURI(markerAddresses[ind1]) + "&taddr=" + myEncodeURI(markerAddresses[ind2]) + "&csz=" + myEncodeURI(markerCityZips[ind1]) + "&country=US&tcsz=" + myEncodeURI(markerCityZips[ind2]) + "&tcountry=US");
            // We just need the zip codes from the end of markerCityZips[].
            // See if they''re there.
            var lastSpace1 = markerCityZips[ind1].lastIndexOf(' ');
            var lastSpace2 = markerCityZips[ind2].lastIndexOf(' ');
            if ((lastSpace1 != markerCityZips[ind1].length - 6) ||
                (lastSpace2 != markerCityZips[ind2].length - 6)) {
                canDoMapquest = false;
            } else {
                dLinkMapquest.childNodes[0].nodeValue = directionsMapquestText;
                dLinkMapquest.setAttribute("href", "http://www.mapquest.com/directions/main.adp?1a=" + myEncodeURI(markerAddresses[ind1]) + "&1z=" + markerCityZips[ind1].substring(markerCityZips[ind1].length-5) + "&1y=US&2a=" + myEncodeURI(markerAddresses[ind2]) + "&2z=" + markerCityZips[ind2].substring(markerCityZips[ind2].length-5) + "&2y=US&go=1");
            }
        } else {
            canDoGoogle = false;
            canDoMapquest = false;
            canDoYahoo = false;
        }
        if (!canDoGoogle || !canDoMapquest || !canDoYahoo) {
            stringToUse = "";
            if (ind1 == '' || ind2 == '') {
                stringToUse = "No directions available.";
            } else {
                stringToUse = "No address for ";
                if (markerAddresses[ind1] == "null") {
                    stringToUse += markerTitles[ind1] + " ";
                    if (markerAddresses[ind2] == "null") {
                        stringToUse += "and ";
                    }
                }
                if (markerAddresses[ind2] == "null") {
                    stringToUse += markerTitles[ind2];
                }
            }
            if (!canDoGoogle) {
                dLinkGoogle.childNodes[0].nodeValue = stringToUse;
                dLinkGoogle.setAttribute("href", "javascript:void(0);");
            }
            if (!canDoMapquest) {
                dLinkMapquest.childNodes[0].nodeValue = stringToUse;
                dLinkMapquest.setAttribute("href", "javascript:void(0);");
            }
            if (!canDoYahoo) {
                dLinkYahoo.childNodes[0].nodeValue = stringToUse;
                dLinkYahoo.setAttribute("href", "javascript:void(0);");
            }
        }
        if (ind1 == '' || ind2 == '') {
            return;
        }
        // Now, calculate the distance.
        var lat1 = getMarkerPointLat(ind1);
        var lng1 = getMarkerPointLng(ind1);
        var lat2 = getMarkerPointLat(ind2);
        var lng2 = getMarkerPointLng(ind2);
        // Following code borrowed from http://www.wcrl.ars.usda.gov/cec/java/lat-long.htm
        var er = 6366.707
        //ave. radius = 6371.315 (someone said more accurate is 6366.707)
        //equatorial radius = 6378.388
        //nautical mile = 1.15078
        var radlat1 = Math.PI * (lat1)/180
        var radlat2 = Math.PI * (lat2)/180
        
        //now long.
        var radlong1 = Math.PI * (lng1)/180
        var radlong2 = Math.PI * (lng2)/180
        //spherical coordinates x=r*cos(ag)sin(at), y=r*sin(ag)*sin(at), z=r*cos(at)
        //zero ag is up so reverse lat
        radlat1=Math.PI/2-radlat1;
        radlat2=Math.PI/2-radlat2;

        var x1 = er * Math.cos(radlong1)*Math.sin(radlat1)
        var y1 = er * Math.sin(radlong1)*Math.sin(radlat1)
        var z1 = er * Math.cos(radlat1)

        var x2 = er * Math.cos(radlong2)*Math.sin(radlat2)
        var y2 = er * Math.sin(radlong2)*Math.sin(radlat2)
        var z2 = er * Math.cos(radlat2)

        var d = Math.sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)+(z1-z2)*(z1-z2))

        //side, side, side, law of cosines and arccos
        var theta = Math.acos((er*er+er*er-d*d)/(2*er*er))
        var distance = theta*er
        form.distanceResultKM.value = distance
        form.distanceResultMiles.value = distance*.621371192;
        form.distanceResultFeet.value = distance*3280.8399;
    }

    function createMarkerOption(index, oneOrTwo) {
        var newOption = document.createElement("option");
        newOption.setAttribute("value", index);
        newOption.setAttribute("id", "option" + oneOrTwo + index);
        var newOptionText = document.createTextNode(markerTitles[index]);
        newOption.appendChild(newOptionText);
        return newOption;
    }

    function addTagsOfEntry(i, title, captionText) {
        var entry = document.createElement("div");
        entry.setAttribute("id", "entry" + i);
        entry.setAttribute("style", "");
        var boldPart = document.createElement("b");
        var linkPart = document.createElement("a");
        linkPart.setAttribute("href", "javascript:callback" + i + "();");
        var boldText = document.createTextNode(title);
        boldPart.appendChild(boldText);
        linkPart.appendChild(boldPart);

        // Get rid of <br/>s in text.
        var captionPart = document.createTextNode(" - " + captionText.replace(/<br\/>/g, " "));

        // Add the item to the distances list.
        var newOption = createMarkerOption(i, "1");
        var newOption2 = createMarkerOption(i, "2");
        var selectMarkers1 = document.getElementById("selectMarker1");
        var selectMarkers2 = document.getElementById("selectMarker2");
        selectMarkers1.appendChild(newOption);
        selectMarkers2.appendChild(newOption2);

        // Find the tags.
        var tagPart = document.createTextNode(" Tags: ");
        var tagsPart = document.createElement("span");
        var tempString = markerTagStrings[i];
        // Skip the first '|'
        tempString = tempString.substring(1);
        for (; tempString.length > 0;) {
            var nextPipe = tempString.indexOf('|');
            if (nextPipe == -1) {
                // String is busticated.
                tempString = ''
            } else {
                var nextTag = tempString.substring(0, nextPipe);
                addTagToList(nextTag);
                // Add links to tags
                tempString = tempString.substring(nextPipe+1);
                var tempLinkPart = document.createElement("a");
                tempLinkPart.setAttribute("href", "javascript:filterTags('" + nextTag + "');");
                var tempLinkText = document.createTextNode(nextTag);
                var space = document.createTextNode(" ");
                tempLinkPart.appendChild(tempLinkText);
                tagsPart.appendChild(tempLinkPart);
                tagsPart.appendChild(space);
            }
        }

        entry.appendChild(linkPart);
        entry.appendChild(captionPart);
        entry.appendChild(tagPart);
        entry.appendChild(tagsPart);
        var info = document.getElementById("info");
        info.appendChild(entry);
    }

    function filterTags(tag) {
        var selectMarkers1 = document.getElementById("selectMarker1");
        var selectMarkers2 = document.getElementById("selectMarker2");
        if (tag == '') {
            // special case - show all
            for (var i = 0; i < markerLength; i++) {
                if (markersShown[i] == false) {
                    // Display it.
                    markersShown[i] = true;
                    addMarkerIndex(i);
                    var divInfo = document.getElementById("entry" + i);
                    divInfo.style.display = "";
                    selectMarkers1.appendChild(createMarkerOption(i, "1"));
                    selectMarkers2.appendChild(createMarkerOption(i, "2"));
                }
            }
            return;
        }
        var tagRE = new RegExp("\\|" + tag + "\\|");
        for (var i = 0; i < markerLength; i++) {
            if (markerTagStrings[i].match(tagRE)) {
                // Display the text and marker
                if (markersShown[i] == false) {
                    // We need to display it.
                    markersShown[i] = true;
                    addMarkerIndex(i);
                    var divInfo = document.getElementById("entry" + i);
                    divInfo.style.display = "";
                    selectMarkers1.appendChild(createMarkerOption(i, "1"));
                    selectMarkers2.appendChild(createMarkerOption(i, "2"));
                }
            } else {
                // Hide text and marker
                if (markersShown[i] == true) {
                    var thisNode1 = document.getElementById("option1" + i);
                    var thisNode2 = document.getElementById("option2" + i);
                    // Hide it.
                    markersShown[i] = false;
                    removeMarkerIndex(i);
                    var divInfo = document.getElementById("entry" + i);
                    divInfo.style.display = "none";
                    selectMarkers1.removeChild(thisNode1);
                    selectMarkers2.removeChild(thisNode2);
                }
            }
        }
    }

    function finishAddingTags() {
        // Sort the tags.
        allTags = new Array();
        var j = 0;
        // Find the maximum count of any one tag.
        var maxTagCount = 0;
        for (tag in tagToCountTable) {
            allTags[j] = tag;
            if (tagToCountTable[tag] > maxTagCount) {
                maxTagCount = tagToCountTable[tag];
            }
            j++;
        }
        // Use this to sort by count
        //allTags.sort(sortByCount);
        allTags.sort();
 
        // Add the list of all tags
        var tags = document.getElementById("tags");
        var tagAllEntry = document.createElement("a");
        tagAllEntry.setAttribute("href", "javascript:filterTags('');");
        var tagAllText = document.createTextNode('(all)(' + markerLength + ')');
        tagAllEntry.appendChild(tagAllText);
        tags.appendChild(tagAllEntry);
        var space = document.createTextNode(' ');
        tags.appendChild(space);

        // And insert them.
        var space = document.createTextNode(' ');
        for (var j = 0; j < allTags.length; j++) {
            var tempLinkEntry = document.createElement("a");
            tempLinkEntry.setAttribute("href", "javascript:filterTags('" + allTags[j] + "');");
            var className;
            var tagCount = tagToCountTable[allTags[j]];
            if (tagCount < (2.5 * maxTagCount) / 10) {
                className = "one";
            } else if (tagCount < (5 * maxTagCount) / 10) {
                className = "two";
            } else if (tagCount < (7.5 * maxTagCount) / 10) {
                className = "three";
            } else {
                className = "four";
            }
            tempLinkEntry.setAttribute("class", className);
            //tempLinkEntry.class = className;
            var tempLinkText = document.createTextNode(allTags[j] + "(" + tagCount + ")");
            tempLinkEntry.appendChild(tempLinkText);
            tags.appendChild(tempLinkEntry);
            var space = document.createTextNode(' ');
            tags.appendChild(space);
        }
        for (var j = 0; j < markerLength; j++) {
            markersShown[j] = true;
            eval('callback' + j + ' = function() {markerCallbacks[' + j + ']();}');
        }
    }

    //]]>
