/*
Westend JavaScript Framework
(C) 2007 Westend, SRL.
*/

window.includes = (window.includes == undefined) ? [] : window.includes;
if(window.includes["general.js"]==undefined){
	window.includes["general.js"]=true;


	var favoriteCookieName = "favorites";
	function addToFavorites(uid){
		var c = Cookie.get(favoriteCookieName);
		if(!isFavorite(uid)){
			c += "'"+uid + "',";
			Cookie.set(favoriteCookieName, c, 0, "/");
		}
		return true;
	}
	function removeFromFavorites(uid){
		var c = Cookie.get(favoriteCookieName);
		c = c.replace("'"+uid+"',", "");
		Cookie.set(favoriteCookieName, c, 0, "/");
	}
	function toggleFavorite(uid){
		var c = Cookie.get(favoriteCookieName);
		if(isFavorite(uid)){
			removeFromFavorites(uid);
		}else{
			addToFavorites(uid);
		}
	}
	function isFavorite(uid){
		var c = Cookie.get(favoriteCookieName);
		return c.indexOf(uid)>-1;
	}



	/** if there's an element used for debug dump the message in there */
	Debug = function(message){
		// if a debug container is present, dump the message in there
		try{
			$("debugContainer").innerHTML = (message + "<br>") + $("debugContainer").innerHTML;
		}catch(e){};
	}
	
	Forms = function(formName){
		return document.forms[formName];
	}
	
	/** convert degrees to radians */
	Number.prototype.toRad = function() {
	  return this * Math.PI / 180;
	}
	
	/** convert radians to degrees (signed) */
	Number.prototype.toDeg = function() { 
	  return this * 180 / Math.PI;
	}
	
	String.prototype.extractScripts = function(){
		var pattern = "<script[^>]*>([\\S\\s]*?)<\/script>";
		var matchAll = new RegExp(pattern, 'img');
		var matchOne = new RegExp(pattern, 'im');
		return (this.match(matchAll) || []).map(function(scriptTag) {
		  return (scriptTag.match(matchOne) || ['', ''])[1];
		});
	}
	
	String.prototype.removeScripts = function(){
		var pattern = "<script[^>]*>([\\S\\s]*?)<\/script>";
		var matchAll = new RegExp(pattern, 'img');
		this.replace(matchAll, "");
	}
		
	String.prototype.evalScripts = function(){
	   function e(s){
		   try{
			   return eval(s);
		   }catch(e){return false};
	   }
	   return this.extractScripts(this).map(e);
  	}
	
	String.prototype.amp = function(){
		return this.replace("&", "&amp;");
	}
	String.prototype.unamp = function(){
		return this.replace("&amp;", "&");
	}
	
	String.prototype.parseQueryString=function(){
		if(this.length<1){
			return[];
		}
		var pairs=this.split("&");
		var result=[];
		for(var i=0;i<pairs.length;i++){
			var param=pairs[i].split("=");
			result[param[0]]=unescape(param[1]);
		}
		return result;
	};
	
	if (!Array.prototype.map){
		Array.prototype.map = function(fun /*, thisp*/){
			var len = this.length;
			if (typeof fun != "function")
				throw new TypeError();
			
			var res = new Array(len);
			var thisp = arguments[1];
			for (var i = 0; i < len; i++){
				if (i in this)
					res[i] = fun.call(thisp, this[i], i, this);
			}
			return res;
		};
	}
	
	/** Point class */
	function Point(x, y){
		this.x = x;
		this.y = y;
		this.toString = function(){
			return "(" + this.x + "," + this.y + ")";
		}
	}
	
	/** Rectangle class */
	function Rectangle(tl, br){
		this.tl = tl;
		this.br = br;
		this.toString = function(){
			return "Rectangle(" + this.tl.x + "," + this.tl.y + ", " + this.br.x + ", " + this.br.y + ")";
		}
	}
	
	/** Sequential search of an array */
	Array.prototype.seqSearch = function(v,n){
		// Sequential search of an array
		n = n || 0; 
		for(var i = n; i < this.length; i++)
			if(this[i] == v)
				return i;
			return -1;
	}
	
	/** Binary search of an array */
	Array.prototype.binSearch = function(what, suggest){
		// Binary search of an array
		var h = this.length, l = -1, m;
		while(h - l > 1)
			if(this[m = h + l >> 1] < what) l = m;
			else h = m;
		return this[h] != what ? suggest ? h : -1 : h;
	}
	
	/** Pad a number with zeros */
	Number.prototype.pad = function(maxlength, padwith){
		// Pad a number with zeros
		var n = this.toString(); 
		padwith = padwith || "0";
		while(n.length < maxlength)
				n = padwith + n; 
		return n;
	} 
	
	function instanceOf(instance, clss) { // beware of ie
		// Not working in IE, not used
		while (instance != null) {
			//Debug("Instance: " + instance + "<br>class.prototype:" + clss.prototype + "<br>class: " + clss + "<br><br><br>");
			if (instance == clss.prototype) {
				return true;
			}
			instance = instance.__proto__ || instance.constructor.prototype;
		}
		return false;
	}
	
	/** Get object properties as a string, used for debug purposes */
	function objectProps(obj) {
		ret = "";
		for(var i in obj){
			ret += (ret.length ? ", " : "") + i + " = " + obj[i] + "<br>";
		}
		return ret;
	}
	
	/* returns a random integer in range */
	Math.rand = function(min, max){
		//returns a random integer in range
		var result;
		if(min && max)
			result = Math.floor(Math.random()*(max-min) + min);
		else if(max)
			result = Math.round(Math.random()*max);
		else
			result = Math.random();
		return result * 1;
	}
	
	/** Returns a random float */
	Math.randF = function(min, max, precision){
		// Returns a random float
		var result;
		if(min && max)
			result = Math.random()*(max-min) + min;
		else if(max)
			result = Math.random()*max;
		else
			result = Math.random();
		return precision ? result.toFixed(precision)*1 : result;
	
	}
	
	/** Add two floats, implemented this for some bug i can't remember, not really used */
	Math.addF = function(f1, f2){
		var precision = Math.pow(10, Math.max(f1.toString().length, f2.toString().length)-1);
		return (f1*precision+f2*precision)/precision;
	}
	
	function WCryptoText(text){
		document.write(Base64.decode(text));
	}
	WCryptoText.initAll = function(){
		WUtility.traverse(
			document.body,
			function(node){
					if(node.nodeType == 1 && node.className == "WCryptoText"){
						node.innerHTML = Base64.decode(node.innerHTML);
						Show(node);
					}
			}
		);
	}
	
	function Table(){
		throw 'RuntimeException: Table is a static utility class and may not be instantiated';
	}
	Table.highlight = function(tableId, options){
		var table = $(tableId);
		if(options.header){
			table.rows[0].className = options.header
			start = 1;
		}else{
			start = 0;
		}
		for(var i=start; i<table.rows.length; i++)
			table.rows[i].className = (i%2==0 ? options.h1 : options.h2);
	}
	
	var Base64 = {
	 
		// private property
		_keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
	 
		// public method for encoding
		encode : function (input) {
			var output = "";
			var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
			var i = 0;
	 
			input = Base64._utf8_encode(input);
	 
			while (i < input.length) {
	 
				chr1 = input.charCodeAt(i++);
				chr2 = input.charCodeAt(i++);
				chr3 = input.charCodeAt(i++);
	 
				enc1 = chr1 >> 2;
				enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
				enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
				enc4 = chr3 & 63;
	 
				if (isNaN(chr2)) {
					enc3 = enc4 = 64;
				} else if (isNaN(chr3)) {
					enc4 = 64;
				}
	 
				output = output +
				this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) +
				this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);
	 
			}
	 
			return output;
		},
	 
		// public method for decoding
		decode : function (input) {
			var output = "";
			var chr1, chr2, chr3;
			var enc1, enc2, enc3, enc4;
			var i = 0;
	 
			input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
	 
			while (i < input.length) {
	 
				enc1 = this._keyStr.indexOf(input.charAt(i++));
				enc2 = this._keyStr.indexOf(input.charAt(i++));
				enc3 = this._keyStr.indexOf(input.charAt(i++));
				enc4 = this._keyStr.indexOf(input.charAt(i++));
	 
				chr1 = (enc1 << 2) | (enc2 >> 4);
				chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
				chr3 = ((enc3 & 3) << 6) | enc4;
	 
				output = output + String.fromCharCode(chr1);
	 
				if (enc3 != 64) {
					output = output + String.fromCharCode(chr2);
				}
				if (enc4 != 64) {
					output = output + String.fromCharCode(chr3);
				}
	 
			}
	 
			output = Base64._utf8_decode(output);
	 
			return output;
	 
		},
	 
		// private method for UTF-8 encoding
		_utf8_encode : function (string) {
			string = string.replace(/\r\n/g,"\n");
			var utftext = "";
	 
			for (var n = 0; n < string.length; n++) {
	 
				var c = string.charCodeAt(n);
	 
				if (c < 128) {
					utftext += String.fromCharCode(c);
				}
				else if((c > 127) && (c < 2048)) {
					utftext += String.fromCharCode((c >> 6) | 192);
					utftext += String.fromCharCode((c & 63) | 128);
				}
				else {
					utftext += String.fromCharCode((c >> 12) | 224);
					utftext += String.fromCharCode(((c >> 6) & 63) | 128);
					utftext += String.fromCharCode((c & 63) | 128);
				}
	 
			}
	 
			return utftext;
		},
	 
		// private method for UTF-8 decoding
		_utf8_decode : function (utftext) {
			var string = "";
			var i = 0;
			var c = c1 = c2 = 0;
	 
			while ( i < utftext.length ) {
	 
				c = utftext.charCodeAt(i);
	 
				if (c < 128) {
					string += String.fromCharCode(c);
					i++;
				}
				else if((c > 191) && (c < 224)) {
					c2 = utftext.charCodeAt(i+1);
					string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
					i += 2;
				}
				else {
					c2 = utftext.charCodeAt(i+1);
					c3 = utftext.charCodeAt(i+2);
					string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
					i += 3;
				}
	 
			}
	 
			return string;
		}
	 
	}
	
	/** Creates a functions wrapper for the original function so that it runs in the provided context. */
	function Delegate(f){
		this.func = f;
		createDelegate = function(obj){
			// Creates a functions wrapper for the original function so that it runs in the provided context.
			// obj: Context in which to run the function.
			return Delegate.create(obj, this.func);
		}	
	}
	Delegate.prototype = new Object();
	Delegate.create = function(scope, func){
		var f = function(){
			var target = arguments.callee.target;
			var func  = arguments.callee.func;
			return func.apply(target, arguments);
		};
		f.target = scope;
		f.func  = func;
		return f;
	}
	
	/** A basic object */
	function CoreObject() {
		var instanceDescription = "";
		this.setClassDescription = function(description){
			this.instanceDescription = description;
		}
		this.setClassDescription('Westend.CoreObject');
		CoreObject.prototype.toString = function(){
			return '[' + this.instanceDescription + ']';
		}
	}
	CoreObject.className = "CoreObject";
	
	/** Base class capable of dispatching custom events */
	function EventDispatcher(){
		CoreObject.call(this);
		this.eventMap = new Array();
		this.setClassDescription('Westend.EventDispatcher');
		
		/** Add an observer for an event */
		this.addEventObserver = function(scope, eventName, eventHandler){
			//alert(eventName);
			if(typeof(eventHandler) != 'function' && typeof(scope[eventHandler]) != 'function')
				return false;
			var eventList = this.eventMap[eventName];
			if (eventList == undefined)
				this.eventMap[eventName] = new Array();
			else{
				var len = eventList.length;
				while (len--)
					if (eventList[len].scope == scope && eventList[len].funct == eventHandler)
						return false;
			}
			var event = new Object();
			event.scope      = scope;
			event.funct      = typeof(eventHandler) == "function" ? eventHandler : scope[eventHandler];
			this.eventMap[eventName].push(event);
			return true;
		}
		
		/** Dispatch a custom event */
		this.Dispatch = function(eventName){
			//alert("EventDispatcher(" + eventName + ")");
			var args = arguments;
			var eventList = this.eventMap[eventName];
			//alert(eventName.length);
			if (eventList == undefined)
				return false;
			var i = -1;
			while (++i < eventList.length){
				eventList[i].funct.apply(eventList[i].scope, Array.prototype.slice.call(arguments, 1));
			}
			return true;
		}
		
		/** Remove an observer identified with scope, name and handler */
		this.removeEventObserver = function(scope, eventName, eventHandler){
			var funct    	= (eventHandler == undefined) ? eventName : eventHandler;
			var eventList 	= this.eventMap[eventName];
			var len			= eventList.length;
			
			while (len--) {
				if (eventList[len].scope == scope && eventList[len].funct == funct) {
					eventList.splice(len, 1);
					
					if (eventList.length == 0)
						delete this.eventMap[eventName];
					return true;
				}
			}
			return false;
		}
		
		/** Remove all observers */
		this.removeAllEventObservers = function(){
			for (var i in this.eventMap) {
				this.eventMap[i].splice(0);
				delete this.eventMap[i];
			}
			
			this.eventMap = new Object();
			return true;
		}
		
		/** Remove all observers for a given event */
		this.removeEventObserversForEvent = function(eventName){
			if (this.eventMap[eventName] == undefined)
				return false;
			delete this.eventMap[eventName];
			return true;
		}
		
		/** Remove all observers for a given scope */
		this.removeEventObserversForScope = function(scope){
			var removed = false;
			for (var i in this.eventMap) {
				var eventList	= this.eventMap[i];
				var len			= eventList.length;
				while (len--) {
					if (eventList[len].scope == scope) {
						this.$eventMap[i].splice(len, 1);
						if (eventList.length == 0)
							delete this.$eventMap[i];
						removed = true;
					}
				}
			}
			return removed;
		}
	}
	EventDispatcher.prototype = new CoreObject;
	
	/** Utility function, gets element by ID */
	$ = function(id){
		return typeof(id) == "string" ? document.getElementById(id) : id;
	}
	/** Utility function, gets element by NAME */
	$$ = function(name){
		return typeof(id) == "string" ? document.getElementsByName(elementName)[0] : id;
	}
	
	/** Utility class for westend applications */
	function WUtility(){};
	
	/** Traverse a subtree and call a function for each node */
	WUtility.traverse = function(node, callback, direction) {  
		node = $(node);
		direction = direction || -1;
		if(typeof(callback) != "function" || node == null)
			return;
		if(node.childNodes){
			if(direction==-1){ // traverse from last child to first, useful when deleting nodes
				for(var i = node.childNodes.length; i>0; i--){
					WUtility.traverse(node.childNodes[i-1], callback, direction); 
				}
			}else{
				for(var i = 0; i<node.childNodes.length; i++){ // traverse from first to last child, not working when deleting nodes
					WUtility.traverse(node.childNodes[i], callback, direction); 
				}
			}
		}
		callback(node);
	}
	
	/** Traverse a subtree and remove all empty text nodes */
	WUtility.cleanEmptyTextNodes = function(node){
		node = (typeof(node) == "object") ? node : $(node);
		WUtility.traverse(
			node,
			function(node){
				//try{
					//Debug("Node value = " + (node.nodeValue == null))
					if(node.nodeType == 3 && (/^[\n\r\t ]*$/.test(node.nodeValue) || (node.nodeValue==null))){
						//Debug("Empty node: " + (/^[\n\r\t ]*$/.test(node.nodeValue)) + ", value = " + node.nodeValue);
						Element.remove(node);
					}
					//else{
						//Debug("Skipping. type = " + node.nodeType);
					//}
				//}catch(e){
					//Debug("exception");
				//}
			}
		);
	}
	
	/* Remove DOM node 
	WUtility.removeNode = function(element){
		element = (typeof(element) == "object") ? element : $(element);
		element.parentNode.removeChild(element);
	}*/
	
	/** Clear a form element */
	WUtility.clearFormElement = function(element){
		element = $(element);
		if(element.type){
			switch(element.type.toUpperCase()){
				case "HIDDEN": // special case, FCK editors fall in this category
					if(window.FCKeditorAPI){
						var oEditor = FCKeditorAPI.GetInstance(element.name) ;
						if(oEditor!=undefined){// try for FCK editor
							if ( document.all ){ // If Internet Explorer.
								oEditor.EditorDocument.body.innerText = "";
							}else{				// If Gecko.
								oEditor.EditorDocument.body.innerHTML = "";
							}
						}
					}
					// do nothing if it is a standard hidden field
				break;
				case "CHECKBOX":
					element.checked = false;
				break;
				case "PASSWORD":
				case "TEXT": // textbox
				case "TEXTAREA":
				case "SELECT-ONE":
					element.value = "";
					if(element.onchange){
						element.onchange();
					}
				break;
			}
		}
	}
	
	/** Change img src */
	WUtility.changeSrc = function(image, src){
		// Change an image's source attribute.
		element = $(image);
		//alert(element + ", src = " + element.src + ", newsrc = " + src);
		element.src = src;
		//return false;
	}
	
	/** Apply a set of styles to an element */
	WUtility.applyStyle = function(element, style){
		// apply a set of CSS styles to an element.
		element = $(element);
		if(typeof(style) != "object" || typeof(element)!="object")
			return false;
		for(var i in style){
			element.style[i] = style[i];
		}
	}
	
	/** Apply a set of attributes to an element. */
	WUtility.applyAttributes = function(element, attributes){
		// Apply a set of attributes to an element. This function is browser-aware.
		if(typeof(attributes) != "object" || !element.setAttribute)
			return false;
		for(var i in attributes){
			if(element[i]){
				element.setAttribute(i, attributes[i]);
			}else{
				var a = document.createAttribute(i);
				a.nodeValue = attributes[i];
				element.setAttributeNode(a);
			}
		}
	}
	
	/** Apply a set of properties to an object */
	WUtility.applyProperties = function(element, properties){
		// Apply a set of properties to an element.
		if(!typeof(properties) == "object")
			return false;
		for(var i in properties)
			element[i] = properties[i];
	}
	
	/** Create an element. Handles PNG issues in IE<7. */
	WUtility.createElement = function(type, attributes, style){
		// Creates an element and applies attributes and style to it
		var element = document.createElement(type);
		if(type.toUpperCase() == "IMG" && BrowserDetect.browser == "Explorer" && BrowserDetect.version<7){ // if user agent is IE uses alphaimageloader filter to load the image
			element.onload = function(){
				if(this.src.match(/\.png/i)){ // if it's a png
					this.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.src + "', sizingMethod='')"; // overlay a filtered image
					this.src = "/imagini/sleeper.gif"; // and replace original image with a blank
				}
				this.onload = function(){}; // clear onload
			}
		}
		WUtility.applyAttributes(element, attributes);
		WUtility.applyStyle(element, style);
		return element;
	}
	
	/** Dispatch an event from a flash DOM object */
	WUtility.dispatchClipEvent = function(elementID, eventName){
		var clip = WUtility.getFlash(elementID);
		arguments[1] = eval(arguments[1]); // evaluate custom event name, just in case
		clip.Dispatch.apply(clip, Array.prototype.slice.call(arguments, 1))
	}
	
	/** Properly retrieves a flash DOM object by it's name */
	WUtility.getFlash = function(movieName){
		// get the flash object identified by it's name
		if (window.document[movieName]){
			return window.document[movieName];
		}
		if (navigator.appName.indexOf("Microsoft Internet")==-1){
			if (document.embeds && document.embeds[movieName])
				return document.embeds[movieName]; 
		}else{// if (navigator.appName.indexOf("Microsoft Internet")!=-1)
			return document.getElementById(movieName);
		}
	}
	
	/** sets an element's value */
	WUtility.setValue = function(elementID, value){
		$(elementID).value = value;
	}
	
	/** Clone a DOM node */
	WUtility.clone = function(node, children){
		var element = $(node);
		return element.cloneNode(children);	
	}
	/** Gets the first child of element of given type */
	WUtility.getFirstChildOfType = function(element, type){
		element = $(element);
		return element.getElementsByTagName(type)[0];
	}
	
	/** Generates a random string using alphabet */
	WUtility.randomId = function(length, alphabet){
		// Generates a string of random characters made of elements of alphabet
		length = typeof(length) != 'undefined' ? length : 32;
		alphabet = typeof(alphabet) != 'undefined' ? alphabet : "aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0123456789";
		var result = "";
		for(var i=0; i<length; i++){
			result += alphabet.charAt(Math.round((alphabet.length-1)*Math.random()));
		}
		return result;
	}
	
	/** A class that represents a function that needs to be called later. Used with Scheduler. */
	function DelayedCall(due, func, scope, args){
		this.__due = due;
		this.__func = func;
		this.__args = args;
		this.__scope = scope
		this.__called = false;
		this.__cancelled = false;
		
		/** Call function */
		this.call = function(){
			var error = false;
			try{
				if(this.pending()){
					Function.prototype.apply.call(this.__func, this.__scope, this.__args);
				}
			}catch(e) {
				alert("Error " + e);// do nothing
				error = true;
			}finally{
				if(!error)
					this.__called = true;
			}
			return error == false;    
		}
		
		/** Cancel function */
		this.cancel = function(){
			this.__cancelled = true;
		}
		
		/** Check if function is pending */
		this.pending = function(){
			return !this.__called && !this.__cancelled;
		}
		
		/** Check if function is due */
		this.due = function(){
			return this.__due<=new Date().getTime();
		}
	}
	
	/** Periodically checks and executes functions that are scheduler. Static. */
	function Scheduler(){
		throw 'RuntimeException: Scheduler is a static utility class and may not be instantiated';
	}
	
	/** Initialize the scheduler */
	Scheduler.run = function(interval){
		if(!Scheduler.timer){
			Scheduler.queue = [];
			Scheduler.interval = interval;	
			Scheduler.timer = setInterval(Scheduler.onTimer, Scheduler.interval);
		}
	}
	
	/** Check the queue and execute due functions. Internal. */
	Scheduler.onTimer = function(){
		var func;
		for(var i = 0; i<Scheduler.queue.length; i++){
			func = Scheduler.queue.shift();
			if(func.due()){
				if(!func.call()){
					//func.__due = new Date().getTime() + 2000;
					//Scheduler.queue.push(func); // postpone	
				}
			}else{
				Scheduler.queue.push(func);
			}
		}
	}
	
	/** Schedule a function for later */
	Scheduler.callLater=function(scope, interval, func){
		// Schedule a function to be called later in a given scope
		var dc = new DelayedCall(new Date().getTime() + interval, func, scope, Array.prototype.slice.call(arguments, 3))
		Scheduler.queue.push(dc);
	}
	
	/** Cancel a scheduled function */
	Scheduler.cancel = function(func){
		// Cancel a scheduled func
		for(var i = 0; i<Scheduler.queue.length; i++){
			if(Scheduler.queue[i].__func == func)
				Scheduler.queue[i].cancel();
		}
	}
	
	/** Check if function is pending */
	Scheduler.isPending = function(func){
		// Check whether a func is pending
		for(var i = 0; i<Scheduler.queue.length; i++){
			if(Scheduler.queue[i].__func == func && Scheduler.queue[i].pending())
				return true;
		}
		return false;
	}
	
	/** Executes an async request to the server and notifies listeners on any change */
	function HTTPRequest(){
		EventDispatcher.call(this);
		try{
			this.__requestObject = new XMLHttpRequest(); // MOZ
		}catch(e){
			try{
				this.__requestObject = new ActiveXObject("Microsoft.XMLHTTP");
			}catch(e){
				alert("Your browser has no AJAX support.");
				return null;
			}
		}
		
		/** Internal, no need to be called */
		this.stateHandler = function(){
			switch(this.__requestObject.readyState){
				case 0:
					this.Dispatch(HTTPRequest.EVENT_UNINITIALIZE);
				break;
				case 1:
					this.Dispatch(HTTPRequest.EVENT_LOADING);
				break;
									   
				case 2:
					this.Dispatch(HTTPRequest.EVENT_LOADED);
				break;
							   
				case 3:
					this.Dispatch(HTTPRequest.EVENT_INTERACTIVE);
				break;
				case 4:
					try{
						var status = this.__requestObject.status;
					}catch(e){
						var status = 400;
					}
					var response = {xml:this.__requestObject.responseXML, text:this.__requestObject.responseText, status:status};
					if (status == 200){
						//this.response = response;
						//alert("Got response.");
						this.Dispatch(HTTPRequest.EVENT_SUCCESS, response);
					}else{
						this.Dispatch(HTTPRequest.EVENT_FAILURE, response);
					}
				break;
			}	
		}
		
		/** Initializes the request */
		this.InitializeRequest = function(method, uri){
			switch (arguments.length){
				case 2:
					this.__requestObject.open(method, uri);
				break;
				case 3:
					this.__requestObject.open(method, uri, arguments[2]);
				break;
			}
			if (arguments.length >= 4) 
				this.__requestObject.open(method, uri, arguments[2], arguments[3]);
			this.SetRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
		}
		
		/** Sets a header for the request */
		this.SetRequestHeader = function(field, value){
			this.__requestObject.setRequestHeader(field, value);
		}
		
		/** Commits the request */
		this.Commit = function(data){
			this.__requestObject.send(data)
		}
		
		/** Aborts the request */
		this.Abort = function(){
			this.__requestObject.abort();
		}
		this.getResponse = function(){
			return {xml:this.__requestObject.responseXML, text:this.__requestObject.responseText, status:this.__requestObject.status}
		}
		this.__requestObject.onreadystatechange = Delegate.create(this, this.stateHandler);
	}
	HTTPRequest.prototype = new EventDispatcher;
	HTTPRequest.DOM = function(url, element){
		var request = new HTTPRequest(); // create a request object
		request.InitializeRequest('POST', url); // initialize the request
		request.addEventObserver(this, HTTPRequest.EVENT_SUCCESS, function(response){	try{ $(element).innerHTML = response.text;}catch(e){}}); // listen to when the request finished
		request.addEventObserver(this, HTTPRequest.EVENT_FAILURE, function(response){	try{ $(element).innerHTML = "Request failed: " + response.status;}catch(e){}}); // listen to when the request finished
		request.Commit(null); // execute the request
	}
	HTTPRequest.get = function(url){
		var request = new HTTPRequest(); // create a request object
		request.InitializeRequest('POST', url, false); // initialize the request
		request.Commit(null); // execute the request
		return request.getResponse();
	}
	HTTPRequest.alert = function(url){
		if(url==undefined)
			return false;
		handleServerResponse = function(response){
			try{
				var root = response.xml.getElementsByTagName("response")[0];
				alert(root.firstChild.nodeValue);
			}catch(e){
				//alert("Serviciu indisponibil. Te rugam incearca mai tarziu.");
			}
		}
		var r = new HTTPRequest();
		r.InitializeRequest("GET", url);
		r.addEventObserver(this, HTTPRequest.EVENT_SUCCESS, handleServerResponse);
		r.Commit();
	}
	HTTPRequest.EVENT_SUCCESS = "ajaxEventSuccess";
	HTTPRequest.EVENT_FAILURE = "ajaxEventFailure";
	HTTPRequest.EVENT_UNINITIALIZE = "ajaxEventUninitialize";
	HTTPRequest.EVENT_LOADING = "ajaxEventLoading";
	HTTPRequest.EVENT_LOADED = "ajaxEventLoaded";
	HTTPRequest.EVENT_INTERACTIVE = "ajaxEventInteractive";
	
	/** Opens a window of given w/h */
	function openWindow(url, width, height){
		var newWindow=window.open(url,"URL","toolbar=0,status=0,menubar=0,fullscreen=no,width=" + width + ",height=" + height + ",resizable=0");
		newWindow.focus();
		return newWindow;
	}
	
	/** Opens a window with options */
	function openWindowOpts(url, title, opts){
		//alert(url + ", " + title + ", " + opts);
		var newWindow=window.open(url,title,opts);
		newWindow.focus();
		return newWindow;
	}
	
	/** Toggles visibility of an object. If you want cookie based visibility handling, see Visibility class */
	function Togg(target){
		if(Validator.isArray(target)){
			for(var i = 0; i<target.length; i++){
				//var target_obj = $(target[i]);
				//target_obj.style.display = ( target_obj.style.display == "none") ? "" : "none";
				Togg(target[i]);
			}
		}else if(target!=null && target!=undefined){
			var target_obj = $(target);
			if(target_obj)
				target_obj.style.display = ( target_obj.style.display == "none") ? "" : "none";
		}
	}
	
	/** Hides an object. If you want cookie based visibility handling, see Visibility class */
	function Hide(target){
		if(Validator.isArray(target)){
			for(var i = 0; i<target.length; i++){
				//var target_obj = typeof(target[i]) == "string" ? $(target[i]) : target[i];
				//target_obj.style.display = "none";
				Hide(target[i]);
			}
		}else if(target!=null && target!=undefined){
			var target_obj = $(target);
			if(target_obj)
				target_obj.style.display = "none";
		}
	}
	
	/**  Shows an object. If you want cookie based visibility handling, see Visibility class */
	function Show(target){
		if(Validator.isArray(target)){
			for(var i = 0; i<target.length; i++){
				//var target_obj = typeof(target[i]) == "string" ? $(target[i]) : target[i];
				//target_obj.style.display = "";
				Show(target[i]);
			}
		}else if(target!=null && target!=undefined){
			var target_obj = $(target);
			if(target_obj)
				target_obj.style.display = "";
		}
	}
	
	function displayErrorsInContainer(){
		var message 	= document.getElementById("error_message");
		var container	= document.getElementById("error_container");
		Show("error_container");
		var errorMsg = "";
		for (x=0; x<this.errorList.length; x++){
			errorMsg += ((x + 1) + "). " + this.errorList[x] + "<br>\n");
		}
		message.innerHTML = errorMsg;		
	}
	
	/** Traverses a form and clears it's elements */
	function clearForm(formIdent) { 
		var form, elements, i, elm; 
		form = typeof(formIdent) == "object" ? formIdent : document.forms[formIdent];
		elements = form.elements;
		for(i=0, elm; elm=elements[i++]; ){
			WUtility.clearFormElement(elm);
		}
	}
	
	/** Class to handle dynamic combos */
	function Combo(){
		throw 'RuntimeException: Combo is a static utility class and may not be instantiated';
	}
	
	/** Insert a combo item before another one */
	Combo.insertBefore = function(combo, num, newOpt){
		if(typeof(newOpt)!="object")
			return false;
		var combo = $(combo);
		if (num >= 0) {
			var oldOpt = combo.options[num];  
			try{
				combo.add(newOpt, oldOpt); // standards compliant; doesn't work in IE
			}catch(e){
			  combo.add(newOpt, num); // IE only
			}
		}
	}
	
	/** Removes a combo item */
	Combo.removeSelected = function(combo){
		var combo = $(combo);
		for(var i=combo.length-1; i>=0; i--)
			if (combo.options[i].selected)
				combo.remove(i);
	}
	
	/** Append a combo item */
	Combo.append = function(combo, newOpt){
		var combo = $(combo);
		try{
			combo.add(newOpt, null); // standards compliant; doesn't work in IE
		}catch(ex) {
			combo.add(newOpt); // IE only
		}
	}
	
	Combo.appendBatch = function(combo, batch){
		var ie = undefined;
		for(var i=0; i<batch.length; i++){
			if(ie==undefined){
				try{
					combo.add(batch[i], null); // standards compliant; doesn't work in IE
					ie = false;
				}catch(ex) {
					combo.add(batch[i]); // IE only
					ie=true;
				}
			}else{
				if(!ie){
					combo.add(batch[i], null); // standards compliant; doesn't work in IE
				}else{
					combo.add(batch[i]); // IE only
				}	
			}
		}
		
	}
	
	/** Unshift a combo item */
	Combo.removeLast = function(combo){
		var combo = $(combo);
		if (combo.length > 0)
			combo.remove(combo.length - 1);
	}
	
	/** Sends a form asynchronously via a dinamically created iframe and calls a callback function on completion. Methods are all static. */
	function asyncUpload(){
		throw 'RuntimeException: asyncUpload is a static utility class and may not be instantiated';
	}
	
	/* Submit upload */
	asyncUpload.submit = function(form, onComplete){
		var name = WUtility.randomId(8); // generate a random id for the frame
		var div = WUtility.createElement('DIV', {}, {position:"absolute", top:"-9999px", left:"-9999px"}); // create a container for the frame, this whole operation works in IE only if div and iframe are created like this
		//div.innerHTML = '<iframe style="display:none" src="about:blank" id="'+name+'" name="'+name+'" onload="asyncUpload.loaded(\''+name+'\')"></iframe>' // create the frame
		div.innerHTML = '<iframe style="display:none" src="about:blank" id="'+name+'" name="'+name+'" onload="asyncUpload.loaded(this)"></iframe>' // create the frame
		document.body.appendChild(div); // append the container to the document
		var frame = $(name);
		if(typeof(onComplete) == 'function')
			frame.onComplete = onComplete;
		frame.form = form;
		form.setAttribute("target", name);
		return true;
	}
	
	/* Handle response */
	asyncUpload.loaded = function(frame){
		if(frame.contentDocument) {
			var d = frame.contentDocument; // get the frame's document to read out the response
		}else if(frame.contentWindow) {
			var d = frame.contentWindow.document;
		}else{
			var d = window.frames[id].document;
		}
		if (d.location.href == "about:blank") // onload is triggered when the frame is created, so do nothing on creation
			return;
		if(typeof(frame.onComplete) == 'function')
			frame.onComplete(d, frame.form);
		else
			alert("Response: " + d.body.innerHTML);
	}
	
	/**
	* Interface for async uploads
	* To use this class you need the upload.tpl PHP template
	* options must contain an id parameter, which is the upload session id.
	* In php, simpy call asyncUpload::getHTML() to get an interface
	*/
	function uploadInterface(options){
		EventDispatcher.call(this);
		this.options = options;
		uploadInterface.INSTANCES.push(this);
	}
	uploadInterface.prototype = new EventDispatcher;
	
	/** Init the interface */
	uploadInterface.prototype.init = function(){
		this.container = $("attachments_"+this.options.id);
		WUtility.traverse(this.container, Delegate.create(this, function(node){
			if(node.className == uploadInterface.CLASS_BASKET)
				this.basket = node;
			else if(node.className == uploadInterface.CLASS_FORM)
				this.form = node;
			else if(node.className == uploadInterface.CLASS_CONSOLE)
				this.console = node;
		}));
		this.form.appendChild(WUtility.createElement("INPUT", {type:"hidden", name:"v", value:this.options.id}))
		if(!this.options.debug) this.form.onsubmit = uploadInterface.submit;
		this.form.backingObject = this.container.backingObject = this;
		this.populate();
	}
	/** Populate the interface with a server call */
	uploadInterface.prototype.populate = function(){
		var updateBasket = function(response){
			response = response.xml.getElementsByTagName("response")[0];
			this.basket.innerHTML = response.text || response.textContent;
			if(BrowserDetect.browser == "Explorer" && BrowserDetect.version<7){
				pngfix(this.basket);
			}
			for(var node = this.basket.firstChild; node; node = node.nextSibling){
				node.backingObject = this;
				node.removeAttachment = function(){
					var file = this.getAttribute("attachmentname");
					var request = new HTTPRequest();
					request.InitializeRequest("GET", "/AJAXSupport/upload.php?v="+this.backingObject.options.id+"&a=remove&file=" + file);
					var remove = function(response){
						var root = response.xml.getElementsByTagName("response")[0];
						if(root.getAttribute("result").toUpperCase()=="SUCCESS"){
							this.backingObject.populate();
						}else{
							alert("Operatiune esuata. [" + response.text + "]");
						}
					}
					request.addEventObserver(this, HTTPRequest.EVENT_SUCCESS, remove);
					request.Commit();
					//alert(this.getAttribute("attachmentName"));
				}
			}
		}
		var request = new HTTPRequest();
		request.InitializeRequest("GET", "/AJAXSupport/upload.php?v="+this.options.id+"&a=queue");
		request.addEventObserver(this, HTTPRequest.EVENT_SUCCESS, updateBasket);
		request.addEventObserver(this, HTTPRequest.EVENT_SUCCESS, updateBasket);
		request.Commit();
	}
	/** Verify uploaded files with a server call */
	uploadInterface.prototype.queue = function(){
		var showQueue = function(response){
			response = response.xml.getElementsByTagName("response")[0];
			alert(response.firstChild.nodeValue);
		}
		var request = new HTTPRequest();
		request.InitializeRequest("GET", "/AJAXSupport/upload.php?v="+this.options.id+"&a=queue&m=plain");
		request.addEventObserver(this, HTTPRequest.EVENT_SUCCESS, showQueue);
		request.Commit();
	}
	/** submit the upload */
	uploadInterface.submit = function(){
		asyncUpload.submit(this, uploadInterface.handleResponse)
	}
	/** Handle server response */
	uploadInterface.handleResponse = function(response){
		response = response.XMLDocument ? response.XMLDocument : response // IE needs some special attention
		try{
			var root = response.getElementsByTagName("response")[0];
			if(root.getAttribute("result").toUpperCase()=="FAILURE"){
				alert(root.firstChild.nodeValue);
			}else{
				this.form.backingObject.populate();
			}
		}catch(e){
			alert("Operatiune esuata.\nTe rugam incearca mai tarziu sau daca problema persista, contacteaza Admin.")
		}
	}
	uploadInterface.INSTANCES = [];
	uploadInterface.CLASS_BASKET = "uploadBasket";
	uploadInterface.CLASS_FORM = "uploadForm";
	uploadInterface.CLASS_CONSOLE = "uploadConsole";
	uploadInterface.CLASS_EMPTY_BASKET = "basketEmptyMessage";
	uploadInterface.CLASS_BASKET_ELEMENT = "basketElement";
	
	/**
	* Interface for async uploads
	* To use this class you need the tags.tpl PHP template
	* options must contain an id parameter, which is the upload session id.
	* In php, simpy call asyncUpload::getHTML() to get an interface
	*/
	function taggingInterface(options){
		EventDispatcher.call(this);
		this.options = options;
		taggingInterface.INSTANCES.push(this);
	}
	taggingInterface.prototype = new EventDispatcher;
	taggingInterface.prototype.init = function(){
		if(this.options.id==null)
			return false;
		this.container = $("tags_"+this.options.id);
		WUtility.traverse(this.container, Delegate.create(this, function(node){
			//alert("init: " + node + ", value = " + node.nodeName);
			try{
				node.backingObject = this;
				if(node.className == taggingInterface.CLASS_BASKET)
					this.basket = node;
				else if(node.className == taggingInterface.CLASS_TAGLIST)
					this.tagList = node;
				else if(node.className == taggingInterface.CLASS_SUBMIT)
					this.tagListSubmit = node;
			}catch(e){}
		}));
		this.tagListSubmit.onclick = Delegate.create(this, function(){
			//alert("Blabla submitting.." + this.tagList.value);
			var updateTagBasket = function(response){
				//alert(response.text);
				var root = response.xml.getElementsByTagName("response")[0];
				if(root.getAttribute("result")=="failure"){
					alert(root.firstChild.nodeValue);
				}else{
					this.populate();
				}
				this.tagList.value = "";
			}
			var request = new HTTPRequest();
			request.InitializeRequest("GET", "/AJAXSupport/tags.php?a=add&v="+this.options.id+"&taglist="+escape(this.tagList.value));
			request.addEventObserver(this, HTTPRequest.EVENT_SUCCESS, updateTagBasket);
			request.Commit();
		});
		this.container.backingObject = this;
		this.populate();
	}
	taggingInterface.prototype.populate = function(){
		var updateBasket = function(response){
			response = response.xml.getElementsByTagName("response")[0];
			this.basket.innerHTML = response.text || response.textContent;
			if(BrowserDetect.browser == "Explorer" && BrowserDetect.version<7){
				pngfix(this.basket);
			}
			for(var node = this.basket.firstChild; node; node = node.nextSibling){
				//alert("populate: " + node + ", value = " + node.nodeName);
				try{
					node.backingObject = this;
					node.removeTag = function(){
						var tagId = this.getAttribute("tagId");
						var request = new HTTPRequest();
						request.InitializeRequest("GET", "/AJAXSupport/tags.php?v="+this.backingObject.options.id+"&a=remove&tag="+tagId);
						var remove = function(response){
							var root = response.xml.getElementsByTagName("response")[0];
							if(root.getAttribute("result").toUpperCase()=="SUCCESS"){
								this.backingObject.populate();
							}else{
								alert("Operatiune esuata. [" + response.text + "]");
							}
						}
						request.addEventObserver(this, HTTPRequest.EVENT_SUCCESS, remove);
						request.Commit();
						//alert(this.getAttribute("attachmentName"));
					}
				}catch(e){}
			}
		}
		var request = new HTTPRequest();
		request.InitializeRequest("GET", "/AJAXSupport/tags.php?v="+this.options.id+"&a=queue");
		request.addEventObserver(this, HTTPRequest.EVENT_SUCCESS, updateBasket);
		request.addEventObserver(this, HTTPRequest.EVENT_SUCCESS, updateBasket);
		request.Commit();
	}
	taggingInterface.prototype.queue = function(){
		var showQueue = function(response){
			response = response.xml.getElementsByTagName("response")[0];
			alert(response.firstChild.nodeValue);
		}
		var request = new HTTPRequest();
		request.InitializeRequest("GET", "/AJAXSupport/tags.php?v="+this.options.id+"&a=queue&m=plain");
		request.addEventObserver(this, HTTPRequest.EVENT_SUCCESS, showQueue);
		request.Commit();
	}
	taggingInterface.INSTANCES = [];
	taggingInterface.CLASS_BASKET = "tagBasket";
	taggingInterface.CLASS_TAGLIST = "tagList";
	taggingInterface.CLASS_SUBMIT = "tagListSubmit";
	taggingInterface.CLASS_EMPTY_BASKET = "basketEmptyMessage";
	taggingInterface.CLASS_BASKET_ELEMENT = "basketElement";
	
	function favoriteInterface(options){
		options.add = options.add || "Adauga la favorite";
		options.remove = options.remove || "Sterge dintre favorite";
		this.options = options;
	}
	favoriteInterface.prototype.init = function(){
		this.container = $(this.options.element);
		this.container.backingObject = this;
		this.container.onclick = Delegate.create(this, this.change);
		//alert("Before populate: " + this.options.add + "\n" + this.options.remove);
		this.populate();
	}
	favoriteInterface.prototype.populate = function(){
		var request = new HTTPRequest();
		request.InitializeRequest("GET", "/AJAXSupport/favorite.php?a=stat&id="+this.options.id);
		request.addEventObserver(this, HTTPRequest.EVENT_SUCCESS, favoriteInterface.update);
		request.addEventObserver(this, HTTPRequest.EVENT_SUCCESS, favoriteInterface.update);
		request.Commit();
	}
	favoriteInterface.prototype.change = function(){
		var request = new HTTPRequest();
		request.InitializeRequest("GET", "/AJAXSupport/favorite.php?&id="+this.options.id);
		request.addEventObserver(this, HTTPRequest.EVENT_SUCCESS, favoriteInterface.update);
		request.addEventObserver(this, HTTPRequest.EVENT_SUCCESS, favoriteInterface.update);
		request.Commit();	
	}
	favoriteInterface.update = function(response){
		var root = response.xml.getElementsByTagName("response")[0];
		if(root.getAttribute("result").toUpperCase()=="FAILURE"){
			alert(root.firstChild.nodeValue);
		}else{
			this.container.innerHTML = root.firstChild.nodeValue.toUpperCase() == "TRUE" ? this.options.remove : this.options.add;
			//alert("Change: " + this.options.add + "\n" + this.options.remove);
			if(BrowserDetect.browser == "Explorer" && BrowserDetect.version<7)
				pngfix(this.container);
		}
	}
	
	/** class that manages keystroke events */
	function Keyboard(){
		throw 'RuntimeException: Keyboard is a static utility class and may not be instantiated';
	}
	/**
	* Filters out a keyboard key
	* Usage: < ... onkeydown="return Keyboard.filter(event, [<keys>])" onkeypress="return Keyboard.filter(event, [<keys>])
	*/
	Keyboard.filter = function(e, f){
		(e) ? e : window.event;
		var code = e.which || e.keyCode;
		if(f.seqSearch(code)>-1){
			return false;
		}
	}
	Keyboard.KEY_ENTER 	= 13;
	Keyboard.KEY_TAB	= 10;
	
	/** Handles tab insertions in textareas */
	Keyboard.tab = function(evt) {
		var tab = "	";
		var t = evt.target;
		var ss = t.selectionStart;
		var se = t.selectionEnd;
		// Tab key - insert tab expansion
		if (evt.keyCode == 9) {
			evt.preventDefault();
			// Special case of multi line selection
			if (ss != se && t.value.slice(ss,se).indexOf("\n") != -1) {
				// In case selection was not of entire lines (e.g. selection begins in the middle of a line)
				// we ought to tab at the beginning as well as at the start of every following line.
				var pre = t.value.slice(0,ss);
				var sel = t.value.slice(ss,se).replace(/\n/g,"\n"+tab);
				var post = t.value.slice(se,t.value.length);
				t.value = pre.concat(tab).concat(sel).concat(post);
				t.selectionStart = ss + tab.length;
				t.selectionEnd = se + tab.length;
			}else {// "Normal" case (no selection or selection on one line only)
				t.value = t.value.slice(0,ss).concat(tab).concat(t.value.slice(ss,t.value.length));
				if (ss == se) {
					t.selectionStart = t.selectionEnd = ss + tab.length;
				}
				else {
					t.selectionStart = ss + tab.length;
					t.selectionEnd = se + tab.length;
				}
			}
		}else if (evt.keyCode==8 && t.value.slice(ss - 4,ss) == tab) {// Backspace key - delete preceding tab expansion, if exists
			evt.preventDefault();
			t.value = t.value.slice(0,ss - 4).concat(t.value.slice(ss,t.value.length));
			t.selectionStart = t.selectionEnd = ss - tab.length;
		}else if (evt.keyCode==46 && t.value.slice(se,se + 4) == tab) {    // Delete key - delete following tab expansion, if exists
			evt.preventDefault();
			t.value = t.value.slice(0,ss).concat(t.value.slice(ss + 4,t.value.length));
			t.selectionStart = t.selectionEnd = ss;
		}else if (evt.keyCode == 37 && t.value.slice(ss - 4,ss) == tab) {// Left/right arrow keys - move across the tab in one go
			evt.preventDefault();
			t.selectionStart = t.selectionEnd = ss - 4;
		}else if (evt.keyCode == 39 && t.value.slice(ss,ss + 4) == tab) {
			evt.preventDefault();
			t.selectionStart = t.selectionEnd = ss + 4;
		}
	}
	
	/** class that manages browser events */
	function Event(){
		throw 'RuntimeException: Event is a static utility class and may not be instantiated';
	};
	
	/** Add observer for event. Captures = ?? */
	Event.observe = function(target, type, callback, captures) {
		// add an event handler to a target DOM element
		var result = true;
		if (target.addEventListener) { // if gecko
			target.addEventListener(type, callback, captures);
		} else if (target.attachEvent) { // if ie
			result = target.attachEvent('on' + type, callback, captures);
		} else { // IE 5 Mac and some others
			target['on'+type] = callback;
		}
		return result;
	}
	
	/**
	* Try to get the target of the event
	* from: the element the mouse left, to: the element the mouse moved over
	*/
	Event.target = function(e){
		return {from:(e.target || e.fromElement || null), to:(e.currentTarget || e.toElement || null)};
	}
	
	/** Get the mouse coordinates in the moment the event was triggered */
	Event.mouse = function(e){
		if (e.pageX || e.pageY){ // gecko
			var x = e.pageX || 0;
			var y = e.pageY || 0;
			ret = new Point(x, y);
		}else if (e.clientX || e.clientY){ // ie
			var x = e.clientX || 0;
			var y = e.clientY || 0;
			//Debug("Client: " + e.clientX + ", " + e.clientY + ", scroll: " + (document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft) + ", " + (document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) );
			// add the amount the page is scrolled in eighter direction (IE)
			ret = new Point(
					(x - 1 + (document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft)) || 0,
					(y - 1 + (document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop)) || 0
			)
		}else{
			ret = new Point(0, 0);
		}
		ret.x = (ret.x<0) ? 0 : ret.x; // correct coordinates in case the mouse moved out of the window area
		ret.y = (ret.y<0) ? 0 : ret.y;
		return ret;
	}
	
	/** Utility class for managing DOM elements*/
	function Element(){
		throw 'RuntimeException: Element is a static utility class and may not be instantiated';
	}
	
	/** Insert a new DOM node before node */
	Element.insertBefore = function(node, newNode){
		//document.body.insertBefore(newNode, node);
		node.parentNode.insertBefore(newNode, node);
		return newNode;
	}
	
	/** Insert a new DOM node after node */
	Element.insertAfter = function(node, newNode){
		node.parentNode.insertBefore(newNode, node.nextSibling);
		return newNode;
	}
	
	/** effectively removes an element from the DOM. Fixes the leakage in IE. */
	Element.remove = function(element) {
		element = $(element);
		/*var garbageBin = $('IELeakGarbageBin');
		if (!garbageBin) {
			garbageBin = document.createElement('DIV');
			garbageBin.id = 'IELeakGarbageBin';
			garbageBin.style.display = 'none';
			document.body.appendChild(garbageBin);
		}
		// move the element to the garbage bin
		garbageBin.appendChild(element);
		garbageBin.innerHTML = '';*/
		element.parentNode.removeChild(element);
	}
	
	/**
	* Execute all scripts inside an element
	* Note: if an element contains only 1 script tag and nothing else, our best friend, IE will not find the tag
	*/
	/*Element.executeScripts = function(element){
		element = $(element);
		//alert(element.innerHTML);
		var scripts = element.getElementsByTagName("SCRIPT");
		//var els = element.getElementsByTagName("*");
		Debug("Scripts = " + scripts.length);
		Debug(element.innerHTML);
		/*for(var i in els){
			Debug(i);
		}*
		for(var i=0; i<scripts.length; i++){
			//alert(scripts[i].text);
			eval(scripts[i].text);
		}
	}*/
	
	/** Checks whether element node is childnode of a node whose class is parentClass */
	Element.parentOfClass = function(element, parentClass){
		element = $(element);
		while(element != null){
			if(element.className == parentClass)
				return element
			element = element.parentNode;
		}
		return null;
	}
	
	/** Makes contents of a node unselectable */
	Element.disableSelection = function(element){
		element = $(element);
		element.onselectstart = function() {
			return false;
		};
		element.unselectable = "on";
		element.style.MozUserSelect = "none";
		element.style.cursor = "default";
	}
	
	/** Checks whether element is contained inside parent */
	Element.parentOf = function(element, parent){
		while(element != null){
			if(element.parentNode == parent)
				return true;
			element = element.parentNode;
		}
		return false;
	}
	
	/** Get computed/current style of an element */
	Element.getCSSStyle = function(sender){
		var style = (sender.currentStyle) ? sender.currentStyle : (window.getComputedStyle ? window.getComputedStyle(sender, null) : false);
		return style;
	}
	
	/** Gets an attribute of computed/current style of the element */
	Element.getCSSStyleAttribute = function(source, attributeName){
		var style = Element.getCSSStyle(source);
		return style[attributeName];
	}
	
	/** Gets an attribute of the stylesheet of an element */
	Element.getCurrentStyleAttribute = function(source, attributeName){
		return source.style[attributeName];
	}
	
	/** Calculate top-left offset and dimensions of an element */
	Element.getOffset = function(element, borders){
		var offsetObj = null;
		element = offsetObj = $(element);
		var offsetTop = 0, offsetLeft = 0
		while(offsetObj != null){ // we need to climb the DOM tree till we reach the root
			//Debug("Object: " + offsetObj.nodeName + ", top: " + offsetObj.offsetTop + ", left: " + offsetObj.offsetLeft)
			offsetTop += ((BrowserDetect.browser == "Explorer" && offsetObj.style.position=="RELATIVE") ? (offsetObj.offsetTop/2) : offsetObj.offsetTop); // add the offsets, except if IE, then add half to all relatively positioned
			offsetLeft += offsetObj.offsetLeft;
			if(borders){
				// IE has some problems if a node has a border and a padding set in the stylesheet
				// If both are set, only padding is taken into consideration, so compensate for that
				if(topBorder = parseInt(Element.getCSSStyleAttribute(offsetObj, "borderTopWidth")))
					offsetTop += topBorder;
				if(leftBorder = parseInt(Element.getCSSStyleAttribute(offsetObj, "borderLeftWidth")))
					offsetLeft += leftBorder;
			}
			offsetObj = offsetObj.offsetParent;
		};
		var scrollX = window.pageXOffset ? window.pageXOffset : (document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft);
		var scrollY = window.pageYOffset ? window.pageYOffset : (document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop);
		return {top:offsetTop, left:offsetLeft, right:offsetLeft + element.offsetWidth, bottom:offsetTop + element.offsetHeight, width:element.offsetWidth, height:element.offsetHeight, scrollX:scrollX, scrollY:scrollY};
	}
	/** Focus on an element */
	Element.focus = function(element){
		element = $(element);
		try{
			var readonly_orig = element.readOnly;
			var disabled_orig = element.disabled;
			element.readOnly = element.disabled = false;
			element.focus();
			element.readOnly = readonly_orig;
			element.disabled = disabled_orig;
		}catch(e){
		}
	}
	
	/** Checks whether the mouse is over an element */
	Element.mouseOver = function(element, mouse){
		var offset = Element.getOffset(element);
		var result = false;
		if(offset.top < mouse.y && mouse.y < offset.bottom && offset.left < mouse.x && mouse.x < offset.right)
			result = true;
		//Debug("Event: x=" + mouse.x + ", y=" + mouse.y + "offset: t=" + offset.top + ", l=" + offset.left + ", b=" + offset.bottom + ", r=" + offset.right + ", over = " + result);
		return result;
	}
	
	/** Mimics flash's movieclip.getNextHighestDepth behavior */
	Element.getNextHighestDepth = function(element){
		var depth = 0;
		for (var child = element.firstChild; child; child = child.nextSibling){
			var tmp = Element.getCSSStyleAttribute(child, "zIndex");
			tmp = (tmp == "auto") ? 0 : tmp;
			depth = Math.max(depth, tmp);
		}
		return depth+1;
	}
	
	/** Get bottommost element from element's children */
	Element.getBottomElement = function(element){
		var bottom = element.firstChild;
		var bottomDepth = Element.getCSSStyleAttribute(bottom, "zIndex")
		for (var child = element.firstChild.nextSibling; child; child = child.nextSibling){
			var tmp = Element.getCSSStyleAttribute(child, "zIndex");
			if(tmp < bottomDepth){
				bottomDepth = tmp;
				bottom = child;
			}
		}
		return bottom;
	}
	
	/** Get topmost element from element's children */
	Element.getTopElement = function(element){
		var top = element.firstChild;
		var topDepth = parseInt(Element.getCSSStyleAttribute(top, "zIndex"));
		for (var child = element.firstChild.nextSibling; child; child = child.nextSibling){
			var tmp = parseInt(Element.getCSSStyleAttribute(child, "zIndex"));
			if(tmp > topDepth){
				topDepth = tmp;
				top = child;
			}
		}
		return top;
	}
	
	/** Swaps two elements' depths */
	Element.swapDepths = function(element1, element2){
		var id = Element.getCSSStyleAttribute(element1, "zIndex");
		WUtility.applyStyle(element1, {zIndex:Element.getCSSStyleAttribute(element2, "zIndex")});
		WUtility.applyStyle(element2, {zIndex:id});
	}
	
	/** Brings an element to top */
	Element.bringToFront = function(element){
		var parent = element.parentNode;
		var topElement = Element.getTopElement(parent);
		Element.swapDepths(topElement, element);
	}
	
	/* Find inputs that have a mirror input (that reflects its value). To specify a mirror, use it like this: <input rel="<formName>[<inputName>]" ... /> */
	Element.mirror = function(){
		var els=document.getElementsByTagName('INPUT');
		for(var i=0; i<els.length; i++){
			//Debug(els[i].name);
			var el = els[i], rel;
			if(el.getAttribute && (rel = el.getAttribute("rel"))){
				var relm = rel.match(/^([a-zA-Z0-9_]+)\[([a-zA-Z0-9_]+)\]/);
				var relo = WForm.find(relm[1]).elements[relm[2]];
				el.relatedField = relo;
				relo.relatedField = el;
				//el.relatedField.relatedField = el;
				//WUtility.applyAttributes(el.relatedField, {"rel":rel});
				els[i].onblur = function(){
					this.relatedField.value = this.value;
				}
			}
		}
	}
	
	/* Form related stuff */
	function WForm(){
		throw 'RuntimeException: Form is a static utility class and may not be instantiated';
	}
	WForm.clearElement = function(element){
		element = $(element);
		if(element.type){
			switch(element.type.toUpperCase()){
				case "HIDDEN": // special case, FCK editors fall in this category
					if(window.FCKeditorAPI){
						var oEditor = FCKeditorAPI.GetInstance(element.name) ;
						if(oEditor!=undefined){// try for FCK editor
							if ( document.all ){ // If Internet Explorer.
								oEditor.EditorDocument.body.innerText = "";
							}else{				// If Gecko.
								oEditor.EditorDocument.body.innerHTML = "";
							}
						}
					}
					// do nothing if it is a standard hidden field
				break;
				case "CHECKBOX":
					element.checked = false;
				break;
				case "PASSWORD":
				case "TEXT": // textbox
				case "TEXTAREA":
				case "SELECT-ONE":
					element.value = "";
					if(element.onchange){
						element.onchange();
					}
				break;
			}
		}
	}
	WForm.clear = function(element){
		WUtility.traverse(
			element, 
			WForm.clearElement,
			1
		);
	}
	WForm.fieldText = function(field, text){
		var field = $(field);
		if(field == undefined || field.type == undefined || (field.type != "text" && field.type != "password"))
			return false;
		field.WFieldType = field.type;
		field.WFieldText = text;
		if(field.value == ""){
			field.value = text;
			try{field.type = "text"}catch(e){}
		}
		field.onfocus =function(){
			if(this.value == this.WFieldText)
				this.value = ""
			try{this.type = this.WFieldType;}catch(e){}
		};
		field.onblur = function(){
			if(this.value == ""){
				//Debug(this.type);
				//this.type = "text";
				try{this.type = "text"}catch(e){};
				this.value = this.WFieldText;
			}
		};
	}
	/* submit a form */
	WForm.submit = function(name){
		WForm.find(name).submit();
	}
	/* Find and return a form identified by its name */
	WForm.find = function(name){
		return (typeof(name)=="string") ? document.forms[name] : name;
	}
	/**
	* Validates a form's elements.
	* 	Parameters:
	*		form 		- the form to be validated
	*		callback	- the function to be called on completion. 
	*		submitOnComplete - submits on success
	*	The validation data for a form is stored in the formfields' "v" attribute in form of:
	*		REQUIRED,LABEL,TYPE,MIN,MAX where
	*		REQUIRED 	= Y|N - if required, an empty value will generate an error, if not required, only an invalid value will generate an error
	*		LABEL		= the label of the form element, used for error reporting
	*		TYPE		= NUMERIC|ALPHABETIC|ALPHANUMERIC|TEXT|MAIL|DATE - determines the method of validation
	*		MIN			= the minimum value or length of the field (value if numeric, length if string type. Optional.
	*		MAX			= the maximum value or length of the field. Optional.
	*	Usage:
	*		<input type="button" ... onclick="WForm.validate(this, callback)" /> - use it like this on a button as a submit button
	*		<input type="text" name="field1" v="Y;The first field;NUMERIC;2;10" /> - this field will pass validation if value is a numeric value between 2 and 10.
	*	Note:
	*		Client side validation is not enough, server side validation is always required. Client side validation is only good for providing instant feedback in style for the user without wasting any time to send the data and get an error message afterwards.
	*	
	*	Created:
	*		2007-10-21 Deezahke weezahke
	*/
	WForm.validate = function(frm, callback, submitOnComplete){
		frm = WForm.find(frm);
		submitOnComplete = submitOnComplete || true;
		//var frm = document.forms[frm];
		var errors = [], radios = [];
		//var th = new templateHandler("<b>{ELEMENT}</b>: {STATUS}");
		for(var i=0; i<frm.elements.length; i++){
			var element = frm.elements[i], range = "", empty = false, status = "", eFocus = "", eFocusRel = "";
			if(element.type.toUpperCase()=="HIDDEN" && element.relatedField){
				//var relm = rel.match(/^([a-zA-Z0-9_]+)\[([a-zA-Z0-9_]+)\]/);
				eFocusRel = ".relatedField";
				element = element.relatedField//WForm.find(relm[1]).elements[relm[2]];
			}
			try{
				var v = element.getAttribute("v").split(";");
				v[0] = v[0].toUpperCase();
				v[3] = v[3];
				v[4] = v[4];
				switch(element.type.toUpperCase()){
					case "HIDDEN":
						/*if(element.getAttribute && (rel = element.getAttribute("rel"))){
							alert("hidden[" + element.name + "]");
							var relm = rel.match(/^([a-zA-Z0-9_]+)\[([a-zA-Z0-9_]+)\]/);
							element = WForm.find(relm[1]).elements[relm[2]];
							var v = element.getAttribute("v").split(";");
							v[0] = v[0].toUpperCase();
							v[3] = v[3];
							v[4] = v[4];
						}*/
					case "PASSWORD":
					case "TEXT": // textbox
					case "TEXTAREA":
						try{
							var oEditor = FCKeditorAPI.GetInstance(element.name) ;
							//alert(oEditor.Focus);
							var oDOM = oEditor.EditorDocument ;
							var iText;
							if ( document.all ){ // If Internet Explorer.
								iText = oDOM.body.innerText;
							}else{					// If Gecko.
								var r = oDOM.createRange() ;
								r.selectNodeContents( oDOM.body ) ;
								iText = r.toString();
							}
							eFocus = "<a onclick=\"FCKeditorAPI.GetInstance('"+element.name+"').Focus()\">"+v[1]+"</a>";
						}catch(e){
							iText = element.value;
							eFocus = "<a onclick=\"Element.focus(WForm.find('"+frm.name+"').elements["+i+"]"+eFocusRel+")\">"+v[1]+"</a>";
						}
						empty = (iText.length == 0);
						if(empty){
							if(v[0]=="Y"){
								status = "necompletat(a).";
							}
						}else{
							switch(v[2].toUpperCase()){
								case "NUMERIC":
									if(isNaN(iText)){
										status = "numar invalid."
									}else if(!Validator.range(parseFloat(iText), v[3], v[4])){
										if(v[3] && v[4]){
											if(v[3]==v[4]){
												status += ("Numarul trebuie sa fie exact " + v[3] + ".");
											}else{
												status += ("Numarul trebuie sa fie intre " + v[3] + " si " + v[4] + ".");
											}
										}else{
											if(v[3]){
												status += "Numarul trebuie sa fie mai mare de " + v[3] + ".";
											}else if(v[4]){
												status += "Numarul trebuie sa fie mai mic de " + v[4] + ".";
											}
											
										}
									}
								break;
								case "ALPHABETIC":
									if(!Validator.validate(iText, Validator.PATTERN_ALPHABETIC)){
										status = "text invalid. Caractere acceptate a-z, A-Z.";
									}else if(!Validator.range(iText, v[3], v[4])){
										if(v[3] && v[4]){
											if(v[3]==v[4]){
												status += ("lungimea textului trebuie sa fie exact " + v[3] + ".");
											}else{
												status += ("lungimea textului trebuie sa fie intre " + v[3] + " si " + v[4] + ".");
											}
										}else{
											if(v[3]){
												status += "textul trebuie sa fie mai lung de " + v[3] + ".";
											}else if(v[4]){
												status += "textul trebuie sa fie mai scurt de " + v[4] + ".";
											}
											
										}
									}
								break;
								case "ALPHANUMERIC":
									if(!Validator.validate(iText, Validator.PATTERN_ALPHANUMERIC)){
										status = "text invalid. Caractere acceptate a-z, A-Z, 0-9.";
									}else if(!Validator.range(iText, v[3], v[4])){
										if(v[3] && v[4]){
											if(v[3]==v[4]){
												status += ("lungimea textului trebuie sa fie exact " + v[3] + ".");
											}else{
												status += ("lungimea textului trebuie sa fie intre " + v[3] + " si " + v[4] + ".");
											}
										}else{
											if(v[3]){
												status += "textul trebuie sa fie mai lung de " + v[3] + ".";
											}else if(v[4]){
												status += "textul trebuie sa fie mai scurt de " + v[4] + ".";
											}
											
										}
									}
								break;
								default:
								case "TEXT":
									if(!Validator.validate(iText, Validator.PATTERN_TEXT)){
										status = "text invalid. Caractere neacceptate $.";
									}else if(!Validator.range(iText, v[3], v[4])){
										if(v[3] && v[4]){
											if(v[3]==v[4]){
												status += ("lungimea textului trebuie sa fie exact " + v[3] + ".");
											}else{
												status += ("lungimea textului trebuie sa fie intre " + v[3] + " si " + v[4] + ".");
											}
										}else{
											if(v[3]){
												status += "textul trebuie sa fie mai lung de " + v[3] + ".";
											}else if(v[4]){
												status += "textul trebuie sa fie mai scurt de " + v[4] + ".";
											}
											
										}
									}
								break;
								case "MAIL":
									if(!Validator.validate(iText, Validator.PATTERN_MAIL)){
										status = "adresa e-mail invalida.";
									}
								break;
								case "HASH":
									if(!Validator.validate(iText, Validator.PATTERN_HASH)){
										status = "invalid.";
									}
								break;
								case "PHONE":
									if(!Validator.validate(iText, Validator.PATTERN_PHONE)){
										status = "numar telefon invalid. Exemple: +40745-123456, 0040745-123456, 0745-123456, 0745123456.";
									}
								break;
								case "DATE":
									if(!DateTime.parse(iText)){
										status = "data invalida. Exemple: " + DateTime.format("{DATE}") + " sau " + DateTime.format("{DATETIME}") + ".";
									}else if(!Validator.range(DateTime.parse(iText), DateTime.parse(v[3]), DateTime.parse(v[4]))){
										if(v[3] && v[4]){
											if(v[3]==v[4]){
												status += ("Data trebuie sa fie exact " + v[3] + ".");
											}else{
												status += ("Data trebuie sa fie intre " + v[3] + " si " + v[4] + ".");
											}
										}else{
											if(v[3]){
												status += "Data trebuie sa fie pe sau dupa " + v[3] + ".";
											}else if(v[4]){
												status += "Data trebuie sa fie inainte sau pe " + v[4] + ".";
											}
										}
									}
								break;
							}
						}
					break;
					case "SELECT-ONE":
						if(v[0]=="Y" && Validator.empty(element.value)){
							status = "necompletat(a)."
						}
						eFocus = "<a onclick=\"Element.focus(WForm.find('"+frm.name+"').elements["+i+"])\">"+v[1]+"</a>";
					break;
					case "RADIO": // leave radios out for now
						if(radios.seqSearch(element.name)==-1){
							radios.push(element.name);
							r = false;
							if(frm[element.name].length == undefined){
								r = frm[element.name].checked;
							}else{
								for(var j=0; j<frm[element.name].length; j++){
									if(frm[element.name][j].checked){
										r = true;
										break;
									}
								}
							}
						}else{
							r = true;
						}
						if(v[0]=="Y" && !r){
							status = "neselectat(a).";
						}
						eFocus = "<a onclick=\"Element.focus(WForm.find('"+frm.name+"').elements["+i+"])\">"+v[1]+"</a>";
					break;
					case "CHECKBOX":
						if(v[0]=="Y" && !element.checked){
							status = "nebifat(a).";
						}
						eFocus = "<a onclick=\"Element.focus(WForm.find('"+frm.name+"').elements["+i+"])\">"+v[1]+"</a>";
					break;
					default: // skip any other
						status = "";
					break;
				}
				if(status!=""){
					errors.push(
						"<b>"+eFocus+"</b>: "+status
						/*templateHandler.cleanup(th.evaluate({
							ELEMENT:	eFocus, 
							STATUS:		status
						}))*/
					);
				}
			}catch(e){}
		}
		if(errors.length){
			errors.push("<br />* Click pentru a merge la campul respectiv.");
			if(typeof(callback)=="function")
				callback(errors.join("<br />"));
			else
				alert(errors.join("\n").replace(Validator.PATTERN_TAG, ""));
			return false;
		}else{
			if(submitOnComplete)
				frm.submit();
			return true;
		}
	}
	
	function Validator(){}
	Validator.validate = function(value, against){
		if(against && !value.match(against)){
			return false;
		}else{
			return true;
		}
	}
	Validator.range = function(value, min, max){
		var result = true;
		switch(typeof(value)){
			case "string":
				if((min && value.length<min) || (max && value.length>max)){
					result = false;
				}
			break;
			case "number":
				if(value<parseFloat(min) || value>parseFloat(max))
					result = false;
			break;
			default:
				if(value.toDateString){ // date object
					if((min && value<min) || (max && value>max)){
						result = false;
					}else{
						result = true;
					}
				}else{
					result = false;
				}
			break;
		}
		return result;
	}
	Validator.empty = function(value){
		if(typeof(value) == "number")
			return false;
		else
			return (value == null || value.match(/^s+$/) || value == "" || value == undefined);
	}
	Validator.checkUserName = function(username, id){
		username = $(username).value;
		var r = new HTTPRequest();
		r.InitializeRequest("GET", "/AJAXSupport/verify.php?t=username&name="+username+"&id="+id);
		r.addEventObserver(this, HTTPRequest.EVENT_SUCCESS, Validator.handleServerResponse);
		r.Commit();
	}
	Validator.checkUserMail = function(mail, id){
		mail = $(mail).value;
		var r = new HTTPRequest();
		r.InitializeRequest("GET", "/AJAXSupport/verify.php?t=mail&mail="+mail+"&id="+id);
		r.addEventObserver(this, HTTPRequest.EVENT_SUCCESS, Validator.handleServerResponse);
		r.Commit();
	}
	Validator.handleServerResponse = function(response){
		try{
			var root = response.xml.getElementsByTagName("response")[0];
			alert(root.firstChild.nodeValue);
		}catch(e){
			alert("Serviciu indisponibil. Te rugam incearca mai tarziu.");
		}
	}
	Validator.validateLat = function(value){
		return ((typeof(value)=="number") && Validator.range(parseFloat(value), -90, 90));
	}
	Validator.validateLon = function(value){
		return ((typeof(value)=="number") && Validator.range(parseFloat(value), -180, 180))
	}
	Validator.isArray = function(obj) {
	   try{
		   if (obj.constructor.toString().indexOf("Array") == -1)
			  return false;
		   else
			  return true;
	   }catch(e){
		   return false;
	   }
	}
	Validator.PATTERN_ALPHABETIC = /^[a-zA-Z]*$/;
	Validator.PATTERN_HASH = /^[a-zA-Z0-9]{32}$/;
	Validator.PATTERN_ALPHANUMERIC = /^[a-zA-Z0-9]*$/;
	Validator.PATTERN_NUMERIC = /^[0-9]*$/;
	Validator.PATTERN_TEXT = /^[^\$]*$/;
	Validator.PATTERN_MAIL = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;
	Validator.PATTERN_PHONE = /^\+?[0-9]{4,}-?[0-9]{6,}$/;
	Validator.PATTERN_DATE = /^([0-9]{4})\-([0-9]{2})\-([0-9]{2})( ([0-9]{2}):([0-9]{2}):([0-9]{2}))?$/;
	Validator.PATTERN_COORDINATE = /^-?[0-9]{1,3}\.[0-9]*$/;
	Validator.PATTERN_TAG = /(<([^>]+)>)/ig;
	
	/** Static class for handling cookies */
	function Cookie(){
		throw 'RuntimeException: Cookie is a static utility class and may not be instantiated';
	}
	/** Set a cookie */
	Cookie.set = function(cookieName, cookieValue, expires, path, domain, secure){
		var cookie = 	escape(cookieName) + '=' + escape(cookieValue)+
						(expires ? '; expires=' + expires.toGMTString() : '')+
						(path ? '; path=' + path : '')+
						(domain ? '; domain=' + domain : '')+
						(secure ? '; secure' : '');
		document.cookie = cookie;
	};
	/** Unset a cookie */
	Cookie.unset = function(cookieName){
		var now = new Date();
		var yesterday = new Date(now.getTime() - 1000 * 60 * 60 * 24);
		Cookie.set(cookieName, '', yesterday);
	};
	/** Get cookie value */
	Cookie.get = function(cookieName){
		var cookieValue = '';
		var posName = document.cookie.indexOf(escape(cookieName) + '=');
		if (posName != -1){
			var posValue = posName + (escape(cookieName) + '=').length;
			var endPos = document.cookie.indexOf(';', posValue);
			if (endPos != -1) 
				cookieValue = unescape(document.cookie.substring(posValue, endPos));
			else 
				cookieValue = unescape(document.cookie.substring(posValue));
		}
		return (cookieValue);
	};
	
	/** Class to handle cookie-based visibility of elements */
	function Visibility(){
		throw 'RuntimeException: Visibility is a static utility class and may not be instantiated';
	}
	
	/**
	* Init the visibility, that is depending on cookie toggle element and element2's visibility
	* If cookie is true, element is visible and element2 is not, and vice versa
	* element and element2 can be arrays of elements
	*/
	Visibility.init = function(cookie, element, element2){
		if(Cookie.get(cookie)=="true"){
			Show(element);
			Hide(element2);
		}else{
			Hide(element);
			Show(element2);
		}
	}
	
	/** Set cookie and show element */
	Visibility.show = function(cookie, element){
		Cookie.set(cookie, 1, 0, "/");
		Show(element);
	}
	
	/** Set cookie and hide element */
	Visibility.hide = function(cookie, element){
		Cookie.set(cookie, 0, 0, "/");
		Hide(element);
	}
	
	/** Toggle element and negate cookie */
	Visibility.toggle = function(cookie, element){
		Togg(element);
		Cookie.set(cookie, (Cookie.get(cookie)==1?0:1), 0, "/");
	}
	
	/**
	* Execute a tween on a property of an object
	* Motion types are defined below
	* This class gives out events, depending on the state of the motion
	*/
	function Tween(obj, prop, func, begin, finish, duration, suffixe){
		EventDispatcher.call(this);
		if (!arguments.length)
			return;
		this.suffixe = suffixe;
		this.obj = $(obj);
		this.prop = prop;
		this.begin = this._pos = begin;
		//this.setDuration(duration);
		this._duration = (duration == null || duration <= 0) ? 100000 : duration;
		this.change = 0;
		this.prevTime = 0;
		this.prevPos = 0;
		this.looping = false;
		this._time = 0;
		//this._pos = 0;
		this._position = 0;
		this._startTime = 0;
		//this.name = '';
		this.func = (typeof(func)=='function') ? func : Tween.easeNone;
		//this.setFinish(finish);
		this.change = finish - this.begin;
	}
	Tween.prototype = new EventDispatcher;
	Tween.prototype.setTime = function(t){
		this.prevTime = this._time;
		if (t > this.getDuration()) {
			if (this.looping) {
				this.rewind (t - this._duration);
				this.update();
				this.Dispatch(Tween.EVENT_LOOPED,{tween:this,target:this.obj,type:Tween.EVENT_LOOPED});
			} else {
				this._time = this._duration;
				this.update();
				this.stop();
				this.Dispatch(Tween.EVENT_FINISHED,{tween:this,target:this.obj,type:Tween.EVENT_FINISHED});
			}
		} else if (t < 0) {
			this.rewind();
			this.update();
		} else {
			this._time = t;
			this.update();
		}
	}
	Tween.prototype.getTime = function(){
		return this._time;
	}
	Tween.prototype.setDuration = function(d){
		this._duration = (d == null || d <= 0) ? 100000 : d;
	}
	Tween.prototype.getDuration = function(){
		return this._duration;
	}
	Tween.prototype.setPosition = function(p){
		//Debug(p);
		this.prevPos = this._pos;
		if(typeof this.prop == "function"){
			this.prop(this.obj, p);
		}else{
			try{ // ie throws an error when some style elements are out of range, ie. width and height
				this.obj.style[this.prop] = p + this.suffixe;
			}catch(e){}
		}
		this._pos = p;
		this.Dispatch(Tween.EVENT_CHANGED,{tween:this,target:this.obj,type:Tween.EVENT_CHANGED, position:p});
	}
	Tween.prototype.getPosition = function(t){
		if (t == undefined) t = this._time;
		return this.func(t, this.begin, this.change, this._duration);
	};
	Tween.prototype.setFinish = function(f){
		this.change = f - this.begin;
	};
	Tween.prototype.getFinish = function(){
		return this.begin + this.change;
	}
	Tween.prototype.start = function(){
		this.rewind();
		this.startEnterFrame();
		this.Dispatch(Tween.EVENT_STARTED,{tween:this,target:this.obj,type:Tween.EVENT_STARTED});
	}
	Tween.prototype.rewind = function(t){
		this.stop();
		this._time = (t == undefined) ? 0 : t;
		this.fixTime();
		this.update();
	}
	Tween.prototype.fforward = function(){
		this._time = this._duration;
		this.fixTime();
		this.update();
	}
	Tween.prototype.update = function(){
		this.setPosition(this.getPosition(this._time));
	}
	Tween.prototype.startEnterFrame = function(){
		this.stopEnterFrame();
		this.isPlaying = true;
		this.onEnterFrame();
	}
	Tween.prototype.onEnterFrame = function(){
		if(this.isPlaying) {
			this.nextFrame();
			setTimeout(Delegate.create(this, this.onEnterFrame), 0);
		}
	}
	Tween.prototype.nextFrame = function(){
		this.setTime((this.getTimer() - this._startTime) / 1000);
	}
	Tween.prototype.stop = function(){
		this.stopEnterFrame();
		this.Dispatch(Tween.EVENT_STOPPED,{tween:this,target:this.obj,type:Tween.EVENT_STOPPED});
	}
	Tween.prototype.stopEnterFrame = function(){
		this.isPlaying = false;
	}
	
	Tween.prototype.continueTo = function(finish, duration){
		this.begin = this._pos;
		this.setFinish(finish);
		if (this._duration != undefined)
			this.setDuration(duration);
		this.start();
	}
	Tween.prototype.resume = function(){
		this.fixTime();
		this.startEnterFrame();
		this.Dispatch(Tween.EVENT_RESUMED,{tween:this,target:this.obj,type:Tween.EVENT_RESUMED});
	}
	Tween.prototype.yoyo = function (){
		this.continueTo(this.begin,this._time);
	}
	Tween.prototype.fixTime = function(){
		this._startTime = this.getTimer() - this._time * 1000;
	}
	Tween.prototype.getTimer = function(){
		return new Date().getTime() - this._time;
	}
	
	Tween.easeNone = function(t, b, c, d){
		return c*t/d + b; 
	};
	Tween.backEaseIn = function(t,b,c,d,a,p){
		if (s == undefined) var s = 1.70158;
		return c*(t/=d)*t*((s+1)*t - s) + b;
	}
	Tween.backEaseOut = function(t,b,c,d,a,p){
		if (s == undefined) var s = 1.70158;
		return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
	}
	Tween.backEaseInOut = function(t,b,c,d,a,p){
		if (s == undefined) var s = 1.70158; 
		if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
		return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
	}
	Tween.elasticEaseIn = function(t,b,c,d,a,p){
		if (t==0) 
			return b;  
		if ((t/=d)==1) 
			return b+c;  
		if (!p) 
			p=d*.3;
		if (!a || a < Math.abs(c)) {
			a=c; 
			var s=p/4;
		}else 
			var s = p/(2*Math.PI) * Math.asin (c/a);
		return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
	}
	Tween.elasticEaseOut = function (t,b,c,d,a,p){
		if (t==0) 
			return b;
		if ((t/=d)==1) 
			return b+c;  
		if (!p) 
			p=d*.3;
		if (!a || a < Math.abs(c)) {
			a=c; 
			var s=p/4; 
		}else 
		var s = p/(2*Math.PI) * Math.asin (c/a);
		return (a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b);
	}
	Tween.elasticEaseInOut = function (t,b,c,d,a,p){
		if (t==0) 
			return b;  
		if ((t/=d/2)==2) 
			return b+c;  
		if (!p) 
			var p=d*(.3*1.5);
		if (!a || a < Math.abs(c)){
			var a=c; 
			var s=p/4;
		}else 
			var s = p/(2*Math.PI) * Math.asin (c/a);
		if (t < 1) 
			return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
		return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b;
	}
	Tween.bounceEaseOut = function(t,b,c,d){
		if ((t/=d) < (1/2.75)) {
			return c*(7.5625*t*t) + b;
		} else if (t < (2/2.75)) {
			return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
		} else if (t < (2.5/2.75)) {
			return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
		} else {
			return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
		}
	}
	Tween.bounceEaseIn = function(t,b,c,d){
		return c - Tween.bounceEaseOut (d-t, 0, c, d) + b;
	}
	Tween.bounceEaseInOut = function(t,b,c,d){
		if (t < d/2) 
			return Tween.bounceEaseIn(t*2, 0, c, d) * .5 + b;
		else 
			return Tween.bounceEaseOut(t*2-d, 0, c, d) * .5 + c*.5 + b;
	}
	Tween.strongEaseInOut = function(t,b,c,d){
		return c*(t/=d)*t*t*t*t + b;
	}
	Tween.regularEaseIn = function(t,b,c,d){
		return c*(t/=d)*t + b;
	}
	Tween.regularEaseOut = function(t,b,c,d){
		return -c *(t/=d)*(t-2) + b;
	}
	Tween.regularEaseInOut = function(t,b,c,d){
		if ((t/=d/2) < 1) return c/2*t*t + b;
			return -c/2 * ((--t)*(t-2) - 1) + b;
	}
	Tween.strongEaseIn = function(t,b,c,d){
		return c*(t/=d)*t*t*t*t + b;
	}
	Tween.strongEaseOut = function(t,b,c,d){
		return c*((t=t/d-1)*t*t*t*t + 1) + b;
	}
	Tween.strongEaseInOut = function(t,b,c,d){
		if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b;
			return c/2*((t-=2)*t*t*t*t + 2) + b;
	}
	Tween.alphaHandler = function(element, p){
		WUtility.applyStyle(element, {"opacity":p/100, "filter":"progid:DXImageTransform.Microsoft.Alpha(opacity=" + p + ")"});
	}
	Tween.EVENT_LOOPED = "onMotionLooped";
	Tween.EVENT_CHANGED = "onMotionChanged";
	Tween.EVENT_FINISHED = "onMotionFinished";
	Tween.EVENT_STARTED = "onMotionStarted";
	Tween.EVENT_STOPPED = "onMotionStopped";
	Tween.EVENT_RESUMED = "onMotionResumed";
	
	/**
	* Gets an XML node and returns an associative array that contains the xml node's children values.
	* Note, this is not recursive, that is it won't follow children's subnodes.
	*/
	function xml2obj(xmlRoot){
		var result = new Object();
		for(var i=0; i<xmlRoot.childNodes.length; i++){
			if(xmlRoot.childNodes[i].firstChild)
				result[xmlRoot.childNodes[i].nodeName] = xmlRoot.childNodes[i].firstChild.nodeValue
			else
				result[xmlRoot.childNodes[i].nodeName] = null;
		}
		return result;
	}
	
	/**
	* Template handler.
	* Fields to be replaced in the template are contained inside { and }.
	*/
	function templateHandler(template){
		this.template = template;
		this.evaluate = function(data){
			/*
			Data is an associative array, the keys representing the template values and values representing the replaced values
			*/
			var temporaryTemplate = this.template; // make a temporary copy so successive calls with different datasets evaluate properly
			for(var i in data)
				temporaryTemplate = temporaryTemplate.replace(eval("/\{!*"+i.toUpperCase()+"\}/g"), data[i]);
			return temporaryTemplate;
		}
		this.setTemplate = function(template){
			this.template = template;
		}
	}
	templateHandler.cleanup = function(template){
		return template.replace(/\{!*[A-Z0-9_]+\}/g, "");
	}
	
	/**
	Searches an element for elements of class [tabImage|tabContent] and links them to make a tab viewer.
	Number of tabImages and tabContents must match
	*/
	function WTabs(element, useCookies){
		this.__element = $(element);
		Hide(this.__element);
		this.__useCookies = useCookies;
		EventDispatcher.call(this);
		WTabs.INSTANCES.push(this);
	}
	WTabs.prototype = new EventDispatcher;
	WTabs.INSTANCES = [];
	WTabs.EVENT_TABCLICK = "Tab clicked";
	WTabs.EVENT_TABROLLOVER = "Tab rolled over";
	WTabs.prototype.init = function(){
		WUtility.cleanEmptyTextNodes(this.__element);
		this.__tabs = [], this.__containers = [], this.__tabsS = [];
		//this.__useCookies = useCookies || true;
		this.__cookieName = this.__element.getAttribute("id")+"_tabs";
		this.__selected = this.__useCookies ? (Cookie.get(this.__cookieName) || 0) : 0;
		this.changeTo = function(sender){
			//alert(this.__selected);
			Hide([this.__containers[this.__selected], this.__tabsS[this.__selected]]);
			Show(this.__tabs[this.__selected]);
			this.__selected = sender.targetTab;
			if(this.__useCookies) Cookie.set(this.__cookieName, this.__selected);
			Show([this.__containers[this.__selected], this.__tabsS[this.__selected]]);
			Hide(this.__tabs[this.__selected]);
			this.Dispatch(WTabs.EVENT_TABCLICK, {sender:this, selected:this.__selected});
		}
		this.rolledOn = function(sender){
			this.Dispatch(WTabs.EVENT_TABROLLOVER, {sender:this, selected:sender.targetTab});
		}
		WUtility.traverse(
			this.__element, 
			Delegate.create(this, function(node){
				if(node.className == "tabImage"){
					EventDispatcher.call(node);
					//alert(node.Dispatch);
					WUtility.applyStyle(node, {cursor:"pointer"});
					node.onclick = function(){
						this.Dispatch(WTabs.EVENT_TABCLICK, this);	
					};
					node.addEventObserver(this, WTabs.EVENT_TABCLICK, "changeTo");
					this.__tabs.push(node);
				}else if(node.className == "tabContent"){
					//node.style.display = (i==this.__selected ? "" : "none");
					this.__containers.push(node);
				}else if(node.className == "tabImageSelected"){
					//node.style.display = (i==this.__selected ? "" : "none");
					Hide(node);
					this.__tabsS.push(node);
				}
			}),
			1
		);
		/*if(this.__tabs.length != this.__containers.length)
			alert("Tab and container count doesn't match.");*/
		for(var i=0; i<this.__tabs.length; i++){
			WUtility.applyStyle(this.__containers[i], {display:(i==this.__selected ? "" : "none")})
			WUtility.applyStyle(this.__tabsS[i], {display:(i==this.__selected ? "" : "none")})
			WUtility.applyStyle(this.__tabs[i], {display:(i==this.__selected ? "none" : "")})
			this.__tabs[i].targetTab = this.__tabsS[i].targetTab = i;
		}
		Show(this.__element);
	}
	WTabs.initAll = function(){
		//alert("initing wtabs")
		for(var i=0; i<WTabs.INSTANCES.length; i++)
			WTabs.INSTANCES[i].init();
	}
	
	/** Handles date and time formatting. Static class. */
	function DateTime(){
		throw 'RuntimeException: DateTime is a static utility class and may not be instantiated';
	}
	
	/** Format time */
	DateTime.format = function(format, time){
		if(time != null && time.match(/^[0-9]*$/))
			var current = new Date(time);
		else
			var current = new Date();
		var leap = ((current.getFullYear()%4==0) || ((current.getFullYear()%100==0)&&!(current.getFullYear() % 400 == 0)));
		var feb = leap ? 29 : 28;
		var calendar = {
			RO		: 	{
								MONTHS 			: ['Ianuarie', 'Februarie', 'Martie', 'Aprilie', 'Mai', 'Iunie', 'Iulie', 'August', 'Septembrie', 'Octombrie', 'Noiembrie', 'Decembrie'],
								DAYS 			: ['Duminica', 'Luni', 'Marti', 'Miercuri', 'Joi', 'Vineri', 'Sambata']
							},
			DIM 		: [31, feb, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
		};
	
		// do some preprocessing
		var t = new templateHandler(format);
		t.setTemplate(
			t.evaluate(
				{
					DATE			: "{YEAR}-{MONTH}-{DAY}",
					TIME12			: "{HOURS12}:{MINUTES}:{SECONDS}{AMPM}",
					TIME24			: "{HOURS24}:{MINUTES}:{SECONDS}",
					DATETIME		: "{YEAR}-{MONTH}-{DAY} {HOURS24}:{MINUTES}:{SECONDS}",
					FULL			: "{DAY_NAME}, {MONTH}-{MONTH_NAME_S}-{YEAR} {HOURS12}:{MINUTES}:{SECONDS}{AMPM}"
				}
			)
		);
		return t.evaluate(
			{
				MONTH_NAME		: calendar.RO.MONTHS[current.getMonth()],
				MONTH_NAME_S	: calendar.RO.MONTHS[current.getMonth()].substr(0, 3),
				DAY_NAME		: calendar.RO.DAYS[current.getDay()],
				DAY_NAME_S		: calendar.RO.DAYS[current.getDay()].substr(0, 2),
				YEAR			: current.getFullYear(),
				MONTH			: (current.getMonth() + 1).pad(2),
				DAY				: (current.getDate() + 1).pad(2),
				HOURS24			: current.getHours().pad(2),
				HOURS12			: (current.getHours() % 12).pad(2),
				MINUTES			: current.getMinutes().pad(2),
				SECONDS			: current.getSeconds().pad(2),
				AMPM			: current.getHours() >= 12 ? "PM" : "AM"
			}
		);
	}
	
	DateTime.parse = function(date){
		if(!date.match || !date.match(Validator.PATTERN_DATE))
			return false
		if(date.toDateString)
			return date;
		var dateArray = date.match(Validator.PATTERN_DATE)
		//date = date.replace(/\-/g, "/");
		var date = new Date();
		date.setFullYear(parseInt(dateArray[1]), parseInt(dateArray[2])-1, parseInt(dateArray[3]));
		date.setHours(parseInt(dateArray[5])||0, parseInt(dateArray[6])||0, parseInt(dateArray[7])||0, 0);
		return date;
	}
	
	/** URL manipulation class. Static. */
	function Address(){
		throw 'RuntimeException: URL is a static utility class and may not be instantiated';
	}
	
	/** Matches all #field# like patterns and replaces them with field's value */
	Address.dynamic = function(lnk){
		var patt = /#(\w+)#/g, elementId, element, elementValue, i, result = lnk;
		while((fld = patt.exec(lnk))){
			elementId = fld[1];
			element = $(elementId);
			switch(element.type.toUpperCase()){
				case "CHECKBOX":
					elementValue = element.checked ? element.value : "";
				break;
				default:
					elementValue = element.value;
				break;
			}
			result = result.replace(eval("/#"+elementId+"#/g"), elementValue);
		}
		return result;
	}
	
	/** Redirect current window */
	Address.redirect = function(lnk, conf){
		conf = conf || false;
		if(conf !==false){
			if(confirm(conf))
				location.href = Address.dynamic(lnk);
		}else{
			location.href = Address.dynamic(lnk);
		}
	}
	
	/** Replace current location */
	Address.replace = function(lnk, conf){
		conf = conf || false;
		if(conf !==false){
			if(confirm(conf))
				location.replace(Address.dynamic(lnk));
		}else{
			location.href = Address.dynamic(lnk);
		}
	}
	
	/* Add a prefix to all src, href attributes and to url()'s in styles */
	Address.prefix = function(content, prefix){
		pregs = [
			[/(src|href) *= *(\'|\")([^\/][^\'\"]+)(\'|\")/gi, "$1=$2"+prefix+"$3$2"], // replaces hrefs and srcs
			[/url *\( *([^\/][^\'\"]+) *\)/gi, "url("+prefix+"$1)"] // replace url(...) in styles
		];
		for(var i in pregs)
			content = content.replace(pregs[i][0], pregs[i][1]);
		return content;
	}
	/* Get the current script's absolute path */
	Address.scriptPath = function(){
		return location.pathname.substring(0,location.pathname.lastIndexOf("/")+1);
	}
	/* Get the current script's absolute path */
	Address.dirname = function(path){
		return path.substring(0,path.lastIndexOf("/")+1);
	}
	/** Timer. Static. */
	function Chrono(){
		throw 'RuntimeException: Chrono is a static utility class and may not be instantiated';
	}
	Chrono.time = null;
	
	/** Start the timer */
	Chrono.start = function(){
		if(Chrono.time != null)
			return false;
		Chrono.time = new Date().getTime();
	}
	
	/** Stops the timer and returns the time passed from last start() */
	Chrono.stop = function(){
		if(Chrono.time == null)
			return false;
		var time = Chrono.time;
		Chrono.time = null;
		return new Date().getTime() - time;
	}
	
	/**
	*	Description:
	*		Creates a link between the parent and child, so that if the parent changes it's value it will dispatch an event that the child listens to.
	*		When the event is captured the child refreshes it's values based on what's parent's value.
	*	Note:
	*		Multiple combos can be linked in chains, every event goes down the chain starting at the dispatcher combo.
	*	Parameters:
	*		child	- the combo that depends on parent's value
	*		parent	- the combo that child depends on
	*	Created:
	*		October 6, 2007 7:21 PM  Deezah, my nizzo!
	*/
	/*function link(child, parent){
		this.child 	= $(child); // get the parent
		if(typeof(parent)=="number"){
			this.parent = new Object();
			this.parent.value = parent;
		}else{
			this.parent = $(parent); // get the child
		}
		
		this.child.backingObject = this; //add a reference of this to the child, in case we need it.
		this.child.backingParent = this.parent;
		if(!this.parent.addEventObserver){
			this.parent.prototype = EventDispatcher.call(this.parent); // make parent able to dispatch events and accept observers, if not already a dispatcher
		}
		this.child.onchange = function(){
			//alert(this.id + " onchange");
			if(this.value=="adauga"){
				this.value="";
				try{
					var nurl = this.getAttribute("new"); // get the link for adding a new value
					nurl += ("&id="+this.backingParent.value);
					var newWnd = openWindow(nurl, 350, 350);
					var interval = setInterval(Delegate.create(this, function(){ // detect window closure, on close refresh the combo
						if(newWnd.closed){
							clearInterval(interval);
							this.Refresh(this.backingParent.value);
						}
					}), 10);
				}catch(e){
					alert("Add: unable to access interface.\nMake sure popups are allowed on this site.");
				}
			}
			try{
				this.Dispatch(link.EVENT_CHANGED, this.value); // if parent changes, dispatch an event for the children
			}catch(e){}
		}
		this.child.Refresh = function(pval){
			if(pval===""){
				this.Disable(); // disable the child if parent hasn't got a selected value
				this.Clear();
			}else{
				//this.Enable(); // otherwise enable the combo
				try{
					//var rurl = this.getAttribute("refresh").replace("{ID}", pval); // generate the url that will get the new values, based on parent's value
					var rurl = this.getAttribute("refresh");
					rurl += ("&id=" + pval + "&r=" + Math.random()); // add the parent's id to the request and make sure the request doesn't get affected by caching by adding a random number at the end
					var request = new HTTPRequest(); // create a request object
					request.InitializeRequest('POST', rurl); // initialize the request
					this.Clear(); // empty the combo
					request.addEventObserver(this, HTTPRequest.EVENT_SUCCESS, this.Fill); // listen to when the request finished
					request.addEventObserver(this, HTTPRequest.EVENT_FAILURE, this.Fail);
					request.Commit(null); // execute the request
				}catch(e){
					alert("Refresh: interface not specified.\nMake sure popups are allowed on this site.");
				}
			}
			try{ 
				this.Dispatch(link.EVENT_CHANGED, this.value); // dispatch event for child's children, if there are any. Note: child becomes a dispatcher only when another combo requests it's parenthood
			}catch(e){}
		}
		this.child.Fill = function(response){ // fill the combo with the new values
			this.Disable();
			var root = response.xml.getElementsByTagName("response")[0]; // process the XML
			if(root.getAttribute("result").toUpperCase()=="FAILURE"){
				alert(root.firstChild.nodeValue);
			}else{
				var elements = root.getElementsByTagName("option"); //
				for(var i=0;i<elements.length;i++){ // fill the combo
					var new_option = new Option(elements[i].firstChild.nodeValue, elements[i].getAttribute("id")) // create the new element
					if(this.options.length>0 && this.options[this.options.length-1].value=="adauga") // if there is an option for adding new values to the combo, it needs to be the last option
						Combo.insertBefore(this, this.options.length-1, new_option); // so we insert the new value before it
					else // otherwise
						Combo.append(this, new_option); // just append to the end
				}
			}
			this.Enable(); // otherwise enable the combo
		}
		this.child.Fail = function(response){
			var new_option = new Option("AJAX request failed", ""); // create the new element
			if(this.options[this.options.length-1].value=="adauga") // if there is an option for adding new values to the combo, it needs to be the last option
				Combo.insertBefore(this, this.options.length-1, new_option); // so we insert the new value before it
			else // otherwise
				Combo.append(this, new_option); // just append to the end
		}
		this.child.Enable = function(){ // enables the combo
			this.disabled=false;
			this.value="";
		}
		this.child.Disable = function(){ // disables the combo
			this.disabled=true;
			this.value="";
			//this.Clear();
		}
		this.child.Clear = function(){ // clears all the options but the default and the one that facilitates new option additons
			var i = 0;
			while(i < this.options.length){
				if(this.options[i].value!="" && this.options[i].value!="adauga"){
					this.remove(i);
				}else{
					i++;
				}
			}
		}
		this.Refresh = function(pval){ // callback for eventChange event
			this.child.Refresh(pval); // call the child's refresh
		}
		this.parent.addEventObserver(this, link.EVENT_CHANGED, "Refresh"); // subscribe child to parent's events
		if(this.parent.value===""){
			this.child.Disable(); // if parent hasn't got a value selected, disable child
		}/*else{
			this.child.Refresh(this.parent.value); // otherwise refresh child
		}*
	}*
	link.EVENT_CHANGED = "eventComboChanged";*/
	
	/*function link2(child, parent, urls){
		this.child 	= $(child); // get the parent
		if(typeof(parent)=="number"){
			this.parent = new Object();
			this.parent.value = parent;
		}else{
			this.parent = $(parent); // get the child
		}
		this.urls = urls;
		this.child.backingObject = this; //add a reference of this to the child, in case we need it.
		this.child.backingParent = this.parent;
		if(!this.parent.addEventObserver){
			this.parent.prototype = EventDispatcher.call(this.parent); // make parent able to dispatch events and accept observers, if not already a dispatcher
		}
		this.child.onchange = function(){
			//alert(this.id + " onchange");
			if(this.value=="adauga"){
				this.value="";
				try{
					var nurl = this.backingObject.urls.add; // get the link for adding a new value
					nurl += ("&id="+this.backingParent.value);
					var newWnd = openWindow(nurl, 350, 350);
					var interval = setInterval(Delegate.create(this, function(){ // detect window closure, on close refresh the combo
						if(newWnd.closed){
							clearInterval(interval);
							this.Refresh(this.backingParent.value);
						}
					}), 10);
				}catch(e){
					alert("Add: unable to access interface.\nMake sure popups are allowed on this site.");
				}
			}
			try{
				this.Dispatch(link.EVENT_CHANGED, this.value); // if parent changes, dispatch an event for the children
			}catch(e){}
		}
		this.child.Refresh = function(pval){
			if(pval===""){
				this.Disable(); // disable the child if parent hasn't got a selected value
				this.Clear();
			}else{
				//this.Enable(); // otherwise enable the combo
				try{
					//var rurl = this.getAttribute("refresh").replace("{ID}", pval); // generate the url that will get the new values, based on parent's value
					var rurl = this.backingObject.urls.get;
					rurl += ("&id=" + pval + "&r=" + Math.random()); // add the parent's id to the request and make sure the request doesn't get affected by caching by adding a random number at the end
					alert(rurl);
					var request = new HTTPRequest(); // create a request object
					request.InitializeRequest('POST', rurl); // initialize the request
					this.Clear(); // empty the combo
					request.addEventObserver(this, HTTPRequest.EVENT_SUCCESS, this.Fill); // listen to when the request finished
					request.addEventObserver(this, HTTPRequest.EVENT_FAILURE, this.Fail);
					request.Commit(null); // execute the request
				}catch(e){
					alert("Refresh: interface not specified.\nMake sure popups are allowed on this site.");
				}
			}
			try{ 
				this.Dispatch(link.EVENT_CHANGED, this.value); // dispatch event for child's children, if there are any. Note: child becomes a dispatcher only when another combo requests it's parenthood
			}catch(e){}
		}
		this.child.Fill = function(response){ // fill the combo with the new values
			this.Disable();
			var root = response.xml.getElementsByTagName("response")[0]; // process the XML
			if(root.getAttribute("result").toUpperCase()=="FAILURE"){
				alert(root.firstChild.nodeValue);
			}else{
				var elements = root.getElementsByTagName("option"); //
				for(var i=0;i<elements.length;i++){ // fill the combo
					var new_option = new Option(elements[i].firstChild.nodeValue, elements[i].getAttribute("id")) // create the new element
					if(this.options.length>0 && this.options[this.options.length-1].value=="adauga") // if there is an option for adding new values to the combo, it needs to be the last option
						Combo.insertBefore(this, this.options.length-1, new_option); // so we insert the new value before it
					else // otherwise
						Combo.append(this, new_option); // just append to the end
				}
			}
			this.Enable(); // otherwise enable the combo
		}
		this.child.Fail = function(response){
			var new_option = new Option("AJAX request failed", ""); // create the new element
			if(this.options[this.options.length-1].value=="adauga") // if there is an option for adding new values to the combo, it needs to be the last option
				Combo.insertBefore(this, this.options.length-1, new_option); // so we insert the new value before it
			else // otherwise
				Combo.append(this, new_option); // just append to the end
		}
		this.child.Enable = function(){ // enables the combo
			this.disabled=false;
			this.value="";
		}
		this.child.Disable = function(){ // disables the combo
			this.disabled=true;
			this.value="";
			//this.Clear();
		}
		this.child.Clear = function(){ // clears all the options but the default and the one that facilitates new option additons
			var i = 0;
			while(i < this.options.length){
				if(this.options[i].value!="" && this.options[i].value!="adauga"){
					this.remove(i);
				}else{
					i++;
				}
			}
		}
		this.Refresh = function(pval){ // callback for eventChange event
			this.child.Refresh(pval); // call the child's refresh
		}
		this.parent.addEventObserver(this, link.EVENT_CHANGED, "Refresh"); // subscribe child to parent's events
		if(this.parent.value===""){
			this.child.Disable(); // if parent hasn't got a value selected, disable child
		}/*else{
			this.child.Refresh(this.parent.value); // otherwise refresh child
		}*
	}*/
	
	
	/*
	Create a link between two combos so that the child listens and acts on the events of the parent
	Combo chains can be created
	Multiple combos can be linked to the same parent
	*/
	function WLink(child, parent, options){
		this.child = $(child);
		this._parent = parent;
		options.controls = options.controls || WLink.CONTROL_NONE;
		this.options = options;
		this.inited = false;
		this.__lastSelected = "";
		this.__surpressChainUpdate = false;
		WLink.INSTANCES.push(this);
	}
	WLink.INSTANCES = [];
	WLink.EVENT_CHANGED = "WLink parent changed";
	WLink.BUTTON_INSERT = "/imagini/wlink/new.png?height=12";
	WLink.BUTTON_UPDATE = "/imagini/wlink/edit.png?height=12";
	WLink.BUTTON_REMOVE = "/imagini/wlink/delete.png?height=12";
	WLink.CONTROL_NONE = 0;
	WLink.CONTROL_INSERT = 1;
	WLink.CONTROL_UPDATE = 2;
	WLink.CONTROL_REMOVE = 4;
	WLink.CONTROL_ALL = WLink.CONTROL_INSERT | WLink.CONTROL_UPDATE | WLink.CONTROL_REMOVE;
	WLink.prototype.init = function(){
		if(!this.inited){
			if(typeof(this._parent) == "number"){
				this._parent = {value:this._parent}
				if(!this._parent.addEventObserver)
					this._parent.prototype = EventDispatcher.call(this._parent);
			}else{
				this._parent = $(this._parent);
				if(!this._parent.addEventObserver)
					this._parent.prototype = EventDispatcher.call(this._parent);
			}
			
			this._parent.backingObject = this.child.backingObject = this;
			this.child.WLinkParent = this._parent;
			this.child.WLinkOptions = this.options;
			
			if(this.options.controls & WLink.CONTROL_REMOVE){
				this.__remove = Element.insertAfter(this.child, WUtility.createElement("IMG", {"src":WLink.BUTTON_REMOVE,"alt":"Sterge", "title":"Sterge"}, {"cursor":"pointer"}));
				this.__remove.onclick = Delegate.create(this, function(){
					if(this.child.value!="" && confirm("Sigur stergi?")){
						try{
							url = this.options.url + "?action=remove&id="+this.child.value;
							//alert("url = " + url);
							url = url.unamp();
							var newWnd = openWindow(url, 350, 350);
							var interval = setInterval(Delegate.create(this, function(){ // detect window closure, on close refresh the combo
								if(newWnd.closed){
									clearInterval(interval);
									this.child.get(this._parent.value);
									this.child.value = "";
									//alert("refresh");
								}
							}), 100);
						}catch(e){
							alert("Unable to access interface.\nMake sure popups are allowed on this site.");
						}
					}
				});
			}

			if(this.options.controls & WLink.CONTROL_UPDATE){
				this.__update = Element.insertAfter(this.child, WUtility.createElement("IMG", {"src":WLink.BUTTON_UPDATE,"alt":"Modifica", "title":"Modifica"}, {"cursor":"pointer"}));
				this.__update.onclick = Delegate.create(this, function(){
					if(this.child.value!=""){
						try{
							this.__surpressChainUpdate = true;
							this.__lastSelected = this.child.value;
							url = this.options.url + "?action=edit&id="+this.child.value;
							//alert("url = " + url);
							url = url.unamp();
							var newWnd = openWindow(url, 350, 350);
							var interval = setInterval(Delegate.create(this, function(){ // detect window closure, on close refresh the combo
								if(newWnd.closed){
									clearInterval(interval);
									this.child.get(this._parent.value);
									this.child.value = this.__lastSelected;
									this.__surpressChainUpdate = false;
									//alert("refresh");
								}
							}), 100);
						}catch(e){
							this.__surpressChainUpdate = false;
							alert("Unable to access interface.\nMake sure popups are allowed on this site.");
						}
					}
				});
			}
			
			if(this.options.controls & WLink.CONTROL_INSERT){
				this.__insert = Element.insertAfter(this.child, WUtility.createElement("IMG", {"src":WLink.BUTTON_INSERT,"alt":"Adauga", "title":"Adauga"}, {"cursor":"pointer"}));
				this.__insert.onclick = Delegate.create(this, function(){
					try{
						url = this.options.url + "?action=edit&pid="+this._parent.value;
						//alert("url = " + url);
						url = url.unamp();

						var newWnd = openWindow(url, 350, 350);
						var interval = setInterval(Delegate.create(this, function(){ // detect window closure, on close refresh the combo
							if(newWnd.closed){
								clearInterval(interval);
								this.child.get(this._parent.value);
								this.child.value = "";
								//alert("refresh");
							}
						}), 100);
					}catch(e){
						alert("Unable to access interface.\nMake sure popups are allowed on this site.");
					}
				});
			}
			
			this.child.get = function(id){
				//Debug("Add value to " + this.getAttribute("id"));
				this.clear();
				if(id !== ""){
					if(this.backingObject.options.url != undefined){
						url = this.backingObject.options.url + "?action=get&pid="+id;
						url = url.unamp();
						WLink.fill(this, HTTPRequest.get(url));
						this.enable(this.backingObject.options.sel);
						delete this.backingObject.options.sel;
					}
				}else{
					this.disable();
				}
			}
			this.child.clear = function(){ // clears all the options but the default and the one that facilitates new option additons
				var i = 0;
				while(i < this.options.length){
					if(this.options[i].value!="" && this.options[i].value!="adauga" && this.options[i].value!="modifica" && this.options[i].value!="sterge"){
						this.remove(i);
					}else{
						i++;
					}
				}
			}
			this.child.enable = function(selected){ // enables the combo
				this.disabled=false;
				this.value= selected || "";
				//Debug("Selecting " + this.getAttribute("id") + "." + selected);
			}
			this.child.disable = function(){ // disables the combo
				this.disabled=true;
				this.value="";
				//this.Clear();
			}
			this.child.onchange = function(){
				if(!this.__surpressChainUpdate)
					try{
						this.Dispatch(WLink.EVENT_CHANGED, this.value);
					}catch(e){}
			}
			this._parent.addEventObserver(this.child, WLink.EVENT_CHANGED, this.child.get);
			this._parent.Dispatch(WLink.EVENT_CHANGED, this._parent.value);
			this.inited = true;
		}
	}
	WLink.initAll = function(){
		//alert("initing wtips")
		for(var i=0; i<WLink.INSTANCES.length; i++)
			WLink.INSTANCES[i].init();
	}
	WLink.create = function(child, parent, options){
		return new WLink(child, parent, options);
	}
	WLink.fill = function(combo, data){
		var root = data.xml.getElementsByTagName("response")[0]; // process the XML
		if(root.getAttribute("result").toUpperCase()=="FAILURE"){
			alert(root.firstChild.nodeValue);
		}else{
			var elements = root.getElementsByTagName("option"); //
			//var newOpts = [];
			for(var i=0;i<elements.length;i++){ // fill the combo
				var new_option = new Option(elements[i].firstChild.nodeValue, elements[i].getAttribute("id")) // create the new element
				//newOpts.push(new_option);
				Combo.append(combo, new_option); // just append to the end	
			}
			//Combo.appendBatch(combo, newOpts);
		}
		//alert(this.value)
	}
	
	

	/*
	* Creates a tooltip.
	*	Parameters:
	*		toolTip - The tooltip itself
	*		trigger - the element that fires the popup
	*	See:
	*		/sablon/toolTip.tpl
	*/
	function toolTip(toolTip, trigger, options){
		this.__tooltip = $(toolTip); // get the tooltip as an object
		this.__frame = this.__tooltip.firstChild;
		this.__trigger = $(trigger); // get the trigger as an object
		this.__inner		= this.__frame.rows[0].cells[0];
		this.options = options;
		WUtility.applyAttributes(this.__frame, {cellpadding:0, cellspacing:0, cellPadding:0, cellSpacing:0, border:0/*, width:this.__width+"px", height:this.__height+"px"*/}); // remove paddings and spacings
		WUtility.applyStyle(this.__tooltip,  {position:"absolute", zIndex:9999/*, top:-9999, left:-9999*/}) // move the tooltip out of sight, if it's not already
		WUtility.applyStyle(this.__trigger, {cursor:"pointer"}); // the trigger will have a hand cursor when floated
		this.__trigger.tooltipObject = this.__tooltip.tooltipObject = this; // save a reference of this for eventual later use
		this.__frame.rows[0].cells[0].appendChild(WUtility.createElement("IMG", {src:"/imagini/tooltip/"+options.skin+"/tl.png"}));
		this.__frame.rows[0].cells[2].appendChild(WUtility.createElement("IMG", {src:"/imagini/tooltip/"+options.skin+"/tr.png"}));
		this.__frame.rows[2].cells[0].appendChild(WUtility.createElement("IMG", {src:"/imagini/tooltip/"+options.skin+"/bl.png"}));
		this.__frame.rows[2].cells[2].appendChild(WUtility.createElement("IMG", {src:"/imagini/tooltip/"+options.skin+"/br.png"}));
		//WUtility.applyStyle(this.__frame, {border:"1px solid red"});
		switch(options.position.toUpperCase()){ // depending on tooltip's position around the object, set up it's tip
			case "B":
				this.__frame.rows[0].cells[1].appendChild(WUtility.createElement("IMG", {src:"/imagini/tooltip/" + options.skin + "/tip_t.png"}, {}));
			break;
			default:
			case "T":
				this.__frame.rows[2].cells[1].appendChild(WUtility.createElement("IMG", {src:"/imagini/tooltip/" + options.skin + "/tip_b.png"}, {}));
			break;
			case "R":
				this.__frame.rows[1].cells[0].appendChild(WUtility.createElement("IMG", {src:"/imagini/tooltip/" + options.skin + "/tip_l.png"}, {}));
			break;
			case "L":
				this.__frame.rows[1].cells[2].appendChild(WUtility.createElement("IMG", {src:"/imagini/tooltip/" + options.skin + "/tip_r.png"}, {}));
			break;
		}
		//alert(Element.getCSSStyleAttribute(this.__frame, "width"));
		//if(BrowserDetect.browser=="Explorer"){ // fix issue of comboboxes and flash overlapping any absolutely positioned div in IE
			//alert("offsetHeight = " + this.__frame.offsetHeight + ", offsetWidth = " + this.__frame.offsetWidth);
			//Debug("Appending IFRAME, w = " + this.__frame.offsetWidth + ", h = " + this.__frame.offsetHeight);
			//this.__tooltip.appendChild(WUtility.createElement("IFRAME", {frameBorder:1, scrolling:"no"}, {backgroundColor:"#FF0000",zIndex:1, filter:"alpha(opacity=50)", position:"absolute", top:"0px", left:"0px", width:this.__frame.offsetWidth+"px", height:this.__frame.offsetHeight+"px"}));
		//}
		switch(options.mode.toUpperCase()){  // set up the event system depending on what type of tooltip this is
			default:
			case "CLICK": // the tooltip will pop up when the trigger is clicked
				var close_btn = WUtility.createElement(
					"IMG", 
					{
						src:"/imagini/tooltip/" + options.skin + "/close.gif", 
						title:"Inchide"
					}, 
					{
						width:"5px", 
						height:"5px", 
						border:0, 
						position:"absolute", 
						top: "15px", 
						right:"20px", 
						cursor:"pointer"
					}
				);
				this.__tooltip.appendChild(close_btn); // append a close button to the top right corner of the tooltip
				close_btn.onclick = Delegate.create(this, function(){
					this.Close();
				})
				this.__trigger.onclick = Delegate.create(this, function(){
					if(this.__opened){
						this.Close();
					}else{
						this.Popup();
					}
				});
			break;
			case "HOVER": // the tooltip will pop up when the trigger is hovered, and close when the trigger is unhovered
				this.__trigger.onmouseover = Delegate.create(this, function(){
					Scheduler.callLater(this, 500, this.Popup); // needs a little hover time before popping up
					//this.Popup();
				});
				this.__tooltip.onmouseout = this.__trigger.onmouseout = Delegate.create(this, function(e){
					if(Scheduler.isPending(this.Popup)) // if mouse doesn't hover enough over the trigger
						Scheduler.cancel(this.Popup); // cancel the popup
					Scheduler.callLater(this, 500, Delegate.create(this, function(){ // delay execution so the popup hides only when mouse not moving between the trigger and popup
						if(!Mouse.over(this.__tooltip) && !Mouse.over(this.__trigger))
							this.Close();
					}));
				})
			break;
		}
	
		this.Popup = function(){ // calculates the tip's proper position and pops it up
			if(!this.__opened){
				this.__opened = true;
				var top=0, left=0, offsetObj = this.__trigger, offsetWidth = parseInt(this.__frame.offsetWidth), offsetHeight = parseInt(this.__frame.offsetHeight);
				if(BrowserDetect.browser=="Explorer" && this.__tooltip.lastChild.nodeName.toUpperCase()!="IFRAME") // IE combobox overlapping issue
					this.__tooltip.appendChild(WUtility.createElement("IFRAME", {frameBorder:"no", scrolling:"no"}, {"opacity":0, zIndex:-9999, filter:"alpha(opacity=0)", position:"absolute", top:"0px", left:"0px", width:this.__frame.offsetWidth+"px", height:this.__frame.offsetHeight+"px"}));
				var offset = Element.getOffset(this.__trigger);
				//Debug("Offset: top = " + offset.top + ", left = " + offset.left + ", bottom = " + offset.bottom + ", right = " + offset.right);
				var overlap = 2;
				switch(this.options.position.toUpperCase()){
					case "B":
						top 	= offset.top + this.__trigger.offsetHeight - overlap;
						left 	= (offset.left + (this.__trigger.offsetWidth  - offsetWidth) / 2) + 1;
					break;
					default:
					case "T":
						top		= 	top	= offset.top - offsetHeight + overlap;
						left	= (offset.left + (this.__trigger.offsetWidth - offsetWidth) / 2) + 1;
					break;
					case "R":
						top		= offset.top + (this.__trigger.offsetHeight - offsetHeight) / 2;
						left 	= offset.right - overlap;
					break;
					case "L":
						top		= offset.top + (this.__trigger.offsetHeight - offsetHeight) / 2;
						left	= offset.left -offsetWidth + overlap;
					break;
				}
				top = top < 0 ? 0 : top;
				left = left < 0 ? 0 : left;
				WUtility.applyStyle(this.__tooltip, {top:top + "px", left:left + "px"})
			}
		}
		
		this.Close = function(){ // moves it out of sight
			if(this.__opened){
				this.__opened = false;
				WUtility.applyStyle(this.__tooltip, {top:"-9999px", left:"-9999px"});
			}
		}
		/*if(this.__opened) // if it's popped by default, pops it up
			this.Popup();
		else{
			this.Close();
		}*/
		return;
	}
	function createTooltip(element, trigger){
		new toolTip(element, trigger);
	}
	
	/* tabs for use inside tooltips */
	function WTipTab(element){
			element = $(element);
			this.WTipTabElement = element;
			this.WTipTabCount = 0;
			this.WTipTabTabs = null;
			this.WTipTabNavi = null;
			this.WTipTabActiveTab = 0;
		}
		// Add a new tab. If tabs are not inited yet, this creates a container that will contain all the tabs.
		// If more than one tabs are added, this creates a paging-like navigation.
		WTipTab.prototype.addTab = function(options){
			if(this.WTipTabCount == 0){ // if no tabs are added yet,
				this.WTipTabTabs = WUtility.createElement("DIV"); // create container
				this.WTipTabElement.appendChild(this.WTipTabTabs);
			}
			this.WTipTabCount ++; // count the tabs
			if(this.WTipTabCount>1 && !this.WTipTabNavi){ // if more than one tabs are present
				options.naviBg = options.naviBg || "#f0f0f0";
				options.naviBorder = options.naviBorder || "#e0e0e0";
				this.WTipTabNavi = WUtility.createElement("DIV", {}, {"marginTop":"2px", "padding":"2px", "fontSize":"10px", "backgroundColor":options.naviBg, "border":"1px solid "+options.naviBorder}); // create navigation
				this.WTipTabElement.appendChild(this.WTipTabNavi);
			}
			var newTab = WUtility.createElement("DIV"); // create the actual tab
			//alert(options.content);
			var uContent = unescape(options.content); // get the content
			newTab.innerHTML = uContent; // add content to tab
			this.WTipTabTabs.appendChild(newTab); // add tab to container
			
			if(BrowserDetect.browser == "Explorer"){
				if(BrowserDetect.version<7)
					pngfix2(newTab, "image"); // fix PNGs if ie
				uContent.evalScripts(); // evaluate scripts inside new tab
			}
			this.redraw(); // redraw the tabs and navi if necessary
		}
		WTipTab.prototype.setActiveTab = function(tabId){ // sets the active tab
			if(Validator.range(tabId, 0, this.WTipTabTabs.childNodes.length))
				this.WTipTabActiveTab = tabId;
		}
		WTipTab.prototype.redraw = function(){ //redraw the entire tabs with navigation
			for(var i=0; i<this.WTipTabTabs.childNodes.length; i++){
				WUtility.applyStyle(this.WTipTabTabs.childNodes[i], {"display":(i==this.WTipTabActiveTab?"block":"none")}); // show active, hide others
			}
			if(this.WTipTabNavi){ // if there is a navi
				this.WTipTabNavi.innerHTML = ""; // empty it
				
				var naviLeft = WUtility.createElement("A"); // create links
				naviLeft.appendChild(WUtility.createElement("IMG", {"alt":"&laquo;", "title":"Pagina anterioara", "src":"/city/imagini/arrow_simple_l.png"}));
				var naviRight = WUtility.createElement("A");
				naviRight.appendChild(WUtility.createElement("IMG", {"alt":"&raquo;", "title":"Pagina urmatoare", "src":"/city/imagini/arrow_simple_r.png"}));
				
				var text = document.createTextNode(" Pagina " + (this.WTipTabActiveTab+1) + " din " + this.WTipTabCount + " ");  // create text
				
				naviLeft.onclick = Delegate.create(this, function(){ // make links work
					if(this.WTipTabActiveTab>0){
						//Debug("navigating left");
						this.setActiveTab(this.WTipTabActiveTab-1);
						this.redraw();
					}
				});
				naviRight.onclick = Delegate.create(this, function(){
					if(this.WTipTabActiveTab<this.WTipTabTabs.childNodes.length-1){
						//Debug("navigating right");
						this.setActiveTab(this.WTipTabActiveTab+1);
						this.redraw();
					}
				});
				
				this.WTipTabNavi.appendChild(naviLeft); // redraw navi
				this.WTipTabNavi.appendChild(text);
				this.WTipTabNavi.appendChild(naviRight);
			}
		}
	
	
	
	function WTip(id, options){
		this.trigger = id;
		this.id = WUtility.randomId(8);
		this.options = options;
		this.options.skin = this.options.skin || "black"
		this.options.position = (this.options.position || "T").toUpperCase();
		this.options.mode = (this.options.mode || "body").toLowerCase();
		this.inited = false;
		WTip.INSTANCES.push(this);
	}
	WTip.prototype.init = function(){
		if(this.inited)
			return true;
		this.trigger = $(this.trigger);
		if(!this.trigger)
			return false;
		var content = this.content = document.body.appendChild(WUtility.createElement("DIV", {id:this.id+"_content"}, {position:"absolute", "zIndex":999999, width:"1px", height:"1px", top:WTip.NOSHOW+"px", left:WTip.NOSHOW+"px"}));
		if(this.options.mode == "local") // if tooltip is inside forms, its important the fields the tip might contain stay inside the forms, so tooltip is created before the trigger in the DOM tree
			this.content = Element.insertBefore(this.trigger, content);
		else
			this.content = document.body.appendChild(content); // append tooltip to the end of the dom tree
		this.frame = [];
		this.frame[0] = this.content.appendChild(WUtility.createElement("TABLE", {"border":0, "cellpadding":0, "cellspacing":0}));
		this.frame[1] = this.frame[0].appendChild(WUtility.createElement("TBODY"));
		var cells = [[], [], []];
		var rows = [];
		rows[0] = this.frame[1].appendChild(WUtility.createElement("TR"));
		rows[1] = this.frame[1].appendChild(WUtility.createElement("TR"));
		rows[2] = this.frame[1].appendChild(WUtility.createElement("TR"));
		cells[0][0] = rows[0].appendChild(WUtility.createElement("TD", {}, {width:"17px", height:"17px"}));
		cells[0][1] = rows[0].appendChild(WUtility.createElement("TD", {align:"center"}, {height:"17px", backgroundImage:"url(/imagini/tooltip/"+this.options.skin+"/t.gif)", backgroundPosition:"bottom left", backgroundRepeat:"repeat-x"}));
		cells[0][2] = rows[0].appendChild(WUtility.createElement("TD", {}, {width:"17px", height:"17px"}));
		cells[1][0] = rows[1].appendChild(WUtility.createElement("TD", {}, {width:"17px", backgroundImage:"url(/imagini/tooltip/"+this.options.skin+"/l.gif)", backgroundPosition:"top right", backgroundRepeat:"repeat-y"}));
		cells[1][1] = rows[1].appendChild(WUtility.createElement("TD", {}, {backgroundImage:"url(/imagini/tooltip/"+this.options.skin+"/m.jpg)", backgroundPosition:"top left", backgroundRepeat:"repeat"}));
		cells[1][2] = rows[1].appendChild(WUtility.createElement("TD", {}, {width:"17px", backgroundImage:"url(/imagini/tooltip/"+this.options.skin+"/r.gif)", backgroundPosition:"top left", backgroundRepeat:"repeat-y"}));
		cells[2][0] = rows[2].appendChild(WUtility.createElement("TD", {}, {width:"17px", height:"17px"}));
		cells[2][1] = rows[2].appendChild(WUtility.createElement("TD", {align:"center"}, {height:"17px", backgroundImage:"url(/imagini/tooltip/"+this.options.skin+"/b.gif)", backgroundPosition:"top left", backgroundRepeat:"repeat-x"}));
		cells[2][2] = rows[2].appendChild(WUtility.createElement("TD", {}, {width:"17px", height:"17px"}));
		cells[0][0].appendChild(WUtility.createElement("IMG", {src:"/imagini/tooltip/"+this.options.skin+"/tl.png", width:"17", height:"17"}));
		cells[0][2].appendChild(WUtility.createElement("IMG", {src:"/imagini/tooltip/"+this.options.skin+"/tr.png", width:"17", height:"17"}));
		cells[2][0].appendChild(WUtility.createElement("IMG", {src:"/imagini/tooltip/"+this.options.skin+"/bl.png", width:"17", height:"17"}));
		cells[2][2].appendChild(WUtility.createElement("IMG", {src:"/imagini/tooltip/"+this.options.skin+"/br.png", width:"17", height:"17"}));
		var tmpClose = cells[0][2].appendChild(WUtility.createElement("IMG", {src:"/imagini/tooltip/"+this.options.skin+"/close.png", "title":"Inchide"}, {position:"absolute", right:"10px", top:"10px", width:"7px", height:"7px", cursor:"pointer", zIndex:"10"}));
		tmpClose.onclick = Delegate.create(this, function(){ this.hide() });
		//var uContent = unescape(this.options.content);
		this.tabs = new WTipTab(cells[1][1]);
		this.tabs.addTab({"content":this.options.content});
		//cells[1][1].innerHTML = uContent;
		/*if(BrowserDetect.browser == "Explorer" && BrowserDetect.version<7)
			pngfix2(cells[1][1], "image");
		uContent.evalScripts();*/
		
		
		
		
		switch(this.options.position.toUpperCase()){ // depending on tooltip's position around the object, set up it's tip
			case "B":
				var tmpCell = cells[0][1];
				var tmpTip = "t";
			break;
			default:
			case "T":
				var tmpCell = cells[2][1];
				var tmpTip = "b";
			break;
			case "R":
				var tmpCell = cells[1][0];
				var tmpTip = "l";
			break;
			case "L":
				var tmpCell = cells[1][2];
				var tmpTip = "r";
			break;
		}
		this.tip = tmpCell.appendChild(WUtility.createElement("IMG", {"src":"/imagini/tooltip/"+this.options.skin+"/tip_"+tmpTip+".png"}, {width:"17px", height:"17px", position:"relative"}));
		this.trigger.onmouseover = Delegate.create(this, function(){
			Scheduler.callLater(this, 500, this.show); // needs a little hover time before popping up
		});
		this.content.onmouseout = this.trigger.onmouseout = Delegate.create(this, function(e){
			if(Scheduler.isPending(this.show)) // if mouse doesn't hover enough over the trigger
				Scheduler.cancel(this.show); // cancel the popup
			Scheduler.callLater(this, 500, Delegate.create(this, function(){ // delay execution so the popup hides only when mouse not moving between the trigger and popup
				if(!Mouse.over(this.content) && !Mouse.over(this.trigger))
					this.hide();
			}));
		})
		//var tmpDim = Element.getOffset(this.frame);
		//Debug(Element.getCSSStyleAttribute(this.frame, "width") + ", " + Element.getCSSStyleAttribute(this.frame, "height"));
		this.inited = true;
	}
	WTip.prototype.show = function(){
		//Debug("Popup");
		if(this.content.lastChild.nodeName.toUpperCase()!="IFRAME"){ // IE combobox overlapping issue + make container the same size as the content itself
			WUtility.applyStyle(this.content, {width:this.frame[0].offsetWidth+"px", height:this.frame[0].offsetHeight+"px"});
			this.content.appendChild(WUtility.createElement("IFRAME", {frameBorder:"yes", scrolling:"no"}, {"opacity":0, zIndex:-9999, filter:"alpha(opacity=0)", position:"absolute", top:"0px", left:"0px", width:this.frame[0].offsetWidth+"px", height:this.frame[0].offsetHeight+"px"}));
		}
		var offset = Element.getOffset(this.trigger);
		//Debug("Offset: top:" + offset.top + ", left: " + offset.left + ", bottom: " + offset.bottom + ", right: " + offset.right + ", width: " + offset.width + ", height: " + offset.height);
		var offsetWidth = parseInt(this.frame[0].offsetWidth), offsetHeight = parseInt(this.frame[0].offsetHeight);
		//Debug("Tooltip: width: " + offsetWidth + ", height: " + offsetHeight);
		var overlap = 2;
		var top = 0, left = 0;
		switch(this.options.position.toUpperCase()){
			case "B":
				top 	= offset.top + this.trigger.offsetHeight - overlap;
				left 	= (offset.left + (this.trigger.offsetWidth  - offsetWidth) / 2) + 1;
			break;
			case "T":
				top		= offset.top - offsetHeight + overlap;
				left	= (offset.left + (this.trigger.offsetWidth - offsetWidth) / 2) + 1;
			break;
			case "R":
				top		= offset.top + (this.trigger.offsetHeight - offsetHeight) / 2;
				left 	= offset.right - overlap;
			break;
			case "L":
				top		= offset.top + (this.trigger.offsetHeight - offsetHeight) / 2;
				left	= offset.left -offsetWidth + overlap;
			break;
		}
		// adjust the tooltip and its tip if off viewport bounds
		WUtility.applyStyle(this.tip, {left:"0px", top:"0px"});
		var inner = Window.getInner(); //x,y
		var tipMovt = [Math.abs((offsetWidth-42)/2), Math.abs((offsetHeight-42)/2)]; // the tooltip's tip can move this far in eighter direction without overlapping the tooltip's corners
		//Debug("Inner: " + inner[0] + "x" + inner[1]);
		if(this.options.position=="T" || this.options.position=="B"){
			if(left < offset.scrollX){
				//Debug("Out on the left");
				WUtility.applyStyle(this.tip, {left:-Math.min(Math.abs(offset.scrollX-left), tipMovt[0])+2+"px"});
				left = offset.scrollX-8;
			}else if(left+offsetWidth>inner[0]+offset.scrollX){
				//Debug("Out on the right");
				var tmpOffset = (left+offsetWidth) - (inner[0]+offset.scrollX);
				WUtility.applyStyle(this.tip, {left:Math.min(tmpOffset, tipMovt[0])-2+"px"});
				left = (inner[0]+offset.scrollX) - offsetWidth - 5;
			}
		}
		if(this.options.position=="L" || this.options.position=="R"){
			if(top < offset.scrollY){
				//Debug("Out on the top");
				WUtility.applyStyle(this.tip, {top:-Math.min(Math.abs(offset.scrollY-top), tipMovt[1])+6+"px"});
				top =offset.scrollY-8;
			}else if(top+offsetHeight>inner[1]+offset.scrollY){
				//Debug("Out on the bottom");
				var tmpOffset = (top+offsetHeight) - (inner[1] + offset.scrollY);
				WUtility.applyStyle(this.tip, {top:Math.min(tmpOffset, tipMovt[1])-8+"px"});
				top = (inner[1]+offset.scrollY)-offsetHeight+8;
			}
		}
		//Debug("Top: " + top + ", left: " + left);
		WUtility.applyStyle(this.content, {top:top + "px", left:left + "px"})
	}
	WTip.prototype.hide = function(){
		//Debug("Popdown");
		WUtility.applyStyle(this.content, {top:WTip.NOSHOW+"px", left:WTip.NOSHOW+"px"});
	}
	WTip.destroy = function(tip){
		Element.remove(tip.content);
		delete tip;
	}
	WTip.INSTANCES = [];
	WTip.NOSHOW = -99999;
	WTip.initAll = function(){
		//alert("initing wtips")
		for(var i=0; i<WTip.INSTANCES.length; i++)
			WTip.INSTANCES[i].init();
	}
	
	/** Browser window manipulation */
	function Window(){
		throw 'RuntimeException: Window is a static utility class and may not be instantiated';
	}
	
	Window.mail = function(address){
		window.location.href = "mailto:" + Base64.decode(address);
	}
	
	
	/** Get rendered width and height of the loaded document */
	Window.getDocDim = function(){
		d = document.documentElement ? document.documentElement : document.body;
		//alert(window.nodeName);
		return {w:d.scrollWidth, h:d.scrollHeight}
	}
	
	/** Get window inner */
	Window.getInner = function() {
		/*var x,y;
		if (self.innerHeight) // all except Explorer
		{
			x = self.innerWidth;
			y = self.innerHeight;
		}
		else if (document.documentElement && document.documentElement.clientHeight)
			// Explorer 6 Strict Mode
		{
			x = document.documentElement.clientWidth;
			y = document.documentElement.clientHeight;
		}
		else if (document.body) // other Explorers
		{
			x = document.body.clientWidth;
			y = document.body.clientHeight;
		}
		return [x,y];*/
		var el = document.body.appendChild(WUtility.createElement("DIV", {}, {position:"absolute", width:"100%", height:"100%", top:"0px", left:"0px"}));
		var result = [el.offsetWidth, el.offsetHeight];
		Element.remove(el);
		return result;
	}
	/** Resize to inner */
	Window.resize = function(w, h, x, y) {
		// make sure we have a final x/y value
		// pick one or the other windows value, not both
		if (x==undefined) x = window.screenLeft || window.screenX;
		if (y==undefined) y = window.screenTop || window.screenY;
		// for now, move the window to the top left
		// then resize to the maximum viewable dimension possible
		window.moveTo(0,0);
		window.resizeTo(screen.availWidth,screen.availHeight);
		// now that we have set the browser to it's biggest possible size
		// get the inner dimensions.  the offset is the difference.
		var inner = Window.getInner();
		var ox = screen.availWidth-inner[0];
		var oy = screen.availHeight-inner[1];
		// now that we have an offset value, size the browser
		// and position it
		window.resizeTo(w+ox, h+oy);
		window.moveTo(x,y);
	}
	Window.open = function(url, options){
		var opts = "width=1, height=1";
		opts += options ? (","+options) : "";
		window.open(url, "", opts);
	}
	
	
	
	
	/** Class for handling mouse events. Static. */
	function Mouse(){
		throw 'RuntimeException: Mouse is a static utility class and may not be instantiated';
	}
	
	/** Updates two globals that hold the current mouse position. Internal, no need to be called. */
	Mouse.capture = function(e){
		e = e ? e : window.event;
		var mouse = Event.mouse(e);
		//Debug("Mouse.capture: " + mouse);
		Mouse.x = mouse.x;
		Mouse.y = mouse.y;
	}
	
	/** Checks if mouse is over an element */
	Mouse.over = function(element){
		var offset = Element.getOffset(element);
		var result = false;
		if(offset.top < Mouse.y && Mouse.y < offset.bottom && offset.left < Mouse.x && Mouse.x < offset.right)
			result = true;
		//Debug("Event: x=" + mouse.x + ", y=" + mouse.y + "offset: t=" + offset.top + ", l=" + offset.left + ", b=" + offset.bottom + ", r=" + offset.right + ", over = " + result);
		return result;
	}
	
	/** Start capturing mouse events. */
	Mouse.init = function(){
		if (document.layers) { // Netscape
			document.captureEvents(Event.MOUSEMOVE);
			document.onmousemove = Mouse.capture;
		} else if (document.all) { // Internet Explorer
			document.onmousemove = Mouse.capture;
		} else if (document.getElementById) { // Netcsape 6 && Firefox
			document.onmousemove = Mouse.capture;
		}
	}
	Mouse.x = 0; // Horizontal position of the mouse on the screen
	Mouse.y = 0; // Vertical position of the mouse on the screen
	
	function WTree(id, options){
		this.element = id;
		options = options == undefined ? {} : options;
		this.options = options;
		this.options.prefix = options.prefix || "";
		if(options.fskin)
			this.options.skin = options.fskin;
		else
			this.options.skin = this.options.prefix + "/imagini/wtree/" + (this.options.skin || "bizjobs") + "/";
		this.options.cookie = "wtree_"+id;
		WTree.INSTANCES.push(this);
	}
	WTree.prototype.init = function(){
		if((this.element = $(this.element))==undefined) return false;
		WUtility.cleanEmptyTextNodes(this.element);
		//alert("Nodes cleaned");
		WUtility.traverse(this.element, Delegate.create(this, WTree.initNode));
		if(this.options.cookie){
			WTree.setMap(this.element, Cookie.get(this.options.cookie));
		}
		Show(this.element);
	}
	WTree.prototype.hasSubMenus = function(element){
		var has = false;
		for(var i=0; i<element.childNodes.length; i++){
			if(element.childNodes[i].nodeName == "DIV"){
				has = true;
				break;
			}
		}
		return has;
	}
	WTree.prototype.toggle = function(element){
		element.className = (element.className == WTree.CLASS_CLOSED) ? WTree.CLASS_OPEN : WTree.CLASS_CLOSED;
		if(this.options.cookie){
			Cookie.set(this.options.cookie, WTree.getMap(this.element));
		}
	}
	WTree.prototype.collapseAll = function(){
		WUtility.traverse(this.element, Delegate.create(this, WTree.collapse));
	}
	WTree.getMap = function(root){
		var map = (root.className == WTree.CLASS_OPEN) ? "1" : (root.className == WTree.CLASS_CLOSED ? "0" : "");
		if(root.backingObject.hasSubMenus(root)){
			for(var i=0; i<root.childNodes.length; i++){
				map += WTree.getMap(root.childNodes[i]);
			}
		}
		return map;
	}
	WTree.mapLength = function(root){
		var length = (root != root.backingObject.element && root.backingObject.hasSubMenus(root)) ? 1 : 0;
		if(root.backingObject.hasSubMenus(root)){
			for(var i=0; i<root.childNodes.length; i++){
				length += WTree.mapLength(root.childNodes[i]);
			}
		}
		return length;
	}
	WTree.setMap = function(root, map){
		var mapL = WTree.mapLength(root);
		if(map.length == mapL){
			function setMapRecursive(root, map){
				if(root != root.backingObject.element && root.backingObject.hasSubMenus(root)){
					var flag = parseInt(map.slice(0, 1));
					map = map.slice(1, map.length);
					switch(flag){
						case 0:
							if(root.className != WTree.CLASS_CLOSED)
								root.firstChild.onclick();
						break;
						case 1:
							if(root.className == WTree.CLASS_CLOSED)
								root.firstChild.onclick();
							else if(root.className == "")
								root.className = WTree.CLASS_OPEN;
						break;
					}
					root.className = parseInt(flag) ? WTree.CLASS_OPEN : WTree.CLASS_CLOSED;
				}
				if(root.backingObject.hasSubMenus(root)){
					for(var i=0; i<root.childNodes.length; i++){
						map = setMapRecursive(root.childNodes[i], map);
					}
				}
				return map;
			}
			setMapRecursive(root, map);
			return true;
		}else{
			Cookie.unset(root.backingObject.options.cookie);
			root.backingObject.collapseAll(root);
			return false;
		}
	}
	WTree.initNode = function(node){
		try{ node.backingObject = this;	}catch(e){}
		if(node.nodeName == "DIV" && node!=this.element){
			if(this.hasSubMenus(node)){
				var trigger = WUtility.createElement("A", {"class":WTree.CLASS_BULLET}, {"textDecoration":"none"});
				trigger.appendChild(WUtility.createElement("IMG", {"src":this.options.skin+(node.className==WTree.CLASS_CLOSED ? WTree.IMAGE_CLOSED : WTree.IMAGE_OPEN)}, {}));
				trigger.appendChild(document.createTextNode(" "));
				trigger.appendChild(node.firstChild);
				Element.insertBefore(node.firstChild, trigger);
				//node.firstChild.appendChild
				//var n = Element.insertBefore(node.firstChild, WUtility.createElement("IMG", {"class":WTree.CLASS_BULLET, "src":this.options.skin+(node.className==WTree.CLASS_CLOSED ? WTree.IMAGE_CLOSED : WTree.IMAGE_OPEN)}, {})); // = "<img src='/city/imagini/directory/nolines_plus.gif' class='bullet' onclick='alert(this.backingObject)'>" + node.innerHTML;
				//n.backingObject = this;
				//n.onclick = function(){
				trigger.backingObject = this;
				trigger.onclick = function(){
					this.backingObject.toggle(this.parentNode);
					this.firstChild.src = this.backingObject.options.skin + (this.firstChild.src.search(WTree.IMAGE_CLOSED)>-1 ? WTree.IMAGE_OPEN : WTree.IMAGE_CLOSED);
				}
			}/*else{
				var n = Element.insertBefore(node.firstChild, WUtility.createElement("IMG", {"class":WTree.CLASS_BULLET, "src":this.options.skin+WTree.IMAGE_BLANK}, {})); // = "<img src='/city/imagini/directory/nolines_plus.gif' class='bullet' onclick='alert(this.backingObject)'>" + node.innerHTML;
			}*/
		}
	}
	WTree.collapse = function(node){
		if(this.hasSubMenus(node) && node != this.element){
			node.firstChild.onclick();
		}
	}
	WTree.INSTANCES = [];
	WTree.CLASS_OPEN = "WTreeNodeOpen";
	WTree.CLASS_CLOSED = "WTreeNodeClosed";
	WTree.CLASS_BULLET = "WTreeBullet";
	WTree.IMAGE_OPEN = "nolines_minus.gif";
	WTree.IMAGE_CLOSED = "nolines_plus.gif";
	WTree.IMAGE_BLANK = "empty.gif";
	WTree.initAll = function(){
		for(var i=0; i<WTree.INSTANCES.length; i++){
			WTree.INSTANCES[i].init();
		}
	}
	
	function WSimpleGallery(options){ // simple javascript gallery
		this.id = "WSimpleGallery"+WUtility.randomId(8);
		this.options = options;
		this.options.interval = this.options.interval || Math.rand(5000, 7000);
		this.options.bgcolor = this.options.bgcolor || "FFFFFF";
		if(this.options.width == undefined || this.options.height == undefined || this.options.images == undefined || !Validator.isArray(this.options.images))
			return false;
		document.write("<div id='"+this.id+"' style='background-color:#"+this.options.bgcolor+"; position:relative; width:"+options.width+"px; height:"+options.height+"px; overflow:hidden;'></div></div>");
		WSimpleGallery.INSTANCES.push(this);
	}
	WSimpleGallery.prototype.init = function(){
		this.container = $(this.id);
		this.images = [];
		for(var i=0; i<this.options.images.length; i++){
			var tmpImg = WUtility.createElement("IMG", {"src":this.options.images[i]}, {"position":"relative", "display":"none"});
			tmpImg.backingObject = this;
			tmpImg.onload = function(){
				this.interval = setInterval(Delegate.create(this, function(){
					if(this.width>0){ // loop till loaded
						clearInterval(this.interval);
						var iW = Math.round((this.backingObject.options.width - this.width) / 2); //center
						var iH =  Math.round((this.backingObject.options.height - this.height) / 2);
						WUtility.applyStyle(this, {left:iW+"px", top:iH+"px"});
					}
				 }), 100);
			};
			this.container.appendChild(tmpImg);
			this.images[i] = tmpImg;
		}
		WUtility.applyStyle(this.container, {"cursor":"pointer"});
		this.container.onclick = Delegate.create(this, function(){
			if(this.options.url)
				window.location.replace(this.options.url);
			else
				this.togglePlay();
		});
		this.play();
	}
	WSimpleGallery.prototype.play = function(){
		this.status = WSimpleGallery.STATUS_PLAYING;
		this.swap();
		this.interval = setInterval(Delegate.create(this, this.swap), this.options.interval);
	}
	WSimpleGallery.prototype.stop = function(){
		this.status = WSimpleGallery.STATUS_STOPPED;
		clearInterval(this.interval);
	}
	WSimpleGallery.prototype.togglePlay = function(){
		if(this.status == WSimpleGallery.STATUS_PLAYING)
			this.stop();
		else
			this.play();
	}
	WSimpleGallery.prototype.swap = function(){
		if(this.activeImage == undefined){
			this.activeImage = 0;
			WUtility.applyStyle(this.images[this.activeImage], {"display":""});
		}else{
			WUtility.applyStyle(this.images[this.activeImage], {"display":"none"});
			this.activeImage = (this.activeImage + 1) % this.images.length;
			WUtility.applyStyle(this.images[this.activeImage], {"display":""});
		}
	}
	WSimpleGallery.initAll = function(){
		//alert("initing wtabs")
		for(var i=0; i<WSimpleGallery.INSTANCES.length; i++)
			WSimpleGallery.INSTANCES[i].init();
	}
	WSimpleGallery.INSTANCES = [];
	WSimpleGallery.STATUS_PLAYING = "Playing";
	WSimpleGallery.STATUS_STOPPED = "Stopped";
	
	
	// MULTIPLE ONLOAD EVENTS START---------------------------------------------------------------------------------
	window.onloadListeners=new Array();
	window.onUnloadListeners=new Array();
	window.addOnLoadListener = function (scope, listener, position) {
		//Makes a function run on page load
		//alert("adding listener" + listener);
		position = (typeof(position)=="number" ? position : window.onloadListeners.length);
		window.onloadListeners.splice(position, 0, {f:listener, s:scope, a:Array.prototype.slice.call(arguments, 2)});
	}
	window.addOnUnloadListener = function (scope, listener) {
		//Makes a function run on page load
		//alert("adding listener");
		window.onUnloadListeners[window.onUnloadListeners.length]={f:listener, s:scope, a:Array.prototype.slice.call(arguments, 2)};
	}
	window.triggerOnLoadEvent = function(){
		// Trigger the listener functions in the specified scope
		//alert("Page loaded, triggering " + window.onloadListeners.length + " listeners.");
		for(var i=0;i<window.onloadListeners.length;i++){
			//alert(i+"-t) " + window.onloadListeners[i].f);
			var listener = window.onloadListeners[i];
			listener.f.apply(listener.s, listener.a);
		}
	}
	window.triggerOnUnloadEvent = function(){
		// Trigger the listener functions in the specified scope
		//alert("Page loaded, triggering " + window.onloadListeners.length + " listeners.");
		for(var i=0;i<window.onUnloadListeners.length;i++){
			var listener = window.onUnloadListeners[i];
			listener.f.apply(listener.s, listener.a);
		}
	}
	Event.observe(window, "load", triggerOnLoadEvent, false);
	Event.observe(window, "unload", triggerOnUnloadEvent, false);
	// MULTIPLE ONLOAD EVENTS END---------------------------------------------------------------------------------
	
	window.addOnLoadListener(window, WTip.initAll); // initialize westend tooltips
	//window.addOnLoadListener(window, WMap.initAll); // init all maps
	window.addOnLoadListener(window, Element.mirror); // initialize mirror inputs
	window.addOnLoadListener(window, Mouse.init); // make browser capture mouse coordinates and store them in Mouse.x,Mouse.y
	window.addOnLoadListener(window, WTabs.initAll);
	window.addOnLoadListener(window, WTree.initAll); // initialize westend trees
	window.addOnLoadListener(window, WLink.initAll); // initialize links between tooltips
	window.addOnLoadListener(window, WSimpleGallery.initAll);
	window.addOnLoadListener(window, WCryptoText.initAll);
	
	Scheduler.run(50); // initialize scheduler, see Scheduler class above
}
