var g_isIE8 = false, g_compatMode = 0;
if (document.documentMode) {
    isIE8 = true;
    g_compatMode = document.documentMode;
}
else {
    g_compatMode = 5;
    if (document.compatMode) {
        if (document.compatMode == "CSS1Compat")
            g_compatMode = 7;
    }
}

function isValid(obj) { return ((typeof obj != 'undefined') && (obj != null)); }

function moveSelectedItems(fromDdl, toDdl) { // this moves the selected items from one dropdown list to another
    var selIndex = selectedIndex(fromDdl);
    while (selIndex > -1) {
        var newOpt = new Option(fromDdl.options[selIndex].text, fromDdl.options[selIndex].value);
        try {
            toDdl.add(newOpt, null); // standards compliant; doesn't work in IE
        }
        catch (ex) {
            toDdl.add(newOpt); // IE only
        }
        if (fromDdl.remove)
            fromDdl.remove(selIndex);
        else
            fromDdl.options.remove(selIndex);
        selIndex = selectedIndex(fromDdl);
    }
}

function selectedIndex(ddl) { // returns index of first selected item in a dropdown list (-1 if not found)
    var ndx = -1;
    for (var i = 0; i < ddl.options.length; i++) {
        if (ddl.options[i].selected) {
            ndx = i;
            break;
        }
    }
    return ndx;
}

function toggleControlEnabled(controlName, recurse) {
    var obj = _getObject(controlName);
    if (isValid(obj)) {
        obj.disabled = !obj.disabled;
        if (recurse)
            toggleControlEnabled_recurse(obj.childNodes);
        else {
            if (!obj.disabled)
                try { obj.focus(); } catch (ex) { }
        }
    }
}
function toggleControlEnabled_recurse(children) {
    if (isValid(children)) {
        for (var i = 0; i < children.length; i++) {
            var obj = children[i];
            if (isValid(obj)) {
                if (typeof obj.disabled != 'undefined')
                    obj.disabled = !obj.disabled;
                toggleControlEnabled_recurse(obj.childNodes);
            }
        }
    }
}

function getFY(d) // typeof(d) == Date
{ // provides a fix for the discrepancy of Date.getYear() between IE and FireFox
    var ye = Math.round(d.getTime() / 31556952000) + 1970;
    return ye + (d.getYear() - ye) % 100;
}

var Client = {
    viewportWidth: function() {
        return self.innerWidth || (document.documentElement.clientWidth || document.body.clientWidth);
    },

    viewportHeight: function() {
        return self.innerHeight || (document.documentElement.clientHeight || document.body.clientHeight);
    },

    viewportSize: function() {
        return { width: this.viewportWidth(), height: this.viewportHeight() };
    }
};

function getScrollerWidth() {
    var scr = null, inn = null;
    var wNoScroll = 0, wScroll = 0;

    // Outer scrolling div
    scr = document.createElement('div');
    scr.style.position = 'absolute';
    scr.style.top = '-1000px';
    scr.style.left = '-1000px';
    scr.style.width = '100px';
    scr.style.height = '50px';
    // Start with no scrollbar
    scr.style.overflow = 'hidden';

    // Inner content div
    inn = document.createElement('div');
    inn.style.width = '100%';
    inn.style.height = '200px';

    // Put the inner div in the scrolling div
    scr.appendChild(inn);
    // Append the scrolling div to the doc
    document.body.appendChild(scr);

    // Width of the inner div sans scrollbar
    wNoScroll = inn.offsetWidth;
    // Add the scrollbar
    scr.style.overflow = 'auto';
    // Width of the inner div width scrollbar
    wScroll = inn.offsetWidth;

    // Remove the scrolling div from the doc
    document.body.removeChild(document.body.lastChild);

    // Pixel width of the scroller
    return (wNoScroll - wScroll);
}

function _setVisibility(objName, isVisible, useDisplayProperty) {
    var obj = _getObject(objName);
    if (!obj) return;
    if (document.layers) {
        obj.visibility = (isVisible ? 'show' : 'hide');
        if (useDisplayProperty) { obj.display = (isVisible ? 'block' : 'none'); }
    }
    else {
        obj.style.visibility = (isVisible ? 'visible' : 'hidden');
        if (useDisplayProperty) { obj.style.display = (isVisible ? 'block' : 'none'); }
    }
}

