//////////////////////////////////////////////////////
// Chron objects                                    //
//////////////////////////////////////////////////////
	function timerObj() {
		this.startTime = (new Date()).getTime();
		this.stopTime = 0;
		this.splitTime = 0;

		this.start = function() {
			this.startTime = (new Date()).getTime();
		}
		this.stop = function() {
			this.stopTime = (new Date()).getTime();
		}
		this.elapsed = function() {
			if (this.stopTime == 0) {
				this.stop();
			}
			return this.stopTime - this.startTime;
		}
		this.split = function() {
			this.splitTime = (new Date()).getTime() - this.startTime;
			return this.splitTime;
		}
		this.diff = function() {
			if (this.split == 0) {
				return this.split();
			} else {
				var oldSplitTime = this.splitTime;
				return this.split() - oldSplitTime;
			}
		}
	}
	// Scheduler (requires timer)
	function ChronometerTask(workFunction, callbackFunction, interval_ms, maxIteration) {
		this.workFunction = workFunction;
		this.callbackFunction = callbackFunction;
		this.interval = interval_ms;
        this.startTime = 0;
		this.lastTime = 0;
		this.maxIteration = maxIteration;
		this.counter = 0;
        var executionInterval = 0;
		this.checkTime = function(currentTime, currentTaskId) {
            if (this.lastTime == 0) {
                this.startTime = currentTime;
				this.lastTime = this.startTime;
			}
            if (currentTime - this.lastTime >= interval_ms) {
                this.counter++;
                this.lastTime = currentTime;
                eval(workFunction);
            }
            if (this.maxIteration > -1 && this.counter >= this.maxIteration) {
                this.destroy(currentTaskId);
            }
		}
        this.pause = function(pause_ms) {
        
        }
		this.destroy = function(currentTaskId) {
            if (this.callbackFunction && this.callbackFunction != null && this.callbackFunction.length > 0) {
				eval(callbackFunction);
			}
			delete pageChronometer.tasks[currentTaskId];
		}
	}
    // pageChronometer.tasks['test'] = new ChronometerTask("console.append(\'test\');", null, 100, 10);
        
