/*
 * MODULE - Class
 */
var Class =
{
    // Creators
    create: function (proto)
    {
        /* Accepting prototype definition of the class.  Idea presented by Greg
         * Wiley: http://wiki.script.aculo.us/scriptaculous/show/ExtendClass
         */
        var klass = function ()
        {
            if (this.initialize && arguments.callee.caller != Class.extend)
            {
                this.__class__ = arguments.callee.prototype;
                Object.extend(this, Class.Methods);
                this.initialize.apply(this, arguments);
            }
        };
        klass.prototype = proto || {};
        klass.extend = Class.extend;
        return klass;
    },
    singleton: function (proto)
    {
        var klass =
        {
            instance: function ()
            {
                if (!this.__instance__)
                {
                    var klass = Class.create(proto);
                    this.__instance__ = eval('new klass');
                    proto = null;
                }
                return this.__instance__;
            }
        };
        return klass;
    },

    // Care-takers
    append_features: function (object, module)
    {
        for (var prop in module)
            if (Class.kind_of(module[prop], Function))
                (function (method)
                {
                    object[method] = function ()
                    {
                        return module[method].apply(object, arguments);
                    };
                })(prop);
            else
                object[prop] = module[prop];
    },
    extend: function (subobj)   // implementation of inheritance
    {
        /* Create an instance of the superclass.  This is necessary to maintain
         * a prototype chain correctly.
         */
        var subproto = new this;
        // Update it with the subclass definitions
        Object.extend(subproto, subobj);
        subproto.__super__ = this.prototype;
        return Class.create(subproto);
    },
    get_method: function (klass, args)  // obtain method name being called
    {
        var c = args.callee.caller;
        for (var method in klass)
            if (klass[method] == c)
                return method;
        return null;
    },
    call_super: function (superclass, self, method, args)
    {
        // NOTE: `self' should always refer to the object being instantiated
        if (superclass && superclass[method])
        {
            /* Make the next call of `this.SUPER()' in the superclass refer
             * farther up the class hierarchy */
            var __class__  = self.__class__;
            self.__class__ = superclass;
            self.__super__ = superclass.__super__;

            try
            {
                superclass[method].apply(self, args);
            }
            finally
            {
                // Restore values
                self.__class__ = __class__;
                self.__super__ = superclass;
            }
        }
    },
    kind_of: function (object, klass)
    {
        return eval('klass.prototype.isPrototypeOf(object)');
    }
};

/*
 * MODULE - Class instance methods
 * Mixed into class-instances, so that these methods will become available as
 * instance methods
 */
Class.Methods =
{
    extend: function ()
    {
        var i = arguments.length;
        while (--i >= 0)
            Object.extend(this, arguments[i]);
        return this;
    },
    include: function ()
    {
        var i = arguments.length;
        while (--i >= 0)
            Class.append_features(this, arguments[i]);
        return this;
    },
    kind_of: function (klass)
    {
        return Class.kind_of(this, klass);
    },
    SUPER: function ()
    {
        var method = Class.get_method(this.__class__, arguments);
        Class.call_super(this.__super__, this, method, arguments);
    }
};




function CreateCookie(name,value,days)
{
	if (days)
	{
		var date = new Date();
		date.setTime(date.getTime()+(days*24*60*60*1000));
		var expires = "; expires="+date.toGMTString();
	}
	else var expires = "";
	document.cookie = name+"="+value+expires+"; path=/";
}

function ReadCookie(name)
{
	var nameEQ = name + "=";
	var ca = document.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;
}

function EraseCookie(name)
{
	CreateCookie(name,"",-1);
}










