// Author: Adrian BER
try {
    if (window != undefined && window.mainWindow == undefined)
        mainWindow = window;
} catch(e) { mainWindow = undefined;}

Object.prototype.instanceOf = function(constructorFunction) {
    if (this != null && this != undefined) {
        if (this == constructorFunction.prototype) {
            return true;
        }
        if (this.constructor && this.constructor.prototype) {
	        return this.constructor.prototype.instanceOf(constructorFunction);
	    }
  }
  return false;
};

Object.prototype.superConstructor = function(parent) {
		if( arguments.length > 1 ) {
			parent.apply( this, Array.prototype.slice.call( arguments, 1 ) );
		} else {
			parent.call( this );
		}
};

Object.prototype.shallowClone = function () {
  return this.deepClone(0);
}

/**
 * Deep clones an object. It goes as many extra levels (except the first one) as
 *  the "levels" parameter specifies.
 * E.g. if levels = 0, this is the same as a shallow clone.
 * If levels is undefined it will clone the first 20 levels.
 * If levels = -1 then it will clone all the levels 
 * (are you sure you want to do this?) 
 */
Object.prototype.deepClone = function(levels) {
    if (levels == undefined) {
        levels = 20;
    }
    
    var clone = new this.constructor();
    for (propName in this) {
        var prop = this[prop];
        if (((levels == -1) || (levels > 0)) && (prop instanceof Object)) {
            prop = prop.deepClone(levels == -1 ? -1 : levels - 1);
        }
        clone[propName] = prop;
    }
    return clone;
}


function Event_AddSupport(type, attachName, detachName) {
    if (attachName == undefined)
        attachName = "attachEvent";
    if (detachName == undefined)
        detachName = "detachEvent";        
    eval("type." + attachName + " = Event_attachEvent;"
            + "type." + detachName + " = Event_detachEvent;");
}

function Event_attachEvent(event, handler) {
    if (event == undefined || handler == undefined)
        return;
    // create the map of handlers if not already existing
    if (this.handlers == undefined) {
        this.handlers = new Array();
    }
    // create the array of handlers for the event if not already existing
    if (this.handlers[event] == undefined) {
        this.handlers[event] = new Array();
        // retain the already existing handler for the event, if defined
        eval("if (this." + event + " != undefined) this.handlers[event].push(this." + event + ")");
        // the event handler will be the function to call all the handlers
        eval("this." + event + " = Event_getCallHandlers(this, event)");    
    }
    this.handlers[event].push(handler);
}

function Event_detachEvent(event, handler) {
    this.handlers[event].removeElement(handler);
}

/** Creates a function to launch the handlers for the given 
 * object and event name.
 */
function Event_getCallHandlers(src, event) {
    return function() {
        var args = new Array();
        for (var i = 0; i < arguments.length; i++) {
            args.push(arguments[i]);
        }
        if (args.length == 0)
            args.push(src);
        for(var i = 0, n = src.handlers[event].length; i < n; i++) {
            var ret = src.handlers[event][i].apply(src.handlers[event][i], args);
            if (ret == false)
                return false;
        }
        return true;
    }
}

if (mainWindow != undefined && mainWindow.document.all == undefined) {
    // Simulate in Mozilla attachEvent/detachEvent from IE
    // Defines a map of (event name, array of handlers)
    /*
    Object.prototype.attachEvent = function(eventType, handler) {
        if (eventType.startsWith("on"))
            eventType = eventType.substr(2);
        this.addEventListener(eventType, handler, false);
    }

    Object.prototype.detachEvent = function(eventType, handler) {
        if (eventType.startsWith("on"))
            eventType = eventType.substr(2);
        this.removeEventListener(eventType, handler, false);
    }
    */
    Event_AddSupport(Object.prototype, "attachEvent", "detachEvent");
    
    // define innerText property in Mozilla
    HTMLElement.prototype.__defineGetter__("innerText", function () {
       var r = this.ownerDocument.createRange();
       r.selectNodeContents(this);
       return r.toString();
    });

    HTMLElement.prototype.__defineSetter__("innerText", function (text) {
        if (text == undefined)
            this.innerHTML = undefined;
        else
            this.innerHTML = text.toString().replace(/\&/g, "&amp;")
                    .replace(/</g, "&lt;").replace(/>/g, "&gt;");
    });

    Event.prototype.__defineGetter__("returnValue", function () {
       return this.__returnValue__;
    });

    Event.prototype.__defineSetter__("returnValue", function (val) {
        this.__returnValue__ = val;
        if (val == true) {
            this.preventDefault();
        }
    });
    
    Event.prototype.__defineGetter__("cancelBubble", function () {
       return this.__cancelBubble__;
    });

    Event.prototype.__defineSetter__("cancelBubble", function (val) {
        this.__cancelBubble__ = val;
        if (val == true) {
            this.stopPropagation();
        }
    });
    
} else {
/*
    Object.prototype.addEventListener = function(eventType, handler) {
        if (!eventType.startsWith("on"))
            eventType = "on" + eventType;
        this.attachEvent(eventType, handler);
    }

    Object.prototype.removeEventListener = function(eventType, handler) {
        if (!eventType.startsWith("on"))
            eventType = "on" + eventType;
        this.detachEvent(eventType, handler);
    }
*/
    Event_AddSupport(Object.prototype, "attachEvent", "detachEvent");
}