//////////////////////////////////////////////////////
// Singleton declarations                           //
//////////////////////////////////////////////////////
	var	pageStopwatch = new function() {	// singleton page stopwaqtch
		this.obj = new timerObj();
	}
	var pageChronometer = new function() { // page Chronometer singleton
        // configuration parameters
        this.DISPLAY_WINDOW_STATUS = false; // show status in window status
		this.SLEEP_THRESHOLD = 0; // number of tasks in the page tasks array beyond which to consider sleeping -- should be 0
        this.SLEEP_TIME = 2500; // number of ms to wait after first loading for nothing to happen before going to sleep
		this.UPDATE_INTERVAL_MS = 40; // milliseconds to update the chronometer -  >40 ms recommended
		this.REM_CYCLE_MS = 500; // milliseconds to update the chronometer in sleep mode
        this.MAX_EXECUTION_TIME = -1; // if <=0, infinite execution

        // object properties
		this.time = 0;
        this.startTime = 0;
        this.peakLag = 0; // the interval will try to catch up with real time.  peakLag will measure max lag
		this.tasks = new function() {} // task singleton leave empty for associate task array
		this.pageLoaded = false;
		this.interval_id = -1;
		this.sleeping = false;
		this.init = function() {
			this.interval_id = setInterval('pageChronometer.updateTime()', this.UPDATE_INTERVAL_MS);
			this.sleeping = false;
            this.startTime = (new Date()).getTime();
		}
		this.checkInterval = function() {// this will change the interval to sleep cycle if there are no tasks after initial 2000ms initialization period
			if (this.REM_CYCLE_MS > this.UPDATE_INTERVAL_MS && this.time > this.SLEEP_TIME) {
				if (!this.sleeping && this.taskCount() == this.SLEEP_THRESHOLD) {
                    // all tasks complete
                    this.sleep();
				} else if (this.sleeping && this.taskCount() > this.SLEEP_THRESHOLD) {
                    // task was added while sleeping
                    this.wakeUp();
				}
			}
		}
        this.wakeUp = function() {
            window.clearInterval(this.interval_id);
            this.init();
        }
        this.sleep = function() {
            window.clearInterval(this.interval_id);
            this.sleeping = true;
            this.time -= this.UPDATE_INTERVAL_MS;
            this.interval_id = setInterval('pageChronometer.updateTime()', this.REM_CYCLE_MS);
        }
        var triggerLock = false;
		this.updateTime = function() {
			this.checkInterval();
            if (this.sleeping) {
                this.time += pageChronometer.REM_CYCLE_MS;
            } else {
                this.time += pageChronometer.UPDATE_INTERVAL_MS;
            }
            if (this.MAX_EXECUTION_TIME > 0) {
                if (this.time > this.MAX_EXECUTION_TIME) {
                    this.kill();
                    triggerLock = true;
                }
            }
            if (!triggerLock) {
    			this.trigger();
            }
            if (this.DISPLAY_WINDOW_STATUS) {
                nightRider.flash(this.time);
            }
		}
        this.currentTask = null;
		this.trigger = function() {
			// do stuff
			if (!this.pageLoaded) {
                try {
                    pageInit(); // do not load page init until the page is loaded
                    this.pageLoaded = true;
                } catch (le) {
                    console.append('page could not be fully loaded : terminal javascript error : ' + le);
                    // shut down the chronometer
                    this.pageLoaded = false;
                    this.kill();
                }
            }
			if (this.pageLoaded) {
                for (var i in this.tasks) {
                    delete this.currentTask;
                    this.currentTask = this.tasks[i];
					this.tasks[i].checkTime(this.time,i);
                }
            }
		}
        var tmpTaskCount;
        this.taskCount = function() {
            tmpTaskCount = 0;
            for (var i in this.tasks) {
                tmpTaskCount++;
            }
            return tmpTaskCount;
        }
        var elapsedTime = 0;
        var lag = 0;
        this.getLag = function() { // this gives a measure of how many seconds the chronometer is off the absolute time due to delays caused by scripts.  Should optimize trigger intervals to minimize this value.
            // the page chronometer time should always be <= real time
            elapsedTime = (new Date()).getTime() - this.startTime;
            lag = elapsedTime - this.time;
            if (lag > this.peakLag) {
                this.peakLag = lag;
            }
            return lag;
        }
		this.kill = function() {
			window.clearInterval(this.interval_id);
		}
        this.addTask = function(newTask, newTaskId) {
            if (this.sleeping == true) {
                this.wakeUp();
            }
            if (!newTaskId) {
                newTaskId = 'auto_task_' + generateRandomNumWord(8, 'upper');
            }
            this.tasks[newTaskId] = newTask;
        }
	}

	var ua = new function() { // user agent singleton
		var u = navigator.userAgent, d = document;
		this.dom = (typeof d.getElementById != "undefined") && (typeof d.createElement != "undefined");
		this.safari = /Safari/.test(u);
		this.opera = /Opera/.test(u);
        this.konqueror = /Konqueror/.test(u);
        this.KHTML = /KHTML/.test(u);
		this.ie = (typeof d.all != "undefined") && (!this.safari && !this.opera && !this.konqueror);
	};
    var console = new function() { // page console for debugging
		this.divObj = document.getElementById("console");
		this.init = function() {
			this.divObj = document.getElementById("console");
			if (!this.divObj) {
                if (parent.document.getElementById("console")) {
                    this.divObj = parent.document.getElementById("console");
                } else {
                    alert("Missing console layer");
                }
			}
		}
        var newline = null;
        var appendTxt = null;
        this.append = function(data) {
			if (!this.divObj) {
				this.init();
			}
			newline = document.createElement("div");
			this.divObj.appendChild(newline);
			appendTxt = document.createTextNode(data);
			newline.appendChild(appendTxt);
		}
        this.render = function(data) {
			if (!this.divObj) {
				this.init();
			}
            this.divObj.innerHTML = data;
		}
	}

	var windowDimensionObj = new function () {
        this.getWidth = function() {
            if( typeof( self.innerWidth ) == 'number' ) {
                //Non-IE
                return self.innerWidth;
            } else if( document.documentElement && document.documentElement.clientWidth ) {
                //IE 6+ in 'standards compliant mode'
                return document.documentElement.clientWidth;
            } else if( document.body && document.body.clientWidth) {
                //IE 4 compatible
                return document.body.clientWidth;
            } else {
                return 640;
            }
        }
        this.getHeight = function() {
            if( typeof( self.innerWidth ) == 'number' ) {
                //Non-IE
                return self.innerHeight;
            } else if( document.documentElement && document.documentElement.clientWidth ) {
                //IE 6+ in 'standards compliant mode'
                return document.documentElement.clientHeight;
            } else if( document.body && document.body.clientWidth) {
                //IE 4 compatible
                return document.body.clientHeight;
            } else {
                return  480;
            }
        }
    }
    var prettyCalendar = new function() {
        function PrettyMonth(label, monthValue) {
            this.label = label;
            this.monthValue = monthValue;
        }
        this.prettyMonths = new Array(
            new PrettyMonth("Jan", 1),
            new PrettyMonth("Feb", 2),
            new PrettyMonth("Mar", 3),
            new PrettyMonth("Apr", 4),
            new PrettyMonth("May", 5),
            new PrettyMonth("Jun", 6),
            new PrettyMonth("Jul", 7),
            new PrettyMonth("Aug", 8),
            new PrettyMonth("Sep", 9),
            new PrettyMonth("Oct", 10),
            new PrettyMonth("Nov", 11),
            new PrettyMonth("Dec", 12)
        );
        this.getPrettyMonth = function(id) {
            thisId = eval(id);
            for (var i=0; i<this.prettyMonths.length; i++) {
                if (this.prettyMonths[i].monthValue == thisId) {
                    return this.prettyMonths[i].label;
                }
            }
            return null;
        }
    }
    // alert(prettyCalendar.getPrettyMonth(09));

    var ordersOfMagnitude = new function() {
        function Scale(label, multiplier) {
            this.label = label;
            this.multiplier = multiplier;
        }
        var SCALE_0 = new Scale("", 1);
        var SCALE_1 = new Scale("tens", 10);
        var SCALE_2 = new Scale("hundreds", 100);
        var SCALE_3 = new Scale("thousands", 1000);
		var SCALE_4 = new Scale("ten thousands", 10000);		
		var SCALE_5 = new Scale("0.1 million", 100000);
        var SCALE_6 = new Scale("millions", 1000000);
        var SCALE_9 = new Scale("billions", 1000000000);
        var SCALE_12 = new Scale("trillions", 1000000000000);

        this.getScale = function(powerOfTen) {
            if (powerOfTen <=0) {
                return SCALE_0;
            }
            switch(powerOfTen){
                case 1: {
                    return SCALE_1;
                    break;
                }
                case 2: {
                    return SCALE_2;
                    break;
                }
                case 3: {
                    return SCALE_3;
                    break;
                }
				case 4: {
                    return SCALE_4;
                    break;
                }
				case 5: {
                    return SCALE_5;
                    break;
                }  				
                case 6: {
                    return SCALE_6;
                    break;
                }
                case 9: {
                    return SCALE_9;
                    break;
                }
                case 12: {
                    return SCALE_12;
                    break;
                }
                default : {
                    var returnLabel = "x10^" + powerOfTen;
                    var returnMultiplier = 10^powerOfTen;
                    return new Scale(returnLabel, returnMultiplier);
                }
            }
        }
    }

    var nightRider = new function() {
        var nightRiderCounter = 0;
        var nightRiderDisplayArr = new Array();
        nightRiderDisplayArr[0] = '\\---------';
        nightRiderDisplayArr[1] = '-\\--------';
        nightRiderDisplayArr[2] = '--\\-------';
        nightRiderDisplayArr[3] = '---\\------';
        nightRiderDisplayArr[4] = '----\\-----';
        nightRiderDisplayArr[5] = '-----\\----';
        nightRiderDisplayArr[6] = '------\\---';
        nightRiderDisplayArr[7] = '-------\\--';
        nightRiderDisplayArr[8] = '--------\\-';
        nightRiderDisplayArr[9] = '---------\\';
        nightRiderDisplayArr[10] = '---------/';
        nightRiderDisplayArr[11] = '--------/-';
        nightRiderDisplayArr[12] = '-------/--';
        nightRiderDisplayArr[13] = '------/---';
        nightRiderDisplayArr[14] = '-----/----';
        nightRiderDisplayArr[15] = '----/-----';
        nightRiderDisplayArr[16] = '---/------';
        nightRiderDisplayArr[17] = '--/-------';
        nightRiderDisplayArr[18] = '-/--------';
        nightRiderDisplayArr[19] = '/---------';
        this.flash = function(thisTime) {
            nightRiderCounter = nightRiderCounter%(nightRiderDisplayArr.length);
            window.status = nightRiderDisplayArr[nightRiderCounter] + ' lag = ' + pageChronometer.getLag() + ' peak == ' + pageChronometer.peakLag;
            nightRiderCounter++;
        }

    }


