
var agt = navigator.userAgent.toLowerCase();
var ver = navigator.appVersion.toLowerCase();

window.common_utils = true;
window.bv_minor = parseFloat(ver);
window.bv_major = parseInt(bv_minor);

window.is_opera  = window.opera != null;
window.is_opera  = (agt.indexOf("opera")   != -1);
window.is_opera7 = (agt.indexOf("opera 7") != -1 || agt.indexOf("opera/7") != -1);
window.is_opera8 = (agt.indexOf("opera 8") != -1 || agt.indexOf("opera/8") != -1);
window.is_opera9 = (agt.indexOf("opera 9") != -1 || agt.indexOf("opera/9") != -1);
window.is_safari = (agt.indexOf('safari')  != -1 && agt.indexOf('mac')     != -1);

window.is_ie  = !window.is_opera && window.showModalDialog != null;
window.is_ie4 = window.is_ie && agt.indexOf("msie 4") == null;
window.is_ie5 = window.is_ie && agt.indexOf("msie 5") != null;
window.is_ie6 = window.is_ie && agt.indexOf("msie 6") != -1;
window.is_ie7 = window.is_ie && agt.indexOf("msie 7") != -1;

window.is_moz = (
	(agt.indexOf('mozilla/5')  != -1) && (agt.indexOf('spoofer') == -1) &&
	(agt.indexOf('compatible') == -1) && (agt.indexOf('opera')   == -1) &&
	(agt.indexOf('webtv')      == -1) && (agt.indexOf('hotjava') == -1));

window.is_win = agt.indexOf("windows") != -1;
window.is_mac = agt.indexOf("mac") != -1;

/**
 * Dispatches events to event listeners.
 * All argument to the constructor will be interpreted as event names
 * and these events will be created.
 * @constructor
 */
function Dispatcher()
{
	/**
	 * Object's defined event types
	 */
	this.events = new Array;
	/**
	 * Object listeners, by event type
	 */
	this.listeners = new Object;

	if (arguments.length != 0)
		for (var i = 0; i < arguments.length; i++)
			this.addEvent(arguments[i]);
}
/**
 * Adds an event type.
 * @param {String} eventType The type of the event.
 */
Dispatcher.prototype.addEvent = function (eventType)
{
	if (!this.hasEvent(eventType))
	{
		this.events.push(eventType);
		this.listeners[eventType] = new Array;
	}
}
/**
 * Returns true if the supplied eventType already exists.
 * @param {String} eventType The type of the event.
 * @return {Boolean} True us the specified event type exists.
 */
Dispatcher.prototype.hasEvent = function (eventType)
{
	for (var i = 0; i < this.events.length; i++)
		if (this.events[i] == eventType)
			return true;

	return false;
}
/**
 * Adds an event listener for the specified event type.
 * The listener can be either an object whose method should be called
 * or just a function not related to an object. To use the second method,
 * pass a null value as the object argument.
 * @param {String} eventType The type of the event.
 * @param {String} object The listener object.
 * @param {String} method The listener method.
 */
Dispatcher.prototype.addListener = function (eventType, object, method)
{
	if (this.hasEvent(eventType) && !this.hasListener(eventType, object, method))
	{
		var listener = { object: object, method: method };
		this.listeners[eventType].push(listener);
	}
}
Dispatcher.prototype.removeListener = function (eventType, object, method)
{
	if (this.hasEvent(eventType))
	{
		for (var i = 0; i < this.listeners[eventType].length; i++)
		{
			if (method)
			{
				if (this.listeners[eventType][i].object == object && this.listeners[eventType][i].method == method)
				{
					this.listeners[eventType].splice(i, 1);
					return;
				}
			}
			else
			{
				if (this.listeners[eventType][i].object == object)
				{
					this.listeners[eventType].splice(i, 1);
					return;
				}
			}
		}
	}
}
/**
 * Returns true if the supplied eventType event listener exists.
 * @param {String} eventType The type of the event.
 * @param {String} object The listener object.
 * @param {String} method The listener method.
 * @return {Boolean} True us the specified listener exists.
 */
Dispatcher.prototype.hasListener = function (event, object, method)
{
	if (this.hasEvent(event))
	{
		for (var i = 0; i < this.listeners[event].length; i++)
		{
			if (method)
			{
				if (this.listeners[event][i].object == object && this.listeners[event][i].method == method)
					return true;
			}
			else
			{
				if (this.listeners[event][i].object == object)
					return true;
			}
		}
	}
	return false;
}
/**
 * Fires the event of the supplied event type.
 * @param {String} eventType The type of the event.
 */
Dispatcher.prototype.fireEvent = function (eventType)
{
	for (var i = 0; i < this.listeners[eventType].length; i++)
	{
		var listener = this.listeners[eventType][i];
		if (listener.object && listener.method)
			listener.object[listener.method](this.getEventObject(eventType));
		else if (listener.object)
			listener.object(this.getEventObject(eventType));
		else if (listener.method)
			listener.method(this.getEventObject(eventType));
	}
}

Dispatcher.prototype.getEventObject = function (eventType)
{
	return { event: eventType, source: this };
}