function _isVisible(objName) {
    var obj = _getObject(objName);
    if (!isValid(obj)) return true; // default to TRUE if object not found
    if (document.layers) {
        return (obj.display != 'none') && (obj.visibility == 'show' || obj.visibility == '');
    }
    else {
        return (obj.style.display != 'none') && (obj.style.visibility == 'visible' || obj.style.visibility == '');
    }
}

function getChildrenOfType(objParent, strType) {	// returns an array of objects who are both contained within objParent and are of type strType
    // (which mainly refers to input objects and their type of input, whether it be radio, button, checkbox, etc.)
    var a = new Array();
    if (isValid(objParent)) {
        var ch = (isValid(objParent.children) ? objParent.children : objParent.childNodes);
        if (isValid(ch)) {
            for (var i = 0; i < ch.length; i++) {
                if (isValid(ch[i])) {
                    if (isValid(ch[i].type)) {
                        if (ch[i].type == strType)
                            a.push(ch[i]);
                    }
                    var childArray = getChildrenOfType(ch[i], strType);
                    for (var x = 0; x < childArray.length; x++)
                        a.push(childArray[x]);
                }
            }
        }
    }
    return a;
}

function getChildrenOfTagType(tagName) {
    var a = new Array();
    if (typeof document.getElementsByTagName != 'undefined')
        a = document.getElementsByTagName(tagName);
    else if (typeof document.all != 'undefined')
        a = document.all.tags("input");
    return a;
}

function getStyle(objectName) {
    var styleObj = null;
    if (document.getElementById || document.all) {
        styleObj = _getObject(objectName).style;
    }
    else //if (document.layers)
    { // in this case, style properties are set directly on the object itself
        styleObj = _getObject(objectName);
    }
    return styleObj;
}

// internal/local variable for keeping a list of event handlers for radio button lists
var _rblHandlers = new Map();

function attachRadioButtonListClickEvent(rblName, eventHandler) {
    // eventHandler: a function with 2 parameters: radio button 'input' object, radio button value
    //    handles the radio button list item click events
    // rblName: the name/id of the asp.net RadioButtonList object
    // this function is used to attach an event handler to all of the 
    // (radio button) items created when using an asp.net RadioButtonList
    // the radiobutton object itself will be passed to the handler so that 
    // radiobutton.value can be accessed
    /* sample usage (at the bottom of a typical aspx page with a radioButtonList having an id of 'rbl'):
    function toggleDates(radioButton)
    {
    var valu = radioButton.value;
    var bDowntime = (valu == "DowntimeReport") ? true : false;
    getStyle('divDowntime').display = (bDowntime) ? 'block':'none';
    }
    attachRadioButtonListClickEvent('rbl', toggleDates);
    */
    if ((typeof eventHandler == 'function') && (rblName != null)) {
        var rbl = _getObject(rblName);
        if (isValid(rbl)) {
            var radios = getChildrenOfType(rbl, 'radio');
            if (isValid(radios) && (radios.length > 0)) {
                if (!_rblHandlers.containsKey(rbl.id))
                    _rblHandlers.put(rbl.id, new Array());
                var handlerArray = _rblHandlers.get(rbl.id);
                handlerArray.push(eventHandler);
                _rblHandlers.remove(rbl.id);
                _rblHandlers.put(rbl.id, handlerArray);
                for (var i = 0; i < radios.length; i++)
                    addEvent(radios[i], 'click', _processRadioButtonListClick);
            }
        }
    }
}
function _processRadioButtonListClick(e) { // a "private" function used internally for the method "attachRadioButtonListClickEvent"
    // this is basically a "preprocessor" for the real radio button list 'click' event handler
    // (it also supports multiple radioButtonLists on a single page as well as multiple handlers for each one)
    var ob = null;
    if (isValid(window.event) && isValid(window.event.srcElement))
        ob = window.event.srcElement;
    else if (isValid(e) && isValid(e.target))
        ob = e.target;

    if (isValid(ob) && (ob.tagName == "INPUT") && (ob.type == "radio")) {
        // find the "parent" radioButtonList object to retrieve the list of handlers for it
        var parent = ob.parentNode; var myId = null;
        while (isValid(parent) && (myId == null)) {
            if (_rblHandlers.containsKey(parent.id))
                myId = parent.id;
            parent = parent.parentNode;
        }
        // if we found our parent's id, then call all handlers associated with this radioButtonList
        if (myId != null) {
            var handlerArray = _rblHandlers.get(myId);
            for (var i = 0; i < handlerArray.length; i++)
                if (typeof handlerArray[i] == 'function') {
                var ret = handlerArray[i](ob, ob.value);
                /*
                //alert(ret + ", " + handlerArray.length);
                if ((typeof ret == 'boolean') && (!ret))
                break;
                */
            }
        }
    }
}