//////////////////////////////////////////////////////
// Static Methods                                   //
//////////////////////////////////////////////////////
    function trimString(sInString) {
      sInString = sInString.replace( /^\s+/g, "" );// strip leading
      return sInString.replace( /\s+$/g, "" );// strip trailing
    }
    
    function checkNumber(theNumCandidate){
        var anum=/(^\d+$)|(^\d+\.\d+$)/
        if (anum.test(theNumCandidate)) {
            return true;
        } else {
            return false;
        }
    }
    
    function validStringNum(testString) {
        var value = true;
        var notValidChars = /[^a-zA-Z0-9]/;
        return !notValidChars.test(testString);
    }
    
    function getKeyEventCharacterCode(e, returnCharacterType) { // returnCharacterType = 'character' or 'decimal'
        var pressedKey;
        if (document.all)    { e = window.event; }
        if (e.keyCode) {
            pressedKey = e.keyCode;
        } else if (e.which) {
            pressedKey = e.which;
        } else {
            return;
        }
        pressedCharacter = String.fromCharCode(pressedKey);
        // alert(' Character = ' + pressedCharacter + ' [Decimal value = ' + pressedKey + ']');

        if (returnCharacterType == 'character') {
            if (pressedCharacter) {
                return pressedCharacter;
            }
        } else if (returnCharacterType == 'decimal') {
            if (pressedKey) {
                return pressedKey;
            }
        } else {
            alert('getKeyEventCharacterCode() Error : Malformed return character type == ' + returnCharacterType);
        }
        return false;
    }

    function printWindow(){
        if (is.v >= 4) {
            window.print();
        } else {
            alert('The current computer does not support this print button.  Please use the browser print function from the file menu.');
        }
    }

    function generateRandomInt(maxRand) {
        if (!maxRand) {
            maxRand = 10000000000000000;
        } else {
            maxRand++;
        }
        var ranNum= Math.floor(Math.random()*maxRand);
        return ranNum;
    }
    var alphabetArray = new Array(
        'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
        'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
        'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
    );
    
    // generates random word with characters limit
    function generateRandomWord(characters, alpha_case) {
        var randWord = '';
        for (var i=0; i<characters; i++) {
            randWord += alphabetArray[generateRandomInt(alphabetArray.length - 1)];
        }
        if (alpha_case) {
            if (alpha_case.toLowerCase() == 'lower') {
                randWord = randWord.toLowerCase();
            } else if (alpha_case.toLowerCase() == 'upper') {
                randWord = randWord.toUpperCase();                
            }
        }
        return randWord;
    }
    function generateRandomNumWord(characters, alpha_case) {
        // this function a word with 50% number and 50% letters (on average)
        var randWord = '';
        for (var i=0; i<characters; i++) {
            if(generateRandomInt(1) == 1) {
                randWord += alphabetArray[generateRandomInt(alphabetArray.length - 1)];
            } else {
                randWord += generateRandomInt(9);
            }
        }
        if (alpha_case) {
            if (alpha_case.toLowerCase() == 'lower') {
                randWord = randWord.toLowerCase();
            } else if (alpha_case.toLowerCase() == 'upper') {
                randWord = randWord.toUpperCase();                
            }
        }
        return randWord;
    }

    var RegexFilters = new function() {
        this.zipCode = /[0-9]{5}((-)[0-9]{4,5})?/;
        this.currencyFilter= /\$\d{1,3}(,\d{3})*\.\d{2}/; // $17.23 or $14,281 or 545.45
        this.internationalPhoneFilter = /^\d(\d|-){7,20}/; // International Phone Number
        this.ipAddressFilter = /^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/;
        this.date = dateFilter = /^\d{1,2}(\-|\/|\.)\d{1,2}\1\d{4}$/; // xx/xx/xxxx
        this.stateShortFilter = /^(AK|AL|AR|AZ|CA|CO|CT|DC|DE|FL|GA|HI|IA|ID|IL|IN|KS|KY|LA|MA|MD|ME|MI|MN|MO|MS|MT|NB|NC|ND|NH|NJ|NM|NV|NY|OH|OK|OR|PA|RI|SC|SD|TN|TX|UT|VA|VT|WA|WI|WV|WY)$/i; // State Abbreviation
        this.socialSecurityFilter = /^\d{3}\-\d{2}\-\d{4}$/; // xxx-xx-xxxx
        this.phoneFilter = /^((\+\d{1,3}(-| )?\(?\d\)?(-| )?\d{1,3})|(\(?\d{2,3}\)?))(-| )?(\d{3,4})(-| )?(\d{4})(( x| ext)\d{1,5}){0,1}$/;
        this.emailFilter = /^.+\@(\[?)[a-zA-Z0-9\-\.]+\.([a-zA-Z]{2}|(com|net|org|edu|int|mil|gov|arpa|biz|aero|name|coop|info|pro|museum)|[0-9]{1,3})(\]?)$/; // a@b.com or a@127.0.0.1 or a@b.co.kr
        this.integer = /^-?\d+$/;
    }
    function regexTest(regexFilter,testString) {
        if (regexFilter == '') {
            alert('Testing filter is empty.');
            return false;
        }
        if (testString == '') {
            alert('Test string is empty.');
            return false;
        }
        return regexFilter.test(testString);
    }

    function validateEmail(formId) {
        var formObj = document.getElementById(formId);
        if (formObj && formObj.value !=  '') {
            if (regexTest(RegexFilters.emailFilter, formObj.value)) {
                return true;
            } else {
                alert("The email entered (" + formObj.value + ") is invalid.");
            }
        } else {
            alert("Please enter a valid email.");
        }
        return false;
    }