/**
 * Represents an object class that depends on presence of given dom elements.
 * This is a superclass that provides shared functionality for referencing
 * a specified list of dom elements. To work with this class, use the inheriting
 * function's name as the argument to the prototype constructor, like this:
 * [ChildClass].prototype = new DomDependentObject([ChildClass]), where [ChildClass]
 * is the name of the inheriting function.
 * The list of dom elements that the child class uses should be specified as property
 * of the function itself, not of the object it creates, like this: [ChildClass].DomElements,
 * where [ChildClass] is the name of the inheriting function, and DomElements is an object
 * where each property name is the id of a required dom element and property value
 * is a 2 element array where the first element is the tag name of the
 * required dom element, and the second a short description of this required element.
 * @constructor
 * @param {Object} r_constructor Reference to the inheriting function.
 */
function DomDependentDispatcher(r_constructor)
{
	this.r_constructor = r_constructor;
}
DomDependentDispatcher.prototype = new Dispatcher;

/**
 * Creates references to the element specified with DomElements property
 */
DomDependentDispatcher.prototype.initializeElements = function ()
{
	this.elementsMissing = new Array;
	for (elementID in this.r_constructor.DomElements)
	{
		var elementObj = document.getElementById(elementID);
		var elementSpec = this.r_constructor.DomElements[elementID];
		if (elementObj != null)
			this.r_constructor.DomElements[elementID] = elementObj;
		else
			this.elementsMissing.push(elementID + ": " +
				(elementSpec.join ? elementSpec.join(" - ") : elementSpec));
	}
	return this.elementsMissing.length;
}

DomDependentDispatcher.prototype.cleanup = function ()
{
	for (elementID in this.r_constructor.DomElements)
	{
		this.r_constructor.DomElements[elementID] = null;
		delete this.r_constructor.DomElements[elementID];
	}
}

/**
 * Shows an alert with the list of dom elements that were not found in the current document.
 */
DomDependentDispatcher.prototype.showMissingList = function ()
{
	alert("Current document is missing some required elements:\n\n" +
		this.elementsMissing.join("\n"));
}

/**
 * Returns a DOM element associated with the supplied ID
 */
DomDependentDispatcher.prototype.controls = function (controlID)
{
	return this.r_constructor.DomElements[controlID];
}

/**
 * Returns a function that can be used for callbacks.
 * @param {Object} object The object whose method should be called
 * @param {String} method The name of the object method to call
 * @param {Array} fxargs Optional array of arguments that should be passed to the method\
 * @return {Function} Function that will call the supplied method of the supplied object
 */
window.createCallback = function (object, method, fxargs)
{
	var callbackFx = function () /**/
	{
		var object = arguments.callee.object;
		var method = arguments.callee.method;
		var fxargs = arguments.callee.fxargs;

		if (fxargs)
			object[method].apply(object, fxargs);
		else if (arguments.length)
			object[method].apply(object, arguments);
		else
			object[method]();
	}
	callbackFx.object = object;
	callbackFx.method = method;
	callbackFx.fxargs = fxargs;

	return callbackFx;
}

window.xml =
{
	createHttpRequest: function (url, async, onload)
	{
		var request;
		try
		{
			var request = window.XMLHttpRequest
				? new XMLHttpRequest()
				: new ActiveXObject("MSXML2.XMLHTTP");
		}
		catch (ex)
		{
			throw new Error("Your browser does not support XmlHttp objects");
		}

		if (onload)
		{
			request.onreadystatechange = function () /**/
			{
				if (request.readyState == 4)
				{
					if (request.status == 0 || request.status == 200)
						onload(request);
					else
						window.setStatus("Error loading xml request: " + request.status);
				}
			}
		}

		if (url)
		{
			request.open("GET", url, async);
			request.send(null);
		}

		return request;
	},
	createDocument: function ()
	{
		try
		{
			// DOM2
			if (document.implementation && document.implementation.createDocument)
			{
				var doc = document.implementation.createDocument("", "", null);

				if (doc.readyState == null)
				{
					doc.readyState = 1;
					doc.addEventListener("load", function () /**/
					{
						doc.readyState = 4;
						if (typeof doc.onreadystatechange == "function")
							doc.onreadystatechange();

					}, false);
				}
				return doc;
			}
			if (window.ActiveXObject)
				return new ActiveXObject("MSXML2.DomDocument");
		}
		catch (ex)
		{
			throw new Error("Your browser does not support XmlDocument objects");
		}
	},
	serializeNode: function (xmlNode)
	{
		if (xmlNode == null)
			return null;

		if (window.is_moz)
			return (new XMLSerializer()).serializeToString(xmlNode);
		else if (window.is_ie)
			return xmlNode.xml;
		else
			return xml.__serializeNode(xmlNode);
	},
	__serializeNode: function (xmlNode)
	{
		switch (xmlNode.nodeType)
		{
			case 1: return xml.__serializeElem(xmlNode);
			case 2: return xml.__serializeAttr(xmlNode);
			case 3: return xml.__serializeText(xmlNode);
			case 4: return xml.__serializeData(xmlNode);
			case 8: return xml.__serializeComm(xmlNode);
			case 9: return xml.__serializeDocu(xmlNode);
			default: return [];
		}
	},
	__serializeDocu: function (xmlNode)
	{
		return xml.__serializeElem(xmlNode.documentElement);
	},
	__serializeElem: function (xmlNode)
	{
		var result = new Array;
		result.push("<");
		result.push(xmlNode.nodeName);
		for (var i = 0; i < xmlNode.attributes.length; i++)
			result.push(" " + xml.__serializeAttr(xmlNode.attributes[i]));

		if (xmlNode.childNodes.length != 0)
		{
			result.push(">");

			for (var i = 0; i < xmlNode.childNodes.length; i++)
				result.push(xml.__serializeNode(xmlNode.childNodes[i]));

			result.push("</");
			result.push(xmlNode.nodeName);
			result.push(">");
		}
		else
		{
			result.push(" />");
		}
		return result.join("");
	},
	__serializeAttr: function (xmlNode)
	{
		return xmlNode.nodeName + "=\"" + xmlNode.nodeValue + "\"";
	},
	__serializeText: function (xmlNode)
	{
		return xmlNode.text;
	},
	__serializeData: function (xmlNode)
	{
		return xmlNode.data;
	},
	__serializeComm: function (xmlNode)
	{
		return "";
	}
};