Function.prototype.Inherits = function(parent) {
		this.prototype = new parent();
		this.prototype.constructor = this;
		this.prototype.parent = parent;
};


/** Returns the index of the element in this array, 
 * or -1 if the element wasn't found.
 * @param element the element to be searched  
 */
Array.prototype.indexOf = function(element) {
    for (var i = 0; i < this.length; i++) {
        if (this[i] == element) {
            return i;
        }
    }
    return -1;
};


/** Returns true if the given element is in the array, false otherwise.
 * @param element the element to be searched  
 */
Array.prototype.contains = function(element) {
    return this.indexOf(element) >= 0;
};

/** Removes the given element from this array.
 * @param element the element to be searched  
 */
Array.prototype.removeElement = function(element) {
    var idx = this.indexOf(element);
    if (idx >= 0) {
        this.splice(idx, 1);
    }
}

/** Returns a new array which is a subarray of this array. 
 * @param startIndex the start index of the subarray; if negative 0 is considered
 * @param endIndex the end index of the subarray; 
 *      if bigger than the array length, array length is considered; 
 *      if smaller than startIndex then undefined is returned 
 */
Array.prototype.subarray = function(startIndex, endIndex) {
    if (startIndex < 0)
        startIndex = 0;
    if (endIndex > this.length)
        endIndex = this.length - 1;
    if (endIndex < startIndex)
        return undefined;
        
    var x = new Array();
    for (var i = startIndex; i <= endIndex; i++)
        x.push(this[i]);
    
    return x;
}

/** Splits an array into subarrays.
 * @param fragmentSize the maximmum length of the subarrays; this should be at least 2
 * @return an array of which element is an array of fragmentSize maximmum length
 */
Array.prototype.split = function(fragmentSize) {
    if (fragmentSize < 2)
        fragmentSize = 2;

    var x = new Array();
    
    for (var i = 0, j = -1; i < this.length; i++) {
        if (i % fragmentSize == 0) {
            j++;
        }
        if (x.length <= j) {
            x.push(new Array());
        }
        x[j].push(this[i]);
    }
    
    return x;
}

/** A version of stringToNumber that returns 0 if there is NaN returned, 
 * or number is part of a string, like 100px... 
 */
function stringToNumber(s, radix) {
    if (radix == undefined)
        radix = 10;
    return parseInt(('0' + s), radix);
}

/** A version of stringToNumber that returns 0 if there is NaN returned, 
 * or number is part of a string, like 100px... 
 */
String.prototype.toNumber = function(radix) {
    if (radix == undefined)
        radix = 10;
    return parseInt(('0' + this), radix);
}

/** Returns true if the given string is a substring of this string,
 * false otherwise.
 * @param string the string to be searched  
 */
String.prototype.contains = function(string) {
    return this.indexOf(object) >= 0;
}; 

/** 
 * Returns the current string where the first letter is converted to lowercase
 * and all others to uppercase. 
 */
String.prototype.toTitleCase = function() {
    return this.substring(0,1).toUpperCase() + this.substring(1).toLowerCase();
}; 

/** 
 * Returns a string from which the given characters are removed.
 * @param chars a string containing all the chars to be removed. 
 */
String.prototype.stripChars = function(chars) {
    var returnString = "";
    for (var i = 0; i < this.length; i++) {
        var c = this.charAt(i);
        if (chars.indexOf(c) == -1) returnString += c;
    }
    return returnString;
};