/***** new event handling helper methods *****/
/**
* addEvent & removeEvent -- cross-browser event handling
* Copyright (C) 2006-2007  Dao Gottwald
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*
* Contact information:
*   Dao Gottwald  <dao at design-noir.de>
*
* @version  1.2.1
*/

function addEvent(o, type, fn) {
    o.addEventListener(type, fn, false);
}
function removeEvent(o, type, fn) {
    o.removeEventListener(type, fn, false);
}
/*@cc_on if (!window.addEventListener) {
    var addEvent = function(o, type, fn) {
        if (!o._events) o._events = {};
        var queue = o._events[type];
        if (!queue) {
            o._events[type] = [fn];
            if (!o._events._callback)
                o._events._callback = function(e) { Event._callListeners(e, o) };
            o.attachEvent("on" + type, o._events._callback);
        } else if (Event._fnIndex(o, type, fn) == -1)
            queue.push(fn);
        else return;
        Event._mem.push([o, type, fn]);
    };
    var removeEvent = function(o, type, fn) {
        var i = Event._fnIndex(o, type, fn);
        if (i < 0) return;
        var queue = o._events[type];
        if (queue.calling) {
            delete queue[i];
            if (queue.removeListeners)
                queue.removeListeners.push(i);
            else
                queue.removeListeners = [i];
        } else
            if (queue.length == 1)
            Event._detach(o, type);
        else
            queue.splice(i, 1);
    };
    var Event = {
        AT_TARGET: 2,
        BUBBLING_PHASE: 3,
        stopPropagation: function() { this.cancelBubble = true },
        preventDefault: function() { this.returnValue = false },
        _mem: [],
        _callListeners: function(e, o) {
            e.stopPropagation = this.stopPropagation;
            e.preventDefault = this.preventDefault;
            e.currentTarget = o;
            e.target = e.srcElement;
            e.eventPhase = e.currentTarget == e.target ? this.AT_TARGET : this.BUBBLING_PHASE;
            switch (e.type) {
                case "mouseover":
                    e.relatedTarget = e.fromElement;
                    break;
                case "mouseout":
                    e.relatedTarget = e.toElement;
            }
            var queue = o._events[e.type];
            queue.calling = true;
            for (var i = 0, l = queue.length; i < l; i++)
                if (queue[i])
                if ("handleEvent" in queue[i])
                queue[i].handleEvent(e);
            else
                queue[i].call(o, e);
            queue.calling = null;
            if (!queue.removeListeners)
                return;
            if (queue.length == queue.removeListeners.length) {
                this._detach(o, e.type);
                return;
            }
            queue.removeListeners = queue.removeListeners.sort(function(a, b) { return a - b });
            var i = queue.removeListeners.length;
            while (i--)
                queue.splice(queue.removeListeners[i], 1);
            if (queue.length == 0)
                this._detach(o, e.type);
            else
                queue.removeListeners = null;
        },
        _detach: function(o, type) {
            o.detachEvent("on" + type, o._events._callback);
            delete o._events[type];
        },
        _fnIndex: function(o, type, fn) {
            var queue = o._events[type];
            if (queue)
                for (var i = 0, l = queue.length; i < l; i++)
                if (queue[i] == fn)
                return i;
            return -1;
        },
        _cleanup: function() {
            for (var m, i = 0; m = Event._mem[i]; i++)
                if (m[1] != "unload" || m[2] == Event._cleanup)
                removeEvent(m[0], m[1], m[2]);
        }
    };
    addEvent(window, "unload", Event._cleanup);
} @*/
/***** *****/
/* old event handling functions 
function addEvent(element, type, handler)
{
if (element.addEventListener)
element.addEventListener(type, handler, false);
else
{
if (!handler.$$guid) handler.$$guid = addEvent.guid++;
if (!element.events) element.events = {};
var handlers = element.events[type];
if (!handlers)
{
handlers = element.events[type] = {};
if (element['on' + type]) handlers[0] = element['on' + type];
element['on' + type] = handleEvent;
}
	
handlers[handler.$$guid] = handler;
}
}
addEvent.guid = 1;
function removeEvent(element, type, handler)
{
if (element.removeEventListener)
element.removeEventListener(type, handler, false);
else if (element.events && element.events[type] && handler.$$guid)
delete element.events[type][handler.$$guid];
}
*/
// gotta keep the following methods from the old addEvent code because the DHTMLMenu relies on it, need to fix that to clean this up
function handleEvent(event) {
    event = event || fixEvent(window.event);
    var returnValue = true;
    if (this.events != null) {
        var handlers = this.events[event.type];

        for (var i in handlers) {
            if (!Object.prototype[i]) {
                this.$$handler = handlers[i];
                if (this.$$handler(event) == false) returnValue = false;
            }
        }
    }
    if (this.$$handler) this.$$handler = null;

    return returnValue;
}
function fixEvent(event) {
    event.preventDefault = fixEvent.preventDefault;
    event.stopPropagation = fixEvent.stopPropagation;
    return event;
}
fixEvent.preventDefault = function() {
    this.returnValue = false;
}
fixEvent.stopPropagation = function() {
    this.cancelBubble = true;
}
/* part of the old addEvent stuff
// This little snippet fixes the problem that the onload attribute on the body-element will overwrite
// previous attached events on the window object for the onload event
if (!window.addEventListener)
{
document.onreadystatechange = function()
{
if (window.onload && window.onload != handleEvent)
{
addEvent(window, 'load', window.onload);
window.onload = handleEvent;
}
}
}
*/