window.drag = new Dispatcher("ondragstart", "ondragstop", "ondragmove");

window.drag.enabled = false;
window.drag.element = null;

window.drag.getEventObject = function (eventName)
{
	return { element: drag.element }
}

window.drag.enableElement = function (element)
{
	window.assignEventHandler("onmousedown", element, window.drag.onmousedown);
	window.assignEventHandler("onmouseup", element, window.drag.onmouseup);
}
window.drag.disableElement = function (element)
{
	window.removeEventHandler("onmousedown", element, window.drag.onmousedown);
	window.removeEventHandler("onmouseup", element, window.drag.onmouseup);

	if (window.is_ie)
		element.releaseCapture();

	if (this.element == element)
	{
		this.element = null;
		this.enabled = false;
	}
}
window.drag.onmousedown = function (e)
{
	var event = window.getEvent(e);

	this.mouseX = event.clientX;
	this.mouseY = event.clientY;

	var cssX = parseInt(this.currentStyle.left);
	var cssY = parseInt(this.currentStyle.top);

	this.posX = cssX || window.getLeft(this);
	this.posY = cssY || window.getTop(this);

	drag.enabled = true;
	drag.element = this;
	drag.fireEvent("ondragstart", { element: drag.element });

	if (window.is_ie)
	{
		this.onmousemove = window.drag.onmousemove;
		this.setCapture();
	}
	else
	{
		document.addEventListener("mousemove", window.drag.onmousemove, true);
	}
}
window.drag.onmouseup = function (e)
{
	var event = window.getEvent(e);

	drag.fireEvent("ondragstop", { element: drag.element });
	drag.enabled = false;
	drag.element = null;

	if (window.is_ie)
	{
		this.onmousemove = null;
		this.releaseCapture();
	}
	else
	{
		document.removeEventListener("mousemove", window.drag.onmousemove, true);
	}
}
window.drag.onmousemove = function (e)
{
	var event = window.getEvent(e);
	if (drag.enabled)
	{
		var diffY = event.clientY - drag.element.mouseY;
		var diffX = event.clientX - drag.element.mouseX;

		var posX = window.getLeft(drag.element);
		var posY = window.getTop(drag.element);

		var targetX = drag.element.posX + (event.clientX - drag.element.mouseX);
		var targetY = drag.element.posY + (event.clientY - drag.element.mouseY);

		drag.element.style.pixelTop = targetY;
		drag.element.style.pixelLeft = targetX;

		drag.fireEvent("ondragmove", { element: drag.element });
	}
}

window.makeUnselectable = function (element, recursive)
{
	if (!window.is_moz)
		element.setAttribute("unselectable", "on");
	if (window.is_moz && !element.onmousedown)
		element.onmousedown = window.preventDefaultEvent;

	if (recursive == true)
	{
		var childNodes = element.getElementsByTagName("*");
		for (var i = 0; i < childNodes.length; i++)
		{
			if (!window.is_moz)
				childNodes[i].setAttribute("unselectable", "on");
			if (window.is_moz && !childNodes[i].onmousedown)
				childNodes[i].onmousedown = window.preventDefaultEvent;
		}
	}
}
window.makeSelectable = function (element, recursive)
{
	if (!window.is_moz)
		element.removeAttribute("unselectable");

	if (window.is_moz)
	{
		var currElem = element;
		while (currElem && currElem.tagName)
		{
			if (currElem.onmousedown == window.preventDefaultEvent)
				currElem.onmousedown = null;
			currElem = currElem.parentNode;
		}
	}
	if (recursive == true)
	{
		var childNodes = element.getElementsByTagName("*");
		for (var i = 0; i < childNodes.length; i++)
		{
			if (!window.is_moz)
				childNodes[i].removeAttribute("unselectable");
			if (window.is_moz && childNodes[i].onmousedown == window.preventDefaultEvent)
				childNodes[i].onmousedown = null;
		}
	}
}
window.preventDefaultEvent = function (e)
{
	var event = window.getEvent(e);
	event.cancelBubble = true;
	event.preventDefault();
}

window.show = function (elementObj, inherit)
{
	if (elementObj == null || elementObj.style == null)
		return;

	elementObj.style.visibility = inherit == true ? "inherit" : "visible";
}

window.hide = function (elementObj)
{
	if (elementObj == null || elementObj.style == null)
		return;

	elementObj.style.visibility = "hidden";
}

window.display = function (elementObj, returnValue)
{
	if (elementObj == null || elementObj.style == null)
		return;

	var displayValue;
	if (window.is_ie)
		displayValue = elementObj.tagName == "SPAN" ? "inline" : "block";
	else
	{
		switch(elementObj.tagName.toUpperCase())
		{
			case("TR"):
				displayValue = "table-row";
				break;
			case("TD"):
				displayValue = "table-cell";
				break;
			case("TABLE"):
				displayValue = "table";
				break;
			case("SPAN"):
				displayValue = "inline";
				break;
			default:
				displayValue = "block";
				break;
		}
	}
	if (returnValue)
		return displayValue;
	else
		elementObj.style.display = displayValue;
}