/** Returns the current string from which we removed all the spaces from left. */
String.prototype.trimLeft = function() {
    return this.replace( /\s*$/, "" );
};

/** Returns the current string from which we removed all the spaces from right. */
String.prototype.trimRight = function() {
    return this.replace( /^\s*/, "" );
};

/** Returns the current string from which we removed all the spaces from left and right. */
String.prototype.trim = function() {
    return this.trimLeft().trimRight();
};

/** Returns if this string is blank (contains only spaces). */
String.prototype.isBlank = function() {
    return (this.trim().length == 0);
};

/** Returns if this string is empty (having empty spaces doesn't mean empty). */
String.prototype.isEmpty = function() {
    return (this.length == 0);
};

/** Returns if this string starts with the given string.
 * @param str the string to compare with
 */
String.prototype.startsWith = function(str) {
    return (this.indexOf(str) == 0);
};

/** Returns if this string ends with the given string.
 * @param str the string to compare with
 */
String.prototype.endsWith = function(str) {
    return (this.lastIndexOf(str) == (this.length - str.length));
};


//Node.prototype.getIndexInParent = function() {
function getNodeIndexInParent(node) {
    var index = 0;
    //var node = this;
    while (node.previousSibling != null) {
        node = node.previousSibling;
        index++;
    }
    return index;
};

function removeAllChildren(node) {
    var child = node.firstChild;
    while (child != null) {
        var next = child.nextSibling;
        node.removeChild(child);
        child = next;
    }
}

function moveAllChildren(srcNode, destNode) {
    var child = srcNode.firstChild;
    while (child != null) {
        var next = child.nextSibling;
        destNode.appendChild(child);
        child = next;        
    }
}

/**
 * Returns the value of the CSS rule.
 * The version if you expect any IE 5.0 users whatsoever.
 * Example: getStyle(document.getElementById("container"), "font-size");
 * @param elem the element for which to get the CSS rule
 * @param cssRuleName the CSS rule name  
 */
function getElementStyle(elem, cssRuleName) {
	var strValue = "";
	if (document.defaultView && document.defaultView.getComputedStyle) {
		strValue = document.defaultView.getComputedStyle(elem, "")
                .getPropertyValue(cssRuleName);
	} else if (elem.currentStyle){
		try {
			cssRuleName = cssRuleName.replace(/\-(\w)/g, function (strMatch, p1) {
				return p1.toUpperCase();
			});
			strValue = elem.currentStyle[cssRuleName];
		}
		catch(e) {
			// Used to prevent an error in IE 5.0
		}
	}
	return strValue;
}


function Element_moveTo(x, y) {
    if (navigator.isNS4x) 
        this.moveTo(x, y);
    else if (navigator.isIE) {
        this.style.pixelLeft = x;
        this.style.pixelTop = y;
    } else if (navigator.isGecko) {
        this.style.left = x;
        this.style.top  = y;
    }
}

function Element_moveBy(dx, dy) {
    if (navigator.isNS4x) 
        this.moveBy(dx, dy);
    else if (navigator.isIE) {
        this.style.pixelLeft += dx;
        this.style.pixelTop += dy;
    } else if (navigator.isGecko) {
        this.style.left = (stringToNumber(this.style.left) + x + "px");
        this.style.top  = (stringToNumber(this.style.top)  + y + "px");
    }
}

/* Returns left edge of elt in pixels. */
function Element_getX() {
    var plus = 0;
    if (this.style && getElementStyle(this, "position") == "fixed") {
        plus = (document.documentElement ? document.documentElement : document.body).scrollLeft;
    }

    if (this.style && this.style.left && (this.style.left.indexOf('%') < 0)) {
        var x = stringToNumber(this.style.left);
        if (!isNaN(x))
            return  x + plus;    
    } 
    if (this.offsetLeft) {
        return this.offsetLeft + plus;
    }
    if (this.style && this.style.pixelLeft) {
        return this.style.pixelLeft + plus;
    }
    
    // Netscape 4.x
    if (this.left) {
        return this.left + plus;
    }
    
    return -1;
}

/* Sets position of left edge of this element in pixels. */
function Element_setX(x) {
    if (navigator.isNS4x) 
        this.left = x;
    else if (navigator.isIE) {
        this.style.pixelLeft = x;
    } else if (navigator.isGecko) {
        this.style.left = (x + "px");
    }
}