var _objectArray = new Map();
function _getObject(objName) {
    var obj = _getObject_func(objName);
    if ((!isValid(obj)) && (_objectArray.containsKey(objName))) {
        obj = _objectArray.get(objName);
        if (isValid(obj)) {
            var obj2 = _getObject_func(obj.id);
            if ((obj2 != obj) && (isValid(obj2))) {
                _objectArray.remove(objName);
                _objectArray.put(objName, obj2);
            }
        }
    }

    if (!isValid(obj)) {
        obj = _getObject_func(objName);
        if (!isValid(obj)) {   // updated to support asp.net framework 2.0 where control names aren't what you might expect
            // (they end with the name you might expect, though)
            if (isValid(document.childNodes))
                obj = _getObject_checkNodes(document.body.childNodes, objName);
        }

        if (_objectArray.containsKey(objName))
            _objectArray.remove(objName);
        _objectArray.put(objName, obj);
    }

    return obj;
}
function _getObject_func(sId) {
    if (document.getElementById)
        return document.getElementById(sId);
    else if (document.all)
        return document.all[sId];
    else if (document.layers)
        return document.layers[sId];
    else
        return null;
}
function _getObject_checkNodes(nodes, objName) { // recursive method to find a tag with an ID *ending* with the specified objName
    var obj = null;
    for (var i = 0; i < nodes.length; i++) {
        var node = nodes[i];
        if (isValid(node)) {
            if (isValid(node.id)) {
                if (node.id.length >= objName.length) {
                    var chk = node.id.substr(node.id.length - objName.length, objName.length);
                    if (chk == objName) {
                        obj = node;
                        //alert('found \'' + objName + '\' as ' + node.id);
                    }
                    //else
                    //    alert('\'' + objName + '\' not found in ' + node.id + '(' + chk + ')');
                }
            }
        }
        if ((!isValid(obj)) && (isValid(node.childNodes)))
            obj = _getObject_checkNodes(node.childNodes, objName);
        if (isValid(obj))
            break;
    }
    return obj;
}