window.undisplay = function (elementObj)
{
	if (elementObj == null || elementObj.style == null)
		return;
	else
		elementObj.style.display = "none";
}

window.containsClassName = function (elementObj, className)
{
	if (elementObj == null || elementObj.className == null)
		return null;

	var rxp = new RegExp("\\b" + className + "\\b");
	if (elementObj.className.match(rxp))
		return true;
	else
		return false;
}

window.addClassName = function (elementObj, className)
{
	if (elementObj == null || elementObj.className == null)
		return;
	else
	{
		if (!containsClassName(elementObj, className))
			elementObj.className += " " + className;
	}
}

window.removeClassName = function (elementObj, className)
{
	if (elementObj == null || elementObj.className == null)
		return;
	else
	{
		var rxp = new RegExp("(?:\\b|\\s)+" + className + "\\b", "g");
		elementObj.className = elementObj.className.replace(rxp, "");
	}
}

window.replaceClassName = function (elementObj, oldClass, newClass)
{
	window.removeClassName(elementObj, oldClass);
	window.addClassName(elementObj, newClass);
}

/**
 * Copies all prototype members from and applies one or more functions to the elementObj.
 * arguments[1] to arguments[arguments.length-1] should be functions to copy from and apply.
 * @param {Object} elementObj The object to apply the interface to
 * @arguments function0,...,functionN The functions toarray.
 * @return {Object} The supplied elementObj argument.
 */
window.applyPrototypes = function (elementObj)
{
	var eventRxp = new RegExp("^on(?:" +
		"activate|beforedeactivate|beforeeditfocus|blur|change|click|contextmenu|dblclick|" +
		"deactivate|error|focus|keydown|keypress|keyup|load|mousedown|mousemove|mouseout|" +
		"mouseover|mouseup|mousewheel|move|resize|scroll|select|selectionchange|submit|unload)$", "i");

	if (elementObj != null)
	{
		for (var i = 1; i < arguments.length; i++)
		{
			var r_function = arguments[i];
			for (var memberName in r_function.prototype)
			{
				if (r_function.prototype[memberName] instanceof Function && memberName.match(eventRxp))
					window.assignEventHandler(memberName, elementObj, r_function.prototype[memberName]);

				else
					elementObj[memberName] = r_function.prototype[memberName];
			}

			r_function.apply(elementObj); /**/
		}
	}
	return elementObj;
}

/**
 * Assigns the supplied event handler function to the supplied element.
 * The assignment takes into account handlers already assigned for this event,
 * and creates an array of functions to call when the event occurs, thereby
 * preserving any handlers previously assigned.
 * @param {String} eventName The event name for which to assign the handler.
 * @param {Object} elementObj Reference to the object to which to assign the handler.
 * @param {Function} eventHandler Reference to the new event handler function to assign.
 * @param {Boolean} insertBefore A switch that indicates that the supplied event handler
 * should be called before any other, previously assigned handlers.
 */
window.assignEventHandler = function (eventName, elementObj, eventHandler, insertBefore)
{
	var handlerArrayName = "handlers__" + eventName;
	if (elementObj[handlerArrayName] == null)
	{
		elementObj[handlerArrayName] = new Array;
		if (elementObj[eventName] != null)
			elementObj[handlerArrayName].push(elementObj[eventName]);
	}

	var handlerExists = false;
	for (var i = 0; i < elementObj[handlerArrayName].length; i++)
		if (elementObj[handlerArrayName][i] == eventHandler)
			handlerExists = true;

	// only assign an event handler once
	if (handlerExists == false)
	{
		if (insertBefore == true)
			elementObj[handlerArrayName].unshift(eventHandler);
		else
			elementObj[handlerArrayName].push(eventHandler);
	}

	elementObj[eventName] = on_eventHandler;
}

window.removeEventHandler = function (eventName, elementObj, eventHandler)
{
	var handlerArrayName = "handlers__" + eventName;
	if (elementObj[handlerArrayName] != null)
	{
		for (var i = 0; i < elementObj[handlerArrayName].length; i++)
			if (elementObj[handlerArrayName][i] == eventHandler)
				elementObj[handlerArrayName].splice(i, 1);
	}
}

function on_eventHandler(e)
{
	var eventObj = window.getEvent(e);
	if (eventObj)
	{
		var eventHandlers = "handlers__on" + eventObj.type;

		var finalResult = true;
		var currentResult;

		try
		{
			for (var i = 0; i < this[eventHandlers].length; i++)
			{
				try
				{
					currentResult = this[eventHandlers][i].apply(this, arguments);
				}
				catch(x)
				{
					if (x.number == -2147418113)
						continue;
					else
						throw x;
				}
				if (currentResult != undefined && typeof(currentResult) == "boolean")
					finalResult &= currentResult;
			}
		}
		catch(e)
		{
			var debug = "{1}.on{2}: {3}".format(this.tagName, eventObj.type, e.message);
			alert(debug);
		}

		return currentResult ? finalResult ? true : false : currentResult;
	}
}

/**
 * returns an element's real left coord on screen
 * @param {Object} object reference to the object
 * @return {Number} the left coord of the object
 */