var _QueryString = location.search;
var QUERYSTRING = new Object ();
var REQUEST = new Object ();
if (_QueryString.length > 1) {
	_QueryString = _QueryString.substr (1, _QueryString.length - 1);
	_QueryString = _QueryString.split ("&");
	for (var i=0; i<_QueryString.length; i++) {
		var parameter = _QueryString[i].split ("=");
		var name = parameter[0];
		var value = decodeURIComponent(parameter[1]);
		REQUEST[ name ] = value;
		QUERYSTRING[ name ] = value;
	}
}
var _Hash = location.hash;
var HASH = new Object ();
if (_Hash.length > 1) {
	_Hash = _Hash.substr (1, _Hash.length - 1);
	_Hash = _Hash.split ("&");
	for (var i=0; i<_Hash.length; i++) {
		var parameter = _Hash[i].split ("=");
		var name = parameter[0];
		var value = decodeURIComponent(parameter[1]);
		REQUEST[ name ] = value;
		HASH[ name ] = value;
	}
}
var PARAMETERS = new Object ();
PARAMETERS.makeQueryString = function () {
	var c = arguments.length;
	var qs = "";
	for (var i=0; i<c/2; i++) {
		qs += arguments[i*2] + "=" + decodeURIComponent(arguments[(i*2) + 1]) + "&";
	}
	qs = "?" + qs;
	return qs;
};
PARAMETERS.addQueryString = function (queryString) {
	var parameters = new Object ();
	queryString = queryString.substr (1, queryString.length - 1);
	queryString = queryString.split ("&");
	for (var i=0; i<queryString.length; i++) {
		var parameter = queryString[i].split ("=");
		var name = parameter[0];
		var value = decodeURIComponent(parameter[1]);
		if (name != "") {
			parameters[ name ] = value;
		}
	}
	var c = arguments.length - 1;
	if (c > 0) {
		for (var i=0; i<c/2; i++) {
			var name = arguments[(i*2) + 1];
			var value = arguments[(i*2) + 2];
			parameters[ name ] = value;
		}
	}
	var qs = "";
	for (var key in parameters) {
		qs += key + "=" + decodeURIComponent(parameters[key]) + "&";
	}
	qs = "?" + qs;
	return qs;
};
PARAMETERS.addHash = function () {
	var hash = location.hash;
	var parameters = new Object ();
	hash = hash.substr (1, hash.length - 1);
	hash = hash.split ("&");
	for (var i=0; i<hash.length; i++) {
		var parameter = hash[i].split ("=");
		var name = parameter[0];
		var value = decodeURIComponent(parameter[1]);
		if (name != "") {
			parameters[ name ] = value;
		}
	}
	var c = arguments.length;
	if (c > 0) {
		for (var i=0; i<c/2; i++) {
			var name = arguments[(i*2)];
			var value = arguments[(i*2) + 1];
			parameters[ name ] = value;
			HASH[ name ] = value;
			REQUEST[ name ] = value;
		}
	}
	hash = "";
	for (var key in parameters) {
		if (parameters[key] && parameters[key] != "") {
			hash += key + "=" + decodeURIComponent(parameters[key]) + "&";
		}
	}
	hash = "#" + hash;
	location.hash = hash;
	return hash;
};
PARAMETERS.removeHash = function () {
	var c = arguments.length;
	var args = [];
	for (var i=0; i<c; i++) {
		args.push (arguments[i]);	
		args.push ("");	
	}
	return PARAMETERS.addHash.apply (null, args);
};
PARAMETERS.clearHash = function () {
	location.hash = "";
};




if (window.XMLSerializer && window.Document && window.Document.prototype && window.Document.prototype.__defineGetter__) {
	Document.prototype.__defineGetter__("xml", function () {
	   return (new XMLSerializer()).serializeToString(this);
	});
	Node.prototype.__defineGetter__("xml", function () {
	   return (new XMLSerializer()).serializeToString(this);
	});
}

var XmlGlobal = new Object();
XmlGlobal.ELEMENT_NODE = 1;


if (window.addEventListener) {
	window.addEventListener("unload", __globalDispose, false );
}
else if (window.attachEvent) {
	window.attachEvent("onunload", __globalDispose);
}