function getconfirm() {
    if (confirm("Are you sure you want to delete this record?") == true)
        return true;
    else
        return false;
}

var g_OpenedWindows = new Array();
var g_OWIndex = 0;

function openWin(u, W, H, X, Y, n, T, fullscreen, resize) {
    var s = '';

    if (fullscreen == 1)
        s = "width=" + screen.availWidth + ",height=" + screen.availHeight;
    else
        s = "width=" + W + ",height=" + H;
    if (resize)
        s += ",scrollbars=1,resizable=1";
    s += ',screenX=' + ((-1 * parseInt(W)) - 10).toString() + ',screenY=0,toolbar=0,menubar=0,location=0';

    var win = window.open(u, n, s);
    if (isValid(win)) {
        try { win.blur(); top.window.focus(); } catch (ex) { }
        if (fullscreen == 1)
            win.moveTo(0, 0);
        else
            win.moveTo(X, Y);
        win.focus();

        g_OpenedWindows[g_OWIndex] = new String();
        g_OpenedWindows[g_OWIndex++] = n;
    }
    else {
        alert(
	        'An error occurred in attempting to open a pop-up window!\n\n' +
	        'The most common cause of this problem is the use of pop-up blocking software.\n' +
	        'If you are not sure how to allow this website to use pop-ups, or think something\n' +
	        'else is causing the problem, contact your system administrator.\n\n' +
	        'Keep in mind that some browsers, like Internet Explorer, now come with pop-up blocking\n' +
	        'features built in that are normally turned ON by default.'
        );
    }
    return true;
}

/* jgg - 12/20/05 - added to make the report window domain-specific */
var g_ReportName = 'CMSReport';
if (top.window.location.href) {
    var tmpDomain = top.window.location.href.match(/:\/\/(www\.)?([^\/:]+)/);
    tmpDomain = tmpDomain[2] ? tmpDomain[2] : '';
    if (tmpDomain) {
        tmpDomain = tmpDomain.replace(/\./g, '_');
        tmpDomain = tmpDomain.replace(/-/g, '_');
        g_ReportName = g_ReportName + tmpDomain;
    }
}
/* */