window.getLeft = function (object)
{
	if (object == null && this && this != window)
		object = this;
	else if (object == null)
		return -1;

	var scrollLeft = 0;
	var bodyElement = object.offsetParent;
	while (bodyElement != null && bodyElement.tagName != "BODY")
		bodyElement = bodyElement.offsetParent;

	if (bodyElement)
		scrollLeft = bodyElement.scrollLeft;

	var left = object.offsetLeft;
	object = object.offsetParent;

	while (object != null)
	{
		if (window.is_gecko)
		{
			if (object.tagName == "TABLE")
			{
				var borderW = parseInt(object.border);
				var frameW = object.getAttribute('frame');

				if (isNaN(borderW) && frameW != null)
					left += 1;
				else if (borderW > 0)
					left += borderW;
			}
		}

		left += object.offsetLeft - object.scrollLeft;
		object = object.offsetParent;
	}
	return left + scrollLeft;
}

/**
 * returns an element's real top coord on screen
 * @param {Object} object reference to the object
 * @return {Number} the top coord of the object
 */
window.getTop = function (object)
{
	if (object == null && this && this != window)
		object = this;
	else if (object == null)
		return -1;

	var scrollTop = 0;
	var bodyElement = object.offsetParent;
	while (bodyElement != null && bodyElement.tagName != "BODY")
		bodyElement = bodyElement.offsetParent;

	if (bodyElement)
		scrollTop = bodyElement.scrollTop;

	var top = object.offsetTop;
	object = object.offsetParent;

	var step = 0;
	while (object != null)
	{
		if (window.is_gecko)
		{
			if (object.tagName == "TABLE")
			{
				var borderW = parseInt(object.border);
				var frameW = object.getAttribute('frame');

				if (isNaN(borderW) && frameW != null)
					top += 1;
				else if (borderW > 0)
					top += borderW;
			}
		}

		top += object.offsetTop - object.scrollTop;
		object = object.offsetParent;
	}
	return top + scrollTop;
}

