            var popupWindow = new Array();
            var nWindows;
            var activeList = new Array();
            var timeRequest = new Array();
            var popStart = new Array();
            var haveWarned = new Array();
            var windowURL = new Array();
            var pauseTime = new Array();
            var alertWindow = new Array();
            var alertWindowTimeout = new Array();
            var updateInterval = null;
            var nOpenWindows = 0;
            var warningContent;
            var warningLoaded;
            var alive = new Array();
            var officialTitle;
            var onAdBox = false;
            
            function ajax(url, vars, callbackFunction)
            {
                if (window.XMLHttpRequest) {
                  var request = new XMLHttpRequest();
                }
                else if(window.ActiveXObject) {
                  request = new ActiveXObject("MSXML2.XMLHTTP.3.0");
                }
                request.open("POST", url, true);
                request.setRequestHeader("Content-Type","application/x-www-form-urlencoded");

                request.onreadystatechange = function()
                {
                    if (request.readyState == 4 && request.status == 200)
                    {
                        if (request.responseText)
                            {
                                callbackFunction(request.responseText);
                            }
                    }
                };
                request.send(vars);
            }

            String.prototype.trim = function() {
                return this.replace(/^\s+|\s+$/g,"");
            }
            String.prototype.ltrim = function() {
                return this.replace(/^\s+/,"");
            }
            String.prototype.rtrim = function() {
                return this.replace(/\s+$/,"");
            }

            function indexOf(array,element)
            {
                var i;
                for(i=0;i<array.length;i++) if(array[i] == element) return i;
                return -1;
            }

            function removeFromActiveList(i)
            {
                var j= indexOf(activeList,i);
                activeList.splice(j,1);
            }

            function stopCountDown(i)
            {
                if(!alive[i]) return;
                alive[i] = false;
                nOpenWindows--;
                if(nOpenWindows == 0)
                {
                    document.title = officialTitle;
                    clearInterval(updateInterval);
                }
                removeFromActiveList(i);
                var templateRow = document.getElementById("templateRow" + i);
                templateRow.parentNode.removeChild(templateRow);
            }

            function killIt(i)
            {
                if(!popupWindow[i].closed) popupWindow[i].close();
                stopCountDown(i);
            }

            function pressedEnter(e)
            {
                //e is event object passed from function invocation
                var characterCode //literal character code will be stored in this variable

                if(e && e.which)
                {
                    //if which property of event object is supported (NN4)
                    e = e
                    characterCode = e.which //character code is contained in NN4's which property
                }
                else{
                    e = event
                    characterCode = e.keyCode //character code is contained in IE's keyCode property
                }

                if(characterCode == 13) return true;
                else return false;
            }

            function fixUrl(string)
            {
                string = string.trim();
                if(string=="") return string;

                //the idea here is to determine whether or not it is preceded by "http://";
                var re = /^[a-z]*:\/\/.*$/i;
                if(!string.match(re)) string = "http://" + string;
                
                //We check to see if it has a top level domain
                re = /\./;
                if(!string.match(re)) string = string + ".com";
                
                return string;
            }

            function extractTime(string,unit,inMilliseconds)
            {
                var result,toReturn=0;
                re = new RegExp("(\\d+\\.?\\d*)\\s*(?:" + unit + ")(?:[^a-z]|$)", "i");
                while(result = string.match(re))
                {
                    string = string.replace(re,"");
                    toReturn += Math.floor(inMilliseconds * parseFloat(result[1]));
                }

                return toReturn;
            }

            function toMilliseconds(string)
            {
                string = string.trim();
                re = /^\d+(\.\d*)?$/
                if(string.match(re)) return Math.floor(60*1000*parseFloat(string));
            
                var time =      extractTime(string,"ms|millisecond|milliseconds",1)
                            +   extractTime(string,"centisecond|centiseconds",10)
                            +   extractTime(string,"decisecond|deciseconds",100)
                            +   extractTime(string,"s|sec|secs|second|seconds",1000)
                            +   extractTime(string,"m|min|mins|minute|minutes",60*1000)
                            +   extractTime(string,"h|hr|hrs|hour|hours",60*60*1000)
                            +   extractTime(string,"d|day|days",24*60*60*1000)
                            +   extractTime(string,"month|months",30*24*60*60*1000)
                            +   extractTime(string,"year|years",365*24*60*60*1000)
                            +   extractTime(string,"decade|decades",10*365*24*60*60*1000)
                            +   extractTime(string,"century|centuries",100*365*24*60*60*1000)
                            +   extractTime(string,"millennium|millennia",1000*365*24*60*60*1000);

                return time;
            }

            function millisecondsToString(remaining,depth)
            {
                var unitArraySingular = new Array("day","hour","minute","second");
                var unitArrayPlural = new Array("days","hours","minutes","seconds");
                var inMilliseconds = new Array(24*60*60*1000,60*60*1000,60*1000,1000);
                var al = inMilliseconds.length,flag=0,nCurrentUnit,currentString ="";
                if(depth == null) depth = al;

                //Round up the seconds, or whatever happens to be the smallest unit
                remaining = inMilliseconds[al-1]*Math.ceil(remaining/inMilliseconds[al-1]);

                for(i=0;i<al && depth;i++)
                {
                    nCurrentUnit = Math.floor(remaining/inMilliseconds[i]);

                    if(nCurrentUnit)
                    {
                        depth--;
                        if(flag) currentString += " ";

                        currentString+=nCurrentUnit + " ";
                        if(nCurrentUnit == 1) currentString += unitArraySingular[i];
                        else currentString += unitArrayPlural[i];

                        remaining -= nCurrentUnit * inMilliseconds[i];

                        flag=1;
                    }
                }

                return currentString;
            }

            function clearAlertWindow(i)
            {
                if(alertWindowTimeout[i]) clearTimeout(alertWindowTimeout[i]);
                alertWindowTimeout[i]=null;

                //If the window is open and the additional time is being edited, we do not close the window.

                if(!alertWindow[i].closed)
                {
                    if(!(alertWindow[i].document.body.style.display=="" && alertWindow[i].document.getElementById("addTimeDialog").style.display==""))
                    {
                        alertWindow[i].close();
                        alertWindow[i] = null;
                    }
                }
                else
                {
                    alertWindow[i] = null;
                }
            }
            
            function handleExistingAlertWindow(i)
            {
                if(alertWindow[i])
                {
                    if(alertWindow[i].closed) clearAlertWindow(i);
                    else
                    {
                        if(alertWindow[i].document)
                        {
                            if(alertWindow[i].document.body)
                            {
                                var addTimeBox = document.getElementById("addTimeBox" + i);
                                if(addTimeBox)
                                {
                                    if(alertWindow[i].document.body.style.display == "none")
                                    {
                                        //In this case, the user has submitted a request for more time.
                                        addTimeBox.value = alertWindow[i].document.getElementById("addTimeBox").value;
                                        addTimeBox.parentNode.setAttribute("sign","+");
                                        addTime(addTimeBox);
                                        clearAlertWindow(i);
                                    }
                                    if(alertWindowTimeout[i] == null && alertWindow[i] && !alertWindow[i].closed)
                                    {
                                        //In this situation, time has run out, so we close the window if appropriate.
                                        clearAlertWindow(i);
                                    }
                                }
                            }
                        }
                    }
                }
            }
            
            function warningTime()
            {
                return(toMilliseconds(document.getElementById("warningLink").innerHTML))
            }
            
            function handleNewAlertWindow(i,remaining)
            {                                                
                if(remaining < warningTime() && warningLoaded && document.getElementById('oneMinuteWarningBox').checked && !haveWarned[i] && (alertWindow[i] == null || alertWindow[i].closed))
                {
                    var alertWidth = 300;
                    var alertHeight = 150;
                    var screenX = (screen.width - alertWidth)/2;
                    var screenY = (screen.height - alertHeight)/2;
                    alertWindow[i] = window.open("" + escape(windowURL[i]),"alert" + i,"screenX=" + screenX + ",screenY=" + screenY + ",toolbar=0,location=0,menubar=0,directories=0,resizable=0,scrollbars=0,height=" + alertHeight + "px,width=" + alertWidth + "px");//window.open("/alert.php?url=" + escape(windowURL[i]),"alert" + i,"screenX=" + screenX + ",screenY=" + screenY + ",toolbar=0,location=0,menubar=0,directories=0,resizable=0,scrollbars=0,height=" + alertHeight + "px,width=" + alertWidth + "px");
                    if((alertWindow[i] && !window.opera) || (alertWindow.opera))
                    {
                        alertWindow[i].document.write(warningContent);
                        alertWindow[i].document.title="You're running out of time";
                        alertWindow[i].document.getElementById("timeLeft").innerHTML = millisecondsToString(warningTime());
                        alertWindow[i].document.getElementById("site").innerHTML = windowURL[i];
                    }             
                    haveWarned[i] = 1;

                    //The following is here because chrome incorrectly resizes popup windows when moveTo is called
                    if(navigator.userAgent.toLowerCase().indexOf('chrome') == -1)
                        alertWindow[i].moveTo(screenX,screenY);
                    alertWindowTimeout[i] = setTimeout("clearAlertWindow(" + i + ")",10*1000);
                }
            }
            
            function die(s)
            {
                    document.getElementById("dieDiv").innerHTML = s;
            }

            function updateTime()
            {

                var someUnpaused = false,i,j,remaining,counterDiv,timeString,counterString,minRemaining = Infinity,minString="",toKill = new Array(),blink;

                for(j=0;j<activeList.length;j++)
                {
                    i = activeList[j];
                    handleExistingAlertWindow(i);
                    counterDiv = document.getElementById("counter" + i);
                    remaining = timeRequest[i] - (getTime() - popStart[i]);
                    if(pauseTime[i]) remaining += getTime() - pauseTime[i];
                    timeString = millisecondsToString(remaining,2);
                    
                    handleNewAlertWindow(i,remaining);
                    
                    if(remaining < 60*1000)
                    {
                        counterDiv.style.color = "red";
                    }
                    else counterDiv.style.color = "black";

                    if(!pauseTime[i])
                    {
                        someUnpaused = true;
                        
                        counterString="";
                        if(popupWindow[i].closed) toKill.push(i);
                        else if(remaining > 0) counterString = timeString;
                        else toKill.push(i);
                        
                        //Blink
                        blink = (remaining < 10*1000 && (remaining % 1000) < 500);
    
                        if((remaining < minRemaining))
                        {
                            minRemaining = remaining;
                            if(blink)
                            {
                                minString = "---------";
                            }
                            else
                            {
                                minString = counterString;
                            }
                        }
                        if(blink) counterDiv.style.visibility="hidden"; else counterDiv.style.visibility="visible";
                        counterDiv.innerHTML = counterString;
                    }
                    else
                    {
                        counterDiv.style.visibility = "visible";
                        counterDiv.innerHTML = timeString;
                    }
                }
                if(someUnpaused) document.title = minString;
                else if(nOpenWindows == 1) document.title = "Timer Paused";
                else document.title = "Timers Paused";             

                for(i=0;i<toKill.length;i++) killIt(toKill[i]);
            }

            function removePrefix(string)
            {
                re = /^\w*:\/\//;
                return string.replace(re,"");
            }

            function getIndex(e)
            {
                if (e.id)
                {
                    var re = /[a-z\s]*(\d*)/i;
                    var result = e.id.match(re);
                    if (result) return result[1];
                }
                if (e.parentNode) return getIndex(e.parentNode);
                else return null;
            }

            function restoreAddTimeLink(e)
            {
                var index = getIndex(e);
                document.getElementById("changeLinks" + index).style.display="";
                document.getElementById("addTimeDialog" + index).style.display="none";
                hide("theWordAdd" + index);
                hide("theWordSubtract" + index);
            }

            function changeTimeDialog(e,sign)
            {
                var index = getIndex(e);
                document.getElementById("changeLinks" + index).style.display="none";
                var addTimeDialog = document.getElementById("addTimeDialog" + index);
                addTimeDialog.setAttribute("sign",sign);
                var addTimeBox = document.getElementById("addTimeBox" + index);
                if(sign=="+") show("theWordAdd" + index);
                else show("theWordSubtract" + index);
                addTimeDialog.style.display = "";
                addTimeBox.focus();
                addTimeBox.select();
            }

            function moreTimeDialog(e)
            {
                changeTimeDialog(e,"+");
            }

            function lessTimeDialog(e)
            {
                changeTimeDialog(e,"-");
            }

            function addTime(e)
            {
                var index = getIndex(e);
                var addTimeBox = document.getElementById("addTimeBox" + index);
                var sign;

                timeToAddString = addTimeBox.value;
                timeToAddMilliseconds = toMilliseconds(timeToAddString);

                if(document.getElementById("addTimeDialog" + index).getAttribute("sign") == "-") sign = -1; else sign=1;

                timeRequest[index] += sign*timeToAddMilliseconds;

                var d = new Date();
                var timeRemaining = timeRequest[index] - (d.getTime() - popStart[index]);
                if (timeRemaining > warningTime()) haveWarned[index] = false;

                restoreAddTimeLink(e);
            }

            function provideIds(e,index)
            {
                if(e.id) e.id += index;
                if(e.childNodes)
                {
                    var i;
                    for(i=0;i<e.childNodes.length;i++)
                    {
                        provideIds(e.childNodes[i],index);
                    }
                }
            }
            
            function addBookmark(bookmarkURL,bookmarkTitle)
            {
                if (document.all)
                    window.external.AddFavorite(bookmarkURL,bookmarkTitle);
                else if ( window.sidebar )
                    window.sidebar.addPanel(bookmarkURL, bookmarkTitle,"");
            }

            function popSite()
            {
                var url = fixUrl(document.getElementById("url").value);
                var operaError = "In order to use this feature, you must allow popups for this site.  Simply unblocking a blocked-popup will not do.";
        
                try
                {
                    var newWindow = window.open(url);
                	if (newWindow == null )
                    {
                        alert("In order to use this feature, you must allow popups for this site.");
                        return;
                    }
                    if (window.opera)
                        if (!newWindow.opera)
                        {
                            alert(operaError);
                            return;
                        }
                }
                catch(err)
                {
                    //This is here to account for inexplicable behavior in opera
                }
                
                nOpenWindows++;
                if(nOpenWindows == 1) updateInterval = setInterval("updateTime()",100);
                newWindow.focus();
                nWindows = popupWindow.push(newWindow);
                var index = nWindows - 1;

                alive[index] = true;
                timeRequest[index] = toMilliseconds(document.getElementById("time").value);

                var d = new Date();
                popStart[index] = d.getTime();

                //Create a new entry in the table of timed sites.
                var templateCopy = document.getElementById("templateRow").cloneNode(true);
                provideIds(templateCopy,index);

                document.getElementById("siteList").appendChild(templateCopy);

                if(removePrefix(url) =="") windowURL[index] = "BLANK"; else windowURL[index] = removePrefix(url).toUpperCase();

                var siteLink = document.getElementById("site"+index);
                siteLink.innerHTML = windowURL[index];

                if (timeRequest[index] <= warningTime()) haveWarned[index] = 1; else haveWarned[index] = 0;

                pauseTime[index] = 0;

                alertWindow[index] = null;

                alertWindowTimeout[index] = null;

                //Now display it
                templateCopy.style.display = "";

                addToActiveList(index);
            }

            function addToActiveList(index)
            {
                activeList.push(index);
            }

            window.onbeforeunload = checkClose;

            function checkClose()
            {
                if (activeList.length > 0)
                {
                    var toReturn = "If you leave, the tabs or windows you have opened will not automatically close.\n";
                    if(onAdBox) toReturn += "You may right-click a link to open it it a new window.";
                    return toReturn;
                }
            }
            
            function adBoxMouseOver()
            {
                onAdBox=true;
                if(activeList.length > 0) document.getElementById('adInstructions').style.visibility='visible';
            }
            
            function adBoxMouseOut()
            {
                onAdBox=false;
                document.getElementById('adInstructions').style.visibility='hidden';
            }

            function cancelLimit(e)
            {
                response = confirm("This tab or window will not have a time limit.  Are you sure you want to do this?");
                if(response) stopCountDown(getIndex(e));
            }

            function getTime()
            {
                var d = new Date();
                return d.getTime();
            }

            function pause(e)
            {
                var index = getIndex(e);
                hide("pause"+index);
                show("unpause"+index);
                pauseTime[index] = getTime();
            }

            function unpause(e)
            {
                var index = getIndex(e);
                popStart[index] += getTime() - pauseTime[index];
                pauseTime[index] = 0;
                hide("unpause"+index);
                show("pause"+index);
            }

            function show(id)
            {
                document.getElementById(id).style.display="";
            }

            function hide(id)
            {
                document.getElementById(id).style.display="none";
            }
            
            function handleExampleLink(e)
            {
                var href=e.getAttribute("href");
                if(nOpenWindows > 0) window.open(href);
                else window.location = href;
            }
            
            function changeWarningTime()
            {
                var warningInput = document.getElementById("warningInput");
                var warningLink = document.getElementById("warningLink");
                                
                hide("warningLink");
                show("warningInput");
                
                warningInput.focus();
                warningInput.select();
            }
            
            function restoreWarningTime()
            {
                var warningInput = document.getElementById("warningInput");
                var warningLink = document.getElementById("warningLink");
                var trimmedUp = warningInput.value.trim();
                
                if(toMilliseconds(trimmedUp) > 0)
                {
                    warningLink.innerHTML = trimmedUp;
                    setWarningTimeCookie();
                }
                else warningInput.value = warningLink.innerHTML;

                show("warningLink");
                hide("warningInput");
                
            }
            
            function bodyOnLoad()
            {
                var timeDiv = document.getElementById('time');
                document.getElementById('url').focus();
                document.getElementById('url').select();
                officialTitle = document.title;
                timeDiv.value = millisecondsToString(toMilliseconds(timeDiv.value));
                                
                ajax("/alert.php","",function(s){warningContent = s;warningLoaded=true;});
            }
            
            function setWarningTimeCookie()
            {
                var warningInput = document.getElementById("warningInput");
                createCookie("minutesPleaseWarningTime",warningInput.value,7);
                //createCookie("minutesPleaseWarningTime","1 minute",7);
            }
            
            function setCheckBoxCookie()
            {                
                if(document.getElementById("oneMinuteWarningBox").checked) createCookie("minutesPleaseWarningChecked","true",7);
                else createCookie("minutesPleaseWarningChecked","false",7)
            }
            
            function createCookie(name,value,days) {
            	if (days) {
            		var date = new Date();
            		date.setTime(date.getTime()+(days*24*60*60*1000));
            		var expires = "; expires="+date.toGMTString();
            	}
            	else var expires = "";
            	document.cookie = name+"="+escape(value)+expires+"; path=/";
            }

