/***
	begin class vector
***/
function Vector(x, y)
{
	this.x = x;
	this.y = y;
	this.add = Vector_add;
	this.substract = Vector_substract;
	this.copy = Vector_copy;
}

function Vector_add(v2)
{
	this.x += v2.x;
	this.y += v2.y;
}
function Vector_substract(v2)
{
	this.x -= v2.x;
	this.y -= v2.y;
}
function Vector_copy()
{
	return new Vector(this.x,this.y);
}


/**************************************
	Array object extension
**************************************/

Array.prototype.removeAt = function (index)
{
	if (index >= this.length)
		return;
	for(var i =index ; i< this.length - 1;i++)
			this[i] = this[i+1];
	this.pop();
	return this;
};

Array.prototype.remove = function (obj)
{
	if (obj == null)
		return;
	for(var i=0;i<this.length;i++)
	{
		if (this[i] == obj)
			this.removeAt(i);
	}
	return this;
};

Array.prototype.indexOf = function (obj, fromIndex)
{
	if (!fromIndex)
		fromIndex = 0;
	for (var i=fromIndex;i<this.length;i++)
		if (this[i] == obj)
			return i;
	return -1;
};
if (!Array.prototype.map)
{
	Array.prototype.map = function (callback)
	{
		var res = [];
		for (var i =0; i< this.length;i++)
			res.push(callback(this[i]));
		return res;
	}	
	
}



/*****
	end class vector
****/



function EventDispatcherFireCallbacks(e)
{
	if (!e)
		e = event;
	var evDisp = this.lk_eventDispatcher;
	for (var i=0;i < evDisp.length;i++)
	{
		this.tmpMethod = evDisp[i];
		this.tmpMethod(e);
	}
}