var g_ReportWindow = null;
//function openReport(reportUrl, pleaseWaitUrl, excelReport, showMenu) {
function openReport(reportUrl, windowID, excelReport, showMenu) {
    var reportWin;
    var width = 900;
    var height = 800;
    var sbars = 'yes';
    var bExcel = false, bShowMenu = false;

    if (arguments.length > 2)
        bExcel = excelReport;

    if (bExcel)
        { bShowMenu = true; }
    else if (arguments.length > 3)
        { bShowMenu = showMenu; }

    if (!bExcel) {
//        //if (reportIsOpen(reportWin))
//        if (reportIsOpen())
//            return true;
//        else
            sbars = 'no';
    }

    var strOptions = 'width=' + width.toString() + ',height=' + height.toString() +
		',directories=no,location=no,menubar=' + (bShowMenu ? 'yes' : 'no') +
    	',resizable=yes,status=yes,titlebar=yes,toolbar=no,scrollbars=' + sbars;

    var skipErrorMessage = false;
    try {
        //alert(strOptions);
//        alert(windowID);
        reportWin = (window.open(reportUrl, g_ReportName + windowID, strOptions));
    }
    catch (ex) {
        alert('An error occurred while opening the report winodw.\nPlease try again.\n\nError Message: ' + ex.message);
        //alert(reportUrl + '\n' + g_ReportName + '\n' + strOptions);
        skipErrorMessage = true;
    }

    if (isValid(reportWin)) {
        try {
            if (reportWin.opener == null)
            { reportWin.opener = window; }
        } // ignoring an error here, not that important
        catch (e) { }

//        try { reportWin.moveTo(0, 0); } catch (ex) { }
        /* we're specifying the width and height in strOptions above and we're just going to use the browser's default open location
            so no need for this anymore
        reportWin.resizeTo(width, height);
       */
        
//        if (pleaseWaitUrl != null)
//            openPleaseWait(pleaseWaitUrl);

//        if (!bExcel)
//            g_ReportWindow = reportWin;
    }
    else if (!skipErrorMessage) {
        alert(
			'An error occurred in attempting to open the report window.\n\n' +
			'The most common cause of this problem is the use of pop-up blocking software.\n\n' +
			'You must allow this website to create pop-ups as the reports are shown in new windows.  ' +
			'If you are not sure how this can be done, or think something else is causing the problem, ' +
			'contact your system administrator.\n\n' +
			'Keep in mind that some browsers, like Internet Explorer, are installed with pop-up blocking ' +
			'features built in that are normally turned ON by default.'
		);
    }
    
    return true;
}
function _reportOnUnload() {
//    alert('report unload arguments: ' + arguments.length);
//    g_ReportWindow = null;
    return true;
}
function reportIsOpen() { // returns a reference to a window if 
    var bOpen = false;
    var bExcel = false;
    var reportWin = null;

    window.focus();

    alert(typeof g_ReportWindow);
    alert(g_ReportWindow);

    if (g_ReportWindow != null)
        if ((g_ReportWindow.open) && (!g_ReportWindow.closed)) { // if a focus() attempt fails, assume the window reference stored in the variable is invalid
        try { g_ReportWindow.focus(); bOpen = true; }
        catch (ex) { bOpen = false; }
    }

    if (!bOpen) {
        /*
        reportWin = window.open('', g_ReportName, 'top=-100,left=-100,width=1,height=1,directories=no,location=no,menubar=no,resizable=yes,status=no,titlebar=no,toolbar=no,scrollbars=none');
        try {
            //reportWin.moveTo(-100, -100);
            if (isValid(reportWin)) {
                if (isValid(reportWin.document)) {
                    if (isValid(reportWin.document.location))
                        if (isValid(reportWin.document.location.href)) {
                        bOpen = (reportWin.document.location.href.indexOf('http') >= 0);
                    }
                }
            }
        }
        catch (ex) { // if the above causes an exception, we most likely have an excel report open in a browser window
            if (isValid(reportWin)) {
                // jgg - 6/6/05 - for some reason we were getting here with an "access denied" error (of type TypeError) 
                // when a report window was actually NOT open, so we're ignoring that specific error
                if (parseInt(ex.number & 0xFFFF) != 5) {
                    // the "not implemented" error, happens when we have a report window open with an excel report opened within the browser
                    bExcel = (parseInt(ex.number & 0xFFFF) == 16385);
                    bOpen = true;
                    g_ReportWindow = reportWin;
                }
                else {
                    try { reportWin.close(); reportWin = null; g_ReportWindow = null; }
                    catch (ex) { }
                }
            }
        }
        */
    }
    else {
        reportWin = g_ReportWindow;
    }

    if (!bOpen) {
        if (arguments.length > 0)
            arguments[0] = reportWin;
        else if (isValid(reportWin))
            reportWin.close();
    }
    else if (reportWin == window) {
        // somehow the current/main window got named "cmsreport" just act as if it's not open and see if the report can open
        g_ReportWindow = null;
        reportWin = null;
        bOpen = false;
    }
    else {
        var sMsg = 'Another report window is open.  Please close or cancel the open report before opening a new one.'
        if (bExcel) {
            sMsg = sMsg + '\n\nIt has been detected that an Excel report may be open in a browser window.' +
				'\nIf this is not the case, you may need to close all browser windows and re-run the report.';
        }
        alert(sMsg);
        try { reportWin.moveTo(0, 0); } catch (ex) { }
        try { reportWin.focus(); } catch (ex) { }
    }

    return bOpen;
}

function openPleaseWait(url) {
    // the rest of the code (to resize, move, etc) SHOULD be in the pleasewait page's javascript
    // (which is why we MUST specify resizeable=1 here)
    var win = window.open(url, 'PleaseWait', 'width=1,height=1,scrollbars=0,resizable=1,left=-100,top=-100');
}