window.getQueryString = function (url)
{
	var address;
	var addressPage;
	var addressQuery;
	var addressHash;

	if (url != null)
	{
		address = new String(url);
		if (address.match(/^((?:\w+:.*?)|(?:(?:\w+)?\/.*?))?(\?.*?)?(#.*)?$/))
		{
			addressPage = RegExp.$1;
			addressQuery = RegExp.$2.substring(RegExp.$2.indexOf("?") + 1);
			addressHash = RegExp.$3;
		}
		else
		{
			addressPage = "";
			addressQuery = address;
			addressHash = "";
		}
	}
	else
	{
		address = location.href;
		addressPage = location.href.replace(location.search, "");
		addressQuery = location.search.substring(location.search.indexOf("?") + 1);
		addressHash = location.hash;
	}

	var queryObject = new Object();
	queryObject.param = new Object();
	queryObject.address = address;
	queryObject.pagepath = addressPage;
	queryObject.pagehash = addressHash;

	var param = addressQuery.split("&");
	for (var i = 0; i < param.length; i++)
	{
		if (param[i].length == 0)
			continue;

		var pair = param[i].split("=");
		var itemKey = pair[0];
		var itemValue = pair[1];

		if (queryObject.param[itemKey] != null)
		{
			if (!isArray(queryObject.param[itemKey]))
				queryObject.param[itemKey] = [queryObject.param[itemKey]];

			queryObject.param[itemKey].push(itemValue);
		}
		else
			queryObject.param[itemKey] = itemValue;
	}
	queryObject.getItem = function (itemKey) /**/
	{
		return this.param[itemKey];
	}
	queryObject.toString = function (full) /* inner */
	{
		var param = new Array();
		for (var name in this.param)
		{
			if (this.param[name] && this.param[name].constructor == Array)
			{
				for (var i = 0; i < this.param[name].length; i++)
					param.push(escape(name) + "=" + escape(this.param[name][i]));
			}
			else
			{
				var itemValue = String(this.param[name]).match(/\{.*\}/) ? this.param[name] : escape(this.param[name]);
				param.push(escape(name) + "=" + itemValue);
			}
		}

		var query = param.join("&");
		if (full == true)
			var result = (param.length ? this.pagepath + "?" + query : this.pagepath) + this.pagehash;
		else
			var result = query;

		return result;
	}
	return queryObject;
}

window.getEvent = function (e)
{
	if (e != null)
		return e;
	else
		return window.event;
}

window.getElementsByClassName = function (className, tagName, parentElement)
{
	var elems = [];
	if (className == null || className == "")
		return elems;

	var parentObj = parentElement ? parentElement : document;

	var elemList = tagName ? parentObj.getElementsByTagName(tagName) : parentObj.getElementsByTagName("*");
	for (var i = 0; i < elemList.length; i++)
	{
		if (containsClassName(elemList[i], className))
			elems.push(elemList[i]);
	}
	return elems;
}

/**
 * searches for an element with a given tagName in a child's hiearchy of parents
 * @param {Object} refObject the child whose hiearchy of parents is to be searched
 * @param {String} tagName the tag name of the parent that we are looking for
 * @return {Object} Reference to the object, if found, or null if it was not found
 */
window.getParentByTagName = function (refObject, tagName)
{
	if (refObject == null || tagName == null)
		return null;

	tagName = String(tagName).toUpperCase();
	var objParent = refObject;
	while(objParent = objParent.parentNode)
	{
		if (objParent.tagName == tagName)
			return objParent;
	}
	return null;
}

window.setStatus = function (message, timeout)
{
	var statusObj = document.getElementById("status");

	if (statusObj)
		statusObj.innerText = message;
	else
		window.status = message;

	if (timeout)
		window.setTimeout(clearStatus, timeout);
}

window.clearStatus = function ()
{
	var statusObj = document.getElementById("status");

	if (statusObj)
		statusObj.innerText = "";
	else
		window.status = "";
}

window.extractCss = function (selectorText)
{
	for (var i = 0; i < document.styleSheets.length; i++)
	{
		var rules = document.styleSheets[i].rules || document.styleSheets[i].cssRules;
		for (var j = 0; j < rules.length; j++)
			if (rules[j].selectorText && rules[j].selectorText.match(selectorText))
				return rules[j].style.cssText;
	}
	return "";
}

window.err = function (message)
{
	window.setStatus(message, 10000);
}

window.trapError = function (errorText, errorFile, errorLine)
{
	var fileLocation = String(errorFile).replace(/.*\//, "");
	window.err(errorText + " (" + "line " + errorLine + " in " + fileLocation + ")");
	window.returnValue = true;
	return true;
}

window.warn = function (message)
{
	window.setStatus("WARNING: " + message, 10000);
}

/**
 * Sets/adds a cookie to the document.cookies collection
 * @param {String} name The name of the cookie. Required.
 * @param {String} value The value of the cookie. Required.
 * @param {String} expires An expression, signifying the expires property of the cookie. See <code>dateCalc</code>. Optional.
 * @param {String} domain The domain property of the cookie. Optional.
 * @param {Boolean} secure The secure property of the cookie. Optional.
 * @return {String} The value of the cookie that has just been set.
 */
window.setCookie = function (name, value, expires, domain, path, secure)
{
	var cookie = name + "=" + escape(value);

	if (expires) cookie += "; expires=" + dateCalc(expires);
	if (domain)  cookie += "; domain="  + domain;
	if (path)    cookie += "; path="    + path;
	if (secure)  cookie += "; secure=true";

	document.cookie = cookie;

	return getCookie(name);
}

/**
 * Returns a cookie with the specified name from the document.cookies collection, if present,
 * and a <code>null</code> if not.
 * @param {String} name The name of the cookie. Required.
 * @return {String|null} The value of the cookie, if found, and a <code>null</code> otherwise.
 */
window.getCookie = function (name)
{
	var cookies = document.cookie.split("; ");
	for (var i = 0; i < cookies.length; i++)
	{
		var cookieName  = cookies[i].substring(0, cookies[i].indexOf("="));
		var cookieValue = cookies[i].substring(cookies[i].indexOf("=") + 1, cookies[i].length);
		if (cookieName == name)
		{
			if (cookieValue.indexOf("&") != -1)
			{
				var pairs  = strValue.split("&");
				var cookie = new Object();
				for (var i in pairs)
				{
					var arrTemp = pairs[i].split("=");
					cookie[arrTemp[0]] = arrTemp[1];
				}
				return cookie;
			}
			else
				return unescape(cookieValue);
		}
	}
	return null;
}

/**
 * Deletes a cookie with the specified name from the document.cookies collection, by setting its expires property
 * to the current date [expire now].
 * @param {String} name The name of the cookie. Required.
 */
window.deleteCookie = function (name)
{
	var dateObj = new Date();
	document.cookie = name + "=null; expires=" + dateObj.toGMTString();
}

window.dateCalc = function (offsetString)
{
	var dateObj = new Date();
	var multip = new Object();
	var offsetTime;
	multip['s'] = 1000*1;
	multip['m'] = 1000*60;
	multip['h'] = 1000*60*60;
	multip['d'] = 1000*60*60*24;
	multip['M'] = 1000*60*60*24*30;
	multip['y'] = 1000*60*60*24*365;

	if (!offsetString || (offsetString == '') || (offsetString.toLowerCase() == 'now'))
	{ // this will set the time calc to now
		offsetTime = 0;
	}
	else if ( matches = offsetString.match( /^([+-]?(\d+|\d*\.\d*))([mhdMy]?)/ ) )
	{ // perform calculation if offsetString matches specification
		offsetTime = multip[matches[3]] * matches[2];
	}
	else
	{ // otherwise assume that we're providing the date ourselves so just return original
		return offsetString;
	}
	dateObj.setTime(dateObj.getTime() + offsetTime);
	return (dateObj.toGMTString());
}

Number.random = function (randTop)
{
	var top = Math.abs(randTop);
	var random = Math.round((top) * Math.random());
	return random;
}

Date.parse = function (dateValue)
{
	if (dateValue == null)
		return null;

	else if (dateValue instanceof Date)
		return dateValue.getTime();

	else if (dateValue instanceof Array)
	{
		if (dateValue.length == 3)
		{
			var currentDate = new Date(dateValue[2], dateValue[1]-1, dateValue[0]);
			if (isNaN(currentDate))
				return null;
			else
				return currentDate.getTime();
		}
		else
			return null;
	}
	else
	{
		var dateString = new String(dateValue);
		if (dateString.length == 0)
			return null;

		var currentDate = new Date();

		// xsl-short: YYYY-MM-DD or general date: YYYY/MM/DD
		if ((arrElem = dateString.match(/^(\d{4})(?:-|\/)(\d{1,2})(?:-|\/)(\d{1,2})$/)))
			currentDate = new Date(arrElem[1], arrElem[2]-1, arrElem[3]);
		// xsl-long:  YYYY-MM-DDTHH:NN:SS
		else if ((arrElem = dateString.match(/^(\d{4})-(\d{1,2})-(\d{1,2})T(\d{1,2}):(\d{1,2}):(\d{1,2})/)))
			currentDate = new Date(arrElem[1], arrElem[2]-1, arrElem[3], arrElem[4], arrElem[5], arrElem[6]);
		// js-string: www MMM dd hh:mm:ss ZON+dddd yyyy
		else if (dateString.match(/^\w{3}\s\w{3}\s\d{1,2}\s\d{2}:\d{2}:\d{2}\s\w{3}\+\d{4}\s\d{4}$/))
			currentDate = new Date(dateString);
		// js-milliseconds date
		else if (dateString.match(/^-?\d+$/))
			currentDate = new Date(parseInt(dateString));
		// lets generalize a bit: [dd-MM-yyyy] or [dd/MM/yyyy] or [dd.MM.yyyy]
		else if ((arrElem = dateString.match(/^(\d{1,2})[\.\/\-](\d{1,2})[\.\/\-](\d{4})$/)))
			currentDate = new Date(arrElem[3], arrElem[2]-1, arrElem[1]);
		// more generalization:  [yyyy-MM-dd] or [yyyy.MM.dd] or [yyyy/MM/dd]
		else if ((arrElem = dateString.match(/^(\d{4})[\.\/\-](\d{1,2})[\.\/\-](\d{1,2})$/)))
			currentDate = new Date(arrElem[1], arrElem[2]-1, arrElem[3]);
		// and some more: [dd-MM-yyyy hh:mm:ss] or [dd/MM/yyyy hh:mm:ss] or [dd.MM.yyyy hh:mm:ss]
		else if ((arrElem = dateString.match(/^(\d{1,2})[\.\/\-](\d{1,2})[\.\/\-](\d{4}) (\d{1,2}):(\d{1,2}):(\d{1,2})$/)))
			currentDate = new Date(arrElem[3], arrElem[2]-1, arrElem[1], arrElem[4], arrElem[5], arrElem[6]);
		// and more:  [yyyy-MM-dd hh:mm:ss] or [yyyy.MM.dd hh:mm:ss] or [yyyy/MM/dd hh:mm:ss]
		else if ((arrElem = dateString.match(/^(\d{4})[\.\/\-](\d{1,2})[\.\/\-](\d{1,2}) (\d{1,2}):(\d{1,2}):(\d{1,2})$/)))
			currentDate = new Date(arrElem[1], arrElem[2]-1, arrElem[3], arrElem[4], arrElem[5], arrElem[6]);
		return currentDate.getTime();

	}
}

Date.offset = function (dateInstance, timeFormat)
{
	var timeMultiplier =  { s: 1000, m: 1000*60, h: 1000*60*60, d: 1000*60*60*24, M: 1000*60*60*24*30, y: 1000*60*60*24*365 }
	var timeOffset = 0;

	if (timeFormat != undefined)
		if (String(timeFormat).match( /^([+-]?(?:\d+|\d*\.\d*))([mhdMy]?)$/ ))
			timeOffset = parseInt(timeMultiplier[RegExp.$2] * RegExp.$1);

	dateInstance.setTime(dateInstance.getTime() + timeOffset);
	return dateInstance;
}

Date.dayNames = ["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];
Date.monthNames = ["January","February","March","April","May","June","July","August","September","October","November","December"];
Date.AM = "AM";
Date.PM = "PM";

Date.prototype.toString = function (format)
{
	if (isNaN(this))
		return "NaN";

	var f = {};
	f.s     = this.getSeconds();
	f.ss    = this.getSeconds().toString().padLeft(2, 0);
	f.h     = this.getHours();
	f.hh    = this.getHours().toString().padLeft(2, 0);
	f.n     = this.getMinutes();
	f.nn    = this.getMinutes().toString().padLeft(2, 0);
	f.d     = this.getDate();
	f.dd    = this.getDate().toString().padLeft(2, 0);
	f.www   = Date.dayNames[this.getDay()].substr(0, 3);
	f.wwww  = Date.dayNames[this.getDay()];
	f.m     = (this.getMonth() + 1);
	f.mm    = (this.getMonth() + 1).toString().padLeft(2, 0);
	f.mmm   = Date.monthNames[this.getMonth()].substr(0, 3);
	f.mmmm  = Date.monthNames[this.getMonth()];
	f.yyyy  = this.getFullYear();
	f.yy    = this.getFullYear().toString().substr(2, 4);
	f.y     = f.yy;

	f.date       = f.dd + "." + f.mm + "." + f.yyyy;
	f.time       = f.hh + ":" + f.nn + ":" + f.ss;
	f.dbdate     = f.yyyy + "/" + f.mm + "/" + f.dd;
	f.dbtime     = f.hh + ":" + f.nn + ":" + f.ss;
	f.dbdatetime = f.dbdate + " " + f.dbtime;
	f.xsl_short  = f.yyyy + "-" + f.mm + "-" + f.dd;
	f.xsl_long   = f.yyyy + "-" + f.mm + "-" + f.dd + "T" + f.hh + ":" + f.nn + ":" + f.ss;

	var offset = this.getTimezoneOffset();
	var offset_hours = Math.floor(Math.abs(offset) / 60);
	var offset_minutes = Math.abs(offset) - (offset_hours * 60);
	oh = offset_hours.toString().padLeft(2, 0);
	om = offset_minutes.toString().padLeft(2, 0);
	f.classic = [f.www, f.mmm, f.d, f.time, "UTC" + (offset > 0 ? "-" : "+") + oh + om, f.yyyy].join(" ");

	if (format)
	{
		var a = format.split(/\W/);
		for (var i in a)
		{
			if (f[a[i]])
			{
				format = format.replace(a[i], f[a[i]]);
			}
		}
	}
	else format = f.classic;
	return format;
}

Date.prototype.offset = function (timeFormat)
{
	return Date.offset(this, timeFormat);
}

Date.prototype.getUTCTime = function ()
{
	return this.getTime() + (this.getTimezoneOffset() * 60000)
}

Array.prototype.contains = function(value)
{
	for (var i = 0; i < this.length; i++)
	{
		if (this[i] == value)
			return true;
	}

	return false;
}

Function.prototype.getName = function (includeArguments, argumentsOnly)
{
	var functionBody = this.toString();

	functionBody = functionBody.replace(/^[\s\S]*?function[\s\n]+(([\w.$]*)[\s\n]*\((.*)\))\W[\s\S]*$/, function () /* rxp */
	{
		var functionName = arguments[2] ? arguments[2] : "anonymous";
		var functionDefinition = arguments[2] ? arguments[1] : [functionName, "(", arguments[3], ")"].join("");

		if (!includeArguments && !argumentsOnly)
			return functionName;

		if (includeArguments && !argumentsOnly)
			return functionDefinition;

		if (includeArguments && argumentsOnly)
			return arguments[3];
	});

	return functionBody;
}

Function.prototype.callStack = function (point, maxIterCount)
{
	var callingFunction = point || arguments.callee.caller;
	var callStack = new Array();
	var functions = new Array();

	var currentCount = 0;
	while (callingFunction != null && callingFunction.getName)
	{
		if (maxIterCount && currentCount >= maxIterCount)
			break;

		// unfortunatelly this script goes into an infinite loop
		// if there is a recursion going on in the function call stack :(
		else if (functions.contains(callingFunction))
			break;

		var functionName = callingFunction.getName();
		var functionArgs = new Array();
		var argValues = callingFunction.arguments;

		for (var i = 0; i < argValues.length; i++)
		{
			if (isAlien(argValues[i]))
				functionArgs.push("[foreign-object]");

			else if (isFunction(argValues[i]))
				functionArgs.push("function: " + argValues[i].getName(true));

			else if (isArray(argValues[i]))
				functionArgs.push("array[" + argValues[i].length + "]");

			else if (isObject(argValues[i]))
				functionArgs.push("object{..}");

			else if (isNull(argValues[i]))
				functionArgs.push("null");

			else if (isString(argValues[i]))
				functionArgs.push((argValues[i].length < 200 ? "\"" + argValues[i] + "\"" : "[string(" + argValues[i].length + " chars)]"));

			else if (isUndefined(argValues[i]))
				functionArgs.push("undefined");

			else
				functionArgs.push(argValues[i]);
		}

		functions.push(callingFunction);
		callStack.unshift(callingFunction.getName() + "(" + functionArgs.join(", ") + ")");
		callingFunction = callingFunction.caller;
		currentCount++;
	}
	callStack.toString = function (joinString)
	{
		return this.join(joinString || "\n");
	}
	return callStack;
}

String.prototype.trim = function(expression)
{
	if (expression == null) expression = "\\s";
	var re = new RegExp("^[" + expression + "]*([\\s\\S]*?)[" + expression + "]*$");
	return this.replace(re, "$1");
}

String.prototype.format = function ()
{
	var arrArguments = (arguments.length == 1 && arguments[0] && isArray(arguments[0])) ? arguments[0] : arguments;

	function applyPadding(string, count, character, direction)
	{
		var string = '' + string;
		var diff = count - string.length;
		var output = new String();
		while (output.length < diff)
			output += character;

		return (direction == 2 ? string + output : output + string);
	}
	function applyFormat()
	{
		try
		{
			var strValue = new String(arrArguments[arguments[1]-1]);
		}
		catch(e) { strValue = ""; }

		if (arguments[2] != "" && arguments[3] != "")
		{
			var direction = arguments[4] == "+" ? 2 : 1;
			strValue = applyPadding(strValue, arguments[3], arguments[2] == "#" ? "0" : " ", direction);
		}
		return strValue;
	}
	return (this.replace(/\{(\d+)([$#])?(\d+)?([+-])?\}/g, applyFormat));
}
String.prototype.padLeft = function (length, padChar)
{
	if (padChar == undefined)
		padChar = " ";

	var string = this.toString();
	while(string.length < length)
		string = padChar + string;
	return string;
};
String.prototype.padRight = function (length, padChar)
{
	if (padChar == undefined)
		padChar = " ";

	var string = this.toString();
	while(string.length < length)
		string = string + padChar;
	return string;
};
function isArray(object)
{
	return isObject(object) && object.constructor == Array;
}
function isBoolean(object)
{
	return typeof object == 'boolean';
}
function isFunction(object)
{
	return typeof object == 'function';
}
function isAlien(object)
{
	return isObject(object) && typeof object.constructor != 'function';
}
function isNull(object)
{
	return typeof object == 'object' && !object;
}
function isNumber(object)
{
	return typeof object == 'number' && isFinite(object);
}
function isObject(object)
{
	return (object &&
		typeof object == 'object' &&
		object.constructor != String &&
		object.constructor != Number) || isFunction(object);
}
function isString(object)
{
	return (typeof object == 'string') || (object != null && object.constructor == String);
}
function isUndefined(object)
{
	return typeof object == 'undefined';
}