window.disposeCollection = [];
function __globalDispose () {
	var c = window.disposeCollection.length;
	for (var i=0; i<c; i++) {
		window.disposeCollection[i].dispose ();	
		window.disposeCollection[i] = null;
	}
	window.disposeCollection = null;
	try {
		Event.unloadCache ();
	}
	catch (x) {
	}
	try {
		EVENT.clearListeners ();
	}
	catch (x) {
	}
}
function __addToDisposeCollection (obj) {
	window.disposeCollection[window.disposeCollection.length] = obj;
}
function __disposeObject (thisObject) {
	if (thisObject) {
		for (var objName in thisObject) {
			thisObject[objName] = null;
		}
	}
	thisObject = null;
}
function __printObject (obj) {
	var msg = "";
	for (var n in obj) {
		msg += n + ":" + obj[n] + "\r\n";
	}
	return msg;
}


// Global Functions
var _JSGLOBAL = Class.create ();
_JSGLOBAL.prototype = {
	initialize: function () {
		this._uid = -1;
	},
	
	getUID: function () {
		this._uid++;
		return "__uid_" + this._uid;
	}
}
var JSGLOBAL = new _JSGLOBAL ();




// Browser Related Functions
var _BROWSER = Class.create ();
_BROWSER.prototype = {
	initialize: function () {
		this.isMozilla;
		this.isIE;
		this.isSafari;
		this.checkIfMozilla ();
		this.checkIfIE ();
		this.checkIfSafari ();
	},
	
	checkIfMozilla: function () {
		if (navigator.product && navigator.product == "Gecko") {
			if (navigator.userAgent.indexOf ("Netscape") > -1) {
				this.isMozilla = true;
				this.isIE = false;
				this.isSafari = false;
			}
			else if (navigator.userAgent.indexOf ("Firefox") > -1) {
				this.isMozilla = true;
				this.isIE = false;
				this.isSafari = false;
			}
		}
	},
	
	checkIfIE: function () {
		if (document.all) {
			this.isMozilla = false;
			this.isIE = true;
			this.isSafari = false;
		}
	},
	
	checkIfSafari: function () {
		if (navigator.userAgent.indexOf ("Safari") > -1) {
			this.isMozilla = false;
			this.isIE = false;
			this.isSafari = true;
		}
	}
}
var BROWSER = new _BROWSER ();