/*********************************************************************************************************************
*  Anthem (AJAX) support code
********************************************************************************************************************/

function Anthem_PreCallBack() {
    setTimeout("toggleEnable(false)", g_submittingTimeout);
    g_bDoSubmitting = true;
    _submittingTimer();
}

function Anthem_PostCallBack() {
    setTimeout("toggleEnable(true)", g_submittingTimeout);
    g_bDoSubmitting = false;
}

/*********************************************************************************************************************
*  END Anthem (AJAX) support code
********************************************************************************************************************/


/*
* Map: a dictionary data structure based on a hash table
* $Id: map.js 1932 2004-04-20 05:04:18Z scott $
* Copyright (C) 2001-2003 Scott Martin (http://www.coffeeblack.org/contact/)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1
* of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, it is available from the Free Software
* Foundation, Inc. at http://www.gnu.org/copyleft/lesser.html or in writing at
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/

/*
* Creates a new map. This method simply initializes the internal hash table
* backing this map. The optional argument 'size' refers to the number
* of buckets that will be used in this map's internal hash table. If
* this argument is unspecified, not a number, or less than one, a
* default value of 10 buckets is used.
*
* A map stores a series of elements. Each element is a key and its
* corresponding value. Once an element is added using put(), the key can then
* be used to retrieve its corresponding value using get(). Keys must be
* defined and non-null, and a map does not allow duplicate keys. An attempt to
* add an element when its key is already present results in the current
* element's value being replaced by the new one. The values themselves must be
* defined, but can be null. Multiple duplicate values are permitted.
*
* Internally, a map uses a hash table to store elements inserted into it.
* This hash table uses several buckets as storage, and the number of
* buckets can be specified at construction. Each bucket is a chain of 
* elements, and the appropriate bucket location of any given element is
* determined by computing a hash code based on the element's key. The hash 
* table implementation used by this map uses chaining to resolve collisions.
*/
function Map(size) {
    this.buckets = new Array();

    if (isNaN(size) || size < 1)
        size = 10;

    for (var i = 0; i < size; i++)
        this.buckets[i] = new Bucket();
}

/*
* Stores the computed hash code for later reference.
*/
Object.prototype.hashCode = -1;

/*
* Computes a hash code for an object.
*/
Object.prototype.hash = function() {
    with (this) {
        if (hashCode == -1) {
            hashCode = 0;
            var str = toString();

            for (var i = 0; i < str.length; i++)
                hashCode ^= str.charCodeAt(i);
        }

        return hashCode;
    }
}

/*
* Finds the appropriate bucket for a given object using its hash code.
*/
Map.prototype.bucketFor = function(obj) {
    with (this) {
        return buckets[obj.hash() % buckets.length];
    }
}

/*
* Gets the size of the map, the number of elements it contains.
*/
Map.prototype.size = function() {
    var sz = 0;

    with (this) {
        for (var i = 0; i < buckets.length; i++)
            sz += buckets[i].depth;
    }

    return sz;
}

/*
* Tests whether this map is currently empty (has no elements).
*/
Map.prototype.isEmpty = function() {
    with (this) {
        for (var i = 0; i < buckets.length; i++)
            if (buckets[i].depth > 0)
            return false;
    }

    return true;
}

/*
* Gets an array of the keys in this map.
*/
Map.prototype.keys = function() {
    var a = new Array();

    with (this) {
        var bucket, e;
        for (var i = 0; i < buckets.length; i++) {
            bucket = buckets[i];

            for (e = bucket.first; e != null; e = e.next)
                a[a.length] = e.key;
        }
    }

    return a;
}

/*
* Gets an array of the values in this map.
*/
Map.prototype.values = function() {
    var a = new Array();

    with (this) {
        var bucket, e;
        for (var i = 0; i < buckets.length; i++) {
            bucket = buckets[i];

            for (e = bucket.first; e != null; e = e.next)
                a[a.length] = e.value;
        }
    }

    return a;
}