var Event = {
	addListener : function(obj, eventName, callback){
		if (!obj || !eventName || !callback)
			return false;
		if (obj.addEventListener) {
			obj.addEventListener (eventName,callback,false);
			return true;
		/*} else if (obj.attachEvent) {
			return obj.attachEvent ("on"+eventName,callback);
		*/
		} else {
			
			if (!obj["lk_eventdispatcher_on"+eventName])
			{
				var last_event = obj["on"+eventName];
				obj["on"+eventName] = function(e){
					if (!e)
						e = event;
					var array = this["lk_eventdispatcher_on"+eventName];
					for (var i=0;i<array.length;i++)
					{
						this.tmpMethod = array[i];
						this.tmpMethod(e);
					}
				};	
				obj["lk_eventdispatcher_on"+eventName] = new Array();
				if (last_event)	
					obj["lk_eventdispatcher_on"+eventName].push(last_event);
			}
			if (obj["lk_eventdispatcher_on"+eventName].indexOf(callback) == -1)
				obj["lk_eventdispatcher_on"+eventName].push(callback);
		}
	}
	,removeListener : function(obj,eventName, callback){
		if (!obj || !eventName || !callback)
			return false;
		if (obj.removeEventListener){
			obj.removeEventListener (eventName,callback,false);
			return true;
		/*}else if (obj.detachEvent){
			return obj.detachEvent(eventName,callback);
		*/
		}else{
			if (obj["lk_eventdispatcher_on"+eventName])
			{
				var pos = obj["lk_eventdispatcher_on"+eventName].indexOf(callback);
				if (pos != -1)
				{
					obj["lk_eventdispatcher_on"+eventName].removeAt(pos);
					return true;
				}
				return false;
			}
		}
	}
	,fireMouseEvent : function (obj, eventName)
	{
		if(obj.addEventListener && obj.dispatchEvent)
		{
			var evt = document.createEvent("MouseEvents");
			evt.initMouseEvent(eventName, true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
			obj.dispatchEvent(evt);
		}
		else if (obj["on"+eventName])
		{
			obj["on"+eventName]();
		}	
		
	}
	
};
Event.addListener(window,"load",function(e) {DomChanged(document.body);});

function DomChanged(htmlObj)
{
	for (var i=0;i<DomChanged.listeners.length;i++)
	{
		if (DomChanged.listeners[i].domChanged)
		{
			DomChanged.listeners[i].domChanged(htmlObj);
		}
		else
		{
			DomChanged.listeners[i](htmlObj);
		}
	}
}
function ClearElement(element)
{
	for (var i=0;i<DomChanged.listeners.length;i++)
	{
		if (DomChanged.listeners[i].clearElement)
		{
			DomChanged.listeners[i].clearElement(element);
		}
	}
}
DomChanged.listeners = new Array();
DomChanged.addListener = function(listener)
{
	if (DomChanged.listeners.indexOf(listener) == -1)
	{
		DomChanged.listeners.push(listener);
	}
}
DomChanged.removeListener = function(listener)
{
	DomChanged.listeners.remove(listener);
}


function ifEnterDo(f, e, param)
{
	var keyCode = getKeyCode(e);
	if (keyCode == 13)
	{
		try	
		{
			f(param);
		}
		catch(e)
		{}
		if (e && e.stopPropagation) {
			e.stopPropagation();
			e.preventDefault();
		}
		return false;
	}	
}

var baseDate = new Date("2000/01/01 00:00:00");
function getCookie (name) 
{
	var arg = name + "=";
	var alen = arg.length;
	var clen = document.cookie.length;
	var i = 0;

	while (i < clen) 
	{
		var j = i + alen;
		if (document.cookie.substring(i, j) == arg)
			return getCookieVal (j);

		i = document.cookie.indexOf(" ", i) + 1;
		if (i == 0)
		break;
	}
	return null;
}

function getCookieVal (offset) 
{
	var endstr = document.cookie.indexOf (";", offset);
	if (endstr == -1)
		endstr = document.cookie.length;
	return unescape(document.cookie.substring(offset, endstr));
}

function setCookie (name, value) 
{
	var argv = setCookie.arguments;
	var argc = setCookie.arguments.length;
	var expires = (argc > 2) ? argv[2] : null;
	var path = (argc > 3) ? argv[3] : null;
	var domain = (argc > 4) ? argv[4] : null;
	var secure = (argc > 5) ? argv[5] : false;
	document.cookie = name + "=" + escape (value) +	((expires == null) ? "" : ("; expires=" + expires.toGMTString())) +	((path == null) ? "" : ("; path=" + path)) +
	((domain == null) ? "" : ("; domain=" + domain)) +	((secure == true) ? "; secure" : "");
}


var utilsIncludedFiles = new Array();
utilsIncludedFiles["utils.js"] = true;

function includeOnce(jsFileName)
{
	if (!utilsIncludedFiles[jsFileName])
	{
		document.write('<script type="text/javascript" language="javascript" src="/js/'+jsFileName+'"></script>');
		utilsIncludedFiles[jsFileName] = true;
/*		var jsInclude = document.createElement("script");
		jsInclude.setAttribute("type","text/javascript");
		jsInclude.src = "/js/"+jsFileName;
		document.getElementsByTagName("HEAD")[0].appendChild(jsInclude);
*/		
	}
}
var configValues = {};
includeOnce("current_config.js");

function linkcss(cssName)
{
	document.write ('<link rel="stylesheet" type="text/css" href="/css/'+cssName+'.css" />');
	if (navigator.appName.indexOf("Explorer") != -1) 
		document.write ('<link rel="stylesheet" type="text/css" href="/css/'+cssName+'IE.css" />');
}

function findPosSize(obj)
{
	var pos = findPos(obj);
	pos.width = obj.offsetWidth;
	pos.height = obj.offsetHeight;
	pos.x1 = pos.x + pos.width;
	pos.y1 = pos.y + pos.height;
	return pos;
}
function findPos(obj)
{
	var pos = new Vector(0,0);
	
	if (obj != null){
		var tmp = obj;
		while (tmp.parentNode && tmp.parentNode != document.body && tmp.parentNode != document.documentElement)
		{
			tmp = tmp.parentNode;
			if (tmp.scrollLeft)
				pos.x -= tmp.scrollLeft;
			if (tmp.scrollTop)
				pos.y -= tmp.scrollTop;
		}
		if (obj.offsetParent)
		{
			while (obj.offsetParent)
			{
				pos.x += obj.offsetLeft;
				pos.y += obj.offsetTop;
				obj = obj.offsetParent;
			}
		}
		else if (obj.x)
		{
			pos.x = obj.x;
			pos.y = obj.y;
		}
	}
	return pos;
}

function isIE()
{
	return navigator.appName && navigator.appName.indexOf("Microsoft") != -1;//document.all?true:false;
}
function getIEVersion()
{
	var ua = navigator.userAgent;
	var re  = /MSIE ([0-9]+)([\.0-9]*)/;
	var tmp = re.exec(ua);
	if (tmp)
	    return tmp[1];
	return 999;
}
function sprintf()
{
	if (arguments == null || arguments.length < 1)
		return "";
	var arg_num = 1;
	var str = arguments[0];
	var strRet = "";
	var myRE = /%([+\- #])?(\d+)?(\.\d+)?([hlL])?([cdieEfgbGosuxX%])(.*)$/;
	
	while(found = myRE.exec(str))
	{
		var itemFlags = found[1];
		var fillWithCeros = (found[2]?found[2].charAt(0) == "0":false);
		var itemWidth = (found[2]?parseInt(found[2],10):0);
		var itemPrecission = (found[3]?parseInt(found[3].substr(1),10):false);
	
		var itemModifiers = found[4]; //nos lo pasamos por el forro porque no hay tipos en JS
		var itemType = found[5];
		var itemRightSide = found[6];
		var itemReplacement= "";
		if (itemType == "%")
		{
			itemReplacement = "%";
		}
		else
		{
			if (arg_num >= arguments.length)
				return strRet+str;
			var val = arguments[arg_num++];
			if (itemType.match(/[ideEfgGo]/))
			{
				if (itemFlags && itemFlags.indexOf(" ") != -1 && val >= 0)
					itemReplacement = " ";
				else if(itemFlags && itemFlags.indexOf("+") != -1 && val >= 0)
					itemReplacement = "+";
			}
			switch (itemType)
			{
				case 'c': 
							itemReplacement = String.fromCharCode(parseInt(val));
					break;
				case 'i':
				case 'd':
							itemReplacement += val.toString(10);
					break;
				case 'b':
							itemReplacement += val.toString(2);
					break;
				case 'u':
							itemReplacement = Math.abs(val).toString(10);
					break;
				case 'E':
				case 'e': 
							var numDigits = Math.floor(Math.log(Math.abs(val))/Math.log(10));
							val = val / Math.pow(10,numDigits);
							if (!(itemPrecission === false))
							{
								val = Math.round(val * Math.pow(10,itemPrecission))/Math.pow(10,itemPrecission);
							}
							if( itemFlags.indexOf("#") != -1 && Math.floor(val) == val )
							{
								val = ""+val+".0";
							}
							itemReplacement += val+itemType+numDigits;
					break;
				case 'f': case 'g': case 'G': 
							if (!(itemPrecission === false))
							{
								val = Math.round(val * Math.pow(10,itemPrecission))/Math.pow(10,itemPrecission);
							}
							if( itemFlags && itemFlags.indexOf("#") != -1 && Math.floor(val) == val )
							{
								val = ""+val+".0";
							}
							itemReplacement += val;
					break;
				case 'x': 
				case 'X': 
							if (itemFlags && itemFlags.indexOf("#") != -1 && val != 0)
								itemReplacement = "0x";
							itemReplacement += Math.abs(val).toString(16).toLowerCase();
							if (itemType == "X")
								itemReplacement = itemReplacement.toUpperCase();
					break;
				case 'o': 
							itemReplacement += val.toString(8).toLowerCase();
							
							if (itemFlags && itemFlags.indexOf("#") != -1 && val != 0)
							{
								if (itemReplacement[0].match(/[\-+ ]/))
									itemReplacement = itemReplacement[0]+"0"+itemReplacement.substr(1);
								else
									itemReplacement = "0"+itemReplacement;
							}
					break;
				case 's': 
							itemReplacement = val;
							if (!(itemPrecission === false) && val.length > itemPrecission)
							{
								itemReplacement = val.substr(0,itemPrecission);
							}
					break;
			}
			if (itemWidth > 0)
			{
				if (fillWithCeros && itemType.match(/[iduEebfGgoxX]/))
				{
					itemWidth = Math.max(itemWidth - itemReplacement.length,0);
					var cerosTxt = "";
					for(var i = 0;i<itemWidth;i++)
					{
						cerosTxt += "0";
					}
					if (itemReplacement.charAt(0).match(/[+\- ]/))
						itemReplacement = itemReplacement.charAt(0) + cerosTxt + itemReplacement.substr(1);
					else if (itemReplacement.match(/^0[xX].*/))
						itemReplacement = itemReplacement.substr(0,2) + cerosTxt + itemReplacement.substr(2);
					else
						itemReplacement = cerosTxt + itemReplacement;
				}
				else if (itemFlags && itemFlags.indexOf("-") != -1)
				{
					for(var i=itemReplacement.length;i<itemWidth;i++)
						itemReplacement += " ";
				}
				else
				{
					itemWidth = Math.max(itemWidth - itemReplacement.length,0);
					for(var i=0;i<itemWidth;i++)
						itemReplacement = " "+itemReplacement;
				}
			}

		}
		strRet += str.substr(0,found.index) + itemReplacement;
		str = itemRightSide;
	}
	return strRet+str;
}

function parseDate(strDate)
{
	var dt = new Date();
	dt.setTime(Date.parse(strDate));
	return dt;
}

function removeClass(obj, className)
{
	obj.className = obj.className.replace(new RegExp("\\b"+className+"\\b",""));
}
function applyClass(obj, className)
{
	if (!obj.className.match(new RegExp("\\b"+className+"\\b")))
		obj.className += " "+className;
}
function applyAndRemoveClass(obj,toRemove, toApply)
{
	obj.className = obj.className.replace(new RegExp("\\b"+toRemove+"\\b"),"");
	applyClass(obj,toApply);
}
function matchClass(classStr, className)
{
	if (!classStr)
		return false;
	return classStr.match(new RegExp("\\b"+className+"\\b"));
}
function getChildsOfClassRecursive(parentObj,clas)
{
	var obj = [];
	var ret = [];
	
	if (!parentObj || !parentObj.childNodes)
		return;
	for (var i=parentObj.childNodes.length-1;i>=0;i--)
	{
		if (parentObj.childNodes[i])
			obj.push(parentObj.childNodes[i]);
	}
	while(obj.length > 0)
	{
		var currObj = obj.pop();
		if (matchClass(currObj.className,clas))
			ret.push(currObj);
		if (currObj.childNodes)
			for (var i=currObj.childNodes.length-1;i>=0;i--)
			{
				if(currObj.childNodes[i])
					obj.push(currObj.childNodes[i]);
			}
	}
	return ret;
	
}
function getChildsOfClass(parentObj, clas, recursive)
{
	if (recursive)
	{
		return getChildsOfClassRecursive(parentObj,clas);
	}
	else
	{
		var res = new Array();
		if (parentObj && parentObj.childNodes)
		{
			for(var i =0;i<parentObj.childNodes.length;i++)
			{
				if (matchClass(parentObj.childNodes[i].className,clas))
					res.push(parentObj.childNodes[i]);
			}
		}
		return res;
	}
}
function getParentOfClass(childObj, clas)
{
	var objTmp = childObj;
	while (objTmp && objTmp.parentNode && !matchClass(objTmp.className,clas))
		objTmp = objTmp.parentNode;
	if (matchClass(objTmp.className,clas))
		return objTmp;
	else
		return null;
}
function getFirstChildOfClassRecursive(parentObj, clas)
{
	var obj = [];
	if (!parentObj || !parentObj.childNodes)
		return;
	for (var i=parentObj.childNodes.length-1;i>=0;i--)
	{
		if (parentObj.childNodes[i])
			obj.push(parentObj.childNodes[i]);
	}

	while(obj.length > 0)
	{
		var currObj = obj.pop();
		if (matchClass(currObj.className,clas))
			return currObj;
		if (currObj.childNodes)
			for (var i=currObj.childNodes.length-1;i>=0;i--)
			{
				if(currObj.childNodes[i])
					obj.push(currObj.childNodes[i]);
			}
	}
}
function getFirstChildOfClass(parentObj, clas, recursive)
{
	if (recursive)
	{
		return getFirstChildOfClassRecursive(parentObj, clas);
	}
	else
	{
		if (parentObj && parentObj.childNodes)
		{
			for(var i =0;i<parentObj.childNodes.length;i++)
			{
				if (matchClass(parentObj.childNodes[i].className,clas))
					return parentObj.childNodes[i];
			}
		}
		return null;
	}
}
function assignProperty(obj,property,value)
{
	if (typeof(property) == "string")
		property = property.split(".");
	var i=0;
	while(i < property.length-1 && obj)
	{
		obj = obj[property[i]];
		i++;
	}
	if (obj)
	{
		try{
			obj[property[i]] = eval(value);
		}catch(ex){
			obj[property[i]] = value;
		}
	}
};
function isset(obj)
{
	return (typeof(window[obj]) != "undefined");
}
function isChildOf(obj, presuntBastard)
{
	try
	{
		var isBastard= true;
		while (isBastard && presuntBastard && presuntBastard.parentNode)
		{
			presuntBastard = presuntBastard.parentNode;
			if (presuntBastard == obj)
				isBastard = false;
		}
		return !isBastard;
	}
	catch(e)
	{
		return false;
	}
}
function forAllChildNodes(obj,callback,param,max_level)
{
	if (max_level != null)
	{
		if (max_level == 0)
			return;
		max_level--;
	}
	if (!obj || !obj.childNodes)
		return;
	for (var i=0;i<obj.childNodes.length;i++)
	{
		callback(obj.childNodes[i],param);
	}
	for (var i=0;i<obj.childNodes.length;i++)
	{
		forAllChildNodes(obj.childNodes[i],callback,param,max_level);
	}
}
function sortNumber(a,b)
{
	return a - b;
}
function getSmallestNonCero()
{
	var ret = 0;
	for(var i=0;i<arguments.length;i++)
		if (arguments[i] && ((arguments[i] != 0 && arguments[i] < ret) || ret == 0))
			ret = arguments[i];
	return ret;
}
function getWindowSize()
{
	var winSize = new Object();
	var myWidth = 0, myHeight = 0;
  	if( typeof( window.innerWidth ) == 'number' ) {
	    //Non-IE
	    myWidth = window.innerWidth;
	    myHeight = window.innerHeight;
	} else if( document.documentElement && ( document.documentElement.clientWidth || document.documentElement.clientHeight ) ) {
	    //IE 6+ in 'standards compliant mode'
	    myWidth = document.documentElement.clientWidth;
	    myHeight = document.documentElement.clientHeight;
	} else if( document.body && ( document.body.clientWidth || document.body.clientHeight ) ) {
	    //IE 4 compatible
	    myWidth = document.body.clientWidth;
	    myHeight = document.body.clientHeight;
	}
	winSize.height = myHeight;
	winSize.width = myWidth;
	winSize.scrollHeight = Math.max(winSize.height,getSmallestNonCero(document.body.scrollHeight,document.documentElement.scrollHeight));
	winSize.scrollWidth = Math.max(winSize.width,getSmallestNonCero(document.body.scrollWidth,document.documentElement.scrollWidth));
	winSize.scrollTop = getSmallestNonCero(document.body.scrollTop,document.documentElement.scrollTop,window.pageYOffset);
	winSize.scrollLeft = getSmallestNonCero(document.body.scrollLeft,document.documentElement.scrollLeft,window.pageXOffset);
	return winSize;
}
function getOuterHTML(element)
{
	if (!getOuterHTML.tmpDiv)
	{
		getOuterHTML.tmpDiv = document.createElement("div");
	}
	getOuterHTML.tmpDiv.innerHTML = "";
	getOuterHTML.tmpDiv.appendChild(element.cloneNode(true));
	return getOuterHTML.tmpDiv.innerHTML;
}
function getStyle(obj)
{
	if( window.getComputedStyle )
		return window.getComputedStyle(obj,null);
	else if( obj.currentStyle )
		return obj.currentStyle;
	else
		return obj.style;
}

function dump(arr,maxLevel,level) {
	var dumped_text = "";
	try
	{
		if(!level) level = 0;
		if (!maxLevel || level < maxLevel)
		{	
			//The padding given at the beginning of the line.
			var level_padding = "";
			for(var j=0;j<level+1;j++) level_padding += "    ";
			
			if(typeof(arr) == 'object') { //Array/Hashes/Objects
				for(var item in arr) {
					var value = arr[item];
					
					if(typeof(value) == 'object') { //If it is an array,
						dumped_text += level_padding + "'" + item + "' ...\n";
						dumped_text += dump(value,maxLevel,level+1);
					} else if (typeof(value) == 'function'){
						dumped_text += level_padding + "'" + item + "' => function()\n";
					} else {
						dumped_text += level_padding + "'" + item + "' => \"" + value + "\"\n";
					}
				}
			} else { //Stings/Chars/Numbers etc.
				dumped_text = "===>"+arr+"<===("+typeof(arr)+")";
			}
		}
	}catch(e){dumped_text += "**err**";}
	return dumped_text;
} 
function dump(arr,maxLevel,level) {
	var dumped_text = "";
	try
	{
		if(!level) level = 0;
		if (!maxLevel || level < maxLevel)
		{	
			//The padding given at the beginning of the line.
			var level_padding = "";
			for(var j=0;j<level+1;j++) level_padding += "    ";
			
			if(typeof(arr) == 'object') { //Array/Hashes/Objects
				for(var item in arr) {
					var value = arr[item];
					
					if(typeof(value) == 'object') { //If it is an array,
						dumped_text += level_padding + "'" + item + "' ...\n";
						dumped_text += dump(value,maxLevel,level+1);
					} else if (typeof(value) == 'function'){
						dumped_text += level_padding + "'" + item + "' => function()\n";
					} else {
						dumped_text += level_padding + "'" + item + "' => \"" + value + "\"\n";
					}
				}
			} else { //Stings/Chars/Numbers etc.
				dumped_text = "===>"+arr+"<===("+typeof(arr)+")";
			}
		}
	}catch(e){dumped_text += level_padding + "'" + item + "' =>**err**\n";}
	return dumped_text;
} 
function dumpFind(arr, what,maxLevel,level, path) {
	var dumped_text = "";
	try
	{
		if(!level) 
		{
			dumpFind.processed = {};
			level = 0;
		}
		if (!path)
			path = "";
		dumpFind.processed[arr] = true;
		if (!maxLevel || level < maxLevel)
		{	
			if(typeof(arr) == 'object') { //Array/Hashes/Objects
				for(var item in arr) {
					var value = arr[item];
					
					if(typeof(value) == 'object') { //If it is an array,
						if (item.match(what))
							dumped_text += path + " --> '" + item + "' ...\n";
						if (!dumpFind.processed[value])
						{
							dumped_text += dumpFind(value,what,maxLevel,level+1,path + "/" + item);
						}
					} else if (typeof(value) == 'function'){
						if (item.match(what))
							dumped_text += path + " --> '" + item + "' = function()\n";
					} else {
						if (item.match(what) || (typeof(value) == "string" &&  value.match(what)))
							dumped_text += path + " --> '" + item + "' => \"val\"\n";
					}
				}
			} else { //Stings/Chars/Numbers etc.
				if (arr.match(what))
					dumped_text = "===>"+arr+"<===("+typeof(arr)+")";
			}
		}
	}catch(e){dumped_text += path + " --> '" + item + "' =>**err**\n";}
	return dumped_text;
} 

function makeUnselectable(div)
{
	div.onselectstart = function(e){return false;};
	div.onselect = function(e){return false;};
	div.ondblclick = function(e){return false;};
	div.onmousedown = function(e){return false;};
}

function splitWithEscape(str, splitChar, escapeChar)
{
	escapeChar = escapeChar.replace(/([\\\]\-])/g,"\\$1");
	var re = new RegExp("([^"+escapeChar+"])"+splitChar+"(.*)$");
	var reUnesc = new RegExp("["+escapeChar+"]("+splitChar+")");
	var tmp;
	var retArray = [];
	while(tmp = re.exec(str))
	{
		retArray.push(str.substr(0,tmp.index+1).replace(reUnesc,"$1"));
		str = tmp[2];
	}
	retArray.push(str);
	return retArray;
}

function setOpacity(obj, opacity) {
	
	if (!obj)
		return;
	opacity = (opacity == 100)?99.999:opacity;
	// IE/Win
	obj.style.filter = "alpha(opacity:"+opacity+")";
	// Safari<1.2, Konqueror
	obj.style.KhtmlOpacity = opacity/100;
	// Older Mozilla and Firefox
	obj.style.MozOpacity = opacity/100;
	// Safari 1.2, newer Firefox and Mozilla, CSS3
	obj.style.opacity = opacity/100;
}

function getKeyCode(event)
{
	keynum = 0;
	if(window.event) // IE
	{
		keynum = window.event.keyCode;
	}
	else if(event.which) // Netscape/Firefox/Opera
	{
		keynum = event.which;
	}
	return keynum;
}
function getMouseDelta(event)
{
	var delta = 0;
	if (!event)
		event = window.event;
	if (event.detail)
		delta = event.detail / 3;
	else if (event.wheelDelta)
	{
		delta = -event.wheelDelta / 120;
		if (window.opera)
			delta = -delta;
	}
	return delta;
}
function getDate(day,month,year)
{
    if (day < 1 || day > 31)
        return false;
    if (month < 1 || month > 12)
        return false;
    var ret = new Date(baseDate.getTime());
    ret.setFullYear(year);
    ret.setMonth(month-1);
    ret.setDate(day);
    return ret;
}

function addBrightness(color, dBrightness)
{
	if (dBrightness < -1)
		dBrightness = -1;
	if (dBrightness > 1)
		dBrightness = 1;
	if (typeof(color) == "string")
	{
		var hasSharp = false;
		if (color.charAt(0) == '#')
			hasSharp = true;
		color = color.replace(/[^0-9a-fA-F]/g,"");
		if (color.length == 3)
			color = color.charAt(0)+color.charAt(0)+color.charAt(1)+color.charAt(1)+color.charAt(2)+color.charAt(2);
		if (color.length == 6)
		{
			var r = parseInt(color.substr(0,2),16);
			var g = parseInt(color.substr(2,2),16);
			var b = parseInt(color.substr(4,2),16);
			if (dBrightness < 0)
			{
				r = (1+dBrightness) * r;
				g = (1+dBrightness) * g;
				b = (1+dBrightness) * b;
			}
			else
			{
				r = r + (255 - r) * dBrightness;
				g = g + (255 - g) * dBrightness;
				b = b + (255 - b) * dBrightness;
			}
			r = Math.round(r);
			g = Math.round(g);
			b = Math.round(b);
			return sprintf("%s%02X%02X%02X",(hasSharp?"#":""),r,g,b);
		}
		else
			return "#000000";
	}
	return "#000000";
}

function getColorByHue(angle)
{
	var angle = parseFloat(angle);
	if (!isNaN(angle))
	{
		while(angle > 360.0)
			angle -= 360.0;
		while (angle < 0)
			angle += 360.0;
		var color = {r:0,g:0,b:0};
		if (angle <= 60)
		{
			color.r = 255;
			color.b = 0;
			color.g = angle * 255 / 60;
		}
		else if (angle > 60 && angle <= 120)
		{
			color.g = 255;
			color.b = 0;
			color.r = (120 - angle) * 255 / 60;
		}
		else if (angle > 120 && angle <= 180)
		{
			color.g = 255;
			color.r = 0;
			color.b = (angle - 120) * 255 / 60;
		}
		else if (angle > 180 && angle <= 240)
		{
			color.b = 255;
			color.r = 0;
			color.g = (240-angle) * 255 / 60;
		}
		else if (angle > 240 && angle <= 300)
		{
			color.b = 255;
			color.g = 0;
			color.r = (angle - 240) * 255 / 60;
		}
		else
		{
			color.r = 255;
			color.g = 0;
			color.b = (360-angle) * 255 / 60;
		}
		color.r = Math.floor(color.r);
		color.g = Math.floor(color.g);
		color.b = Math.floor(color.b);
		return sprintf("#%02X%02X%02X",color.r,color.g,color.b); 
	
	}
	return "#000000";
}
function strReplace(from, to, str)
{
	if (typeof(from) == "object" && typeof(to) == "object")
	{
		for (var i=0 ; i < to.length && i < from.length ; i++)
		{
			str = str.replace(from[i],to[i]);
		}
	}
	else
		str = str.replace(from,to);
	return str;
}




function updateFormLabels()
{
	if (document.getElementsByTagName)
	{
		var labels = document.getElementsByTagName("label");
		for (var i=0;i<labels.length;i++)
		{
			var input;
			if (labels[i].htmlFor && (input = document.getElementById(labels[i].htmlFor)))
			{
				input.htmlLabel = labels[i];
				//alert(labels[i].innerHTML+" --> "+input.value);
			}
		}
	}
}
function updateFormLabelsIn(domElement)
{
	var labels = new Object();
	var inputs = new Object();
	var queue = new Array();
	queue.push(domElement);
	while(queue.length > 0)
	{
		var obj = queue.pop();
		for (var i=0;i<obj.childNodes.length;i++)
		{
			queue.push(obj.childNodes[i]);
		}
		if (obj.tagName && obj.tagName.toLowerCase() == "label" && obj.htmlFor)
		{
			labels[obj.htmlFor] = obj;
			if (inputs[obj.htmlFor])
				inputs[obj.htmlFor].htmlLabel = obj;
		}
		else if(obj.id)
		{
			inputs[obj.id] = obj;
			if(labels[obj.id])
				obj.htmlLabel = labels[obj.id];
		}
	}
}

DomChanged.addListener(updateFormLabelsIn);




function date2str (format, date)
{
	var formatExp = /([\\dDjlNSwzWFmMntLoYyaABgGhHiscrU])(.*)$/;
	var outStr = "";
	var found;
	while(found = formatExp.exec(format))
	{
		var element = found[1];
		outStr += format.substr(0,found.index);
		format = found[2];
		switch(element)
		{
			case 'd': outStr += sprintf("%02d",date.getDate());
				break;
			case 'D': outStr += date2str.getShortWeekDay(date.getDay());
				break;
			case 'j': outStr += date.getDate();
				break;
			case 'l': outStr += date2str.getWeekDay(date.getDay());
				break;
			case 'N': outStr += (date.getDay() == 0)?7:date.getDay();
				break;
			case 'S': 
					var ten = date.getDate() % 10;
					if (ten == 1)
						outStr += "st";
					else if (ten == 2)
						outStr += "nd";
					else if (ten == 3)
						outStr += "rd";
					else 
						outStr += "th";
				break;
			case 'w': outStr += date.getDay();
				break;
			case 'z': 
					var day0 = new Date(date);
					day0.setDate(1);
					day0.setMonth(0);
					var days = Math.floor((date.getTime()-day0.getTime()) / (24*3600000));
					outStr += days;
				break;
			case 'F': outStr += date2str.getMonth(date.getMonth());
				break;
			case 'm': outStr += sprintf("%02d",date.getMonth()+1);
				break;
			case 'M': outStr += date2str.getShortMonth(date.getMonth());
				break;
			case 'n': outStr += date.getMonth()+1;
				break;
			case 't': 
					var tmp = new Date(date);
					tmp.setDate(1);
					tmp.setMonth(tmp.getMonth()+1);
					tmp.setDate(0);
					outStr += tmp.getDate();
				break;
			case 'L': 	
					outStr += (date.getFullYear()%4 == 0?1:0);
				break;
			case 'o': 
			case 'Y': outStr += sprintf("%04d",date.getFullYear());
				break;
			case 'y': outStr += sprintf("%02d",date.getFullYear()%100);
				break;
			case 'a': outStr += (date.getHours() < 12?"am":"pm");
				break;
			case 'A': outStr += (date.getHours() < 12?"AM":"PM");
				break;
			case 'B': outStr += Math.floor((date.getUTCHours()*60 + date.getUTCMinutes())*1000/(24*60));
				break;
			case 'g': 
					var hours = date.getHours()%12; 
					if (hours == 0)
						hours = 12;
					outStr += hours;
				break;
			case 'G': outStr += date.getHours();
				break;
			case 'h': 
					var hours = date.getHours()%12; 
					if (hours == 0)
						hours = 12;
					outStr += sprintf("%02d",hours);
				break;
			case 'H': outStr += sprintf("%02d",date.getHours());
				break;
			case 'i': outStr += sprintf("%02d",date.getMinutes());
				break;
			case 's': outStr += sprintf("%02d",date.getSeconds());
				break;
			case 'c': outStr += sprintf("%04d-%02d-%02dT%02d:%02d:%02d%s%02d:%02d",date.getFullYear(),date.getMonth()+1,date.getDate(),date.getHours(),date.getMinutes(),date.getSeconds(),date.getTimezoneOffset() < 0?"+":"-",Math.floor(Math.abs(date.getTimezoneOffset()/60)),Math.abs(date.getTimezoneOffset()%60));
				break;
			case 'r': outStr += date.toString();
				break;
			case 'U': outStr += Math.floor(date.getTime()/1000);
				break;
			case '\\':
				if (format.length > 0)
				{
					outStr += format.charAt(0);
					format = format.substr(1);
				}
				else
					return false;
				break;
		}
	}
	return outStr;
}

date2str.getShortWeekDay = function (day)
{
	if (day >= 0 && day < 7)
		return date2str.shortWeekDayNames[day];
	else
		return (day + 6)%7;
};
date2str.setShortWeekDays = function (days)
{
	date2str.shortWeekDayNames = days;
};
date2str.setShortWeekDays(["D","L","M","M","J","V","S"]);

date2str.getWeekDay = function (day)
{
	if (day >= 0 && day < 7)
		return date2str.weekDayNames[day];
	else
		return (day+6)%7;
};
date2str.setWeekDays = function (days)
{
	date2str.weekDayNames = days;
};
date2str.setWeekDays(["Domingo","Lunes","Martes","Miercoles","Jueves","Viernes","Sabado"]);


date2str.getShortMonth = function (month)
{
	if (month >= 0 && month < 12)
		return date2str.shortMonthNames[month];
	else
		return month+1;
};
date2str.setShortMonths = function (months)
{
	date2str.shortMonthNames = months;
};
date2str.setShortMonths(["Ene","Feb","Mar","Abr","May","Jun","Jul","Ago","Sep","Oct","Nov","Dic"]);

date2str.getMonth = function (month)
{
	if (month >= 0 && month < 12)
		return date2str.weekMonths[month];
	else
		return month+1;
};
date2str.setMonths = function (months)
{
	date2str.weekMonths = months;
};
date2str.setMonths(["Enero","Febrero","Marzo","Abril","Mayo","Junio","Julio","Agosto","Septiembre","Octubre","Noviembre","Diciembre"]);

function resetTime(date)
{
	date.setHours(0);
	date.setMinutes(0);
	date.setSeconds(0);
	date.setMilliseconds(0);
}
function str2date (format, str)
{
	var outStr = "";
	var date = new Date(baseDate);
	var formatExp = /([dDjlNSwzWFmMntLoYyaABgGhHiscr\\U])(.*)$/;
	var found;
	var pm = false;
	var pmHour = false;
	while (found = formatExp.exec(format))
	{
		var before = format.substr(0,found.index);
		if (str.indexOf(before) === 0)
			str = str.substr(before.length);
		var element = found[1];
		format = found[2];
		if (element.match(/[djNwzmntLoYyBgGhHiscU]/))
		{
			var i=0;
			while (i < str.length && !str.charAt(i).match(/\d/))
				i++;
			if (i!=0)
				str = str.substr(i);			
			if (str.length == 0)
				return false;
		}
		switch(element)
		{
			case 'd': 
			case 'j': 				
				var tmp;
				if (str.substr(0,2).match(/\d{2}/) && (tmp = parseInt(str.substr(0,2),10)) <= 31)
				{
					date.setDate(tmp);
					str = str.substr(2);
				}
				else
				{
					tmp = parseInt(str.substr(0,1),10);
					date.setDate(tmp);
					str = str.substr(1);
				}
				break;
			case 'N': str = str.substr(1);
				break;
			case 'w': str = str.substr(1);
				break;
			case 'z': 
				var digit = 0;
				while (digit < str.length && digit < 3 && str.charAt(digit).match(/\d/))
					digit++;
				digit++;
				var yearDay = parseInt(str.substr(0,digit),10);
				date.setDate(1);
				date.setMonth(0);
				date.setDate(yearDay);
				str = str.substr(digit);
				break;
			case 'm': 
			case 'n': 
				var tmp;
				if (str.substr(0,2).match(/\d{2}/) && (tmp = parseInt(str.substr(0,2),10)) < 13)
				{	
					date.setMonth(tmp-1);
					date.setMonth(tmp-1);
					str = str.substr(2);
				}
				else
				{
					date.setMonth(parseInt(str.substr(0,1))-1);
					date.setMonth(parseInt(str.substr(0,1))-1);
					str = str.substr(1);
				}
				break;
			case 't': 
					if (str.substr(0,2).match(/\d{2}/))
						str = str.substr(2);
					else
						return false;
				break;
			case 'L': 	
					if (str.charAt(0).match(/[01]/))
						str = str.substr(1);
					else
						return false;
				break;
			case 'o': 
			case 'Y': 
				if(str.substr(0,4).match(/\d{4}/))
				{
					date.setFullYear(parseInt(str.substr(0,4),10));
					str = str.substr(4);
				}
				else
					return false;
				break;
			case 'y': 
				var tmp;
				var tmpExp = /(\d{1,2})(.*)$/;
				if(tmp = tmpExp.exec(str))
				{
					date.setYear(parseInt(tmp[1],10));
					str = tmp[2];
				}
				else
					return false;
				break;
			case 'B': 
				var digit = 0;
				while (digit < str.length && digit < 3 && str.charAt(digit).match(/\d/))
					digit++;
				digit++;
				var swatch = parseInt(str.substr(0,digit),10)*24.0*60/1000;
				date.setHours(Math.floor(swatch/60));
				date.setMinutes(Math.floor(swatch%60));
				date.setSeconds(Math.floor((swatch-Math.floor(swatch))*60));
				str = str.substr(digit);
				break;
			case 'h':
			case 'g': 
				var tmp;
				if (str.substr(0,2).match(/\d{2}/) && (tmp = parseInt(str.substr(0,2),10)) < 13)
					str = str.substr(2);
				else
				{
					tmp = parseInt(str.substr(0,1));
					str = str.substr(1);
				}
				if (tmp == 12)
					tmp = 0;
				pmHour = tmp;
				if (pm)
					date.setHours(pmHour+12);
				else
					date.setHours(pmHour);
				break;
			case 'G': 
			case 'H': 				
				var tmp;
				if (str.substr(0,2).match(/\d{2}/) && (tmp = parseInt(str.substr(0,2),10)) < 24)
					str = str.substr(2);
				else
				{
					tmp = parseInt(str.substr(0,1));
					str = str.substr(1);
				}
				date.setHours(tmp);
				break;
			case 'a':
			case 'A':
				var pm = /([pPaA][mM])(.*)$/;
				var tmp;
				if (tmp = pm.exec(str))
				{
					str = tmp[2];
					if (tmp[1].toLowerCase() == "pm")
					{
						pm = true;
						if (pmHour !== false)
							date.setHours(pmHour+12);
					}
					else
						pm = false;
				}
				else
					return false;
				break;
			case 'i': 
				var tmp;
				var tmpExp = /(\d{1,2})(.*)$/;
				if (tmp = tmpExp.exec(str))
				{
					date.setMinutes(parseInt(tmp[1]));
					str = tmp[2];
				}
				else
					return false;
				break;
			case 's':
				var tmp;
				var tmpExp = /(\d{1,2})(.*)$/;
				if (tmp = tmpExp.exec(str))
				{
					date.setSeconds(parseInt(tmp[1]));
					str = tmp[2];
				}
				else
					return false;
				break;
			case 'c': 
				var tmpExp =  /(\d{1,4})-(\d{1,2})-(\d{1,2})T(\d{1,2}):(\d{1,2}):(\d{1,2})([+-Z])(?:(\d{1,2}):(\d{1,2}))?(.*)$/;
				var tmp;
				if (tmp = tmpExp.exec(str))
				{
					//we put the date in utc
					date.setUTCFullYear(parseInt(tmp[1]));
					date.setUTCDate(1);
					date.setUTCMonth(parseInt(tmp[2])-1);
					date.setUTCDate(parseInt(tmp[3]));
					date.setUTCHours(parseInt(tmp[4]));
					date.setUTCMinutes(parseInt(tmp[5]));
					date.setUTCSeconds(parseInt(tmp[6]));
					
					//and then apply the offset
					if (tmp[7] != "Z")
					{
						var offsetMinutes = (tmp[7] == "+"?-1:1)*(60*parseInt(tmp[8])+parseInt(tmp[9]));
						date.setMinutes(date.getMinutes()+offsetMinutes);
						
					}
					
				}
				else
					return false;
				break;
			case 'r': 
				//@@@ implementar esto
				return false;
				break;
			case 'U': 
				var digit = 0;
				while (digit < str.length && str.charAt(digit).match(/\d/))
					digit++;
				digit++;
				var time = parseInt(str.substr(0,digit));
				date.setTime(time*1000);
				str = str.substr(digit);
				break;
			case '\\':
				if (format.length > 0)
				{
					str = str.substr(str.indexOf(format.charAt(0)));
					format = format.substr(1);
				}
				break;
		}
	}
	return date;
}


function Dictionary()
{}

Dictionary.texts = {
	"yes":"si",
	"no":"no",
	"ok":"aceptar",
	"cancel":"cancelar",
	"save":"guardar",
	"delete":"borrar",
	"modify":"modificar",
	"close":"cerrar"
};


Dictionary.addText = function(code, text)
{
	Dictionary.texts[code] = text;
};
Dictionary.addTextIfEmpty = function(code, text)
{
	if (!Dictionary.texts[code])
		Dictionary.texts[code] = text;
};
Dictionary.addTexts = function(textHash)
{
	for (var i in textHash)
	{
		Dictionary.texts[i] = textHash[i];
	}
};
Dictionary.addTextsIfEmpty = function(textHash)
{
	for (var i in textHash)
	{
		if (!Dictionary.texts[i])
			Dictionary.texts[i] = textHash[i];
	}
};
Dictionary.getText = function(code)
{
	if (Dictionary.texts[code])
		return Dictionary.texts[code];
	else
		return code;
};
Dictionary.domChanged = function(domElement)
{
	var queue = new Array();
	queue.push(domElement);
	while(queue.length > 0)
	{
		var obj = queue.pop();
		for (var i=0;i<obj.childNodes.length;i++)
		{
			queue.push(obj.childNodes[i]);
		}
		var dict;
		if (obj.getAttribute && (dict = obj.getAttribute("dict")))
		{
			var dicts = dict.split(",");
			for (var i=0;i<dicts.length;i++)
			{
				var entrance = dicts[i].split("=");
				obj[entrance[0]] = Dictionary.getText(entrance[1]);
			}
		}
	}
	
};
DomChanged.addListener(Dictionary);


function addDebugLine(element,str,maxLines)
{
	if(!element)
		return;
	if (!isNaN(maxLines))
	{
		var tmp = element.value;
		tmp = tmp.split("\n");
		while(tmp.length >= maxLines)
			tmp.shift();
		element.value = tmp.join("\n");
	}
	element.value += str+"\n";
}


/*********************************************************
	Default event handler, with the cancel function
*********************************************************/
function EventArgs(sender)
{
	this.cancelled = false;
	this.sender = sender;
}
EventArgs.prototype.cancel = function ()
{
	this.cancelled = true;
};

/*********************************************************
	listener functions 
*********************************************************/
function AddListener(listener)
{
	if (!this.listeners)
		this.listeners = [];
	for (var i =0;i<this.listeners.length;i++)
		if (listener == this.listeners[i])
			return;
	this.listeners.push(listener);
}
function RemoveListener(listener)
{	
	var i = 0;
	var found = false;
	while (i < this.listeners && !found)
	{
		if (this.listeners[i] == listener)
			found = true;
		i++;
	}
	while (i+1 < this.listeners)
	{
		this.listeners[i] = this.listeners[i+1];
	}
	if (found)
	{
		this.listeners.pop();
	}
}
function FireEvent(eventName)
{
	if (this && this.listeners)
	{
		var e = new EventArgs(this);
		for (var i=0;i<this.listeners.length;i++)
			if (this.listeners[i] && this.listeners[i][eventName])
				this.listeners[i][eventName](e);
	}
}
function doXml(str)
{
	return str.replace(/&/g,"&amp;").replace(/"/g,'&quot;').replace(/</g,"$lt;").replace(/>/g,"&gt;");
}
function checkEnter(e)
{ 
	var characterCode; //literal character code will be stored in this variable
	
	if(e){ //if which property of event object is supported (NN4)
		e = e;
		characterCode = e.which; //character code is contained in NN4's which property
	}
	else{
	e = event;
	characterCode = e.keyCode; //character code is contained in IE's keyCode property
	}
	
	if(characterCode == 13) //if generated character code is equal to ascii 13 (if enter key)
		document.login_form.submit();

}


function loadAutoProps()
{
	forAllChildNodes(document.body,function(obj){
		if (obj && obj.getAttribute && obj.getAttribute("autoprops"))
		{
			var tmpAct = splitWithEscape(obj.getAttribute("autoprops"),";","\\");
			for (var j=0;j<tmpAct.length;j++)
			{
				var prop = tmpAct[j].substr(0,tmpAct[j].indexOf(":"));
				var val = tmpAct[j].substr(tmpAct[j].indexOf(":")+1);
				assignProperty(obj,prop.split("."),val);
			}
		}
	});
}
Event.addListener(window,"load",loadAutoProps);

function returnFalse()
{return false;}
function stopSelection()
{
    document.onselectstart = returnFalse;
	document.onselect = returnFalse;
	document.ondblclick = returnFalse;
	document.onmousedown = returnFalse;
	document.ondragstart = returnFalse;
}
function startSelection()
{
    document.onselectstart = null;
	document.onselect = null;
	document.ondblclick = null;
	document.onmousedown = null;
	document.ondragstart = null;
}

function applyHTMLToObj(elem, text)
{
	ClearElement(elem);
	elem.innerHTML = text;
	DomChanged(elem);
}

function overRelatedIsChild(e,obj)
{
	if (!e)
		e = window.event;
	var relatedTarget = e.relatedTarget;
	if (e.relatedTarget)
		relatedTarget = e.fromElement;
	return isChildOf(obj,relatedTarget) || obj == relatedTarget;
}
function outRelatedIsChild(e,obj)
{
	if (!e)
		e = window.event;
	var relatedTarget = e.relatedTarget;
	if (!e.relatedTarget)
		relatedTarget = e.toElement;
	return isChildOf(obj,relatedTarget) || obj == relatedTarget;
}

/**************** RAUL ******************/
var nav = window.Event ? true : false;
function acceptNum(evt) 
{
	var key = nav ? evt.which : evt.keyCode;
	return (key < 13 || (key >= 48 && key <= 57));
}

function open_window(url,width, height)
{
	open(url,"subwindow","resizable=yes,scrollbars=yes,width="+width+"px,height="+height+"px");
}