/* Returns left edge of this element in pixels. */
function Element_getY() {
    var plus = 0;
    if (this.style && getElementStyle(this, "position") == "fixed") {
        plus = (document.documentElement ? document.documentElement : document.body).scrollTop;
    }
    
    if (this.style && this.style.top && (this.style.top.indexOf('%') < 0)) {
        var x = stringToNumber(this.style.top);
        if (!isNaN(x))
            return  x + plus;    
    } 
    if (this.offsetTop != null) {
        return this.offsetTop + plus;
    }
    if (this.style && this.style.pixelTop) {
        return this.style.pixelTop + plus;
    }
    
    // Netscape 4.x
    if (this.top) {
        return this.top + plus;
    }
    
    return -1;
}

/* Sets position of left edge of this element in pixels. */
function Element_setY(y) {
    if (navigator.isNS4x) {
        this.top = y;
    } else if (navigator.isIE) {
        this.style.pixelTop = y;
    } else if (navigator.isGecko) {
        this.style.top = (y + "px");
    }
}

function Element_setPosition(x, y) {
    this.setX(x);
    this.setY(y);
}

function Element_getVerticalScrollbarWidth() {
    if (this.offsetWidth == undefined)
        return undefined;
    return this.clientLeft ? this.offsetWidth - this.clientWidth - this.clientLeft : 16;
}

/* Returns the width of this element in pixels. */
function Element_getWidth() {
    // Mozilla
    if (this.style.width && (this.style.width.indexOf('%') < 0)) {
        var x = stringToNumber(this.style.width);
        if (!isNaN(x))
            return  x;    
    } 
    
    if (this.offsetWidth) {
        var x = stringToNumber(this.offsetWidth);
        if (!isNaN(x))
            return  x;    
    }

    // IE
    if (this.style.pixelWidth) {
        return this.style.pixelWidth;
    }
    
    if (this.clientWidth) {
        return this.clientWidth;
    }

    // Netscape 4.x
    if (this.document && this.document.width) {
        return this.document.width;
    } 
    if (this.clip && this.clip.right) {
        return this.clip.right - this.clip.left;
    }
    
    return -1;
}

/* Sets the width of this element in pixels */
function Element_setWidth(width) {
    if (this.style) { 
        // Mozilla, IE
        this.style.width = width + "px";
    } else {
        // Netscape 4.x
        this.document.width = width;
    } 
}

/* Returns the height of this element in pixels. */
function Element_getHeight() {
    // Mozilla
    if (this.style.height && (this.style.height.indexOf('%') < 0)) {
        var x = stringToNumber(this.style.height);
        if (!isNaN(x))
            return  x;    
    } 
    
    if (this.offsetHeight) {
        var x = stringToNumber(this.offsetHeight);
        if (!isNaN(x))
            return  x;    
    }

    // IE
    if (this.style.pixelHeight) {
        return this.style.pixelHeight;
    }
    
    if (this.clientHeight) {
        return this.clientHeight;
    }

    // Netscape 4.x
    if (this.document && this.document.height) {
        return this.document.height;
    } 
    if (this.clip && this.clip.bottom) {
        return this.clip.bottom - this.clip.top;
    }
    
    return -1;
}

/* Sets the width of this element in pixels. */
function Element_setHeight(height) {
    if (height < 0)
        return;
    if (this.style) { 
        // Mozilla, IE
        this.style.height = height + "px";
    } else {
        // Netscape 4.x
    	this.document.height = height;
    }
}

/** Scrolls the page so that this element becomes visible. */
function Element_scrollToVisible() {
    // IE6 +4.01 and user has scrolled
    if (this.ownerDocument.documentElement) {
        this.ownerDocument.documentElement.scrollTop = this.getY();
    // IE5 or DTD 3.2
    } else if (this.ownerDocument.body) {
        this.ownerDocument.body.scrollTop = this.getY();
    }
}

function Element_toggleVisibility(elem) {
    if (elem == undefined)
        elem = this;
    if (elem.style.display == "none") {
        if (elem.style.visibilityValue == undefined) {
            elem.style.visibilityValue = DISPLAY_VALUES[elem.tagName];
            if (elem.style.visibilityValue == undefined) {
                elem.style.visibilityValue = "inline";
            }
        }
        elem.style.display = elem.style.visibilityValue;
    } else {
         elem.style.visibilityValue = elem.style.display;
         elem.style.display = "none";
    }       
}