// DOM Related Functions
var _DOM = Class.create ();
_DOM.prototype = {
	initialize: function () {
		this.ns = new Object ();
		this.rns = new Object ();
	},
	
	clearChildren: function (parent) {
		if (parent.constructor == String) {
			parent = $(parent);
		}
		var children = parent.childNodes;
		var c = children.length;
		for (var i=0; i<c; i++) {
			var child = children[0];
			parent.removeChild (child);
		}
	},
	
	findElementRange: function (nodeOne, nodeTwo) {
		// Return all elements between two elements that share
		// the same parent element in an array. The result includes 
		// the two elements passed to the function.
		var parentOne = nodeOne.parentNode;
		var parentTwo = nodeTwo.parentNode;
		if (parentOne != parentTwo) {
			return [];
		}
		var children = parentOne.childNodes;
		var range = [];
		for (var i=0; i<children.length; i++) {
			var child = children[i];
			if (child.nodeType == 1) {
				if (range.length == 0 && (child == nodeOne || child == nodeTwo)) {
					range.push (child);
				}
				else if (range.length > 0 && (child == nodeOne || child == nodeTwo)) {
					range.push (child);
					return range;
				}
				else if (range.length > 0) {
					range.push (child);
				}
			}
		}
		return range;
	},
	
	cloneReplace: function (orig, newId, parent) {
		if (parent.constructor == String) {
			parent = $(parent);
		}
		if (orig.constructor == String) {
			orig = $(orig);
		}
		this.clearChildren (parent);
		if (document.all) {
			var clone = orig.cloneNode (true);
			clone.id = newId;
			parent.innerHTML = clone.outerHTML;
			return parent.ownerDocument.getElementById (newId);
		}
		else {
			var clone = parent.ownerDocument.importNode (orig, true);
			clone.id = newId;
			return parent.appendChild (clone);
		}
	},
	
	cloneAppend: function (orig, newId, parent) {
		if (parent.constructor == String) {
			parent = $(parent);
		}
		if (orig.constructor == String) {
			orig = $(orig);
		}
		var clone = orig.cloneNode (true);
		clone.id = newId;
		return parent.appendChild (clone);
	},
	
	findAncestorByTagName: function (thisNode, tagName, upperBoundary) {
		tagName = tagName.toUpperCase ();
		if (!upperBoundary) {
			upperBoundary = document.body;
		}
		var parent = thisNode.parentNode;
		if (!parent) {
			return null;	
		}
		else if (parent.tagName == tagName) {
			return parent;	
		}
		else if (parent == document.body) {
			return null;	
		}
		else {
			return this.findAncestorByTagName (parent, tagName);
		}
	},
	
	findAncestorSelfByTagName: function (thisNode, tagName, upperBoundary) {
		tagName = tagName.toUpperCase ();
		if (thisNode.tagName == tagName) {
			return thisNode;	
		}
		else {
			return this.findAncestorByTagName (thisNode, tagName, upperBoundary);
		}
	},
	
	findAncestorByClassName: function (thisNode, className, upperBoundary) {
		if (!upperBoundary) {
			upperBoundary = document.body;
		}
		var parent = thisNode.parentNode;
		if (!parent || parent.nodeType != 1) {
			return null;	
		}
		else if (parent.className && Element.hasClassName (parent, className) == true) {
			return parent;	
		}
		else if (parent == upperBoundary) {
			return null;	
		}
		else {
			return this.findAncestorByClassName (parent, className);
		}
	},
	
	findAncestorSelfByClassName: function (thisNode, className, upperBoundary) {
		if (!upperBoundary) {
			upperBoundary = document.body;
		}
		if (!thisNode || thisNode.nodeType != 1) {
			return null;	
		}
		else if (thisNode.className && Element.hasClassName (thisNode, className) == true) {
			return thisNode;	
		}
		else if (thisNode == upperBoundary) {
			return null;	
		}
		else {
			return this.findAncestorSelfByClassName (thisNode.parentNode, className);
		}
	},
	
	makeUnselectable: function (thisNode) {
		if (thisNode.style.MozUserSelect != undefined) {
			thisNode.style.MozUserSelect  = "none";
		}
		else if (document.all) {
			thisNode.ondrag = function () { return false; };
			thisNode.onselectstart = function () { return false; };
		}
	},
	
	makeSelectable: function (thisNode) {
		if (thisNode.style.MozUserSelect != undefined) {
			thisNode.style.MozUserSelect  = "";
		}
		else if (document.all) {
			thisNode.ondrag = function () { return true; };
			thisNode.onselectstart = function () { return true; };
		}
	},
	
	parseXML: function (xmlString) {
		if (window.DOMParser) {
			try {
				var parser = new DOMParser();
				xml = parser.parseFromString (xmlString, "text/xml");
				return xml;
			}
			catch (x) {
				alert (x);
			}
		}
		else if (window.ActiveXObject) {
			try {
				xml = new ActiveXObject("Msxml2.DOMDocument.3.0");
				xml.loadXML(xmlString);
				return xml;
			} 
			catch (x) {
				alert (x);
			}
		}
	},
	
	registerNS: function (prefix, urn) {
		// Haven't implement the code to clear out obsolete urn to prefix relationships
		if (!this.rns[urn]) {
			this.rns[urn] = [prefix];
			this.ns[prefix] = urn;
		}
		else {
			this.rns[urn][this.rns[urn].length] = prefix;
			this.ns[prefix] = urn;
		}
	},
	
	getAttribute: function (node, attributeName, urn) {
		var prefixes = this.rns[urn];
		var c = prefixes.length;
		for (var i=0; i<c; i++) {
			var prefix = prefixes[i];
			var prefixAttribute = prefix + ":" + attributeName;
			if (node.getAttribute (prefixAttribute)) {
				return node.getAttribute (prefixAttribute);
			}
			if (node.getAttributeNS) {
				var attr = node.getAttributeNS (urn, attributeName);
				if (attr) {
					return attr;
				}
			}
		}
		return null;
	},
	
	getPrefix: function (urn) {
		// Getting a prefix by namespace is never safe, use it with caution
		var prefixes = this.rns[urn];
		var c = prefixes.length;
		if (c > 0) {
			return prefixes[0];
		}
		return null;
	},
	
	setAttribute: function (node, attributeName, value, urn) {
		var prefixes = this.rns[urn];
		var c = prefixes.length;
		for (var i=0; i<c; i++) {
			var prefix = prefixes[i];
			var prefixAttribute = prefix + ":" + attributeName;
			if (node.setAttribute (prefixAttribute, value)) {
				return node.setAttribute (prefixAttribute, value);
			}
		}
		return null;
	},
	
	selectSingleNodeString: function (node, expression, namespaces) {
		var returnNode = this.selectSingleNode (node, expression, namespaces);
		if (returnNode != null) {
			return returnNode.nodeValue;	
		}
		return "";
	},
	
	selectSingleNode: function (node, expression, namespaces) {
		// namespaces format:
		// "a='abc',b='def'"
		var mozNamespaces = new Object ();
		var ownerDoc = node.ownerDocument;
		if (namespaces && namespaces != "") {
			var splits = namespaces.split (",");
			var c = splits.length;
			for (var i=0; i<c; i++) {
				var namespace = splits[i].split ("=");
				var prefix = namespace[0];
				var uri = namespace[1].substr (1, namespace[1].length - 2);
				if (window.ActiveXObject && ownerDoc) {
					ownerDoc.setProperty ("SelectionNamespaces", "xmlns:" + prefix + "='" + uri + "'");
				}
				else if (ownerDoc.evaluate) {
					mozNamespaces[prefix] = uri;
				}
			}
		}
		var nsResolver = function (prefix) {
			if (mozNamespaces[prefix]) {
				return mozNamespaces[prefix];
			}
			return null;
		}
		if (window.ActiveXObject && ownerDoc) {
			ownerDoc.setProperty("SelectionLanguage", "XPath");
			var foundNode = ownerDoc.selectSingleNode(expression);
			foundNode = (foundNode) ? foundNode : null;
			return foundNode;
		}
		else if (ownerDoc.evaluate) {
			var foundNode = ownerDoc.evaluate(expression, node, nsResolver, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
			foundNode = (foundNode) ? foundNode.singleNodeValue : null;
			return foundNode;
		}
		return null;
	},
	
	getDefaultView: function (element) {
		var doc = null;
		if (element.constructor == String) {
			element = $(element);
			doc = element.ownerDocument;
		}
		else if (element.nodeType == 9) {
			doc = element;
		}
		else {
			doc = element.ownerDocument;
		}
		if (doc) {
			if (doc.defaultView) {
				return doc.defaultView;
			}
			else if (doc.parentWindow) {
				return doc.parentWindow;
			}
			return null;
		}
	}
}
var DOM = new _DOM ();



// Event Related Functions
var _EVENT = Class.create ();
_EVENT.prototype = {
	initialize: function () {
		this.listeners = [];
	},
	
	addEventListener: function (object, eventType, listener, useCapture) {
		if (object.addEventListener) {
			object.addEventListener (eventType, listener, useCapture);
			this.listeners.push ([object, eventType, listener, useCapture]);
		}
		else if (object.attachEvent) {
			object.attachEvent ("on" + eventType, listener);
			this.listeners.push ([object, eventType, listener, useCapture]);
		}
	},

	clearListeners: function () {
		var c = this.listeners.length;
		for (var i=0; i<c; i++) {
			var listener = this.listeners[i];
			if (listener[0].removeEventListener) {
				listener[0].removeEventListener (listener[1], listener[2], listener[3]);
			}
			else if (listener[0].detachEvent) {
				listener[0].detachEvent (listener[1], listener[2]);
			}
			this.listeners[i][0] = null;
		}
	},
	
	getEvent: function (e) {
		e = (e)? e : window.event;
		return e;
	}
}
var EVENT = new _EVENT ();



// Element Related Functions
var _ELEMENT = Class.create ();
_ELEMENT.prototype = {
	initialize: function () {
	},
	
	makeVisibleNoDisplay: function (element) {
		element = $(element);
		element.style.display = "none";
		element.style.visibility = "visible";
	},
	
	makeInvisibleDisplay: function (element) {
		element = $(element);
		element.style.visibility = "hidden";
		element.style.display = "block";
	},
	
	getComputedStyle: function (element) {
		element = $(element);
		var computedStyle = null;
		if (window.getComputedStyle) {
			computedStyle = window.getComputedStyle (element, "");
		}
		else if (element.currentStyle) {
			computedStyle = element.currentStyle;
		}
		if (!computedStyle && arguments.length < 2) {
			return null;	
		}
		var returnStyle = new Object ();
		returnStyle.style = computedStyle;
		for (var i=1; i<arguments.length; i++) {
			var argument = arguments[i];
			if (argument == "spacing-horizontal") {
				var margin = parseInt (computedStyle.getPropertyValue ("margin-left")) + parseInt (computedStyle.getPropertyValue ("margin-right"));
				var padding = parseInt (computedStyle.getPropertyValue ("padding-left")) + parseInt (computedStyle.getPropertyValue ("padding-right"));
				var border = parseInt (computedStyle.getPropertyValue ("border-left-width")) + parseInt (computedStyle.getPropertyValue ("border-right-width"));
				returnStyle[argument] = margin + padding + border;
			}
			else if (argument == "spacing-vertical") {
				var margin = parseInt (computedStyle.getPropertyValue ("margin-top")) + parseInt (computedStyle.getPropertyValue ("margin-bottom"));
				var padding = parseInt (computedStyle.getPropertyValue ("padding-top")) + parseInt (computedStyle.getPropertyValue ("padding-bottom"));
				var border = parseInt (computedStyle.getPropertyValue ("border-top-width")) + parseInt (computedStyle.getPropertyValue ("border-bottom-width"));
				returnStyle[argument] = margin + padding + border;
			}
			else {
				returnStyle[argument] = computedStyle.getPropertyValue (argument);
			}
		}
		return returnStyle;
	}
}
var ELEMENT = new _ELEMENT ();



// Position Related Functions
var _POSITION = Class.create ();
_POSITION.prototype = {
	initialize: function () {
	},
	
	getScroll: function () {
		var scrolling = new Object ();
		if (window.scrollX !== undefined) {
			scrolling.x = window.scrollX;
			scrolling.y = window.scrollY;
		}
		else if (document.all) {
			if (document.body && document.compatMode == "CSS1Compat") {
				scrolling.x = document.body.parentNode.scrollLeft;
				scrolling.y = document.body.parentNode.scrollTop;
			}
			else if (document.body) {
				scrolling.x = document.body.scrollLeft;
				scrolling.y = document.body.scrollTop;
			}
		}
		return scrolling;
	},
	
	getWindowDimension: function () {
		var dimension = new Object ();
		if (top.innerWidth || top.innerHeight) {
			dimension.width = top.innerWidth;
			dimension.height = top.innerHeight;
			return dimension;
		}
		else if (top.document.documentElement && (top.document.documentElement.clientWidth || top.document.documentElement.clientHeight)) {
			dimension.width = top.document.documentElement.clientWidth;
			dimension.height = top.document.documentElement.clientHeight;
			return dimension;
		}
		else if (top.document.body && (top.document.body.clientWidth || top.document.body.clientHeight)) {
			dimension.width = top.document.body.clientWidth;
			dimension.height = top.document.body.clientHeight;
			return dimension;
		}
		return null;
	},
	
	_cumulativeOffset: function (view, offset) {
		if (view.frameElement) {
			var offsetArray = Position.cumulativeOffset (view.frameElement);
			offset.x += offsetArray[0];
			offset.y += offsetArray[1];
			var defaultView = DOM.getDefaultView (view.frameElement);
			return POSITION._cumulativeOffset (defaultView, offset);
		}
		else {
			var scrollingArray = Position.realOffset (view);
			return offset;
		}
	},
	
	cumulativeOffset: function (element) {
		element = $(element);
		var offsetArray = Position.cumulativeOffset (element);
		var scrollingArray = Position.realOffset (element);
		var offset = new Object ();
		offset.x = offsetArray[0] - scrollingArray[0];
		offset.y = offsetArray[1] - scrollingArray[1];
		var defaultView = DOM.getDefaultView (element);
		return POSITION._cumulativeOffset (defaultView, offset);
	},
	
	_positionByTrigger: function (pos, view) {
		pos.rating = 0;
		if (pos.x >= view.x) {
			pos.rating++;
		}
		if (pos.y >= view.y) {
			pos.rating++;
		}
		if (pos.width <= view.width) {
			pos.rating++;
		}
		if (pos.height <= view.height) {
			pos.rating++;
		}
	},
	
	positionByTrigger: function (triggerElement, targetElement, offset) {
		var offsetX = (offset && offset.x) ? offset.x : 5;
		var offsetY = (offset && offset.y) ? offset.y : 5;
	
		triggerElement = $(triggerElement);
		var trigger = POSITION.cumulativeOffset (triggerElement);
		var triggerDimension = Element.getDimensions (triggerElement);
		trigger.width = triggerDimension.width;
		trigger.height = triggerDimension.height;
		
		targetElement = $(targetElement);
		var target = Element.getDimensions(targetElement);
		
		var view = POSITION.getWindowDimension ();
		
		var scrolling = top.POSITION.getScroll ();
		view.x = scrolling.x;
		view.y = scrolling.y;
		view.width = view.x + view.width;
		view.height = view.y + view.height;
	
		var pos1 = new Object ();
		pos1.x = trigger.x - target.width + offsetX + view.x;
		pos1.y = trigger.y - target.height + offsetY + view.y;
		pos1.width = pos1.x + target.width;
		pos1.height = pos1.y + target.height;
		pos1.toString = function () { return 1 };
		POSITION._positionByTrigger (pos1, view);
		
		var pos2 = new Object ();
		pos2.x = trigger.x + trigger.width - offsetX + view.x;
		pos2.y = trigger.y - target.height + offsetY + view.y;
		pos2.width = pos2.x + target.width;
		pos2.height = pos2.y + target.height;
		pos2.toString = function () { return 2 };
		POSITION._positionByTrigger (pos2, view);
	
		var pos3 = new Object ();
		pos3.x = trigger.x - target.width + offsetX + view.x;
		pos3.y = trigger.y + trigger.height - offsetY + view.y;
		pos3.width = pos3.x + target.width;
		pos3.height = pos3.y + target.height;
		pos3.toString = function () { return 3 };
		POSITION._positionByTrigger (pos3, view);
		
		var pos4 = new Object ();
		pos4.x = trigger.x + trigger.width - offsetX + view.x;
		pos4.y = trigger.y + trigger.height - offsetY + view.y;
		pos4.width = pos4.x + target.width;
		pos4.height = pos4.y + target.height;
		pos4.toString = function () { return 4 };
		POSITION._positionByTrigger (pos4, view);
		
		var pos = [pos2, pos1, pos3, pos4];
		var lastPost = null;
		var best = pos.sortBy (
			function (value, index) {
				return value.rating;
			}
		);
		
		targetElement.style.left = best[3].x + "px";
		targetElement.style.top = best[3].y + "px";
		
		return best[3];
	}
}
var POSITION = new _POSITION ();





// Input Related Functions
var _INPUT = Class.create ();
_INPUT.prototype = {
	initialize: function () {
	},
	
	setValue: function (inputObj, value) {
		if (inputObj.constructor == String) {
			this.setValueById (inputObj, value);
			return;
		}
		if (inputObj) {
			if (inputObj.type == "checkbox") {
				var splits = value.split (",");
				var c = splits.length;
				inputObj.checked = false;
				for (var i=0; i<c; i++) {
					var split = splits[i];
					if (inputObj.value == split) {
						inputObj.checked = true;
						break;
					}
				}
			}
			else if (inputObj.type == "radio" && inputObj.value == value) {
				inputObj.checked = true;
			}
			else if (inputObj.type == "select-one") {
				var c = inputObj.options.length;
				for (var i=0; i<c; i++) {
					if (inputObj.options[i].value == value) {
						inputObj.options[i].selected = true;
					}
					else {
						inputObj.options[i].selected = false;
					}
				}
			}
			else if (inputObj.type == "select-multiple") {
				var splits = value.split (",");
				var c = inputObj.options.length;
				var d = splits.length;
				for (var i=0; i<c; i++) {
					for (var j=0; j<d; j++) {
						var split = splits[j];
						if (inputObj.options[i].value == split) {
							inputObj.options[i].selected = true;
							break;
						}
						else {
							inputObj.options[i].selected = false;
						}
					}
				}
			}
			else {
				inputObj.value = value;
			}
		}
	},
	
	setValueById: function (id, value) {
		var inputObj = id;
		if (id.constructor == String) {
			inputObj = $(id);
		}
		this.setValue (inputObj, value);
	},
	
	setValueByName: function (formName, name, value) {
		var form = formName;
		if (formName.constructor == String) {
			form = document.forms[formName];
		}
		if (form) {
			var elements = form.elements[name];
			if (elements.type == undefined) {
				var c = elements.length;
				var splits = value.split (",");
				var d = splits.length;
				for (var i=0; i<c; i++) {
					var element = elements[i];
					if (element.type == "checkbox") {
						this.setValue (element, value);
					}
					else if (element.type == "radio") {
						this.setValue (element, value);
					}
					else if (element.type == "select-one") {
						this.setValue (element, value);
					}
					else if (element.type == "select-multiple") {
						this.setValue (element, value);
					}
					else {
						if (splits[i]) {
							this.setValue (element, splits[i]);
						}
					}
				}
			}
			else {
				this.setValue (elements, value);
			}
		}
	},
	
	getValue: function (inputObject) {
		return $F(inputObject);
	},
	
	getValueById: function (id) {
		return $F(id);
	},
	
	getValueByName: function (formName, name) {
		var form = formName;
		if (formName.constructor == String) {
			form = document.forms[formName];
		}
		if (form) {
			var elements = form.elements[name];
			if (elements.type == undefined) {
				var c = elements.length;
				var values = [];
				for (var i=0; i<c; i++) {
					var element = elements[i];
					var value = $F(element);
					if (value) {
						values[values.length] = value;
					}
				}
				if (values == []) {
					return "";
				}
				else {
					return values;
				}
			}
			else {
				return $F(elements);
			}
		}
		return "";
	}
}
var INPUT = new _INPUT ();
var $I = INPUT.getValueByName; // a shortcut to INPUT.getValueByName


// Validation Related Functions
var _VALIDATION = Class.create ();
_VALIDATION.prototype = {
	initialize: function () {
	},
	
	checkRequired: function (fields, errorMessage) {
		// error message is in this format:
		// "Text text text\r\n${missing}\r\ntext text text."
		var c = fields.length;
		var missing = "";
		for (var i=0; i<c; i++) {
			var fieldObject = $(fields[i]);
			if ($F(fields[i]) == "") {
				missing += ((fieldObject.title) ? fieldObject.title : fields[i]) + "\r\n";
			}
		}
		if (missing != "") {
			errorMessage = errorMessage.replace ("${missing}", missing);	
			alert (errorMessage);
			return false;
		}
		return true;
	}
}
var VALIDATION = new _VALIDATION ();











// Logic Related Functions
var _IF = Class.create ();
_IF.prototype = {
	initialize: function () {
	},

	HasOne: function (collection, funcRef, args, hasNotFunc) {
		// Usage:
		// var a = document.links
		// IF.HasOne (a, functionA)
		// IF.HasOne (a, functionA, {"Pass some additional parameters"})
		// IF.HasOne (a, functionA, null, functionB)
		// IF.HasOne (a, functionA, {"Pass some additional parameters"}, functionB)
		if (collection && collection.length > 0) {
			funcRef (collection[0], args);	
		}
		else if (hasNotFunc && (!collection || collection.length < 1)) {
			hasNotFunc (args);
		}
	}
}
var IF = new _IF ();






var __customNamespace = "urn:jslib";
DOM.registerNS ("jslib", __customNamespace);