//////////////////////////////////////////////////////
// Static GUI Methods                               //
//////////////////////////////////////////////////////

    function hideObject(strId) {
        var visObj = document.getElementById(strId);
        if (visObj) {
            visObj.style.display = 'none';
        }
    }

    function showObject(strId) {
        var visObj = document.getElementById(strId);
        if (visObj) {
            visObj.style.display = '';
        }
    }
    function preloadImages(thisImgArray) {
        if (document.images) {
            for(var loop = 0; loop < thisImgArray.length; loop++) {
                var an_image = new Image();
                an_image.src = thisImgArray[loop];
            }
        }
    }
    function toggleImages(thisDivImgStart, thisToggleImg_1, thisToggleImg_2) {
        thisDivImgStartObj = document.images[thisDivImgStart];
        var curImgSrc = thisDivImgStartObj.src;
        if (curImgSrc.indexOf(thisToggleImg_1) > 0) {
            thisDivImgStartObj.src = thisToggleImg_2;
        } else if (curImgSrc.indexOf(thisToggleImg_2) > 0) {
            thisDivImgStartObj.src = thisToggleImg_1;
        }
    }

    function toggleVisibility(visId) {
        var visObj = document.getElementById(visId);
        if (visObj) {
            if (visObj.style.display=='none') {
                visObj.style.display = ''
            } else {
                visObj.style.display = 'none'
            }
        }
    }

    function isVisible(visId) {
        var visObj = document.getElementById(visId);
        if (visObj) {
            if (visObj.style.display.toLowerCase() == 'none') {
                return false;
            }
        }
        return true;
    }
    function toggleCheckboxRadio(checkboxId) {
        var checkboxObj = document.getElementById(checkboxId);
        if (checkboxObj) {
            if (checkboxObj.checked) {
                checkboxObj.checked = false;
            } else {
                checkboxObj.checked = true;
            }
        }
    }

    function objectCoordinates(objCoordX, objCoordY, objTrueX, objTrueY) {
        this.x = objCoordX;
        this.y = objCoordY;
        this.xx = objTrueX; // includes scrolled space from left
        this.yy = objTrueY; // includes scrolled space from top
    }

    function getImageCoordinates(imageObjId, xOffset, yOffset) {
        var theObject = document.images[imageObjId];
        if (theObject == null) {
            return null;
        }

        if (imageObjId.indexOf('_right') != -1) {
            xOffset = xOffset - theObject.width;
        }
        try {
            theObject.style.position = "absolute";
        } catch (pe) {}
        var objX = 0;
        var objY = 0;
        var objTX = 0;
        var objTY = 0;

        if (document.layers) {
            objX=theObject.x;
            objY=theObject.y;
            objTX=objX - window.innerWidth;
            objTY=objY - window.innerHeight;
        } else if (document.all) {
            objX=theObject.offsetLeft;
            objY=theObject.offsetTop;
            objTX=objX - document.body.scrollLeft;
            objTY=objY - document.body.scrollTop;
        } else {
            objX=theObject.offsetLeft;
            objY=theObject.offsetTop;
            objTX=objX - document.documentElement.scrollLeft;
            objTY=objY - document.documentElement.scrollTop;
        }
        objX+=xOffset;
        objY+=yOffset;
        objTX+=xOffset;
        objTY+=yOffset;
        try {
            theObject.style.position = "static";
        } catch (pe) {}
        return new objectCoordinates(objX, objY, objTX, objTY);
    }

    function getAbsoluteTop() {
        if (document.layers) {
            return window.pageYOffset;
        } else if (document.all) {
            return document.body.scrollTop;
        } else {
            return document.body.scrollTop;
        }
    }
    function pxToInt(size) {
        if (regexTest(RegexFilters.integer,size)) {
            return size;
        }
        if (size.indexOf('px') != -1) {
            size = size.substring(0, size.indexOf('px'));
        }
        return eval(size);
    }

    function fade(initial_opacity, final_opacity, chronId) {
        var cronObj = pageChronometer.tasks[chronId];
        var fractionComplete = (cronObj.counter / cronObj.maxIteration);
        var opacityDelta = parseInt((final_opacity - initial_opacity)/cronObj.maxIteration);
        var nextOpacity = initial_opacity + (opacityDelta * cronObj.counter);
        changeOpac(nextOpacity, "popupMask");
    }
    function fadeIn() {
        var cronObj = pageChronometer.tasks['popupMaskFadeIn'];
        var nextOpacity = parseInt(((cronObj.maxIteration - cronObj.counter) / cronObj.maxIteration) * 100);
        changeOpac(nextOpacity, "popupMask");
        return true;
    }
    function fadeOut() {
        var cronObj = pageChronometer.tasks['popupMaskFadeIn'];
        var nextOpacity = parseInt(100 - ((cronObj.maxIteration - cronObj.counter) / cronObj.maxIteration) * 100);
        changeOpac(nextOpacity, "popupMask");
        return true;
    }

    function changeOpac(opacity, objectid) {
        var object = document.getElementById( objectid );
        changeObjOpac(opacity,object);
    }
    function changeObjOpac(opacity, obj) {
        var objStyle = obj.style;
        if (objStyle) {
            objStyle.opacity = (opacity / 100); 
            objStyle.MozOpacity = (opacity / 100); 
            objStyle.KhtmlOpacity = (opacity / 100); 
            objStyle.filter = "alpha(opacity=" + opacity + ")";
        }
    }
    function getOpac(objectid) {
        var object = document.getElementById( objectid ).style;
        object.visibility = "visible";
        if (object.opacity) {
            return parseFloat(object.opacity);
        } else if (object.MozOpacity){
            return parseFloat(object.MozOpacity);
        } else if (object.KhtmlOpacity){
            return parseFloat(object.KhtmlOpacity);
        } else if (object.filter){
            return 0.00;
        }
    }
    function getEventTarget(e) { // returns the mouseover or click event target object
        var targ;
        if (!e) var e = window.event;
        if (e.target) {
            targ = e.target;
        } else if (e.srcElement) {
            targ = e.srcElement;
        }
        if (targ && targ.nodeType == 3) { // defeat Safari bug
            targ = targ.parentNode;
        }
        return targ;
    }
    function removeChildNodes(divLayerId) {
        var divObj = document.getElementById(divLayerId);
        if (divObj) {
            while (divObj.hasChildNodes()) {
                divObj.removeChild(divObj.firstChild);
            }
        }
    }
    function removeNode(nodeId) {
        var nodeObj = document.getElementById(nodeId);
        if (nodeObj) {
            nodeObj.parentNode.removeChild(nodeObj);
        }
    }
    function stopEventBubbling(e) {
        if (!e) var e = window.event;
        e.cancelBubble = true;
        if (e.stopPropagation) e.stopPropagation();
    }

    function getViewportSize(axes, includeScrollbar) {
        var windowWidth=0;
        var windowHeight=0;
        if (document.documentElement) {
            if (includeScrollbar) {
                windowWidth = document.documentElement.offsetWidth;
                windowHeight = document.documentElement.offsetHeight;
            } else {
                windowWidth = document.documentElement.clientWidth;
                windowHeight = document.documentElement.clientHeight;
            }
        } else if (document.body) {
            if (includeScrollbar) {
                windowWidth = document.body.offsetWidth;
                windowHeight = document.body.offsetHeight;
            } else {
                windowWidth = document.body.clientWidth;
                windowHeight = document.body.clientHeight;
            }
        } else if (window.innerWidth){
            if (includeScrollbar) {
                windowWidth = window.innerWidth;
                windowHeight = window.innerHeight;
            } else {
                windowWidth = window.outerWidth;
                windowHeight = window.outerHeight;
            }
        } else {
            alert("Unable to determine window size.");
            return false;
        }
        if (axes.toLowerCase() == 'x') {
            return windowWidth;
        } else if (axes.toLowerCase() == 'y') {
            return windowHeight;
        } else {
            alert("Invalid axes.");
            return false;
        }
    }

    function getScrollSize(axes) {
        var scrollWidth=0;
        var scrollHeight=0;
        if (document.documentElement) {
            scrollWidth = document.documentElement.scrollLeft;
            scrollHeight = document.documentElement.scrollTop;
        } else if (window.pageXOffset){
            scrollWidth = window.pageXOffset;
            scrollHeight = window.pageYOffset;
        } else if (document.body) {
            scrollWidth = document.body.scrollLeft;
            scrollHeight = document.body.scrollTop;
        } else {
            alert("Unable to determine scrollbar size.");
            return false;
        }
        if (axes == 'x') {
            return scrollWidth;
        } else {
            return scrollHeight;
        }
    }

    function hex2RGB(hexColor,returnColor) {
        if (hexColor.length != 6) {
            return -1;
        }

        var intColor = parseInt(hexColor, 16); // integer representation of hexadecimal value

        var red   = (intColor >> 16) & 0xFF;
        var green = (intColor >> 8) & 0xFF;
        var blue  = intColor & 0xFF;
        if (returnColor.toLowerCase() == 'r' || returnColor.toLowerCase() == 'red') {
            return red;
        } else if (returnColor.toLowerCase() == 'g' || returnColor.toLowerCase() == 'green') {
            return green;
        } else if (returnColor.toLowerCase() == 'b' || returnColor.toLowerCase() == 'blue') {
            return blue;
        }
        return -1;
    }

    function URLencode(sStr) {
        var returnStr = escape(sStr);
        // following characters not escaped by js escape function
        returnStr = returnStr.replace(/\+/g, '%2B');
        returnStr = returnStr.replace(/\"/g,'%22');
        returnStr = returnStr.replace(/\'/g, '%27');
        returnStr = returnStr.replace(/\//g,'%2F');
        return (returnStr);
    }

    function copyToClipboard(id){
        var textRange = document.body.createTextRange();
        textRange.moveToElementText(document.getElementById(id));
        textRange.execCommand("SelectAll");
        textRange.execCommand("Copy");
    }

    function stringToId(sStr) {
        var returnStr = sStr.replace(/ /g, '_');
        returnStr = returnStr.replace(/\-/g, '_');
        returnStr = returnStr.replace(/\+/g, '_');
        returnStr = returnStr.replace(/\'/g, '_');
        returnStr = returnStr.replace(/\"/g, '_');
        returnStr = returnStr.replace(/\//g, '_');
        returnStr = returnStr.replace(/\?/g, '_');
        returnStr = returnStr.replace(/\!/g, '_');
        returnStr = returnStr.replace(/___/g, '_');
        returnStr = returnStr.replace(/__/g, '_');
        return (returnStr);
    }

    function setClassName(objId, className) {
        if (document.getElementById(objId)) {
            document.getElementById(objId).className = className;
        }
    }

    function getElementStyle(elemID, IEStyleProp, CSSStyleProp) {
        // usage getElementStyle(colorItemId, "backgroundColor", "background-color")
        var elem = document.getElementById(elemID);
        if (elem.currentStyle) {
            return elem.currentStyle[IEStyleProp];
        } else if (window.getComputedStyle) {
            var compStyle = window.getComputedStyle(elem, "");
            return compStyle.getPropertyValue(CSSStyleProp);
        }
        return "";
    }

    function HashMap() {
        this.length = 0;
        this.items = new Array();
        for (var i = 0; i < arguments.length; i += 2) {
            if (typeof(arguments[i + 1]) != 'undefined') {
                this.items[arguments[i]] = arguments[i + 1];
                this.length++;
            }
        }
        this.removeItem = function(in_key) {
            var tmp_value;
            if (typeof(this.items[in_key]) != 'undefined') {
                this.length--;
                var tmp_value = this.items[in_key];
                delete this.items[in_key];
            }
           
            return tmp_value;
        }
        this.getItem = function(in_key) {
            return this.items[in_key];
        }
        this.setItem = function(in_key, in_value) {
            if (typeof(in_value) != 'undefined') {
                if (typeof(this.items[in_key]) == 'undefined') {
                    this.length++;
                }
                this.items[in_key] = in_value;
            }
            return in_value;
        }
        this.hasItem = function(in_key) {
            return typeof(this.items[in_key]) != 'undefined';
        }
        this.getFirstItemKey = function() {
            for (var i in this.items) {
                return i;
            }
        }
        this.getLastItemKey = function() {
            var tmpCount = 0;
            for (var i in this.items) {
                tmpCount++;
                if (tmpCount == this.length) {
                    return i;
                }
            }
        }
    }