function addGeometryMethods(elem) {
    // if already added
    if (elem.geometryMethodsAdded)
        return;
        
    if (!elem.moveBy)
        elem.moveBy = Element_moveBy;
    if (!elem.moveTo)
        elem.moveTo = Element_moveTo;
    elem.setPosition = Element_setPosition;
    elem.getX = Element_getX;
    elem.setX = Element_setX;
    elem.getY = Element_getY;
    elem.setY = Element_setY;  
    elem.getWidth = Element_getWidth;
    elem.setWidth = Element_setWidth;
    elem.getHeight = Element_getHeight;  
    elem.setHeight = Element_setHeight;  
    elem.scrollToVisible = Element_scrollToVisible;
    elem.getVerticalScrollbarWidth = Element_getVerticalScrollbarWidth;
    elem.toggleVisibility = Element_toggleVisibility;
    
    elem.geometryMethodsAdded = true;
}






if (mainWindow != undefined) {

mainWindow.isShiftPressed = function(event) {
    if (event == undefined)
        event = this.event;
    if (event.modifiers != undefined) {
        return (event.modifiers + 32).toString(2).substring(3,6).charAt(0) == "1";
    } else {
        return event.shiftKey;
    }
}

mainWindow.isCtrlPressed = function(event) {
    if (event == undefined)
        event = this.event;
    if (event.modifiers != undefined) {
        return (event.modifiers + 32).toString(2).substring(3,6).charAt(1) == "1";
    } else {
        return event.ctrlKey;
    }
};

mainWindow.isAltPressed = function(event) {
    if (event == undefined)
        event = this.event;
    if (event.modifiers != undefined) {
        return (event.modifiers + 32).toString(2).substring(3,6).charAt(2) == "1";
    } else {
        return event.altKey;
    }
};

mainWindow.getMousePageCoordinates = function(e) {
    var win = this;
    if (e == undefined)
        e = win.event;

    var xcoord = 0, ycoord = 0; 
    if (e.pageX || e.pageY) 	{
    		xcoord = e.pageX;
    		ycoord = e.pageY;
  	}
    else if (e.clientX || e.clientY) 	{
        xcoord = e.clientX + this.document.body.scrollLeft
                + this.document.documentElement.scrollLeft;
        ycoord = e.clientY + this.document.body.scrollTop
                + this.document.documentElement.scrollTop;
    }
    
    var coord = new Object();
    coord.x = xcoord;
    coord.y = ycoord;
    return coord;
}

mainWindow.addBookmark = function(title, url) {
    if (this.sidebar) { // firefox
        this.sidebar.addPanel(title, url, "");
        return true;
    } else if( this.external ) { //MSIE
        this.external.AddFavorite( url, title);
        return true;
    } else {
        return false;
    }
}
mainWindow.addFavorite = mainWindow.addBookmark;

mainWindow.blur = function(color) {
    if (this.blurDiv == undefined) {
        this.blurDiv = this.document.createElement("DIV");
        addGeometryMethods(this.blurDiv);
        this.blurDiv.style.position = "absolute";
        this.blurDiv.style.opacity = "0.7";
        this.blurDiv.style.filter = "progid:DXImageTransform.Microsoft.Alpha(opacity=70)";
        this.blurDiv.style.backgroundColor = (color != undefined ? color : "black");
        this.document.body.appendChild(this.blurDiv);
        this.blurDivResizeEvent = function(event) {
            window.blurDiv.setWidth(this.document.body.offsetLeft + this.document.body.offsetWidth);
            window.blurDiv.setHeight(this.document.body.offsetTop + this.document.body.offsetHeight);                        
        }
    }
    this.document.body.attachEvent("onresizeend", this.blurDivResizeEvent);
    if (color != undefined)
        this.blurDiv.style.backgroundColor = color;
    this.blurDiv.setX(0);
    this.blurDiv.setY(0);
    this.blurDiv.setWidth(this.document.body.offsetLeft + this.document.body.offsetWidth);
    this.blurDiv.setHeight(this.document.body.offsetTop + this.document.body.offsetHeight);
    this.blurDiv.style.display = "block";
}

mainWindow.unblur = function() {
    if (this.blurDiv != undefined) {
        this.blurDiv.style.display = "none";
        this.document.body.detachEvent("onresizeend", this.blurDivResizeEvent);
    }
}

mainWindow.getWidth = function() {
    if (this.innerWidth) {
    	 return this.innerWidth;
    } else if (this.document.documentElement && this.document.documentElement.clientWidth) {
    	 return this.document.documentElement.clientWidth;
    } else if (this.document.body) {
    	 return this.document.body.clientWidth;
    }
}

mainWindow.getHeight = function() {
    if (this.innerHeight) {
    	 return this.innerHeight;
    } else if (this.document.documentElement && document.documentElement.clientHeight) {
    	 return this.document.documentElement.clientHeight;
    } else if (this.document.body) {
    	 return this.document.body.clientHeight;
    }
}

/**
 * Centers the given element in this window.
 * @param elem the element to be centered 
 */ 
mainWindow.centerElem = function(elem) {
    addGeometryMethods(elem);
    elem.setX((window.getWidth() - elem.getWidth()) / 2);    
    elem.setY((window.getHeight() - elem.getHeight()) / 2);    
}

mainWindow.createXMLHttpRequest = function() {
    var xmlHttp;
    try {
        xmlHttp = new ActiveXObject("Msxml2.XMLHTTP");
    } catch (e) {
        try {
            xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
        } catch (e2) {
            xmlHttp = undefined;
        }
    }
    
    if (!xmlHttp && typeof XMLHttpRequest != 'undefined') {
        xmlHttp = new XMLHttpRequest();
    }
    
    return xmlHttp;
};

mainWindow.toggleVisibility = Element_toggleVisibility;


/** Browser detection. */
mainWindow.navigator.detect = function() {
   var ua = this.userAgent.toLowerCase(); 

   // browser engine name
   this.isGecko       = (ua.indexOf('gecko') != -1 && ua.indexOf('safari') == -1);
   this.isAppleWebKit = (ua.indexOf('applewebkit') != -1);

   // browser name
   this.isKonqueror   = (ua.indexOf('konqueror') != -1); 
   this.isSafari      = (ua.indexOf('safari') != - 1);
   this.isOmniweb     = (ua.indexOf('omniweb') != - 1);
   this.isOpera       = (ua.indexOf('opera') != -1); 
   this.isIcab        = (ua.indexOf('icab') != -1); 
   this.isAol         = (ua.indexOf('aol') != -1); 
   this.isIE          = (ua.indexOf('msie') != -1 && !this.isOpera && (ua.indexOf('webtv') == -1) ); 
   this.isMozilla     = (this.isGecko && ua.indexOf('gecko/') + 14 == ua.length);
   this.isFirebird    = (ua.indexOf('firebird/') != -1);
   this.isNS          = ( (this.isGecko) ? (ua.indexOf('netscape') != -1) : ( (ua.indexOf('mozilla') != -1) && !this.isOpera && !this.isSafari && (ua.indexOf('spoofer') == -1) && (ua.indexOf('compatible') == -1) && (ua.indexOf('webtv') == -1) && (ua.indexOf('hotjava') == -1) ) );
   
   // spoofing and compatible browsers
   this.isIECompatible = ( (ua.indexOf('msie') != -1) && !this.isIE);
   this.isNSCompatible = ( (ua.indexOf('mozilla') != -1) && !this.isNS && !this.isMozilla);
   
   // rendering engine versions
   this.geckoVersion = ( (this.isGecko) ? ua.substring( (ua.lastIndexOf('gecko/') + 6), (ua.lastIndexOf('gecko/') + 14) ) : -1 );
   this.equivalentMozilla = ( (this.isGecko) ? parseFloat( ua.substring( ua.indexOf('rv:') + 3 ) ) : -1 );
   this.appleWebKitVersion = ( (this.isAppleWebKit) ? parseFloat( ua.substring( ua.indexOf('applewebkit/') + 12) ) : -1 );
   
   // browser version
   this.versionMinor = parseFloat(this.appVersion); 
   
   // correct version number
   if (this.isGecko && !this.isMozilla) {
      this.versionMinor = parseFloat( ua.substring( ua.indexOf('/', ua.indexOf('gecko/') + 6) + 1 ) );
   }
   else if (this.isMozilla) {
      this.versionMinor = parseFloat( ua.substring( ua.indexOf('rv:') + 3 ) );
   }
   else if (this.isIE && this.versionMinor >= 4) {
      this.versionMinor = parseFloat( ua.substring( ua.indexOf('msie ') + 5 ) );
   }
   else if (this.isKonqueror) {
      this.versionMinor = parseFloat( ua.substring( ua.indexOf('konqueror/') + 10 ) );
   }
   else if (this.isSafari) {
      this.versionMinor = parseFloat( ua.substring( ua.lastIndexOf('safari/') + 7 ) );
   }
   else if (this.isOmniweb) {
      this.versionMinor = parseFloat( ua.substring( ua.lastIndexOf('omniweb/') + 8 ) );
   }
   else if (this.isOpera) {
      this.versionMinor = parseFloat( ua.substring( ua.indexOf('opera') + 6 ) );
   }
   else if (this.isIcab) {
      this.versionMinor = parseFloat( ua.substring( ua.indexOf('icab') + 5 ) );
   }
   
   this.versionMajor = parseInt(this.versionMinor); 
   
   // dom support
   this.isDOM1 = (document.getElementById);
   this.isDOM2Event = (document.addEventListener && document.removeEventListener);
   
   // css compatibility mode
   this.mode = document.compatMode ? document.compatMode : 'BackCompat';

   // platform
   this.isWin    = (ua.indexOf('win') != -1);
   this.isWin32  = (this.isWin && ( ua.indexOf('95') != -1 || ua.indexOf('98') != -1 || ua.indexOf('nt') != -1 || ua.indexOf('win32') != -1 || ua.indexOf('32bit') != -1 || ua.indexOf('xp') != -1) );
   this.isMac    = (ua.indexOf('mac') != -1);
   this.isUnix   = (ua.indexOf('unix') != -1 || ua.indexOf('sunos') != -1 || ua.indexOf('bsd') != -1 || ua.indexOf('x11') != -1)
   this.isLinux  = (ua.indexOf('linux') != -1);
   
   // specific browser shortcuts
   this.isNS4x = (this.isNS && this.versionMajor == 4);
   this.isNS40x = (this.isNS4x && this.versionMinor < 4.5);
   this.isNS47x = (this.isNS4x && this.versionMinor >= 4.7);
   this.isNS4up = (this.isNS && this.versionMinor >= 4);
   this.isNS6x = (this.isNS && this.versionMajor == 6);
   this.isNS6up = (this.isNS && this.versionMajor >= 6);
   this.isNS7x = (this.isNS && this.versionMajor == 7);
   this.isNS7up = (this.isNS && this.versionMajor >= 7);
   
   this.isIE4x = (this.isIE && this.versionMajor == 4);
   this.isIE4up = (this.isIE && this.versionMajor >= 4);
   this.isIE5x = (this.isIE && this.versionMajor == 5);
   this.isIE55 = (this.isIE && this.versionMinor == 5.5);
   this.isIE5up = (this.isIE && this.versionMajor >= 5);
   this.isIE6x = (this.isIE && this.versionMajor == 6);
   this.isIE6up = (this.isIE && this.versionMajor >= 6);
   
   this.isIE4xMac = (this.isIE4x && this.isMac);   
};

mainWindow.navigator.detect();


/** Returns the given parameter from the URL string. Please keep in mind
 * that the POST parameter will not be returned by this method, 
 * only the GET ones.
 * @param name the name of the parameter
 * @return the parameter value or undefined if such a parameter does not exist
 * in the URL  
 */
mainWindow.document.getParameter = function(name) {
    // this is done for caching, the URL parsing is done only once
    // and the parameters map is stored as the 'parameters' document property
    if (this.parameters == undefined) {
        this.initParameters();         
    }
    return this.parameters[name];
}

/** Returns an array with all the parameters from the URL string. 
 * Please keep in mind that the POST parameters will not be returned 
 * by this method, only the GET ones.
 * @param name the name of the parameter
 * @return the array with parameters values, the index is the parameter name
 * and the value is the parameter value 
 */
mainWindow.document.getParameters = function() {
    if (this.parameters == undefined) {
        this.initParameters();         
    }
    return this.parameters;
}

mainWindow.document.getRequestParameter = mainWindow.document.getParameter;
mainWindow.document.getRequestParameters = mainWindow.document.getParameters;

mainWindow.document.initParameters = function() {
    this.parameters = new Array();
    var queryString = this.URL.toString();
    if (queryString.indexOf("?") >= 0) {
        // splitting into parameters
        var paramsString = queryString.substr(queryString.indexOf("?") + 1);
        var params = paramsString.split("&");
        for (var i = 0; i < params.length; i++) {
            var paramName, paramValue;
            var idx = params[i].indexOf("=");
            if (idx < 0) {
                paramName = unescape(params[i].substr(0));
                paramValue = "";
            } else {
                paramName = unescape(params[i].substr(0, idx));
                paramValue = unescape(params[i].substr(idx + 1));
            }
            if (this.parameters[paramName] == undefined)
                this.parameters[paramName] = paramValue;
        }
    } 
}


mainWindow.document.createCookie = function(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 = "";
    this.cookie = name+"="+value+expires+"; path=/";
}

mainWindow.document.getCookie = function(name) {
    var nameEQ = name + "=";
    var ca = this.cookie.split(';');
    for(var i=0;i < ca.length;i++) {
        var c = ca[i];
        while (c.charAt(0)==' ') c = c.substring(1,c.length);
        if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
    }
    return null;
}

mainWindow.document.deleteCookie = function(name) {
    this.createCookie(name, "", -1);
}


mainWindow.document.createTableElement = function(name) {
    var table = this.createElement("TABLE");
    if (name) {
        table.setAttribute("id", name);
        table.name = name;
    }
    table.border = 0;
    table.cellPadding = 0;
    table.cellSpacing = 0;
    return table;
};

if (!mainWindow.document.getSelection)
mainWindow.document.getSelection = function() {
    if (document.selection && document.selection.createRange) {
        var range = document.selection.createRange();
        return range.text;
    }
    return undefined;
};  
mainWindow.document.getSelectedText = mainWindow.document.getSelection;


var DISPLAY_VALUES = new Object();
DISPLAY_VALUES["div"] = "block";
DISPLAY_VALUES["li"] = "list-item";
DISPLAY_VALUES["thead"] = "table-header-group";
DISPLAY_VALUES["tfoot"] = "table-footer-group";

if (navigator.isNS4x) {
// these values are only in Netscape/Mozilla/Firefox
DISPLAY_VALUES["table"] = "table";
DISPLAY_VALUES["tbody"] = "table-row-group";
DISPLAY_VALUES["colgroup"] = "table-column-group";
DISPLAY_VALUES["col"] = "table-column";
DISPLAY_VALUES["tr"] = "table-row";
DISPLAY_VALUES["td"] = "table-cell";
DISPLAY_VALUES["caption"] = "table-caption";
}


} // mainWindow methods