/*
* Tests whether this map contains the specified key.
*/
Map.prototype.containsKey = function(key) {
    if (key && key != null) {
        with (this) {
            var bucket = bucketFor(key);

            for (var e = bucket.first; e != null; e = e.next)
                if (e.key == key)
                return true;
        }
    }

    return false;
}

/*
* Tests whether this map contains the specified value.
*/
Map.prototype.containsValue = function(value) {
    if (value) {
        with (this) {
            var bucket, e;

            for (var i = 0; i < buckets.length; i++) {
                bucket = buckets[i];

                for (e = bucket.first; e != null; e = e.next)
                    if (e.value == value)
                    return true;
            }
        }
    }

    return false;
}

/*
* Adds an element to this map. The key must be defined
* and non-null. The value must be defined, but can be null.
*
* If a key is currently contained in this map that is the same
* as the key to be added, the new element is inserted in place of
* the old one and the old element's value is then returned. If the new
* key is not already present, this method returns null.
*/
Map.prototype.put = function(key, value) {
    with (this) {
        return (key && key != null && value)
			? bucketFor(key).add(key, value) : null;
    }
}

/*
* Gets the value associated with the specified key, if any.
* Otherwise, this method returns null.
*/
Map.prototype.get = function(key) {
    if (key && key != null) {
        with (this) {
            var bucket = bucketFor(key);

            for (var e = bucket.first; e != null; e = e.next)
                if (e.key == key)
                return e.value;
        }
    }

    return null;
}

/*
* Removes the element with the specified key from this map, if any
* such key is present. The removed element is then returned. If no such
* key is present in this map, this method returns null. If an element is
* successfully removed, ths size of this map decreases by 1.
*/
Map.prototype.remove = function(key) {
    if (key && key != null) {
        with (this) {
            return bucketFor(key).remove(key);
        }
    }

    return null;
}


/*
* Clears this map. This method reduces the size of the map to 0.
*/
Map.prototype.clear = function() {
    with (this) {
        for (var i = 0; i < buckets.length; i++)
            buckets[i].clear();
    }
}

/*
* Gets a string representation of this map.
*/
Map.prototype.toString = function() {
    return "[object Map]";
}

/*
* A hash table bucket that holds entries.
*/
function Bucket() {	// stores the number of elements contained
    this.depth = 0;
    // the first element in the chain
    this.first = null;
}

/*
* Adds an entry to this bucket. If an entry already existed with the same
* key, its value is replaced and the old value is then returned.
*/
Bucket.prototype.add = function(key, value) {
    with (this) {
        if (first != null) // look for the key
        {
            for (var e = first; e != null; e = e.next) {
                if (e.key == key) // same key already present
                {
                    var old = e.value;
                    e.value = value;
                    return old;
                }
            }
        }

        // bucket empty or key not present, add a new entry
        first = new Entry(key, value, first);
        depth++;
    }

    return null;
}

/*
* Removes an entry from this bucket. If an entry was removed,
* its value is returned and the bucket's depth is decreased by one.
*/
Bucket.prototype.remove = function(key) {
    with (this) {
        if (first != null) {
            for (var e = first, prev = null; e != null; prev = e, e = e.next) {
                if (e.key == key) {
                    if (prev == null) // it's the first entry
                        first = e.next;
                    // otherwise, link previous to next
                    else prev.next = e.next;

                    depth--;
                    return e.value;
                }
            }
        }
    }

    return null;
}

/*
* Removes all entries from this bucket.
*/
Bucket.prototype.clear = function() {
    with (this) {
        first = null;
        depth = 0;
    }
}

/*
* Gets a string representation of this bucket.
*/
Bucket.prototype.toString = function() {
    return "[object Bucket]";
}

/*
* A map entry. This object simply ties a key to its associated value.
* An entry also stores a reference to the next object in the chain of
* entries in the bucket they belong to.
*/
function Entry(k, val, nxt) {
    this.key = k;
    this.value = val;
    this.next = nxt ? nxt : null;
}

/*
* Gets a string representation of this entry.
*/
Entry.prototype.toString = function() {
    return "[object Entry]";
}