function toggleCheckbox(id) {
    var checkbox;

    checkbox = document.getElementById(id);
    checkbox.checked = !checkbox.checked;
}

toggleRadio = toggleCheckbox;

function enableShowTooltipOnStatusBar(element) {
    element.attachEvent("onmouseover", ShowTooltipOnStatusBar);
    element.attachEvent("onmouseout", HideTooltipOnStatusBar);
}

function disableShowTooltipOnStatusBar(element) {
    element.detachEvent("onmouseover", ShowTooltipOnStatusBar);
    element.detachEvent("onmouseout", HideTooltipOnStatusBar);
}

function ShowTooltipOnStatusBar(event) {
    // in Mozilla the event source is received as argument
    // in IE you can get it from window.event
    if (event == undefined) {
        event = window.event;
    }
    var element = (event.srcElement != undefined ? event.srcElement : event.currentTarget);
    if (element.getAttribute("title") != undefined) {
        element.previousStatus = window.status;
        window.status = element.getAttribute("title");
    }
}

function HideTooltipOnStatusBar(event) {
    // in Mozilla the event source is received as argument
    // in IE you can get it from window.event
    if (event == undefined) {
        event = window.event;
    }
    var element = (event.srcElement != undefined ? event.srcElement : event.currentTarget);
    if (element.previousStatus != undefined) {
        window.status = element.previousStatus;
    }
}

function enableHoverEffect(elem, suffix) {
//    if (navigator.isIE) {
        if (!suffix)
            suffix = "Hover";
        elem.hoverSuffix = suffix;
        elem.attachEvent("onmouseover", function(event) {
            if (event == undefined)
                event = window.event;
            var elem = event.srcElement;
            if (elem.hoverSuffix != undefined) {
                elem.className += elem.hoverSuffix;
            }
        });
        elem.attachEvent("onmouseout", function(event) {
            if (event == undefined)
                event = window.event;
            var elem = event.srcElement;
            if (elem.hoverSuffix != undefined) {
                elem.className = elem.className.substring(0, 
                        elem.className.length - elem.hoverSuffix.length);
            }
        });
//    }
}
