/**

	TÃ­tulo..: VeryTinyAJAX2 0.2, Wrapper JavaScript simple a funciones XMLHTTP para AJAX
	          e integraciÃ³n con PHP en busca de la reducciÃ³n y simplificaciÃ³n de cÃ³digo.
  Licencia: GPLv2 (http://www.gnu.org/licenses/gpl.txt)
	Autores.: Pablo RodrÃ­guez Rey (mr.xkr -en- inertinc -punto- org)
	          http://mr.xkr.inertinc.org/
            Javier Gil Motos (cucaracha -en- inertinc -punto- org)
            http://cucaracha.inertinc.org/

	Agradecimientos a Cucaracha, por darme interÃ©s en el desarrollo de webs usando
	AJAX y proveerme del ejemplo bÃ¡sico con el que estÃ¡ desarrollada esta librerÃ­a.

	MÃ³dulo de funciones cliente JavaScript.
	
	Ejemplo de usos comunes (pueden ser probados en ajax.test.php):
	
		PETICIÃ“N COMPLETA (GET ajax=eco POST data=datos):
			ajax({
				"get":{"ajax":"eco"},
				"post":{"data":"datos de ejemplo"},
				"async":function(resultado){
					alert(adump(resultado.data));
				},
				"error":function(error){
					error.show();
				}
			});
		
		PETICIÃ“N ABREVIADA EQUIVALENTE (GET ajax=eco POST data=datos):
			ajax("eco","datos de ejemplo",function(resultado){
				alert(adump(resultado.data));
			});
		
		PETICIÃ“N DE TEXTO ABREVIADA (solo campos tipo POST):
			ajax({
				"datos":"datos de ejemplo"
			},function(resultado){
				alert(adump(resultado.data));
			});

*/

// informaciÃ³n de versiÃ³n
function ajaxVersion() { return("VeryTinyAJAX2/0.2"); }

// get object id (incluida en common.js)
function gid(id) {
	try {
		if (typeof(id)=="object") return id;
		else return document.getElementById(id);
	} catch(e) {
		return(null);
	}
}

// generar un nuevo objeto XMLHttpRequest
function httpObject() {
	var xmlhttp;
	try { xmlhttp=new ActiveXObject("Msxml2.XMLHTTP"); }
	catch (e) { try { xmlhttp=new ActiveXObject("Microsoft.XMLHTTP"); }
	catch (e) { try { xmlhttp=new XMLHttpRequest(); }
	catch (e) { xmlhttp=false; } } }
	return xmlhttp;
}

// cadena de estado de la peticiÃ³n
function httpStateString(readyState) {
	switch (readyState) {
	case 0: return("Uninitialized")
	case 1: return("Loading");
	case 2: return("Loaded");
	case 3: return("Interactive");
	case 4: return("Complete");
	case 5: return("Server Crashed");
	}
}

// comprobar si las peticiones AJAX estÃ¡n soportadas por este navegador
function ajaxEnabled() {
	return (httpObject()?true:false);
}

// parsear cadena para ser enviada por GET/POST
function gescape(torg) {
	var d=""+torg;
	try { var d=d.replace(/\"/gi,"%22"); } catch(e) {}
	try { var d=d.replace(/\\/gi,"%5C"); } catch(e) {}
	try { var d=d.replace(/\?/gi,"%3F"); } catch(e) {}
	try { var d=d.replace(/&/gi,"%26"); } catch(e) {}
	try { var d=d.replace(/=/gi,"%3D"); } catch(e) {}
	try { var d=d.replace(/\+/gi,"%2B"); } catch(e) {}
	try { var d=d.replace(/ /gi,"%20"); } catch(e) {}
	return(d);
}

// hard escape: codifica aparte de los especiales,
// tambiÃ©n aquellos cuyo ASCII sea <32 o >127
function hescape(t) {
	var s=gescape(t);
	var r="";
	var c;
	for (var i=0;i<s.length;i++) {
		c=s.charCodeAt(i);
		r+=(c<32 || c>127?"%"+c.toString(16):s.charAt(i));
	}
	return r;
}

// funciÃ³n auxiliar para crear cadenas PHP sin caracteres de control
function jescape(torg) {
	var d=""+torg;
	try { var d=d.replace(/\\/gi,"\\\\"); } catch(e) {}
	try { var d=d.replace(/\"/gi,"\\\""); } catch(e) {}
	try { var d=d.replace(/\n/gi,"\\n"); } catch(e) {}
	try { var d=d.replace(/\t/gi,"\\t"); } catch(e) {}
	try { var d=d.replace(/\f/gi,"\\f"); } catch(e) {}
	try { var d=d.replace(/\r/gi,"\\r"); } catch(e) {}
	return(d);
}

// array to get
function atoget(a,extra) {
	var g="";
	for (var i in a)
		g+=(g?"&":"?")+gescape(i)+"="+gescape(a[i]);
	if (extra)
		for (var i in extra)
			g+=(g?"&":"?")+gescape(i)+"="+gescape(extra[i]);
	return g;
}

// convertir variable JavaScript a JSON
function json(a,level) {
	if (!level) level=0;
	if (a==null) return 'null';
	switch (typeof(a)) {
	case 'object':
		var s="";
		for (var i in a) s+=(s?",":"")+(a.length?'':'"'+jescape(i)+'":')+json(a[i],level+1);
		return (a.length?"[":"{")+s+(a.length?"]":"}");
	case 'boolean': return (a?'true':'false');
	case 'number': return a;
	case 'string': default: return '"'+jescape(a)+'"';
	}
	return null;
}

// peticiÃ³n AJAX
function ajax(data,realdata,func,isplain) {
	
	// convertir llamada abreviada en significado real: llamada en plano
	if (typeof(data)=="object" && typeof(realdata)=="function") {
		// configuraciÃ³n por defecto:
		ajax({
			"post":data, // datos que se enviarÃ¡n por post
			"async":realdata, // funciÃ³n de retorno asÃ­ncrona
			"showerrors":false, // se mostrarÃ¡n errores tÃ­picos
			"plain":true // la peticiÃ³n es AJAX o es de texto plano/XML
		});
		return;
	}
	
	// convertir llamada abreviada en significado real: llamada abreviada
	if (typeof(data)=="string" && typeof(func)=="function") {
		// configuraciones por defecto
		if (typeof(isplain)=="function") {
			ajax({
				"ajax":data, // comando ajax
				"data":realdata, // datos que se enviarÃ¡n
				"showerrors":true, // se mostrarÃ¡n errores tÃ­picos
				"always":func, // ejecutar esta funciÃ³n siempre (al terminar o al ocurrir un error)
				"async":isplain // funciÃ³n de retorno asÃ­ncrona
			});
		} else {
			ajax({
				"ajax":data, // comando ajax
				"data":realdata, // datos que se enviarÃ¡n
				"async":func, // funciÃ³n de retorno asÃ­ncrona
				"showerrors":true, // se mostrarÃ¡n errores tÃ­picos
				"plain":(isplain?true:false) // la peticiÃ³n es AJAX o es de texto plano/XML
			});
		}
		return;
	}

	// si no estÃ¡ soportado, cancelar peticiÃ³n
	if (!ajaxEnabled()) return false;

	// si no se especifica donde se realiza la peticiÃ³n, se presupone a si mismo
	if (data.url==undefined) {
		var url=location.href;
		if ((i=url.indexOf("?"))!=-1) url=url.substring(0,i);
		data.url=url;
	}
	
	// control de eventos HTTP
	function events(http) {
		
		// objeto resultado
		function result() {
			
			// estado de la peticiÃ³n y cadena de estado
			try { this.state=http.readyState; } catch(e) { this.state=5; }
			this.stateString=httpStateString(this.state);

			// indicar si se ha completado la operaciÃ³n
			this.complete=(http.readyState==4?true:false);

			// cÃ³digo de protocolo del servidor
			try { this.status=http.status; } catch(e) { this.status=null; }
			
			// si el estado es OK, devolver datos
			if (this.status==200) {
				this.text=http.responseText; // datos recibidos en texto plano
				this.xml=http.responseXML; // datos recibidos en XML
				this.data=null; // ausencia de datos por defecto
				try { eval("this.data="+http.responseText); }
				catch(e) { this.error=true; } // datos recibidos en JSON son preparados
			}
			
		}

		// Comprobar que la respuesta del servidor es la 200 (HTTP OK)
		var error=false;
		if (http.readyState==4) {
			try { error=(http.status!=200); }
			catch(e) { error=true; }
		}

		// crear objeto resultado
		var r=new result();
		
		// devolver evento
		if (error) {
			if (data.error || data.showerrors) {
				function result_error() {
					this.status=r.status;
					this.error=(r.status
						?"Se ha encontrado el error "+r.status+" en el servidor."
						:"El servidor no responde a la peticiÃ³n!\nPruebe dentro de unos instantes."
					);
					this.show=function(){
						if (typeof(newalert)=="function") newalert({"ico":"error","id":"verytinyajax2","msg":this.error});
						else alert(this.error);
					}
				}
				var re=new result_error();
				switch (typeof(data.error)) {
				case "boolean": re.show(); break;
				case "string":
					if (typeof(newalert)=="function") newalert(data.error);
					else alert(data.error);
					break;
				case "function": data.error(re); break;
				}
				if (always) always(re);
				if (data.showerrors && re.status) re.show();
			}
		} else {
			if (r.complete) {
				if (data.showerrors && r.error && !data.plain) {
					var alertmsg="Error en buffer de salida: No se puede procesar la peticiÃ³n AJAX";
					if (typeof(newalert)=="function") newalert({"ico":"error","id":"verytinyajax2","msg":r.text,"title":alertmsg});
					else alert(alertmsg+"\n\n"+r.text);
				}
				if (always) always(r);
				func(r);
			} else {
				if (data.events)
					data.events(r);
			}
		}
	
	}
	
	// preparar datos
	var http=httpObject();
	var async=(data.sync?false:true);
	var func=(async?data.async:data.sync);
	var always=data.always;
	var post="";
	var url=data.url;
	var urlalmp=url.indexOf("#");
	var urlalm="";
	if (urlalmp!=-1) {
		urlalm=url.substring(urlalmp);
		url=url.substring(0,urlalmp);
	}

	// si se especifica acciÃ³n, incluir parÃ¡metro GET ajax=acciÃ³n
	if (data.ajax) url+=(url.indexOf("?")<0?"?":"&")+"ajax="+data.ajax;
	
	// si se especifican parÃ¡metros GET adicionales, incluirlos
	if (data.get)
		if (typeof(data.get)=="object") {
			for (var i in data.get)
				url+=(url.indexOf("?")<0?"?":"&")+i+"="+gescape(data.get[i]);
		} else {
			url+=(url.indexOf("?")<0?"?":"&")+data.get;
		}
	
	// si se especifican datos por POST, incluirlos
	if (data.post)
		if (typeof(data.post)=="object") {
			for (var i in data.post)
				post+=(post?"&":"")+i+"="+gescape(data.post[i]);
		} else {
			post=data.post;
		}

	// si hay datos prefijados, aÃ±adir al POST en formato JSON
	if (data.data)
		post+=(post?"&":"")+"data="+gescape(json(data.data));

	// peticiÃ³n HTTP
	url+=urlalm;
	http.open((post?"POST":"GET"),url,async);
	if (async) http.onreadystatechange=function(){ events(http); };
	http.setRequestHeader('Content-Type','application/x-www-form-urlencoded; charset=UTF-8"');
	http.send(post?post:null);
	if (!async) events(http);
	
	// completado correctamente
	return true;
	
}

// mÃ©todos de xform
function xform() {

	// devuelve un valor de un campo
	this.value=function(object) {
		switch (gid(object).type) {
		case "checkbox": return(object.checked?"1":"0");
		case "select-multiple": var d=[]; for (var i=0; i<object.length; i++) if (object.options[i].selected) d.push(object.options[i].value); return(d);
		case "radio": case "button": case "select-one": case "text": case "textarea": default: return(object.value);
		}
	}
	
	// habilitar o deshabilitar la posibilidad de introducciÃ³n
	// o modificaciÃ³n de datos de un formulario completo.
	this.enabled=function(formObject,isEnabled) {
		var formObject=gid(formObject);
		for (var i=0;i<formObject.length;i++) {
			try { formObject[i].disabled=!isEnabled; } catch(e) {}
		}
	}
	
	// devuelve todos los campos y datos de un formulario en formato JSON
	this.form=function(formObject){
		var formObject=gid(formObject);
		var fields=new Object();
		for (i=0;i<formObject.length;i++) {
			if (!formObject[i].name) continue;
			if (formObject[i].type=="radio" && !formObject[i].checked) continue;
			fields[formObject[i].name]=this.value(formObject[i]);
		}
		return fields;
	}
	
	// devuelve todos los campos y datos de un lista de identificadores
	// tipo id1,id2,id3 y lo devuelve en formato JSON
	this.fields=function(fieldNames) {
		var fn=(typeof(fieldNames)=="object"?fieldNames:fieldNames.split(","));
		var fields=new Object();
		var formValue;
		for (i=0;i<fn.length;i++) {
			formValue=gid(fn[i]);
			if (!formValue) continue;
			if (formValue.type=="radio" && !formValue.checked) continue;
			fields[fn[i]]=this.value(formValue);
		}
		return fields;
	}

}

// instanciar xform
var xf=new xform();
// common.js by mr.xkr v2 rev.4
// Gracias a Binny V A (binnyva -en- hotmail -punto- com - binnyva.com) por la funciÃ³n adump.

// pequeÃ±as funciones para reducir cÃ³digo
function gid(id) {
	try {
		if (typeof(id)=="object") return id;
		else return document.getElementById(id);
	} catch(e) {
		return(null);
	}
}
function gidget(id) { return(gid(id).innerHTML); }
function gidset(id,html) { gid(id).innerHTML=html; }
function gidval(id,data) { if (typeof(data)!="undefined") gid(id).value=(data==null?"":data); else return(gid(id).type=="checkbox"?(gid(id).checked?gid(id).value:""):gid(id).value); }
function gidvals(idsdata) { for (var i in idsdata) gidval(i,idsdata[i]); }
function giddel(id) { var d=gid(id); d.parentNode.removeChild(d); }
function gidmove(id_org,id_dst) { gid(id_dst).innerHTML=gid(id_org).innerHTML; gid(id_org).innerHTML=""; }
function alter(id) { gid(id).style.display=(gid(id).style.display=="none"?"block":"none"); }
function show(id) { gid(id).style.display="block"; }
function hide(id) { gid(id).style.display="none"; }
function cell(id) { gid(id).style.display="table-cell"; }
function visible(id) { gid(id).style.visibility="visible"; }
function hidden(id) { gid(id).style.visibility="hidden"; }
function isShow(id) { return(gid(id).style.display=="block"?true:false); }
function isVisible(id) { return(gid(id).style.display!="none"?true:false); }
function showSwitch(id) { gid(id).style.display=(gid(id).style.display=="block"?"none":"block"); }

// obtener todos los datos de campos segÃºn su ID prefijados y/o sufijados
function gpreids(prefix,ids,sufix) {
	var ids=ids.split(" ");
	var a={};
	for (var i in ids)
		if (gid((prefix?prefix+"_":"")+ids[i]+(sufix?"_"+sufix:"")))
			a[ids[i]]=gidval((prefix?prefix+"_":"")+ids[i]+(sufix?"_"+sufix:""));
	return a;
}

// establecer todos los datos de campos segÃºn su ID prefijados y/o sufijados
function spreids(prefix,ids,values,sufix) {
	var ids=ids.split(" ");
	for (var i in ids)
		if (gid((prefix?prefix+"_":"")+ids[i]+(sufix?"_"+sufix:""))) {
			var o=gid((prefix?prefix+"_":"")+ids[i]+(sufix?"_"+sufix:""));
			var v=values[ids[i]];
			switch (o.type) {
			case "checkbox":
				if (parseInt(v) || (v.length>0 && v!="0")) o.checked=true;
				break;
			case "select-one":
			case "select-multiple":
				for (var j=0;j<o.options.length;j++)
					if (o.options[j].value==v) {
						gidval(o,v);
						break;
					}
				break;
			default:
				gidval(o,v);
			}
		}
}

// carga el contenido HTML de una capa y realiza reemplazos para usarla como template para ventanas o bÃºsquedas AJAX
// por defecto, los reemplazos que hace son automÃ¡ticamente de id y name con prefijo $
function gtemplate(id,replaces) {
	var s=gidget("template:"+id);
	s=s.replace(/ id=\$/gi," id=");
	s=s.replace(/ id=\'\$/gi," id='");
	s=s.replace(/ id=\"\$/gi,' id="');
	s=s.replace(/ name=\$/gi," name=");
	s=s.replace(/ name=\'\$/gi," name='");
	s=s.replace(/ name=\"\$/gi,' name="');
	if (replaces)
		for (var i in replaces)
			s=s.replace(new RegExp(i.replace(/([.?*+^$[\]\\(){}-])/g, "\\$1"),'g'),replaces[i]);
	return s;
}

// volcar el Ã¡rbol de una variable JavaScript
function adump(arr,level) {
	if (!level) level=0;
	var s="";
	var t=""; for (var j=0;j<level;j++) t+="\t";
	try {
		if (typeof(arr)=='object') {
			if (arr.nextSibling) return t+"{*}\n"; // NO devolver elementos internos del navegador
			for (var item in arr) {
				var value=arr[item];
				if (typeof(value)=='object') {
					var size=0; for (var none in value) size++;
					s+=t+'"' + item + '" = '+typeof(value)+'('+size+'):\n';
					s+=adump(value,level+1);
				} else {
					s+=t+'"' + item + '" = '+typeof(value)+'("' + value + '")\n';
				}
			}
		} else {
			s="("+typeof(arr)+") "+arr;
		}
	} catch(e) {}
	return s;
}

// funciones auxiliares
function getTop(id) { var o=gid(id); var p=0; do { p+=o.offsetTop; } while (o=o.offsetParent); return(p); }
function getLeft(id) { var o=gid(id); var p=0; do { p+=o.offsetLeft; } while (o=o.offsetParent); return(p); }
function getWidth(id) { return gid(id).offsetWidth; }
function getHeight(id) { return gid(id).offsetHeight; }
function style(id,styles) { var o=gid(id); for (var i in styles) o.style[i]=styles[i]; }

// propiedades del documento y ventana
function ieTrueBody() { return((!ischrome() && document.compatMode && document.compatMode!="BackCompat")?document.documentElement:document.body); }
function scrollLeft() { return(ieTrueBody().scrollLeft); }
function scrollTop() { return(ieTrueBody().scrollTop); }
function windowWidth() { return(document.documentElement.clientWidth?document.documentElement.clientWidth:(window.innerWidth?window.innerWidth:document.body.clientWidth)); }
function windowHeight() { return(document.documentElement.clientHeight?document.documentElement.clientHeight:(window.innerHeight?window.innerHeight:document.body.clientHeight)); }
function documentWidth() { return(document.body.clientWidth); }
function documentHeight() { return(document.body.clientHeight); }

// propiedades naturales de una imagen (tamaÃ±o real)
function naturalWidth(idimg) {
	if (typeof(gid(idimg).naturalWidth)=="number") return gid(idimg).naturalWidth
	else { var tmp=new Image(); tmp.src=gid(idimg).src; return tmp.width; }
}
function naturalHeight(idimg) {
	if (typeof(gid(idimg).naturalHeight)=="number") return gid(idimg).naturalHeight
	else { var tmp=new Image(); tmp.src=gid(idimg).src; return tmp.height; }
}

// establecer cursor
function setCursor(cursor) { document.body.style.cursor=(cursor?cursor:"auto"); }

// obtiene el ancho del borde (horizontal)
function getBorderWidth(id) {
	var wext=(parseInt(getStyle(id,"border-left-width"))+parseInt(getStyle(id,"border-right-width")));
	return (!isNaN(wext)?wext:0);
}

// obtiene el alto del borde (vertical)
function getBorderHeight(id) {
	var wext=(parseInt(getStyle(id,"border-top-width"))+parseInt(getStyle(id,"border-bottom-width")));
	return (!isNaN(wext)?wext:0);
}

// obtiene el alto del borde superior
function getBorderTopHeight(id) {
	var wext=parseInt(parseInt(getStyle(id,"border-top-width")));
	return (!isNaN(wext)?wext:0);
}

// obtiene el alto del borde inferior
function getBorderBottomHeight(id) {
	var wext=parseInt(parseInt(getStyle(id,"border-bottom-width")));
	return (!isNaN(wext)?wext:0);
}

// obtiene el ancho del padding (horizontal)
function getPaddingWidth(id) {
	var wext=(parseInt(getStyle(id,"padding-left"))+parseInt(getStyle(id,"padding-right")));
	return (!isNaN(wext)?wext:0);
}

// obtiene el alto del padding (vertical)
function getPaddingHeight(id) {
	var wext=(parseInt(getStyle(id,"padding-top"))+parseInt(getStyle(id,"padding-bottom")));
	return (!isNaN(wext)?wext:0);
}

// obtiene el estilo final computado de un elemento
function getStyle(id,styleProp) {
	var x=gid(id);
	if (x.currentStyle) { return x.currentStyle[styleProp]; }
	else if (window.getComputedStyle) { return document.defaultView.getComputedStyle(x,null).getPropertyValue(styleProp); }
	return null;
}

// ancho interno (sin mÃ¡rgenes/paddings/bordes)
function crossInnerWidth(id) {
	var element=gid(id);
	try {
		if (window.getComputedStyle(element,""))
			return(element.clientWidth-parseInt(window.getComputedStyle(element,"").getPropertyValue("padding-left"))-parseInt(window.getComputedStyle(element,"").getPropertyValue("padding-right")));
	} catch(e) {
		return(element.clientWidth-parseInt(element.currentStyle.paddingLeft)-parseInt(element.currentStyle.paddingRight));
	}
}

// alto interno (sin mÃ¡rgenes/paddings/bordes)
function crossInnerHeight(id) {
	var element=gid(id);
	try {
		if (window.getComputedStyle(element,""))
			return(element.clientHeight-parseInt(window.getComputedStyle(element,"").getPropertyValue("padding-top"))-parseInt(window.getComputedStyle(element,"").getPropertyValue("padding-bottom")));
	} catch(e) {
		return(element.clientHeight-parseInt(element.currentStyle.paddingTop)-parseInt(element.currentStyle.paddingBottom));
	}
}

// precarga de imÃ¡genes
var imagePreloadList=new Object();
function imagePreload(imageorlist) {
	var image_list=(typeof image=="string"?[imageorlist]:imageorlist);
	for (var i in image_list) {
		var image=image_list[i];
		imagePreloadList[image]={"loaded":false,"img":new Image()};
		imagePreloadList[image].img.src=image;
		imagePreloadList[image].img.onload=function(){imagePreloadList[image].loaded=true;};
	}
}

// ancho del scroll vertical
// thanks to Alexandre Gomes (Portugal)
// http://www.alexandre-gomes.com/?p=115
function scrollWidth() {

	var inner=document.createElement('p');
	inner.style.width='100%';
	inner.style.height='200px';

	var outer=document.createElement('div');
	outer.style.position='absolute';
	outer.style.top='0px';
	outer.style.left='0px';
	outer.style.visibility='hidden';
	outer.style.width='200px';
	outer.style.height='150px';
	outer.style.overflow='hidden';

	outer.appendChild(inner);
	document.body.appendChild(outer);

	var w1=inner.offsetWidth;
	outer.style.overflow='scroll';
	var w2=inner.offsetWidth;
	if (w1==w2) w2=outer.clientWidth;

	document.body.removeChild(outer);
	return(w1-w2);
}

// almacenar cookie
function setCookie(name,value,days) {
	var expires="";
	value=""+value;
	if (days) {
		var date=new Date();
		date.setTime(date.getTime()+(days*86400000));
		expires="; expires="+date.toGMTString();
	}
	document.cookie=name+"="+value.replace(/\\/gi,"\\\\").replace(/\n/gi,"\\n").replace(/;/gi,"\\,")+expires+"; path=/";
}

// obtener cookie
function getCookie(name) {
	var nameEQ=name+"=";
	var ca=document.cookie.split(';');
	for (i=0;i<ca.length;i++) {
		var c=ca[i];
		while (c.charAt(0)==' ')
			c=c.substring(1,c.length);
		if (c.indexOf(nameEQ)==0)
			return(c.substring(nameEQ.length,c.length).replace(/\\\\/gi,"\\").replace(/\\n/gi,"\n").replace(/\\,/gi,";"));
	}
	return("");
}

// borrar cookie
function delCookie(name) {
	setCookie(name,"",-1);
}

// comprobaciÃ³n de navegadores
function isie() { return (navigator.userAgent.indexOf("MSIE")!=-1); }
function ismoz() { return (navigator.userAgent.indexOf("Firefox")!=-1 || navigator.userAgent.indexOf("Iceweasel")!=-1); }
function ischrome() { return (navigator.userAgent.indexOf("Chrome")!=-1); }

// oculta todos los selects de la pÃ¡gina si es IE
function hideSelects(hidden) {
	if (!isie()) return;
	selects=document.getElementsByTagName("select");
	for (i=0;i<selects.length;i++)
		selects[i].style.visibility=(hidden?"hidden":"visible");
}

// buscar y ejecutar tags <script> embebidos
function getrunjs(data) {
	runjs(getjs(data));
}

// buscar tags <script> embebidos
function getjs(data) {
	scode="";
	while (true) {
		ss=data.toLowerCase().indexOf("<script>"); if (ss<0) break;
		es=data.toLowerCase().indexOf("<\/script>",ss+2); if (es<0) break;
		scode=scode+data.substring(ss+8,es);
		data=data.substring(0,ss)+data.substring(es+9);
	}
	return(scode);
}

// ejecutar cadena de javascript (mucho mejor que eval)
function runjs(data) {
	if (!data) return;
	var escode=document.createElement("script");
	escode.setAttribute("type","text/javascript");
	escode.text=data;
	document.getElementsByTagName("body").item(0).appendChild(escode);
}

// convertir retornos de carro en nuevas lineas HTML
function nl2br(t) {
	try { var e=/\n/gi; t=t.replace(e,"<br />"); } catch(e) {}
	return(t);
}

// id/object merge: de una lista de identificadores separadas por comas,
// mezclar sus datos con objetos JavaScript previamente existentes
function ioMerge(ids,root,obj) {
	ids=ids.split(",");
	for (i=0;i<ids.length;i++)
		if (gid(root+ids[i]))
			obj[ids[i]]=gidval(root+ids[i]);
	return(obj);
}

// object/object merge: de una lista de objetos separados por comas,
// copia los los datos del primero objeto en el segundo y devuelve este
function ooMerge(ids,obj1,obj2) {
	ids=ids.split(",");
	for (i=0;i<ids.length;i++)
		obj2[ids[i]]=obj1[ids[i]];
	return(obj2);
}

// aÃ±ade CSS al documento (no funciona bien en IE6)
function cssAdd(css) {
  var style=document.createElement("style");
  style.type="text/css";
  if (style.styleSheet) style.styleSheet.cssText=css;
  else style.appendChild(document.createTextNode(css));
  document.getElementsByTagName("head")[0].appendChild(style);
}

// array_merge: mezcla arrays puros o asociativos
// es equivalente a la funcion de PHP
function array_merge(a1,a2) {
	var a=array_copy(a1);
	var b=array_copy(a2);
	for (var i in b) a[i]=b[i];
	return a;
}

// array_remove: elimina claves de un array asociativo
function array_remove(a1,a2) {
	var a=new Object();
	var clone;
	for (var i in a1) {
		clone=true;
		for (var j in a2)
			if (i==a2[j]) {
				clone=false;
				break;
			}
		if (clone)
		a[i]=a1[i];
	}
	return a;
}

// elimina un elemento en la posiciÃ³n del indice de un array
function array_delete(a,index) {
	var n=Array();
	for (var i in a)
		if (i!=index)
			n[n.length]=a[i];
	return n;
}

// array_get: devuelve las claves de un array dada una lista de ellas
function array_get(a,list) {
	var o=new Object();
	for (var i in list)
		o[list[i]]=a[list[i]];
	return o;
}

// array_save: busca las claves de la lista en el segundo array y los mezcla con el primero
function array_save(a1,a2,list) {
	for (var i in list)
		a1[list[i]]=a2[list[i]];
	return a1;
}

// copia en profundidad de un objeto
function array_copy(o) {
	if (typeof o != "object" || o === null) return o;
	var r = o.constructor == Array ? [] : {};
	for (var i in o) r[i] = array_copy(o[i]);
	return r;
}

// aÃ±ade un objeto a un array plano
function array_push(a,o) {
	a.push(o);
}

// verifica si un array estÃ¡ vacÃ­o o no
function array_isclean(a) {
	if (!a) return true;
	for (var i in a)
		return false;
	return true;
}

// control de impresiÃ³n, sobrecargar este mÃ©todo
function doprint() { window.print(); }

// init_fast
var init_fast_func=new Array();
function init_fast(add) {
	if (add) init_fast_func[init_fast_func.length]=add;
	else { for (var i in init_fast_func) { try { init_fast_func[i](); } catch(e) {} } }
}

// onload
var init_func=new Array();
var init_func_last=window.onload;
function init(add) {
	if (add) init_func[init_func.length]=add;
	else { for (var i in init_func) { try { init_func[i](); } catch(e) {} } }
}
window.onload=function(){
	try { init_func_last(); } catch(e) {}
	try { init(); } catch(e) {}
}

// onunload
var unload_func=new Array();
var unload_func_last=window.onunload;
function unload(add) {
	if (add) unload_func[unload_func.length]=add;
	else { for (var i in unload_func) { try { unload_func[i](); } catch(e) {} } }
}
window.onunload=function(){
	try { unload_func_last(); } catch(e) {}
	try { unload(); } catch(e) {}
}

// onresize
var resize_func=new Array();
var resize_func_last=window.onresize;
function resize(add) {
	if (add) resize_func[resize_func.length]=add;
	else { for (var i in resize_func) { try { resize_func[i](); } catch(e) {} } }
}
window.onresize=function(){
	try { resize_func_last(); } catch(e) {}
	try { resize(); } catch(e) {}
}

// onkeydown
var keydown_func=new Array();
var keydown_func_last=document.onkeydown;
function keydown(p) {
	if (typeof(p)=="function") keydown_func[keydown_func.length]=p;
	else { for (var i in keydown_func) { try { keydown_func[i](p); } catch(e) {} } }
}
document.onkeydown=function(we){
	try { keydown_func_last(we); } catch(e) {}
	try { keydown(we); } catch(e) {}
}

// onkeyup
var keyup_func=new Array();
var keyup_func_last=document.onkeyup;
function keyup(p) {
	if (typeof(p)=="function") keyup_func[keyup_func.length]=p;
	else { for (var i in keyup_func) { try { keyup_func[i](p); } catch(e) {} } }
}
document.onkeyup=function(we){
	try { keyup_func_last(we); } catch(e) {}
	try { keyup(we); } catch(e) {}
}

// onscroll
var scroll_func=new Array();
var scroll_func_last=document.onscroll;
function scroll(p) {
	if (typeof(p)=="function") scroll_func[scroll_func.length]=p;
	else { for (var i in scroll_func) { try { scroll_func[i](p); } catch(e) {} } }
}
document.onscroll=function(we){
	try { scroll_func_last(we); } catch(e) {}
	try { scroll(we); } catch(e) {}
}

// onmouseup
var mouseup_func=new Array();
var mouseup_func_last=document.onmouseup;
function mouseup(p) {
	if (typeof(p)=="function") mouseup_func[mouseup_func.length]=p;
	else { for (var i in mouseup_func) { try { mouseup_func[i](p); } catch(e) {} } }
}
document.onmouseup=function(we){
	if (!we) we=window.event;
	try { mouseup_func_last(we); } catch(e) {}
	try { mouseup(we); } catch(e) {}
}

// onmousedown
var mousedown_func=new Array();
var mousedown_func_last=document.onmousedown;
function mousedown(p) {
	var ret=null;
	if (typeof(p)=="function") mousedown_func[mousedown_func.length]=p;
	else {
		for (var i in mousedown_func) { try { ret=mousedown_func[i](p); } catch(e) {} }
		if (typeof(ret)!="undefined" && typeof(ret)!="null") return(ret);
	}
}
document.onmousedown=function(we){
	var ret=null;
	if (!we) we=window.event;
	try { ret=mousedown_func_last(we); } catch(e) {}
	try { ret=mousedown(we); } catch(e) {}
	if (typeof(ret)!="undefined" && typeof(ret)!="null") return(ret);
}

// onmousemove
var mousemove_func=new Array();
var mousemove_func_last=document.onmousemove;
function mousemove(p) {
	if (typeof(p)=="function") mousemove_func[mousemove_func.length]=p;
	else { for (var i in mousemove_func) { try { mousemove_func[i](p); } catch(e) {} } }
}
document.onmousemove=function(we){
	if (!we) we=window.event;
	try { mousemove_func_last(we); } catch(e) {}
	try { mousemove(we); } catch(e) {}
}

// mouse delta
var mousewheel_func=new Array();
function mousewheel(p) {
	if (typeof(p)=="function") mousewheel_func[mousewheel_func.length]=p;
	else { for (var i in mousewheel_func) { try { mousewheel_func[i](p); } catch(e) {} } }
}
function mousewheel_eventhandler(event) {
	var delta=0;
	if (!event) event=window.event; // IE
	if (event.wheelDelta) { // IE/Opera
		delta=event.wheelDelta/120;
		// In Opera 9, delta differs in sign as compared to IE.
		if (window.opera) delta=-delta;
	} else if (event.detail) { // Mozilla
		// In Mozilla, sign of delta is different than in IE. Also, delta is multiple of 3.
		delta=-event.detail/3;
	}
	// If delta is nonzero, handle it. Basically, delta is now positive
	// if wheel was scrolled up, and negative, if wheel was scrolled down.
	if (delta) {
		//handle(delta);
		var cancel=false;
		for (var i in mousewheel_func) { try { if (mousewheel_func[i](delta,event)) cancel=true; } catch(e) {} }
	}
	// Prevent default actions caused by mouse wheel. That might be ugly,
	// but we handle scrolls somehow anyway, so don't bother here..
	if (cancel) {
		if (event.preventDefault)
			event.preventDefault();
		event.returnValue=false;
	}
}
if (window.addEventListener) window.addEventListener('DOMMouseScroll', mousewheel_eventhandler, false); // DOMMouseScroll for Mozilla
window.onmousewheel=document.onmousewheel=mousewheel_eventhandler; // IE/Opera

// habilitar/deshabilitar seleccionar texto en un elemento
function selectionEnabled(o,enable) {
	var o=gid(o);
	if (typeof o.onselectstart!="undefined") { if (enable) o.onselectstart=null; else { o.onselectstart=function(){ return false; } } } // IE
	else if (typeof o.style.MozUserSelect!="undefined") { o.style.MozUserSelect=(enable?"":"none"); } //Firefox
	else { if (enable) o.onmousedown=null; else { o.onmousedown=function(){ return false; } } } // all other navs
	o.style.cursor="default";
}

// entrada sÃ³lo numÃ©rica entera
function gInputInt(id,negatives,floating) {
	var input=gid(id);
	input.style.textAlign="right";
	input.onkeydown=function(e){
		var c=e.keyCode;
		if (c>=35 && c<=39) return true;
		if (c==8) return true;
		if (c==46) return true;
		if (c==116) return true;
		if (c==9) return true;
		if (c==13) return true;
		if (c==15) return true;
		if (floating)
			if (c==110 || c==190)
				return (this.value.indexOf(".")==-1?true:false);
		if (negatives)
			if (c==109)
				return (this.value.indexOf("-")==-1?true:false);
		if (c>=48 && c<=57) return true;
		return false;
	}
	input.onblur=function(e){
		var v=parseFloat(this.value);
		this.value=(isNaN(v)?"":v);
	}
}

// entrada sÃ³lo numÃ©rica floatante
function gInputFloat(id,negatives) {
	gInputInt(id,negatives,true);
}

// eliminar espacios de una cadena
function trim(str) {
	return (""+str).replace(/^\s*|\s*$/g,"");
}

// elimina la ruta de un nombre de fichero completo,
// y tambiÃ©n su sufijo, si se especifica y coincide
function basename(path, suffix) {
	var b=path.replace(/^.*[\/\\]/g, '');
	if (typeof(suffix) == 'string' && b.substr(b.length-suffix.length) == suffix)
		b=b.substr(0, b.length-suffix.length);
	return b;
}

// equivalente a br2nl en php
function br2nl(s) {
	return s.replace(/<br\s*\/?>/mg,"\n");
}

// mostrar un nÃºmero en formato X.XXX,XX
function spf(n) {
	var n=Math.round(n*100)/100;
	var d=Math.round((n-parseInt(n))*100);
	var x=""+parseInt(n);
	var rgx=/(\d+)(\d{3})/;
	while (rgx.test(x))
		x=x.replace(rgx,'$1'+'.'+'$2');
	return x+","+d;
}

// convierte una cadena YYYY-MM-DD HH:II:SS a DD/MM/YYYY HH:II:SS
function sqlDateSP(d) {
	if (!d || (d.length!=10 && d.length!=19)) return "";
	return d.substring(8,10)+"/"+d.substring(5,7)+"/"+d.substring(0,4)+d.substring(10);
}

// convierte una cadena DD/MM/YYYY HH:II:SS a YYYY-MM-DD HH:II:SS
function spDateSQL(d) {
	if (!d || (d.length!=10 && d.length!=19)) return "";
	return d.substring(6,10)+"-"+d.substring(3,5)+"-"+d.substring(0,2)+d.substring(10);
}

// devuelve una fecha javascript en formato DD/MM/YYYY
function spDate(f) {
	var dd=f.getDate(); if (dd<10) dd='0'+dd;
	var mm=f.getMonth()+1; if (mm<10) mm='0'+mm;
	var yyyy=f.getFullYear();
	return String(dd+"/"+mm+"/"+yyyy);
}

// devuelve la fecha actual en formato DD/MM/YYYY
function spDateNow() {
	return spDate(new Date());
}

// obtiene una fecha en formato YYYY-MM-DD de tres campos de texto con sufijos _d, _m e _y para dia, mes, aÃ±o
function gidvalFecha(id) {
	var d=intval(gidval(id+"_d"));
	var m=intval(gidval(id+"_m"));
	var y=intval(gidval(id+"_y"));
	if (isNaN(d) || d<1 || d>31) return "";
	if (isNaN(m) || m<1 || m>12) return "";
	if (isNaN(y) || y<1900 || y>3000) return "";
	return y+"-"+(m<10?"0":"")+m+"-"+(d<10?"0":"")+d;
}

// getElementsByClassName, implementaciÃ³n para IE (el Ãºnico que no lo soporta)
function getElementsByClassName(oElm, strTagName, strClassName){
	var arrElements = (strTagName == "*" && oElm.all)? oElm.all :	oElm.getElementsByTagName(strTagName);
	var arrReturnElements = new Array();
	strClassName = strClassName.replace(/\-/g, "\\-");
	var oRegExp = new RegExp("(^|\\s)" + strClassName + "(\\s|$)");
	var oElement;
	for (var i=0; i<arrElements.length; i++) {
		oElement = arrElements[i];     
		if(oRegExp.test(oElement.className))
			arrReturnElements.push(oElement);
	}
	return arrReturnElements;
}

// convierte bytes a un string fÃ¡cilmente legible
function bytesToString(bytes) {
	if (bytes >= 1099511627776) return((Math.round(bytes/10995116277.76)/100)+" TB");
	if (bytes >= 1073741824) return((Math.round(bytes/10737418.24)/100)+" GB");
	if (bytes >= 1048576) return((Math.round(bytes/10485.76)/100)+" MB");
	if (bytes >= 1024) return((Math.round(bytes/10.24)/100)+" KB");
	return(((""+bytes).length?bytes+" bytes":""));
}

// pasa cualquier cadena a entero/decimal, incluyendo nÃºmeros que comienzan con 0
function intval(t) { while (t.substring(0,1)=="0") t=t.substring(1); return parseInt(t); }
function doubleval(t) { while (t.substring(0,1)=="0") t=t.substring(1); return parseFloat(t); }
function gid(id) {
	try {
		if (typeof(id)=="object") return id;
		else return document.getElementById(id);
	} catch(e) {
		return(null);
	}
}

function comboEnabled(combo,enabled) {
	gid(combo).disabled=!enabled;
}

function comboVisible(combo,visible) {
	gid(combo).style.visibility=(visible?"visible":"hidden");
}

function comboAdd(combo,text,value,selected,sBold) {
	var combo=gid(combo);
	var selOpcion=new Option(text,value);

	selOpcion.selected=selected;

	try {
		try { combo.add(selOpcion,null); } catch(e) { combo.add(selOpcion); }
		if (sBold!=undefined) selOpcion.style.fontWeight=(sBold?"bold":"normal");
	} catch(e) {
		//alert(e+"\nError adding option ("+value+") - "+text);
		return(false);
	}

	return(true);
}

function comboReplace(combo,text,value,selected,sBold) {
	var combo=gid(combo);
	for (var i in combo.options) {
		if (combo.options[i].value==value) {
			combo.options[i].text=text;
			return true;
		}
	}
	return comboAdd(combo,text,value,selected,sBold);
}

function comboDel(combo,index) {
	combo=gid(combo);
	try {
		combo.options[index]=null;
		return(true);
	} catch(e) {
		return(false);
	}
}

function comboDelSelected(combo) {
	while (combo.selectedIndex>=0)
		comboDel(combo,combo.selectedIndex);
}

function comboClear(combo) {
	gid(combo).length=0;
}

function comboValue(combo,value,newvalue) {
	combo=gid(combo);
	if (newvalue==undefined) {
		if (combo.selectedIndex<0) return(false);
		if (value!=undefined) { combo.value=value; return true; }
		return combo.value;
	} else {
		for (var i in combo.options) {
			if (combo.options[i].value==value) {
				combo.options[i].value=newvalue;
				return true;
			}
		}
		return false;
	}
}

function comboText(combo,id,text) {
	var combo=gid(combo);
	if (typeof(id)=="undefined") {
		if (combo.selectedIndex<0) return(false);
		return(combo.options[combo.selectedIndex].text);
	} else {
		for (var i in combo.options) {
			if (combo.options[i].value==id) {
				if (typeof(text)=="undefined") return combo.options[i].text;
				else {
					combo.options[i].text=text;
					return true;
				}
			}
		}
		return false;
	}
}

function comboIndexByValue(combo,value) {
	combo=gid(combo);
	for (var i=0;i<combo.options.length;i++)
		if (combo.options[i].value==value) return(i);
	return -1;
}

function comboIndexByText(combo,text) {
	combo=gid(combo);
	for (var i=0;i<combo.options.length;i++)
		if (combo.options[i].text==text) return(i);
	return -1;
}

function comboValueExists(combo,value) {
	combo=gid(combo);
	return (comboIndexByValue(combo,value)>=0);
}

function comboTextExists(combo,text) {
	combo=gid(combo);
	return (comboIndexByText(combo,text)>=0);
}

function comboClearFill(combo,lista,valorActual,formaMostrar,indiceValor,filtro) {
	combo=gid(combo);
	comboClear(combo);
	comboFill(combo,lista,valorActual,formaMostrar,indiceValor,filtro);
}

function comboFill(combo,lista,valorActual,formaMostrar,indiceValor,filtro) {

	combo=gid(combo);

	if (!indiceValor) indiceValor="i";
	if (!formaMostrar) formaMostrar="lista[i]";
	if (!filtro) filtro="";

	eval // es más eficiente meter el bucle for dentro que fuera, aunque el código quede más sucio
		("for (var i in lista) {"
		+"	"+(filtro?"if("+filtro+")":"")+"comboAdd(combo,"+formaMostrar+","+indiceValor+",(valorActual=="+indiceValor+"?true:false));"
		+"}");

}

// copia todo el contenido de un combo a otro
// OJO: No limpia el combo, así que se agregan los valores al combo sin quitar los existentes
function comboCopy(destiny,source) {
	var d=gid(destiny);
	var s=gid(source);
	for (var i in s.options)
		comboAdd(d,s.options[i].text,s.options[i].value);
}

function comboSortTextNaturalSP(t) {
	var s=t.toLowerCase();
	s=s.replace("á","a");
	s=s.replace("é","e");
	s=s.replace("í","i");
	s=s.replace("ó","o");
	s=s.replace("ú","u");
	s=s.replace("Á","a");
	s=s.replace("É","e");
	s=s.replace("Í","i");
	s=s.replace("Ó","o");
	s=s.replace("Ú","u");
	s=s.replace("Ñ","nz");
	s=s.replace("ñ","nz");
	return s;
}

function comboSortCompareText(o1, o2) {
	return (comboSortTextNaturalSP(o1.text)<comboSortTextNaturalSP(o2.text)
		?-1
		:(comboSortTextNaturalSP(o1.text)>comboSortTextNaturalSP(o2.text)?1:0)
	);
}

function comboSortCompareTextCaseSensitive(o1, o2) {
	return (o1.text<o2.text?-1:o1.text>o2.text?1:0);
}

function comboSort(combo,compareFunction) {
	combo=gid(combo);
	if (!compareFunction) compareFunction=comboSortCompareText;
	var options=new Array (combo.options.length);
	for (var i=0; i<options.length; i++)
		options[i]=new Option(
			combo.options[i].text,
			combo.options[i].value,
			combo.options[i].defaultSelected,
			combo.options[i].selected
		);
	options.sort(compareFunction);
	combo.options.length=0;
	for (var i=0; i<options.length; i++)
		combo.options[i]=options[i];
}

function comboMove(combo1,combo2,sorted,compareFunction) {
	combo1=gid(combo1);
	combo2=gid(combo2);
	while (combo1.selectedIndex>=0) {
		var option=new Option(
			combo1.options[combo1.selectedIndex].text,
			combo1.options[combo1.selectedIndex].value,
			combo1.options[combo1.selectedIndex].defaultSelected,
			combo1.options[combo1.selectedIndex].selected
		);
		try { combo2.add(option,null); } catch(e) { combo2.add(option); }
		combo1.options[combo1.selectedIndex]=null;
	}
	if (sorted==undefined || sorted) comboSort(combo2,compareFunction);
}

function comboMoveIndex(combo1,index,combo2,sorted,compareFunction) {
	combo1=gid(combo1);
	combo2=gid(combo2);
	var option=new Option(
		combo1.options[index].text,
		combo1.options[index].value,
		combo1.options[index].defaultSelected,
		combo1.options[index].selected
	);
	try { combo2.add(option,null); } catch(e) { combo2.add(option); }
	combo1.options[index]=null;
}

function combosVisible(visible) {
	var elements=document.body.getElementsByTagName("select");
	for (var i in elements)
		if (elements[i].type)
			if (elements[i].type=="select-one" || elements[i].type=="select-multiple")
				elements[i].style.visibility=(visible?"visible":"hidden");
}

function combosVisibleIE(visible) {
	if (isie()) combosVisible(visible);
}

function comboAutoImage(s) {
	gid(s).style.backgroundImage=gid(s).options[gid(s).selectedIndex].style.backgroundImage;
}

function comboAutoImageSetup(s) {
	gid(s).onclick=function(){ comboAutoImage(s); }
	gid(s).onchange=function(){ comboAutoImage(s); }
	gid(s).onkeyup=function(){ comboAutoImage(s); }
	comboAutoImage(s);
}
// requiere common.js

var newalert_images="images/";
var newalert_id="newalert_";
var newalert_iecomboshide=false;

var newalert_active=new Object();
var newalert_return_function=new Object();
var newalert_open_windows=0;
var newalert_action_functions=new Object();

function newalert_support_opacity() { return (navigator.userAgent.indexOf("MSIE 6")==-1 && navigator.userAgent.indexOf("MSIE 7")==-1); }
function newalert_support_fixed() { return ( navigator.userAgent.indexOf("MSIE 6")==-1); }
function newalert_exec_action(id,i) { newalert_action_functions[id][i](); }

function newalert(o) {
	if (newalert_iecomboshide) combosVisibleIE(false);
	if (typeof(o)=="string") {
		var id="";
		var msg=o;
		var buttons=null;
		var ico="notice";
	} else {
		var id=(o.id?o.id:"");
		var msg=(o.msg?o.msg:"");
		var ico=(o.ico?o.ico:null);
		var buttons=o.buttons;
	}
	if (buttons==null) buttons=[{"caption":"Aceptar"}];
	newalert_return_function[id]=o.func;
	newalert_action_functions[id]=new Object();
	var d=document.createElement("div");
	newalert_remove(id);
	newalert_active[id]=true;
	d.setAttribute("id",newalert_id+id);
	style(d,{
		"position":(newalert_support_fixed()?"fixed":"absolute"),
		"left":(newalert_support_fixed()?0:scrollLeft())+"px",
		"top":(newalert_support_fixed()?0:scrollTop())+"px",
		"width":windowWidth()+"px",
		"height":windowHeight()+"px",
		"zIndex":990
	});
	if (!o.noshadow) style(d,{"backgroundImage":"url('"+newalert_images+"trans."+(newalert_support_opacity()?"png":"gif")+"')"});
	var cols=(ico?"colspan='2'":"");
	s="<table cellpadding='0' cellspacing='0' width='100%' height='100%'><tr><td align='center'>";
	if (o.body) s+=o.body;
	else {
		s+="<table class='"+(o.className?o.className:"newalert")+"' cellpadding='0' cellspacing='0'>"
			+(o.title==null?"":"<tr><th "+cols+" class='newalert_title'>"+(o.title?o.title:"")+"</th></tr>")
			+"<tr>"
			+(ico
				?"<td class='newalert_icon' width='48' valign='top'>"
				+"<img src='"+newalert_images+"newalert-"+(o.ico?o.ico+(o.ico.indexOf(".")>=0?"":".png"):"notice.png")+"' alt='' />"
				+"</td>"
				:""
			)
			+"<td class='newalert_body' valign='middle'>"+msg+"</td></tr>";
		if (buttons.length) {
			s+="<tr><td "+cols+" class='newalert_cmd' align='center'>";
			for (var i in buttons) {
				if (buttons[i].caption) {
					if (buttons[i].ico) {
						s+=" <a id='"+newalert_id+id+"_cmd_"+i+"' class='cmd' href='javascript:"
							+(buttons[i].action
								?(typeof(buttons[i].action)=="function"
									?"newalert_exec_action(\""+id+"\","+i+");"
									:buttons[i].action
								)
								:"newalert_close(\""+id+"\")"
							)
							+";'>"
							+"<span class='icon' style='background-image:url(\""+buttons[i].ico+"\")'>"
							+buttons[i].caption
							+"</span>"
							+"</a>";
					} else {
						s+=" <input id='"+newalert_id+id+"_cmd_"+i+"' class=cmd type=button onClick='javascript:"
							+(buttons[i].action
								?(typeof(buttons[i].action)=="function"
									?"newalert_exec_action(\""+id+"\","+i+");"
									:buttons[i].action
								)
								:"newalert_close(\""+id+"\")"
							)
							+";' value='"+buttons[i].caption+"' />";
					}
					newalert_action_functions[id][i]=buttons[i].action;
				}
			}
			s+"</td></tr>";
		}
		s+="</table>";
	}
	s+="</td></tr></table>";
	d.innerHTML=s;
	document.body.appendChild(d);
	newalert_open_windows++;
	try { gid(newalert_id+id+"_cmd_0").focus(); } catch(e) {}
	return {
		"id":id,
		"close":function(){ newalert_close(id); }
	};
}

function newalert_event_timer() {
	for (var id in newalert_active) {
		if (newalert_active[id]) {
			style(newalert_id+id,{
				"left":(newalert_support_fixed()?0:scrollLeft())+"px",
				"top":(newalert_support_fixed()?0:scrollTop())+"px",
				"width":windowWidth()+"px",
				"height":windowHeight()+"px"
			});
		}
	}
	newalert_event_poll=setTimeout("newalert_event_timer()",30);
}

function newwait(o) {
	if (typeof(o)=="string") {
		var msg=o;
		o=new Object();
		o.id="wait";
		o.msg=msg;
		o.ico="busy.gif";
		o.buttons=[];
	} else {
		if (!o) o=new Object();
		o.id=(o.id!=null?o.id:"wait");
		o.msg="Proceso en curso, por favor, espere...";
		o.ico=(o.ico!=null?o.ico:"busy.gif");
		o.buttons=[];
	}
	newalert(o);
}

function newsimplewait() {
	var o=new Object();
	o.id="wait";
	o.noshadow=true;
	o.body="<img src='"+newalert_images+"newalert-busy.gif' />";
	newalert(o);
}

var newok_num=0; function newok(msg,action) { var myid="ok"+(++newok_num); newalert({"id":myid,"ico":"ok","msg":msg,"buttons":[{"caption":"Aceptar","action":function(){ if (action) action(); newalert_close(myid); }}]}); }
var newwarn_num=0; function newwarn(msg,action) { var myid="warn"+(++newok_num); newalert({"id":myid,"ico":"warn","msg":msg,"buttons":[{"caption":"Aceptar","action":function(){ if (action) action(); newalert_close(myid); }}]}); }
var newerror_num=0; function newerror(msg,action) { var myid="error"+(++newok_num); newalert({"id":myid,"ico":"error","msg":msg,"buttons":[{"caption":"Aceptar","action":function(){ if (action) action(); newalert_close(myid); }}]}); }

function newalert_remove(id) {
	if (!id) var id="";
	newalert_active[id]=false;
	if (gid(newalert_id+id)) {
		newalert_open_windows--;
		gid(newalert_id+id).parentNode.removeChild(gid(newalert_id+id));
		if (newalert_iecomboshide && !newalert_open_windows) combosVisibleIE(true);
	}
}

function newalert_close(id) {
	if (!id) var id="";
	newalert_remove(id);
	try { newalert_return_function[id](id); } catch(e) {}
}

function newwait_close(id) {
	newalert_close(id?id:'wait');
}

// lanzar timer de eventos
newalert_event_timer();
var newphotos_list;
var newphotos_bg;
var newphotos_div;
var newphotos_img;
var newphotos_imgdiv;
var newphotos_navup;
var newphotos_navdown;
var newphotos_anipos;
var newphotos_lastimage;
var newphotos_lastselected;
var newphotos_caption;
var newphotos_actual;
var newphotos_newphotos=[];
var newphotos_conf={
	"opacity":0.5, // 50% opacidad
	"margin":0.1 // 10% margen
};

if (typeof(style)=="undefined") {
	alert("newphotos.js: Falta librerÃ­a de funciones requerida: common.js");
}

function newphotos(photos) {
	this.id=newphotos_newphotos.length;
	newphotos_newphotos[this.id]=this;
	this.shownames=false;
	this.photos=photos;
	this.photoscache=[];
	this.loaded=[];
	this.cached=true;
	this.cancelclick=false;
	this.opacity=newphotos_conf.opacity;
	this.margin=newphotos_conf.margin;
	this.setup=function() { newphotos_actual=this; }
	this.cache=function(enabled) { this.cached=enabled; }
	this.names=function(visible) { this.shownames=visible; }
	this.select=function(i) { newphotos_select(i); }
	this.show=function(i){
		this.setup();
		newphotos_show(i);
		if (this.cached) {
			for (var i in this.photos) {
				this.photoscache[i]=new Image();
				this.photoscache[i].src=this.geturl(i);
				eval("this.photoscache["+i+"].onload=function(){ newphotos_loaded("+i+"); };");
			}
		}
	}
	this.close=function() { newphotos_close(); }
	this.get=function(i) { return this.photos[i]; }
	this.set=function(i,photo) { this.photos[i]=photo; }
	this.geturl=function(i) {
		var img=this.get(i)[0];
		return img+(this.cached?"":(img.indexOf("?")!=-1?"&":"?")+"nocache="+parseInt(Math.random()*2000000000));
	}
	this.getthumb=function(i) {
		var img=this.get(i)[3];
		if (!img) return this.geturl(i);
		return img+(this.cached?"":(img.indexOf("?")!=-1?"&":"?")+"nocache="+parseInt(Math.random()*2000000000));
	}
	this.html=function(s1,s2,sc,s4) {
		this.setup();
		var s="";
		for (var i in this.photos) {
			s+=(s?s1:(s2?s1:""))+"<a href='"+this.geturl(i)+"' class='newphotos_photo' onClick='javascript:newphotos_newphotos["+this.id+"].show("+i+");return(false);'><img src='"+this.getthumb(i)+"' /></a>"+(s2?s2:"");
			if ((i%sc==sc-1) && (i<this.photos.length-1)) s+=s4;
		}
		return s;
	}
	this.prev=function() {
		var n=this.photos.length-1;
		if (newphotos_lastselected>0) n=newphotos_lastselected-1;
		newphotos_select(n);
		this.locate();
	}
	this.next=function() {
		var n=0;
		if (newphotos_lastselected<this.photos.length-1) n=newphotos_lastselected+1;
		newphotos_select(n);
		this.locate();
	}
	this.locate=function() {
		var s=getTop("newphoto_thumb"+newphotos_lastselected)-getHeight(newphotos_list)/2;
		newphotos_list.scrollTop=(s>0?s:0);
	}
	this.description=function(descriptions) {
		for (var i in descriptions)
			for (var j in this.photos)
				if (this.photos[j][0]==i)
					this.photos[j][4]=descriptions[i];
	}
	this.setup();
}

function newphotos_loaded(i) {
	newphotos_actual.loaded[i]=true;
	newphotos_thumbclass(i);
}

function newphotos_thumbclass(i) {
	gid("newphoto_thumb"+i).className="newphotos_thumbnail"
		+(newphotos_lastselected==i?" newphotos_thumbnail_active":"")
		+(newphotos_actual.loaded[i]?" newphotos_thumbnail_loaded":"");
}

function newphotos_select(i) {
	var i=parseInt(i);
	
	var lastthumb=newphotos_lastselected;
	newphotos_lastselected=i;
	newphotos_thumbclass(lastthumb?lastthumb:0);
	newphotos_thumbclass(i);

	var margin=getBorderWidth(newphotos_imgdiv);
	var x=getWidth(newphotos_list),y=0;
	var w=windowWidth()-x,h=windowHeight();
	var mw=(w-margin),mh=(h-margin);
	var img=newphotos_actual.get(i);
	var iw=img[1],ih=img[2];
	var ratio=iw/ih;

	var ma=newphotos_actual.margin;
	if (ma>=0 && ma<1) { mw*=(1-ma); mh*=(1-ma); }
	else if (ma>=1) { mw-=ma*2; mh-=ma*2; }
	
	if (iw>mw) { iw=mw; ih=iw/ratio; }
	if (ih>mh) { ih=mh; iw=ih*ratio; }
	
	var image=newphotos_actual.geturl(i);

	newphotos_caption.innerHTML
		="<div class='newphotos_caption_content'>"
			+"<div class='newphotos_counter'><span class='newphotos_counter_active'>"+(i+1)+"</span> de <span class='newphotos_counter_max'>"+newphotos_actual.photos.length+"</span></div>"
			+(newphotos_actual.shownames?"<div class='newphotos_filename'>"+basename(img[0])+"</div>":"")
			+(img[4]?"<div class='newphotos_description'>"+img[4]+"</div>":"")
		+"</div>";

	var navuph=getHeight(newphotos_navup);
	var navdownh=getHeight(newphotos_navdown);
	style(newphotos_list,{
		"top":navuph+"px",
		"height":(windowHeight()-navuph-navdownh)+"px"
	});
	style(newphotos_navup,{
		"top":"0px",
		"width":getWidth(newphotos_list)+"px"
	});
	style(newphotos_navdown,{
		"top":(windowHeight()-navdownh)+"px",
		"width":getWidth(newphotos_list)+"px"
	});

	style(newphotos_caption,{
		"top":(windowHeight()-getHeight(newphotos_caption))+"px",
		"left":(windowWidth()-getWidth(newphotos_caption))+"px"
	});

	style(newphotos_imgdiv,{
		"left":x+parseInt((w-iw-getBorderWidth(newphotos_imgdiv))/2)+"px",
		"top":y+parseInt((h-ih-getBorderWidth(newphotos_imgdiv))/2)+"px",
		"width":"auto",
		"height":"auto"
	});
	style(newphotos_img,{
		"visibility":(isie() || newphotos_lastimage==image?"visible":"hidden"),
		"width":iw+"px",
		"height":ih+"px"
	});
	if (newphotos_lastimage!=image)
		newphotos_img.src="";
	newphotos_img.src=image;
		newphotos_img.onload=function(){ style(newphotos_img,{"visibility":"visible"}); } // OJO: en IE no funciona este evento
	newphotos_lastimage=image;
	
}

function newphotos_show(i) {
	
	newphotos_close();

	var ishow=(i?i:0);
	newphotos_anipos=new Date();

	var d=document.createElement("div");
	d.id="newphotos_bg";
	d.title="Click para cerrar";
	d.onmouseup=function(e){
		if (!e) var e=window.event;
		if (e.clientX>getWidth("newphotos_list"))
			newphotos_close();
	};
	document.body.appendChild(d);
	newphotos_bg=d;

	newphotos_navup=document.createElement("div");
	newphotos_navup.id="newphotos_navup";
	newphotos_navup.innerHTML="<a href='javascript:void(0)' onMouseDown='javascript:void(newphotos_actual.prev())'><span>Anterior</span></a>";
	document.body.appendChild(newphotos_navup);
	style(newphotos_navup,{"left":"-"+getWidth(newphotos_navup)+"px"});

	newphotos_navdown=document.createElement("div");
	newphotos_navdown.id="newphotos_navdown";
	newphotos_navdown.innerHTML="<a href='javascript:void(0)' onMouseDown='javascript:void(newphotos_actual.next())'><span>Siguiente</span></a>";
	document.body.appendChild(newphotos_navdown);
	style(newphotos_navdown,{"left":"-"+getWidth(newphotos_navdown)+"px"});

	newphotos_list=document.createElement("div");
	newphotos_list.id="newphotos_list";
	document.body.appendChild(newphotos_list);
	style(newphotos_list,{"left":"-"+getWidth(newphotos_list)+"px"});
	
	var s="";
	for (var i in newphotos_actual.photos) {
		var thumb=newphotos_actual.getthumb(i);
		s+="<div id='newphoto_thumb"+i+"' class='newphotos_thumbnail'><a href='"+newphotos_actual.geturl(i)+"' onClick='javascript:return false;' onMouseDown='javascript:newphotos_select(\""+i+"\");return false;'><img src='"+thumb+"' width='100%' /></a></div>";
	}
	newphotos_list.innerHTML=s;

	newphotos_imgdiv=document.createElement("div");
	newphotos_imgdiv.id="newphotos_imgdiv";
	document.body.appendChild(newphotos_imgdiv);
	
	newphotos_img=document.createElement("img");
	newphotos_img.id="newphotos_img";
	newphotos_imgdiv.appendChild(newphotos_img);
	newphotos_imgdiv.onclick=function(){ newphotos_actual.next(); }

	newphotos_caption=document.createElement("div");
	newphotos_caption.id="newphotos_caption";
	document.body.appendChild(newphotos_caption);

	newphotos_select(ishow);
	newphotos_ani();
	
	newphotos_actual.locate();
}

function newphotos_close() {
	if (newphotos_lastselected!=null) {
		newphotos_lastselected=null;
		if (newphotos_bg) newphotos_bg.parentNode.removeChild(newphotos_bg);
		if (newphotos_list) newphotos_list.parentNode.removeChild(newphotos_list);
		if (newphotos_imgdiv) newphotos_imgdiv.parentNode.removeChild(newphotos_imgdiv);
		if (newphotos_img) newphotos_img.parentNode.removeChild(newphotos_img);
		if (newphotos_navup) newphotos_navup.parentNode.removeChild(newphotos_navup);
		if (newphotos_navdown) newphotos_navdown.parentNode.removeChild(newphotos_navdown);
		if (newphotos_caption) newphotos_caption.parentNode.removeChild(newphotos_caption);
	}
}
	
function newphotos_ani() {
	var d=newphotos_bg;
	var i=new Date()-newphotos_anipos;
	var r=i/400; if (r>=1) r=1;
	try { d.style.opacity=r*newphotos_actual.opacity; } catch(e) {}
	try { d.style.filter="alpha(opacity="+parseInt(r*newphotos_actual.opacity*100)+")"; } catch(e) {}
	var p=parseInt(getWidth(newphotos_list)*(1-r)*(1-r));
	style(newphotos_navup,{"left":"-"+p+"px"});
	style(newphotos_navdown,{"left":"-"+p+"px"});
	style(newphotos_list,{"left":"-"+p+"px"});
	if (r<1) setTimeout(newphotos_ani,1);
}

var newphotosLastWindowOnResize=window.onresize;
window.onresize=function(){
	if (newphotos_lastselected!=null)
		newphotos_select(newphotos_lastselected);
	try { newphotosLastWindowOnResize(); } catch(e) {}
}
/*
Copyright (c) 2005 Tim Taylor Consulting <http://tool-man.org/>

Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/

var ToolMan = {
	events : function() {
		if (!ToolMan._eventsFactory) throw "ToolMan Events module isn't loaded";
		return ToolMan._eventsFactory
	},

	css : function() {
		if (!ToolMan._cssFactory) throw "ToolMan CSS module isn't loaded";
		return ToolMan._cssFactory
	},

	coordinates : function() {
		if (!ToolMan._coordinatesFactory) throw "ToolMan Coordinates module isn't loaded";
		return ToolMan._coordinatesFactory
	},

	drag : function() {
		if (!ToolMan._dragFactory) throw "ToolMan Drag module isn't loaded";
		return ToolMan._dragFactory
	},

	dragsort : function() {
		if (!ToolMan._dragsortFactory) throw "ToolMan DragSort module isn't loaded";
		return ToolMan._dragsortFactory
	},

	helpers : function() {
		return ToolMan._helpers
	},

	cookies : function() {
		if (!ToolMan._cookieOven) throw "ToolMan Cookie module isn't loaded";
		return ToolMan._cookieOven
	},

	junkdrawer : function() {
		return ToolMan._junkdrawer
	}

}
/* Copyright (c) 2005 Tim Taylor Consulting (see LICENSE.txt)

based on http://www.quirksmode.org/js/cookies.html
*/
ToolMan._cookieOven = {

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

	get : function(name) {
		var namePattern = name + "="
		var cookies = document.cookie.split(';')
		for(var i = 0, n = cookies.length; i < n; i++) {
			var c = cookies[i]
			while (c.charAt(0) == ' ') c = c.substring(1, c.length)
			if (c.indexOf(namePattern) == 0)
				return c.substring(namePattern.length, c.length)
		}
		return null
	},

	eraseCookie : function(name) {
		createCookie(name, "", -1)
	}
}
/* Copyright (c) 2005 Tim Taylor Consulting (see LICENSE.txt) */

/* FIXME: assumes position styles are specified in 'px' */

ToolMan._coordinatesFactory = {

	create : function(x, y) {
		// FIXME: Safari won't parse 'throw' and aborts trying to do anything with this file
		//if (isNaN(x) || isNaN(y)) throw "invalid x,y: " + x + "," + y
		return new _ToolManCoordinate(this, x, y)
	},

	origin : function() {
		return this.create(0, 0)
	},

	/*
	 * FIXME: Safari 1.2, returns (0,0) on absolutely positioned elements
	 */
	topLeftPosition : function(element) {
		var left = parseInt(ToolMan.css().readStyle(element, "left"))
		var left = isNaN(left) ? 0 : left
		var top = parseInt(ToolMan.css().readStyle(element, "top"))
		var top = isNaN(top) ? 0 : top

		return this.create(left, top)
	},

	bottomRightPosition : function(element) {
		return this.topLeftPosition(element).plus(this._size(element))
	},

	topLeftOffset : function(element) {
		var offset = this._offset(element) 

		var parent = element.offsetParent
		while (parent) {
			offset = offset.plus(this._offset(parent))
			parent = parent.offsetParent
		}
		return offset
	},

	bottomRightOffset : function(element) {
		return this.topLeftOffset(element).plus(
				this.create(element.offsetWidth, element.offsetHeight))
	},

	scrollOffset : function() {
		if (window.pageXOffset) {
			return this.create(window.pageXOffset, window.pageYOffset)
		} else if (document.documentElement) {
			return this.create(
					document.body.scrollLeft + document.documentElement.scrollLeft, 
					document.body.scrollTop + document.documentElement.scrollTop)
		} else if (document.body.scrollLeft >= 0) {
			return this.create(document.body.scrollLeft, document.body.scrollTop)
		} else {
			return this.create(0, 0)
		}
	},

	clientSize : function() {
		if (window.innerHeight >= 0) {
			return this.create(window.innerWidth, window.innerHeight)
		} else if (document.documentElement) {
			return this.create(document.documentElement.clientWidth,
					document.documentElement.clientHeight)
		} else if (document.body.clientHeight >= 0) {
			return this.create(document.body.clientWidth,
					document.body.clientHeight)
		} else {
			return this.create(0, 0)
		}
	},

	/**
	 * mouse coordinate relative to the window (technically the
	 * browser client area) i.e. the part showing your page
	 *
	 * NOTE: in Safari the coordinate is relative to the document
	 */
	mousePosition : function(event) {
		event = ToolMan.events().fix(event)
		return this.create(event.clientX, event.clientY)
	},

	/**
	 * mouse coordinate relative to the document
	 */
	mouseOffset : function(event) {
		event = ToolMan.events().fix(event)
		if (event.pageX >= 0 || event.pageX < 0) {
			return this.create(event.pageX, event.pageY)
		} else if (event.clientX >= 0 || event.clientX < 0) {
			return this.mousePosition(event).plus(this.scrollOffset())
		}
	},

	_size : function(element) {
	/* TODO: move to a Dimension class */
		return this.create(element.offsetWidth, element.offsetHeight)
	},

	_offset : function(element) {
		return this.create(element.offsetLeft, element.offsetTop)
	}
}

function _ToolManCoordinate(factory, x, y) {
	this.factory = factory
	this.x = isNaN(x) ? 0 : x
	this.y = isNaN(y) ? 0 : y
}

_ToolManCoordinate.prototype = {
	toString : function() {
		return "(" + this.x + "," + this.y + ")"
	},

	plus : function(that) {
		return this.factory.create(this.x + that.x, this.y + that.y)
	},

	minus : function(that) {
		return this.factory.create(this.x - that.x, this.y - that.y)
	},

	min : function(that) {
		return this.factory.create(
				Math.min(this.x , that.x), Math.min(this.y , that.y))
	},

	max : function(that) {
		return this.factory.create(
				Math.max(this.x , that.x), Math.max(this.y , that.y))
	},

	constrainTo : function (one, two) {
		var min = one.min(two)
		var max = one.max(two)

		return this.max(min).min(max)
	},

	distance : function (that) {
		return Math.sqrt(Math.pow(this.x - that.x, 2) + Math.pow(this.y - that.y, 2))
	},

	reposition : function(element) {
		element.style["top"] = this.y + "px"
		element.style["left"] = this.x + "px"
	}
}
ToolMan._helpers = {
	map : function(array, func) {
		for (var i = 0, n = array.length; i < n; i++) func(array[i])
	},

	nextItem : function(item, nodeName) {
		if (item == null) return
		var next = item.nextSibling
		while (next != null) {
			if (next.nodeName == nodeName) return next
			next = next.nextSibling
		}
		return null
	},

	previousItem : function(item, nodeName) {
		var previous = item.previousSibling
		while (previous != null) {
			if (previous.nodeName == nodeName) return previous
			previous = previous.previousSibling
		}
		return null
	},

	moveBefore : function(item1, item2) {
		var parent = item1.parentNode
		parent.removeChild(item1)
		parent.insertBefore(item1, item2)
	},

	moveAfter : function(item1, item2) {
		var parent = item1.parentNode
		parent.removeChild(item1)
		parent.insertBefore(item1, item2 ? item2.nextSibling : null)
	}
}

/** 
 * scripts without a proper home
 *
 * stuff here is subject to change unapologetically and without warning
 */
ToolMan._junkdrawer = {
	serializeList : function(list) {
		var items = list.getElementsByTagName("li")
		var array = new Array()
		for (var i = 0, n = items.length; i < n; i++) {
			var item = items[i]

			array.push(ToolMan.junkdrawer()._identifier(item))
		}
		return array.join('|')
	},

	inspectListOrder : function(id) {
		alert(ToolMan.junkdrawer().serializeList(document.getElementById(id)))
	},

	restoreListOrder : function(listID) {
		var list = document.getElementById(listID)
		if (list == null) return

		var cookie = ToolMan.cookies().get("list-" + listID)
		if (!cookie) return;

		var IDs = cookie.split('|')
		var items = ToolMan.junkdrawer()._itemsByID(list)

		for (var i = 0, n = IDs.length; i < n; i++) {
			var itemID = IDs[i]
			if (itemID in items) {
				var item = items[itemID]
				list.removeChild(item)
				list.insertBefore(item, null)
			}
		}
	},

	_identifier : function(item) {
		var trim = ToolMan.junkdrawer().trim
		var identifier

		identifier = trim(item.getAttribute("id"))
		if (identifier != null && identifier.length > 0) return identifier;
		
		identifier = trim(item.getAttribute("itemID"))
		if (identifier != null && identifier.length > 0) return identifier;
		
		// FIXME: strip out special chars or make this an MD5 hash or something
		return trim(item.innerHTML)
	},

	_itemsByID : function(list) {
		var array = new Array()
		var items = list.getElementsByTagName('li')
		for (var i = 0, n = items.length; i < n; i++) {
			var item = items[i]
			array[ToolMan.junkdrawer()._identifier(item)] = item
		}
		return array
	},

	trim : function(text) {
		if (text == null) return null
		return text.replace(/^(\s+)?(.*\S)(\s+)?$/, '$2')
	}
}
/* Copyright (c) 2005 Tim Taylor Consulting (see LICENSE.txt) */

// TODO: write unit tests
ToolMan._cssFactory = {
	readStyle : function(element, property) {
		if (element.style[property]) {
			return element.style[property]
		} else if (element.currentStyle) {
			return element.currentStyle[property]
		} else if (document.defaultView && document.defaultView.getComputedStyle) {
			var style = document.defaultView.getComputedStyle(element, null)
			return style.getPropertyValue(property)
		} else {
			return null
		}
	}
}
/* Copyright (c) 2005 Tim Taylor Consulting (see LICENSE.txt) */

ToolMan._dragFactory = {
	createSimpleGroup : function(element, handle) {
		handle = handle ? handle : element
		var group = this.createGroup(element)
		group.setHandle(handle)
		group.transparentDrag()
		group.onTopWhileDragging()
		return group
	},

	createGroup : function(element) {
		var group = new _ToolManDragGroup(this, element)

		var position = ToolMan.css().readStyle(element, 'position')
		if (position == 'static') {
			element.style["position"] = 'relative'
		} else if (position == 'absolute') {
			/* for Safari 1.2 */
			ToolMan.coordinates().topLeftOffset(element).reposition(element)
		}

		// TODO: only if ToolMan.isDebugging()
		group.register('draginit', this._showDragEventStatus)
		group.register('dragmove', this._showDragEventStatus)
		group.register('dragend', this._showDragEventStatus)

		return group
	},

	_showDragEventStatus : function(dragEvent) {
		window.status = dragEvent.toString()
	},

	constraints : function() {
		return this._constraintFactory
	},

	_createEvent : function(type, event, group) {
		return new _ToolManDragEvent(type, event, group)
	}
}

function _ToolManDragGroup(factory, element) {
	this.factory = factory
	this.element = element
	this._handle = null
	this._thresholdDistance = 0
	this._transforms = new Array()
	// TODO: refactor into a helper object, move into events.js
	this._listeners = new Array()
	this._listeners['draginit'] = new Array()
	this._listeners['dragstart'] = new Array()
	this._listeners['dragmove'] = new Array()
	this._listeners['dragend'] = new Array()
}

_ToolManDragGroup.prototype = {
	/*
	 * TODO:
	 *   - unregister(type, func)
	 *   - move custom event listener stuff into Event library
	 *   - keyboard nudging of "selected" group
	 */

	setHandle : function(handle) {
		var events = ToolMan.events()

		handle.toolManDragGroup = this
		events.register(handle, 'mousedown', this._dragInit)
		handle.onmousedown = function() { return false }

		if (this.element != handle)
			events.unregister(this.element, 'mousedown', this._dragInit)
	},

	register : function(type, func) {
		this._listeners[type].push(func)
	},

	addTransform : function(transformFunc) {
		this._transforms.push(transformFunc)
	},

	verticalOnly : function() {
		this.addTransform(this.factory.constraints().vertical())
	},

	horizontalOnly : function() {
		this.addTransform(this.factory.constraints().horizontal())
	},

	setThreshold : function(thresholdDistance) {
		this._thresholdDistance = thresholdDistance
	},

	transparentDrag : function(opacity) {
		var opacity = typeof(opacity) != "undefined" ? opacity : 0.75;
		var originalOpacity = ToolMan.css().readStyle(this.element, "opacity")

		this.register('dragstart', function(dragEvent) {
			var element = dragEvent.group.element
			element.style.opacity = opacity
			if (isie()) {
				try { element.style.filter = 'alpha(opacity=' + (opacity * 100) + ')'; } catch(e) {};
			}
		})
		this.register('dragend', function(dragEvent) {
			var element = dragEvent.group.element
			element.style.opacity = originalOpacity
			if (isie()) {
				try { element.style.filter = 'alpha(opacity=100)'; } catch(e) {};
			}
		})
	},

	onTopWhileDragging : function(zIndex) {
		var zIndex = typeof(zIndex) != "undefined" ? zIndex : 100000;
		var originalZIndex = ToolMan.css().readStyle(this.element, "z-index")

		this.register('dragstart', function(dragEvent) {
			dragEvent.group.element.style.zIndex = zIndex
		})
		this.register('dragend', function(dragEvent) {
			dragEvent.group.element.style.zIndex = (originalZIndex?originalZIndex:0);
		})
	},

	_dragInit : function(event) {
		event = ToolMan.events().fix(event)
		var group = document.toolManDragGroup = this.toolManDragGroup
		var dragEvent = group.factory._createEvent('draginit', event, group)

		group._isThresholdExceeded = false
		group._initialMouseOffset = dragEvent.mouseOffset
		group._grabOffset = dragEvent.mouseOffset.minus(dragEvent.topLeftOffset)
		ToolMan.events().register(document, 'mousemove', group._drag)
		document.onmousemove = function() { return false }
		ToolMan.events().register(document, 'mouseup', group._dragEnd)

		group._notifyListeners(dragEvent)
	},

	_drag : function(event) {
		event = ToolMan.events().fix(event)
		var coordinates = ToolMan.coordinates()
		var group = this.toolManDragGroup
		if (!group) return
		var dragEvent = group.factory._createEvent('dragmove', event, group)

		var newTopLeftOffset = dragEvent.mouseOffset.minus(group._grabOffset)

		// TODO: replace with DragThreshold object
		if (!group._isThresholdExceeded) {
			var distance = 
					dragEvent.mouseOffset.distance(group._initialMouseOffset)
			if (distance < group._thresholdDistance) return
			group._isThresholdExceeded = true
			group._notifyListeners(
					group.factory._createEvent('dragstart', event, group))
		}

		for (i in group._transforms) {
			var transform = group._transforms[i]
			newTopLeftOffset = transform(newTopLeftOffset, dragEvent)
		}

		var dragDelta = newTopLeftOffset.minus(dragEvent.topLeftOffset)
		var newTopLeftPosition = dragEvent.topLeftPosition.plus(dragDelta)
		newTopLeftPosition.reposition(group.element)
		dragEvent.transformedMouseOffset = newTopLeftOffset.plus(group._grabOffset)

		group._notifyListeners(dragEvent)

		var errorDelta = newTopLeftOffset.minus(coordinates.topLeftOffset(group.element))
		if (errorDelta.x != 0 || errorDelta.y != 0) {
			coordinates.topLeftPosition(group.element).plus(errorDelta).reposition(group.element)
		}
	},

	_dragEnd : function(event) {
		event = ToolMan.events().fix(event)
		var group = this.toolManDragGroup
		var dragEvent = group.factory._createEvent('dragend', event, group)

		group._notifyListeners(dragEvent)

		this.toolManDragGroup = null
		ToolMan.events().unregister(document, 'mousemove', group._drag)
		document.onmousemove = null
		ToolMan.events().unregister(document, 'mouseup', group._dragEnd)
	},

	_notifyListeners : function(dragEvent) {
		var listeners = this._listeners[dragEvent.type]
		for (i in listeners) {
			listeners[i](dragEvent)
		}
	}
}

function _ToolManDragEvent(type, event, group) {
	this.type = type
	this.group = group
	this.mousePosition = ToolMan.coordinates().mousePosition(event)
	this.mouseOffset = ToolMan.coordinates().mouseOffset(event)
	this.transformedMouseOffset = this.mouseOffset
	this.topLeftPosition = ToolMan.coordinates().topLeftPosition(group.element)
	this.topLeftOffset = ToolMan.coordinates().topLeftOffset(group.element)
}

_ToolManDragEvent.prototype = {
	toString : function() {
		return "mouse: " + this.mousePosition + this.mouseOffset + "    " +
				"xmouse: " + this.transformedMouseOffset + "    " +
				"left,top: " + this.topLeftPosition + this.topLeftOffset
	}
}

ToolMan._dragFactory._constraintFactory = {
	vertical : function() {
		return function(coordinate, dragEvent) {
			var x = dragEvent.topLeftOffset.x
			return coordinate.x != x
					? coordinate.factory.create(x, coordinate.y) 
					: coordinate
		}
	},

	horizontal : function() {
		return function(coordinate, dragEvent) {
			var y = dragEvent.topLeftOffset.y
			return coordinate.y != y
					? coordinate.factory.create(coordinate.x, y) 
					: coordinate
		}
	}
}
/* Copyright (c) 2005 Tim Taylor Consulting (see LICENSE.txt) */

ToolMan._dragsortFactory = {
	makeSortable : function(item) {
		var group = ToolMan.drag().createSimpleGroup(item)

		group.register('dragstart', this._onDragStart)
		group.register('dragmove', this._onDragMove)
		group.register('dragend', this._onDragEnd)

		return group
	},

	/** 
	 * Iterates over a list's items, making them sortable, applying
	 * optional functions to each item.
	 *
	 * example: makeListSortable(myList, myFunc1, myFunc2, ... , myFuncN)
	 */
	makeListSortable : function(list) {
		var helpers = ToolMan.helpers()
		var coordinates = ToolMan.coordinates()
		var items = list.getElementsByTagName("li")

		helpers.map(items, function(item) {
			var dragGroup = dragsort.makeSortable(item)
			dragGroup.setThreshold(4)
			var min, max
			dragGroup.addTransform(function(coordinate, dragEvent) {
				return coordinate.constrainTo(min, max)
			})
			dragGroup.register('dragstart', function() {
				var items = list.getElementsByTagName("li")
				min = max = coordinates.topLeftOffset(items[0])
				for (var i = 1, n = items.length; i < n; i++) {
					var offset = coordinates.topLeftOffset(items[i])
					min = min.min(offset)
					max = max.max(offset)
				}
			})
		})
		for (var i = 1, n = arguments.length; i < n; i++)
			helpers.map(items, arguments[i])
	},

	_onDragStart : function(dragEvent) {
	},

	_onDragMove : function(dragEvent) {
		var helpers = ToolMan.helpers()
		var coordinates = ToolMan.coordinates()

		var item = dragEvent.group.element
		var xmouse = dragEvent.transformedMouseOffset
		var moveTo = null

		var previous = helpers.previousItem(item, item.nodeName)
		while (previous != null) {
			var bottomRight = coordinates.bottomRightOffset(previous)
			if (xmouse.y <= bottomRight.y && xmouse.x <= bottomRight.x) {
				moveTo = previous
			}
			previous = helpers.previousItem(previous, item.nodeName)
		}
		if (moveTo != null) {
			helpers.moveBefore(item, moveTo)
			return
		}

		var next = helpers.nextItem(item, item.nodeName)
		while (next != null) {
			var topLeft = coordinates.topLeftOffset(next)
			if (topLeft.y <= xmouse.y && topLeft.x <= xmouse.x) {
				moveTo = next
			}
			next = helpers.nextItem(next, item.nodeName)
		}
		if (moveTo != null) {
			helpers.moveBefore(item, helpers.nextItem(moveTo, item.nodeName))
			return
		}
	},

	_onDragEnd : function(dragEvent) {
		ToolMan.coordinates().create(0, 0).reposition(dragEvent.group.element)
	}
}
/* Copyright (c) 2005 Tim Taylor Consulting (see LICENSE.txt) */

ToolMan._eventsFactory = {
	fix : function(event) {
		if (!event) event = window.event

		if (event.target) {
			if (event.target.nodeType == 3) event.target = event.target.parentNode
		} else if (event.srcElement) {
			event.target = event.srcElement
		}

		return event
	},

	register : function(element, type, func) {
		if (element.addEventListener) {
			element.addEventListener(type, func, false)
		} else if (element.attachEvent) {
			if (!element._listeners) element._listeners = new Array()
			if (!element._listeners[type]) element._listeners[type] = new Array()
			var workaroundFunc = function() {
				func.apply(element, new Array())
			}
			element._listeners[type][func] = workaroundFunc
			element.attachEvent('on' + type, workaroundFunc)
		}
	},

	unregister : function(element, type, func) {
		if (element.removeEventListener) {
			element.removeEventListener(type, func, false)
		} else if (element.detachEvent) {
			if (element._listeners 
					&& element._listeners[type] 
					&& element._listeners[type][func]) {

				element.detachEvent('on' + type, 
						element._listeners[type][func])
			}
		}
	}
}
/**
*
*  Secure Hash Algorithm (SHA1)
*  http://www.webtoolkit.info/
*
**/

function SHA1 (msg) {

	function rotate_left(n,s) {
		var t4 = ( n<<s ) | (n>>>(32-s));
		return t4;
	};

	function lsb_hex(val) {
		var str="";
		var i;
		var vh;
		var vl;

		for( i=0; i<=6; i+=2 ) {
			vh = (val>>>(i*4+4))&0x0f;
			vl = (val>>>(i*4))&0x0f;
			str += vh.toString(16) + vl.toString(16);
		}
		return str;
	};

	function cvt_hex(val) {
		var str="";
		var i;
		var v;

		for( i=7; i>=0; i-- ) {
			v = (val>>>(i*4))&0x0f;
			str += v.toString(16);
		}
		return str;
	};


	function Utf8Encode(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;
	};

	var blockstart;
	var i, j;
	var W = new Array(80);
	var H0 = 0x67452301;
	var H1 = 0xEFCDAB89;
	var H2 = 0x98BADCFE;
	var H3 = 0x10325476;
	var H4 = 0xC3D2E1F0;
	var A, B, C, D, E;
	var temp;

	msg = Utf8Encode(msg);

	var msg_len = msg.length;

	var word_array = new Array();
	for( i=0; i<msg_len-3; i+=4 ) {
		j = msg.charCodeAt(i)<<24 | msg.charCodeAt(i+1)<<16 |
		msg.charCodeAt(i+2)<<8 | msg.charCodeAt(i+3);
		word_array.push( j );
	}

	switch( msg_len % 4 ) {
		case 0:
			i = 0x080000000;
		break;
		case 1:
			i = msg.charCodeAt(msg_len-1)<<24 | 0x0800000;
		break;

		case 2:
			i = msg.charCodeAt(msg_len-2)<<24 | msg.charCodeAt(msg_len-1)<<16 | 0x08000;
		break;

		case 3:
			i = msg.charCodeAt(msg_len-3)<<24 | msg.charCodeAt(msg_len-2)<<16 | msg.charCodeAt(msg_len-1)<<8	| 0x80;
		break;
	}

	word_array.push( i );

	while( (word_array.length % 16) != 14 ) word_array.push( 0 );

	word_array.push( msg_len>>>29 );
	word_array.push( (msg_len<<3)&0x0ffffffff );


	for ( blockstart=0; blockstart<word_array.length; blockstart+=16 ) {

		for( i=0; i<16; i++ ) W[i] = word_array[blockstart+i];
		for( i=16; i<=79; i++ ) W[i] = rotate_left(W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16], 1);

		A = H0;
		B = H1;
		C = H2;
		D = H3;
		E = H4;

		for( i= 0; i<=19; i++ ) {
			temp = (rotate_left(A,5) + ((B&C) | (~B&D)) + E + W[i] + 0x5A827999) & 0x0ffffffff;
			E = D;
			D = C;
			C = rotate_left(B,30);
			B = A;
			A = temp;
		}

		for( i=20; i<=39; i++ ) {
			temp = (rotate_left(A,5) + (B ^ C ^ D) + E + W[i] + 0x6ED9EBA1) & 0x0ffffffff;
			E = D;
			D = C;
			C = rotate_left(B,30);
			B = A;
			A = temp;
		}

		for( i=40; i<=59; i++ ) {
			temp = (rotate_left(A,5) + ((B&C) | (B&D) | (C&D)) + E + W[i] + 0x8F1BBCDC) & 0x0ffffffff;
			E = D;
			D = C;
			C = rotate_left(B,30);
			B = A;
			A = temp;
		}

		for( i=60; i<=79; i++ ) {
			temp = (rotate_left(A,5) + (B ^ C ^ D) + E + W[i] + 0xCA62C1D6) & 0x0ffffffff;
			E = D;
			D = C;
			C = rotate_left(B,30);
			B = A;
			A = temp;
		}

		H0 = (H0 + A) & 0x0ffffffff;
		H1 = (H1 + B) & 0x0ffffffff;
		H2 = (H2 + C) & 0x0ffffffff;
		H3 = (H3 + D) & 0x0ffffffff;
		H4 = (H4 + E) & 0x0ffffffff;

	}

	var temp = cvt_hex(H0) + cvt_hex(H1) + cvt_hex(H2) + cvt_hex(H3) + cvt_hex(H4);

	return temp.toLowerCase();

}
/*
	Ejemplos de uso:
	
	var xcal1,xcal2,xcal3,xcal4;
	
	init(function(){
		
		xcal1=new xcalendar({
			"input":"fecha_inicio",
			"trigger":"fecha_inicio",
			"min":new Date(2011,3,12),
			"max":"xcal2",
			"onselect":function(fecha){
				//xcal2.min=fecha;
			}
		});

		xcal2=new xcalendar({
			"input":"fecha_fin",
			"trigger":"fecha_fin",
			"min":"xcal1"
		});
			
		xcal3=new xcalendar({
			"div":"calendario1",
			"input":"fecha_inicio2",
			"min":new Date(2011,3,12),
			"max":"xcal4",
			"onselect":function(fecha){
				//xcal2.min=fecha;
			}
		});

		xcal4=new xcalendar({
			"div":"calendario2",
			"input":"fecha_fin2",
			"min":"xcal3"
		});
			
		gid("fecha_inicio").focus();
		
	});
*/
var xcalendars=[];
var xcalendars_active=null;
var xcalendars_cancelclick=false;
function xcalendar(o) {
	this.fecha=o.fecha;
	if (!this.fecha) this.fecha=new Date();

	var a=xcalendars.length;
	xcalendars_active=a;
	xcalendars[a]=this;
	var xcal=xcalendars[a];
	
	this.seleccionada=null;
	this.seleccionados={};
	
	this.div=gid(o.div);
	this.input=gid(o.input);
	this.trigger=gid(o.trigger);
	this.min=o.min;
	this.max=o.max;
	this.onselect=o.onselect;
	
	this.loaded=false;

	this.y=this.fecha.getFullYear();
	this.m=this.fecha.getMonth();
	this.d=this.fecha.getDate();
	var week_abrev="LMXJVSD";
	var months=[
		"Enero","Febrero","Marzo","Abril","Mayo","Junio","Julio",
		"Agosto","Septiembre","Octubre","Noviembre","Diciembre"
	];

	this.mesAnterior=function(){
		this.m--; if (this.m<0) { this.m=11; this.y--; }
		this.refresh();
	};

	this.mesSiguiente=function(){
		this.m++; if (this.m>11) { this.m=0; this.y++; }
		this.refresh();
	};
	
	this.setAnyo=function(ny){
		if (ny>=1900 && ny<3000)
			this.y=ny;
		this.refresh();
	};

	this.spDate=function(fecha){
		return (fecha.getDate()<10?"0":"")+fecha.getDate()+"/"+(fecha.getMonth()<9?"0":"")+(1+fecha.getMonth())+"/"+fecha.getFullYear();
	};

	this.sqlDate=function(fecha){
		return fecha.getFullYear()+"-"+(fecha.getMonth()<9?"0":"")+(1+fecha.getMonth())+"-"+(fecha.getDate()<10?"0":"")+fecha.getDate();
	};
		
	this._efectiveDate=function(minmax){
		if (typeof(minmax)=="string") {
			eval("var o="+minmax+";");
			if (o && o.seleccionada) {
				return o.seleccionada;
			}
			return null;
		}
		return minmax;
	};
		
	// actualizar
	this.refresh=function(){
		if (!this.div) return;
		
		var month_day=((new Date(this.y-1900,this.m,1)).getDay()+1)%7;
		var month_days=(32-new Date(this.y-1900,this.m,32).getDate());
		
		var i;
		var h="";
		h+="<table class='xcalendar"+(this.trigger?" xcalendar_popup":"")+"'>";
		h+="<thead>";
		h+="<tr class='xcalendar_title'>";
		h+="<td><a href='javascript:void(0)' onClick='javascript:xcalendars["+a+"].mesAnterior();'>&lt;</a></td>";
		h+="<td colspan='5'>"
			+months[this.m]
			+" <input type='text' value='"+this.y+"' style='text-align:center;width:32px;'"
				+" onFocus='javascript:this.select()'"
				+" onChange='javascript:xcalendars["+a+"].setAnyo(this.value)'"
				+" onKeyPress='javascript:if(event.keyCode==13)xcalendars["+a+"].setAnyo(this.value)'"
			+" />"
			+"</td>";
		h+="<td><a href='javascript:void(0)' onClick='javascript:xcalendars["+a+"].mesSiguiente();'>&gt;</a></td>";
		h+="</tr>";
		h+="<tr>";
		for (i=0;i<7;i++) {
			h+="<th>"+week_abrev[i]+"</th>";
		}
		h+="</tr>\n";
		h+="</thead>\n";
		h+="<tbody>\n";
		h+="<tr>";
		for (i=0;i<month_day;i++) {
			h+="<td></td>";
		}
		
		var today=new Date();
		for (i=0;i<month_days;i++) {
			var dia=new Date(this.y,this.m,i+1)
			var isToday=(this.sqlDate(dia)==this.sqlDate(today));
			if (dia)
				h+="<td>"
					+(this._efectiveDate(this.min) && dia<this._efectiveDate(this.min)
						|| this._efectiveDate(this.max) && dia>this._efectiveDate(this.max)
						?"<span>"+(i+1)+"</span>"
						:"<a"
						+" class='"
							+(isToday?"xcalendar_today ":"")
							+(this.seleccionados[this.sqlDate(dia)]?"xcalendar_selected":"")
						+"'"
						+" title='"+(isToday?"Hoy":"")+"'"
						+" href='javascript:void(0)'"
						+" onClick='javascript:xcalendars["+a+"]._seleccionar("+(i+1)+");'>"+(i+1)+"</a>"
					)
					+"</td>"
			if (!((i+month_day+1)%7)) {
				h+="</tr>\n";
				if (i+1!=month_days) {
					h+="<tr>";
				}
			}
		}
		for (i=((i+month_day)%7);i<7;i++) {
			h+="<td></td>";
		}
		h+="</tr>\n";
		h+="</tbody>\n";
		h+="</table>";
		this.div.innerHTML=h;
	};
	
	// actualizar otros divs relaccionados
	this._updateOthers=function(){
		if (typeof(this.min)=="string") {
			eval("var o="+this.min+";");
			if (o && o.refresh) o.refresh();
		}
		if (typeof(this.max)=="string") {
			eval("var o="+this.max+";");
			if (o && o.refresh) o.refresh();
		}
		this.refresh();
	};
	
	// seleccionar
	this._seleccionar=function(dia){
		var fecha=new Date(this.y,this.m,dia);
		this.seleccionar(fecha);
		if (this.loaded)
			if (this.onselect)
				this.onselect(fecha);
		if (this.input)
			this.input.value=this.spDate(this.seleccionada);
	};

	// seleccionar
	this.seleccionar=function(fecha){
		this.seleccionada=fecha;
		this.seleccionados={};
		if (fecha) {
			this.y=fecha.getFullYear();
			this.m=fecha.getMonth();
			this.seleccionados[this.sqlDate(this.seleccionada)]=this.seleccionada;
		}
		this.refresh();
		this._updateOthers();
	};
	
	// cerrar popup
	this.close=function(){
		if (xcal.trigger && xcal.div) {
			xcal.div.parentNode.removeChild(xcal.div);
			delete xcal.div;
		}
	};
	
	// convertir valor en fecha
	this.dateFromInput=function(v){
		if (v) {
			var x=v.split("/");
			if (x
				&& parseInt(x[0],10)>=1 && parseInt(x[0],10)<=31
				&& parseInt(x[1],10)>=1 && parseInt(x[1],10)<=12
				&& parseInt(x[2],10)>=1900 && parseInt(x[2],10)<=2999
			) {
				this.y=parseInt(x[2],10);
				this.m=parseInt(x[1],10)-1;
				var nueva=new Date(this.y,this.m,parseInt(x[0],10));
				return nueva;
			}
		} else {
			return null;
		}
		this.refresh();
	}
	
	// actualizar desde valor de input
	this.fromInput=function(){
		if (this.input) {
			var nueva=this.dateFromInput(this.input.value);
			if (nueva) {
				if (
					(!this._efectiveDate(this.min) || this.min && nueva>=this._efectiveDate(this.min))
					&& (!this._efectiveDate(this.max) || this.max && nueva<=this._efectiveDate(this.max))
				) {
					this.seleccionar(nueva);
				}
			} else {
				this.seleccionar(null);
			}
		}
	};
	
	// activar triggers
	if (this.input) {
		this.input.onfocus=this.input.onclick=function(){
			
			var xcal=xcalendars[xcalendars_active];
			xcal.close();
			
			xcalendars_active=a;
			var xcal=xcalendars[xcalendars_active];
			
			if (xcal.input) {
				xcal.fromInput();
				xcal.input.select();
			}
			
			if (xcal.trigger) {

				if (!xcal.div) {
					xcal.div=document.createElement("div");
					style(xcal.div,{
						"display":"block",
						"position":"absolute",
						"top":(getTop(xcal.input)+getHeight(xcal.input))+"px",
						"left":getLeft(xcal.input)+"px",
						"position":"absolute"
					});
					xcal.div.onmousedown=function(){
						xcalendars_cancelclick=true;
					}
					document.body.appendChild(xcal.div);
				}
				
				xcal.refresh();
				
			}
			
		};
	}
		
	if (xcal.trigger) {
		this.trigger.onkeydown=function(e){
			if (!e) var e=window.event;
			if (e.keyCode==9)
				xcal.close();
		};
		
	}
	
	// inicialización de eventos por primera vez
	if (xcalendars.length==1) {
		if (this.trigger) {
			mouseup(function(){
				var xcal=xcalendars[xcalendars_active];
				if (!xcalendars_cancelclick)
					if (xcal.div && xcal.trigger)
						xcal.close();
				xcalendars_cancelclick=false;
			});
		}
	}
	
	// filtrar inputs
	if (this.input) {
		
		this.input.onkeydown=function(e) {
			if (!e) var e=window.event;
			var c=e.keyCode;
			if (c>=35 && c<=39) return true;
			switch (c) {
			case 32:
			//case 190:
				//if (with_time)
					//return true;
			case 67: // C
			case 86: // V
			case 88: // X
				if (xcal.keyControl)
					return true;
				return false;
				if (xcal.keyControl)
					return true;
				return false;
			case 16: xcal.keyShift=true;
			case 17: xcal.keyControl=true;
			case 46:
			case 116:
			case 8:
			case 13:
			case 9:
				if (xcal.trigger)
					xcal.close();
			case 15:
			case 55:
				return true;
			default:
				//alert(c);
			}
			//if (selectedText()=="" && i.value.length==10) return false;
			if (!xcal.keyShift && c>=48 && c<=57) return true;
			return false;
		}

		this.input.onkeypress=function(e) {
			if (!e) var e=window.event;
			var c=e.keyCode;
		}

		this.input.onkeyup=function(e) {
			if (!e) var e=window.event;
			var c=e.keyCode;
			//var l=(with_time?16:10);
			switch (c) {
			case 16: xcal.keyShift=false; break;
			case 17: xcal.keyControl=false; break;
			}
			//if (xcal.input.value.length>l) xcal.input.value=xcal.input.value.substring(0,l);
			xcal.fromInput();
		}

		this.input.onchange=function(){
			xcal.fromInput();
		};
		
	}
	
	// actualizar fecha desde input
	this.fromInput();
	
	// si hay DIV indicado, escribir el calendario en dicho DIV
	this.refresh();
	
	// actualizar otros divs asociados
	setTimeout(function(){
		xcal._updateOthers();
		xcal.loaded=true;
	},1);

}
var xformdata={};

function xformDateDown(e,i,with_time) {
	if (!e) var e=window.event;
	var c=e.keyCode;
	if (c>=35 && c<=39) return true;
	switch (c) {
	case 32:
	case 190:
		if (with_time)
			return true;
	case 16: keyShift=true;
	case 46:
	case 116:
	case 8:
	case 13:
	case 9:
	case 15:
		return true;
	}
	//if (selectedText()=="" && i.value.length==10) return false;
	if (!keyShift && c>=48 && c<=57) return true;
	return false;
}

function xformDatePress(e,i) {
	if (!e) var e=window.event;
	var c=e.keyCode;
	if (c==16) keyShift=false;
	if (i.value.length==2 && e.keyCode!=8)
		i.value+="/";
	if (i.value.length==5 && e.keyCode!=8)
		i.value+="/";
}

function xformDateUp(e,i,with_time) {
	if (!e) var e=window.event;
	var c=e.keyCode;
	var l=(with_time?16:10);
	if (c==16) keyShift=false;
	if (i.value.length>l) i.value=i.value.substring(0,l);
}

function xformPhoneDown(e,i) {
	if (!e) var e=window.event;
	var c=e.keyCode;
	if (c>=35 && c<=39) return true;
	switch (c) {
	case 16: keyShift=true;
	case 46:
	case 116:
	case 107:
	case 8:
	case 13:
	case 9:
	case 15:
		return true;
	}
	if (!keyShift && c>=48 && c<=57) return true;
	return false;
}
/*
	Ejemplo de uso:
	filer.open({
		"title":"Pruebas para seleccionar fichero",
		"mode":"", // default(newalert)/xwin/div
		"div":"contenedor", // para modo div
		"xwin":{ // para modo xwin
			"top":100,
			"left":100,
		},
		"path":"",
		"vista":"imagenes",
		"onopen":function(f){
			alert(adump(f));
		},
		"onclose":function(f){
			alert("close!");
		}
	});
*/
var filer={
	"ext":null,
	"o":{},
	"path":"",
	"dir":[],
	"seleccionado":null,
	"vista":"",
	"vistanext":function(){
		switch (this.vista) {
		case "": this.vista="imagenes"; break;
		default: this.vista="";
		}
		this.refresh();
	},
	"back":function(){
	},
	"up":function(){
	},
	"nuevacarpeta":function(){
		newalert({
			"id":"newfolder",
			"ico":"newfolder",
			"msg"
				:"<div>Indique nombre de nueva carpeta:</div>"
				+"<div><input id='filer_newfolder' value='Nueva carpeta' class='txt' type='text' style='width:200px;' /></div>"
			,
			"buttons":[
				{"caption":"Crear","ico":"images/ico16/foldernew.png","action":function(){
					newwait();
					ajax("filer:newfolder",{
						"filer":(filer.o.filer?filer.o.filer:""),
						"path":filer.path,
						"folder":gidval("filer_newfolder")
					},function(){
						newwait_close();
					},function(r){
						newalert_close("newfolder");
						if (r.data.err) newerror(r.data.err);
						if (r.data.ok) {
							newok("Nueva carpeta creada correctamente.");
							filer.refresh();
						}
					});
				}},
				{"caption":"Cancelar","ico":"images/ico16/cancel.png"}
			]
		});
		gid("filer_newfolder").focus();
		gid("filer_newfolder").select();
	},
	"ira":function(p){
		if (this.path!=p) {
			this.path=p;
			this.refresh();
		}
	},
	"uploader_url":"/functanalysis/class/js.php?ajax=filer:uploader",
	"open":function(o){
		this.o=o;
		this.path=(o.path?o.path:"");
		this.vista=(o.vista?o.vista:"");
		var h
			="<div class='filer'>"
				+"<div class='filer_head'>"
					+"<div class='filer_address'>"
						+"<table><tr>"
							+"<td width='99%'><select id='filer_path' class='cmb' style='width:99%;' onClick='javascript:filer.ira(this.value)' onChange='javascript:filer.ira(this.value)' onKeyUp='javascript:filer.ira(this.value)'>"
							+"</select></td>"
							+"<td width='1%'><div class='filer_tools'>"
								+"<a href='javascript:filer.subir()' style=\"background-image:url('images/ico16/up.png')\"><span>Subir</span></a>"
								+"<a href='javascript:filer.nuevacarpeta()' style=\"background-image:url('images/ico16/foldernew.png')\"><span>N.Carpeta</span></a>"
								+"<a href='javascript:filer.refresh()' style=\"background-image:url('images/ico16/refresh.png')\"><span>Recargar</span></a>"
								+"<a href='javascript:filer.vistanext()' style=\"background-image:url('images/ico16/search.png')\"><span>Vista</span></a>"
							+"</div></td>"
						+"</tr></table>"
					+"</div>"
					+"<div class='filer_thead'>"
						+"<div class='filer_row'>"
							+"<span class='filer_file filer_th'>Nombre del fichero</span>"
							+"<span class='filer_scroll filer_th'></span>"
							+"<span class='filer_fecha filer_th'>Fecha</span>"
							+"<span class='filer_size filer_th'>Tama&ntilde;o</span>"
						+"</div>"
					+"</div>"
				+"</div>"
				+"<div id='filer_dir' class='filer_body'>"
				+"</div>"
				+"<div class='filer_foot'>"
					+"<div class='filer_selectors'>"
						+"<table>"
																	
							+"<tr>"
								+"<th width='1%'>Seleccionado:</th>"
								+"<td width='97%'>"
									+"<input id='filer_seleccionado' class='txt' value='' style='width:99%;' onChange='javascript:filer.filename(this.value);' onKeyUp='javascript:filer.filename(this.value);' />"
								+"</>"
								+"<td width='1%'>"
									+"<a class='cmd' href='javascript:filer.borrar()' style='padding-left:8px;padding-right:6px;'><span class='icon' style=\"background-image:url('images/ico16/delete.png');padding-left:16px;\"></span></a>"
								+"</td>"
								+"<td width='1%'><a class='cmd' href='javascript:filer.seleccionar()'>"
									+"<span class='icon' style=\"background-image:url('images/ico16/ok.png')\">Aceptar</span>"
								+"</a></td>"
							+"</tr>"
							
							+"<tr>"
								+"<th width='1%'>Formatos:</th>"
								+"<td width='98%' colspan='2'>"
									+"<select id='filer_formatos' class='cmb' style='width:99%;' onClick='javascript:filer.filter(this.value)' onChange='javascript:filer.filter(this.value)' onKeyUp='javascript:filer.filter(this.value)'>"
										+"<option value='' selected>Todos los archivos</option>"
									+"</select>"
								+"</td>"
								+"<td width='1%'><a class='cmd' href='javascript:filer.close();'>"
									+"<span class='icon' style=\"background-image:url('images/ico16/cancel.png')\">Cancelar</span>"
								+"</a></td>"
							+"</tr>"

							+"<tr id='file_upload'>"
								+"<th width='1%'>Subir:</th>"
								+"<td width='98%' colspan='2'>"
									+"<iframe id='file_uploader' src='"+this.uploader_url+"&path="+gescape(this.path)+"' style='width:100%;height:25px;' frameborder='0'></iframe>"
								+"</td>"
								+"<td width='1%'><a class='cmd' href='javascript:filer.upload();'>"
									+"<span class='icon' style=\"background-image:url('images/ico16/up.png')\">Subir</span>"
								+"</a></td>"
							+"</tr>"
							
						+"</table>"
					+"</div>"
				+"</div>"
			+"</div>"
		;
		
		var title=(o.title?o.title:"Seleccionar archivo");
		switch (this.o.mode) {
		case "div":
			gidset(gid(this.o.div),h);
			break;
			
		case "xwin":
			var opciones={
				"caption":title,
				"width":580,"height":600,
				"minwidth":500,"minheight":300,
				"center":true,
				"body":h
			}
			this.o.xwin=xwinNew(array_merge(opciones,(o.xwin?o.xwin:{})));
			break;
		
		default:
			newalert({
				"id":"filer",
				"ico":"",
				"title":title,
				"msg":"<div style='width:550px;height:500px;padding-bottom:40px;'><div style='width:550px;height:500px;'>"+h+"</div></div>",
				"buttons":[]
			});
		}
		
		this.refresh();
		
	},
	"close":function(){
		switch (this.o.mode) {
		case "div": break;
		case "xwin": xwinClose(this.o.xwin); break;
		default: newalert_close("filer");
		}
		if (this.o.onclose)
			this.o.onclose(this);
	},
	"upload":function(){
		if (!gid("file_uploader").contentWindow.upload()) {
			newwarn("Por favor, especifique un fichero.");
		}
	},
	"uploaded":function(o){
		if (o && o.ok) {
			newok("Fichero "+o.file+" de "+o.sizet+" bytes subido correctamente.");
			filer.refresh();
		} else {
			if (o) {
				parent.newwarn("Acceso denegado en escritura a esta carpeta."+adump(o));
			} else {
				parent.newwarn("Error en operacioacute;n");
			}
		}
		gid("file_uploader").src=this.uploader_url+"&path="+gescape(this.path)+"&nocache="+(new Date().getTime())
	},			
	"refresh":function(){
		newsimplewait();
		ajax("filer:list",{
			"filer":(this.o.filer?this.o.filer:""),
			"path":this.path,
			"ext":filer.ext
		},function(){
			newwait_close();
		},function(r){
			if (r.data.ok) {
				// actualizar datos
				filer.root=r.data.root;
				filer.path=r.data.path;
				filer.dir=r.data.dir;
				filer.count=r.data.count;
				// crear listado de ficheros
				var h="";
				var num=0;
				for (var i in filer.dir) {
					num++;
					if (num>filer.count) break;
					var dir=filer.dir[i];
					var url=dir.path+filer.path+dir.file;
					switch (filer.vista) {
					case "imagenes":
						h+="<a href='"+url+"'"
									+" onClick='javascript:filer.marcar("+i+");return(false);'"
									+" onDblClick='javascript:filer.double("+i+")'"
									+" class='filer_image' title='"+dir.file+"'"
									+" style='background-image:url(\""+dir.imagen+"\");'"
								+">"
								+"<div>"+dir.file+"</div>"
							+"</a>";
						break;
					default:
						h+="<a href='"+url+"'"
									+" onClick='javascript:filer.marcar("+i+");return(false);'"
									+" onDblClick='javascript:filer.double("+i+")'"
									+" class='filer_row filer_entry' title='"+dir.file+"'"
								+">"
								+"<span class='filer_file' style=\"background-image: url('"+dir.ico+"');\">"+dir.file+"</span>"
								+"<span class='filer_fecha'>"+dir.mtimet+"</span>"
								+"<span class='filer_size'>"+dir.sizet+"</span>"
							+"</a>"
						;
					}
				}
				// rellenar extensiones (si hay diferentes)
				if (r.data.exts) {
					filer.ext=r.data.ext;
					comboClear('filer_formatos');
					"ext"
					var i=0;
					for (var e in r.data.exts) {
						comboAdd('filer_formatos',r.data.exts[e],e,(!i && filer.ext===null || filer.ext==e?true:false));
						i++;
					}
				}
				// rellenar arbol de carpetas
				comboClear('filer_path');
				var dpath=filer.path;
				var i=0;
				while (true) {
					comboAdd('filer_path',"/"+dpath,dpath,(!i?true:false));
					if (!dpath) break;
					dpath=filer.previo(dpath)
					i++;
				}
				// actualizar ruta de subida de ficheros
				if (gid("file_uploader").contentWindow) {
					try {
						gid("file_uploader").contentWindow.document.getElementById("path").value=filer.path;
					} catch(e) {}
				}
				// establecer visibilidad del cuadro de upload
				gid("file_upload").style.visibility=(r.data.upload?"visible":"hidden");
				// mostrar directorio y subir scroll al inicio
				gidset("filer_dir",h);
				gid("filer_dir").scrollTop="0px";
			}
		});
		
	},
	"filename":function(filename){
		this.seleccionado={
			"file":filename,
			"path":this.root+this.path,
			"manual":true
		}
	},
	"double":function(id){
		if (this.dir[id].dir) {
			this.ira(this.path+this.dir[id].file+"/");
			this.desmarcar();
		} else {
			this.seleccionar();
		}
	},
	"desmarcar":function(){
		this.seleccionado=null;
		gidval("filer_seleccionado","");
	},
	"marcar":function(id){
		this.seleccionado=this.dir[id];
		this.seleccionado.path+=this.path,
		gidval("filer_seleccionado",this.dir[id].file);
	},
	"seleccionar":function(){
		this.o.onopen(this.seleccionado);
	},
	"subir":function(){
		this.ira(this.previo(this.path));
	},
	"borrar":function(){
		if (!filer.seleccionado) {
			newwarn("Por favor, primero seleccione un archivo/carpeta.");
			return;
		}
		newalert({
			"id":"delete",
			"ico":"warn",
			"msg":"¿Est&aacute; seguro de querer borrar "+(filer.seleccionado.dir?"esta carpeta":"este fichero")+"?",
			"buttons":[
				{"caption":"Borrar","ico":"images/ico16/delete.png","action":function(){
					newwait();
					ajax("filer:delete",{
						"filer":(filer.o.filer?filer.o.filer:""),
						"path":filer.path,
						"file":filer.seleccionado.file
					},function(){
						newwait_close();
					},function(r){
						newalert_close("delete");
						if (r.data.err) newerror(r.data.err);
						if (r.data.ok) {
							newok(filer.seleccionado.dir
								?"Carpeta borrada correctamente."
								:"Fichero borrado correctamente."
							);
							filer.desmarcar();
							filer.refresh();
						}
					});
				}},
				{"caption":"Cancelar","ico":"images/ico16/cancel.png"}
			]
		});
		
	},
	"previo":function(p){
		var dpath="";
		for (var i=p.length-2;i>=0;i--)
			if (p[i]=="/") {
				dpath=p.substring(0,i+1);
				break;
			}
		return dpath;
	},
	"filter":function(ext){
		if (this.ext!=ext) {
			this.ext=ext;
			this.refresh();
		}
	}
};
/*
	Ejemplo de uso:
	mailerOpen({
		"from":"Usuario origen <origen@servidor.org>",
		"to":"Destino <destino@servidor.org>",
		"cc":"",
		"bcc":"",
		"subject":"Asunto del mensaje",
		"text":"AhÃ­ va un <b>mensaje</b> de prueba :)",
		"html":true,
		"onsend":function(o,r){
			newok("Solicitud enviada.");
		}
	});
*/
function mailerOpen(o) {
	var prefix="mailer";
	var ids="from reply to cc bcc subject text";
	newalert({
		"id":"mailer",
		"ico":"",	
		"title":(o.title?o.title:"Mailer"),
		"msg":"<table class='ftable'>"
			+"<tr><th class='nowrap'>Emisor:</th><td><input id='mailer_from' class='txt' type='text' value='' style='width:100%;' /></td></tr>"
			+"<tr><th class='nowrap'>Responder a:</th><td><input id='mailer_reply' class='txt' type='text' value='' style='width:100%;' /></td></tr>"
			+"<tr><th class='nowrap'>Receptor:</th><td><input id='mailer_to' class='txt' type='text' value='' style='width:100%;' /></td></tr>"
			+"<tr><th class='nowrap'>CC:</th><td><input id='mailer_cc' class='txt' type='text' value='' style='width:100%;' /></td></tr>"
			+"<tr><th class='nowrap'>CCO:</th><td><input id='mailer_bcc' class='txt' type='text' value='' style='width:100%;' /></td></tr>"
			+"<tr><th class='nowrap'>Asunto:</th><td><input id='mailer_subject' class='txt' type='text' value='' style='width:100%;' /></td></tr>"
			+"<tr><th class='nowrap'>Mensaje:</th><td><textarea id='mailer_text' class='txt' style='width:500px;height:400px;'></textarea></td></tr>"
			+"</table>"
			,
		"buttons":[
			{"caption":"Enviar","ico":"images/ico16/email.png","action":function(){
				newwait();
				var datos=gpreids(prefix,ids);
				if (tinyMCE && o.html) {
					delete datos.text;
					datos.html=tinyMCE.get('mailer_text').getContent();
				}
				ajax("mailer:send",datos,function(){
					newwait_close();
				},function(r){
					if (r.data.err) {
						if (o.onsenderr) o.onsenderr(o,r);
						else newerror(r.data.err);
					}
					if (r.data.ok) {
						newalert_close("mailer");
						if (o.onsendok) o.onsendok(o,r);
						else newok("Mensaje enviado correctamente.");
					}
				});
			}},
			{"caption":"Cancelar","ico":"images/ico16/cancel.png","action":function(){
				if (o.oncancel)
					o.oncancel(o);
				newalert_close("mailer");
			}}
		]
	});
	spreids(prefix,ids,{
		"from":(o.from?o.from:""),
		"reply":(o.reply?o.reply:""),
		"to":(o.to?o.to:""),
		"cc":(o.cc?o.cc:""),
		"bcc":(o.bcc?o.bcc:""),
		"subject":(o.subject?o.subject:""),
		"text":(o.text?o.text:"")
	});
	if (o.html) {
		if (typeof(tinyMCE)=="undefined") {
			newwarn("No se puede usar el editor HTML porque no estÃ¡ disponible tinyMCE.");
			o.html=false;
		} else {
			tinyMCE.init({
				
				// setup
				"mode":"exact",
				"elements":"mailer_text",
				"theme":"advanced",
				"language":"es",
				"plugins":"autolink,lists,pagebreak,style,layer,table,save,advhr,advimage,advlink,emotions,iespell,inlinepopups,insertdatetime,preview,media,searchreplace,print,contextmenu,paste,directionality,fullscreen,noneditable,visualchars,nonbreaking,xhtmlxtras,template,wordcount,advlist,autosave",

				// theme options
				theme_advanced_buttons1 : "newdocument,|,bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,styleselect,formatselect,fontselect,fontsizeselect",
				theme_advanced_buttons2 : "cut,copy,paste,pastetext,pasteword,|,search,replace,|,bullist,numlist,|,outdent,indent,blockquote,|,undo,redo,|,link,unlink,anchor,image,cleanup,help,code,|,insertdate,inserttime,preview,|,forecolor,backcolor",
				theme_advanced_buttons3 : "tablecontrols,|,hr,removeformat,visualaid,|,sub,sup,|,charmap,emotions,iespell,media,advhr,|,print,|,ltr,rtl,|,fullscreen",
				theme_advanced_buttons4 : "insertlayer,moveforward,movebackward,absolute,|,styleprops,|,cite,abbr,acronym,del,ins,attribs,|,visualchars,nonbreaking,template,pagebreak,restoredraft",
				theme_advanced_toolbar_location : "top",
				theme_advanced_toolbar_align : "left",
				theme_advanced_statusbar_location : "bottom",
				theme_advanced_resizing : true,

				// example content CSS (should be your site CSS)
				content_css : "index.css"

				// drop lists for link/image/media/template dialogs
				//template_external_list_url : "lists/template_list.js",
				//external_link_list_url : "lists/link_list.js",
				//external_image_list_url : "lists/image_list.js",
				//media_external_list_url : "lists/media_list.js",

				// style formats
				/*style_formats : [
					{title : 'Bold text', inline : 'b'},
					{title : 'Red text', inline : 'span', styles : {color : '#ff0000'}},
					{title : 'Red header', block : 'h1', styles : {color : '#ff0000'}},
					{title : 'Example 1', inline : 'span', classes : 'example1'},
					{title : 'Example 2', inline : 'span', classes : 'example2'},
					{title : 'Table styles'},
					{title : 'Table row 1', selector : 'tr', classes : 'tablerow1'}
				]*/
				
			});
		}
	}
}
/*
	TÃ­tulo..: xpopup - mr.xkr's JavaScript Non-obstrusive Popup
	Licencia: GPL (http://www.gnu.org/licenses/gpl.txt)
	Autor...: Pablo RodrÃ­guez Rey (mr -en- xkr -punto- es)
	          http://mr.xkr.es/
	Requiere: common.js
	Usa libremente esta librerÃ­a bajo los tÃ©rminos de la licencia GPL, pero por favor,
	deja la autorÃ­a intacta, es lo Ãºnico que te pido, sÃ³lo son 419 bytes de carga ;-)
*/

var xpopup_menu=null;
var xpopup_cancelContextMenu=false;
var xpopup_cancelClick=false;
var xpopup_menuItem=null;
var xpopup_menuFirstClick=true;
var xpopup_lastShift=null;
var xpopup_lastHold=null;
var xpopup_selectedItems={};

// item actual seleccionado
function xpopupItem() {
	return xpopup_menuItem;
}

// seleccionar un item
function xpopupItemSelect(o,swap) {
	var i=o.getAttribute("xType")+o.getAttribute("xItem");
	//xpopup_selectedItems[i]=(xpopup_selectedItems[i]?(swap?false:o):o);
	if (xpopup_selectedItems[i]) {
		if (swap) {
			o.className=o.className.replace(" xpopupItemSelected","");
			delete xpopup_selectedItems[i];
		}
	} else {
		xpopup_selectedItems[i]=o;
		o.className+=" xpopupItemSelected";
	}
	//alert(i+" - swap:"+swap);
}

// deseleccionar todos los items
function xpopupSelectNone() {
	for (var i in xpopup_selectedItems)
		xpopupItemSelect(xpopup_selectedItems[i],true);
}

// contar el nÃºmero de items seleccionados
function xpopupSelectCount() {
	var i=0;
	for (var v in xpopup_selectedItems)
		i++;
	return i;
}

// devolver la lista de items seleccionados
function xpopupSelectedItems() {
	var a=[];
	for (var i in xpopup_selectedItems) {
		var o=xpopup_selectedItems[i];
		a.push({
			"item":o.getAttribute("xItem"),
			"type":o.getAttribute("xType"),
			"template":o.getAttribute("xTemplate"),
			"o":o
		});
	}
	return a;
}

// hacer click en un item
function xpopupItemClick(selectable,o,func,unfunc) {
	var lastItem=xpopup_menuItem;
	// setup
	if (xpopup_menuFirstClick) {
		xpopup_menuFirstClick=false;
		setTimeout(function(){
			scroll(function(){ xpopup_cancelClick=true; });
			mouseup(function(){
				setTimeout(function(){
					if (!xpopup_cancelClick) {
						xpopupSelectNone();
						xpopupDestroy();
					}
					xpopup_cancelClick=false;
				},1);
			});
			xpopup_cancelClick=false;
		},1);
	}
	// actions
	if (xpopup_menuItem && xpopup_menuItem.item==o.getAttribute("xItem") && xpopup_menuItem.type==o.getAttribute("xType")) {
		if (xpopup_menuItem.unfunc) xpopup_menuItem.unfunc(xpopup_menuItem);
		return (o.href=="javascript:void(0)"?false:true);
	}
	xpopupDestroy();
	xpopup_cancelClick=true;
	xpopup_menuItem={
		"item":o.getAttribute("xItem"),
		"type":o.getAttribute("xType"),
		"template":o.getAttribute("xTemplate"),
		"func":(func?func:null),
		"unfunc":(unfunc?unfunc:null),
		"o":o,
		"multi":false // selecciÃ³n mÃºltiple
	};
	if (selectable && ((xpopup_lastShift && lastItem) || (xpopup_lastHold && lastItem))) {
		if (xpopup_lastShift && lastItem) {
			var min=Math.min(lastItem.o.parentNode.offsetTop,xpopup_menuItem.o.parentNode.offsetTop);
			var max=Math.max(lastItem.o.parentNode.offsetTop,xpopup_menuItem.o.parentNode.offsetTop);
		} else {
			var min=xpopup_menuItem.o.parentNode.offsetTop;
			var max=min;
		}
		var elements=o.parentNode.parentNode.getElementsByTagName("LI");
		for (var i=0;i<elements.length;i++) {
			var a=elements[i].getElementsByTagName("A")[0];
		 	var pos=elements[i].offsetTop;
			//alert("("+i+") "+pos+" "+min+"/"+max+" "+a.getAttribute("xItem")+" "+a.getAttribute("xType"));
			if (pos==lastItem.o.parentNode.offsetTop || pos<min || pos>max) continue;
			xpopupItemSelect(a,true);
		}
		xpopup_menuItem.multi=true;
		var last=null;
		for (var i in xpopup_selectedItems)
			if (!last || last.parentNode.offsetTop<xpopup_selectedItems[i].parentNode.offsetTop)
				last=xpopup_selectedItems[i];
		if (last) {
			var aux=xpopup_menuItem.o;
			xpopup_menuItem.o=last;
			xpopupDisplay({"multi":true});
			xpopup_menuItem.o=aux;
		}
	} else {
		xpopupSelectNone();
		xpopupItemSelect(o);
		xpopupDisplay();
	}
	return false;
}

// destruir popup
function xpopupDestroy(preserve_menuItem) {
	if (xpopup_menu) xpopup_menu.parentNode.removeChild(xpopup_menu);
	if (xpopup_menuItem) if (xpopup_menuItem.o) xpopup_menuItem.o.className=xpopup_menuItem.o.className.replace(" xpopupItemActive","");
	xpopup_menu=null;
	if (!preserve_menuItem) xpopup_menuItem=null;
}

// mostrar popup
function xpopupDisplay(o) {
	if (!(o && o.multi))
		xpopup_menuItem.o.className=xpopup_menuItem.o.className+" xpopupItemActive";
	xpopup_menu=document.createElement("div");
	var template="popup."+(o && o.multi?"multi":xpopup_menuItem.template);
	if (!gid("template:"+template)) {
		xpopup_menu=null;
		return;
	}
	gidset(xpopup_menu,gtemplate(template,{
		"$item":xpopup_menuItem.item,
		"$type":xpopup_menuItem.type,
		"$template":xpopup_menuItem.template
	}));
	document.body.appendChild(xpopup_menu);
	xpopup_menu.className="xPopup";
	style(xpopup_menu,{"position":"fixed","float":"left"});
	xpopup_menu.onmousedown=function(){ xpopup_cancelClick=true; }
	xpopup_menu.onload=function(){ xpopupDisplay(o); }
	if (xpopup_menuItem.func) xpopup_menuItem.func(xpopup_menuItem);
	var w=getWidth(xpopup_menu);
	style(xpopup_menu,{
		"left":(getLeft(xpopup_menuItem.o)+getWidth(xpopup_menuItem.o)-w)+"px",
		"top":(getTop(xpopup_menuItem.o)+getHeight(xpopup_menuItem.o)-getBorderBottomHeight(xpopup_menuItem.o))+"px",
		"display":"block",
		"position":"absolute"
	});
}

// eventos
resize(function(){
	xpopupDestroy(true);
	xpopupDisplay();
});
keydown(function(e){
	if (!e) var e=window.event;
	if (e.keyCode==16) xpopup_lastShift=true;
	if (e.keyCode==17) xpopup_lastHold=true;
});
keyup(function(e){
	if (!e) var e=window.event;
	if (e.keyCode==16) xpopup_lastShift=false;
	if (e.keyCode==17) xpopup_lastHold=false;
});
/*

	Clase xtabs v0.1, generador de pestaÃ±as con JavaScript no intrusivo.
	Creada por Pablo RodrÃ­guez Rey (en mr @ xkr punto(.) es) el 21/11/2010.

	HTML:
		<div id='tabs'>
			<ul>
				<li>Dependencia</li>
				<li>Edificio</li>
			</ul>
			<div xname='dependencia'>
				Contenido de la primera pestaÃ±a
			</div>
			<div xname='edificio'>
				Contenido de la segunda pestaÃ±a
			</div>
		</div>

	JavaScript:
		var tabs=new xtabs("pestaÃ±as");
		tabs.go(1); // opcional
		tabs.go("edificio"); // opcional
		alert(tabs.actual) // devuelve el atributo xname de la pestaÃ±a actual, o el objeto en caso de no especificar atributo xname
		tabs.onclick=function(pos,tab){ alert(pos+" "+tab); }; // opcional: evento de pulsaciÃ³n

*/
var tabgo={};
function xtabs(id,o) {
	var a=this;
	a.xnames={};
	a.actual="";
	a.tab=0;
	a.o=(o?o:{});
	a.onclick=null;
	a.go=function(n) {
		if (typeof(n)=="string") {
			if (typeof(a.xnames[n])=="undefined") return false;
			var n=a.xnames[n];
		}
		for (i=0;;i++) {
			var t=gid(a.id+"_t"+i);
			var c=gid(a.ids[i]);
			if (!t) break;
			t.className=(t.style.backgroundImage?"xtabico ":"")+(i==n?"xtab_active":"");
			var tabhide=(t.getAttribute("xhide")=="1"?true:false);
			t.style.display=(tabhide?"none":(a.o.vertical?"block":"inline"));
			if (c) {
				c.className="xtab";
				c.style.display=(i==n?"block":"none");
				if (i==n)
					a.actual=(c.getAttribute("xname")?c.getAttribute("xname"):c);
			}
		}
		a.tab=n;
		if (a.onclick)
			a.onclick(a.tab,a.actual);
	};
	a.refresh=function() {
		a.go(a.tab);
	};
	a.gettab=function(tabname){
		for (i=0;;i++) {
			var t=gid(a.id+"_t"+i);
			var c=gid(a.ids[i]);
			if (!t || !c) break;
			if (c.getAttribute("xname")==tabname) return t;
		}
		return false;
	};
	a.visible=function(tabname,state){
		var t=a.gettab(tabname);
		t.setAttribute("xhide",(state?"":"1"));
		a.refresh();
	};
	a.hasClass=function(element,c) {
		var e=element.className.split(" ");
		for (var i=0; i<e.length; i++)
			if (e[i]==c)
				return true;
		return false;
	};
	a.ids=[];
	a.id=id;
	tabgo[a.id]=a;
	gid(id).className="xtabs";
	var ul=gid(a.id).getElementsByTagName("ul")[0];
	ul.className=(a.o.vertical?"xtabs_vertical":"xtabs_horizontal");
	var tabs=ul.getElementsByTagName("li");
	for (i=0;i<tabs.length;i++) {
		if (tabs[i].parentNode.parentNode.id!=a.id) continue;
		tabs[i].id=a.id+"_t"+i;
		tabs[i].setAttribute("onmousedown","javascript:void(tabgo['"+a.id+"'].go("+i+"));");
		if (a.o.vertical) tabs[i].style.display="block";
	}
	a.go(-1); // establece CSS en pestaÃ±as, necesario para calcular el ancho de separaciÃ³n con el contenido
	var tabs=gid(id).getElementsByTagName("div");
	for (i=0;i<tabs.length;i++) {
		if (tabs[i].parentNode.id!=a.id) continue;
		tabs[i].className="xtab";
		if (!tabs[i].id)
			tabs[i].id=a.id+"_c"+i;
		a.ids.push(tabs[i].id);
		var xname=tabs[i].getAttribute("xname");
		if (xname)
			a.xnames[xname]=a.ids.length-1;
		if (a.o.width) tabs[i].style.width=o.width;
		if (a.o.height) tabs[i].style.height=o.height;
		if (a.o.vertical) tabs[i].style.marginLeft=(getWidth(ul)-1)+"px";
	}
	a.go(0);
}
/*
	TÃ­tulo..: xwin - mr.xkr's JavaScript Windows, implementaciÃ³n de ventanas DHTML
	Licencia: GPL (http://www.gnu.org/licenses/gpl.txt)
	Autor...: Pablo RodrÃ­guez Rey (mr -en- xkr -punto- es)
	          http://mr.xkr.es/
	Requiere: common.js
	Usa libremente esta librerÃ­a bajo los tÃ©rminos de la licencia GPL, pero por favor,
	deja la autorÃ­a intacta, es lo Ãºnico que te pido, sÃ³lo son 419 bytes de carga ;-)
*/

// rutas por defecto
var xwinImagePath="images/";
var xwinImageMin="xwin_bmin.gif";
var xwinImageMax="xwin_bmax.gif";
var xwinImageRestore="xwin_bres.gif";
var xwinImageClose="xwin_bclose.gif";
var xwinImageGenIcon="xwin_ico-generic.gif";
var xwinImageTrans="xwin_trans.gif";
var xwinAlphaShadow=true;

// opciones por defecto
var xwinBorderSize=3;
var xwinBorderResize=10;
var xwinShadowSizeLeft=4;
var xwinShadowSizeTop=8;
var xwinMoveMinSize=4;
var xwinMinWidth=150;
var xwinMinHeight=24;

// variables de las ventanas
var xwin=new Array();
var xwinMax=0;

// estado de las ventanas
var xwinActive=0;
var xwinActiveAction=0;
var xwinForeground=0;
var xwinIsTitle=false;
var xwinIsMain=false;
var xwinMoving=false;
var xwinResizing=false;
var xwinMaximized=false;
var xwinMoveMinSizeReached=false;
var xwinNoSelect=false;

// posiciones iniciales en movimientos/redimensionamiento
var xwinStartL;
var xwinStartT;
var xwinStartX;
var xwinStartY;
var xwinStartW;
var xwinStartH;
var xwinLastScrollX;
var xwinLastScrollY;
var xwinCreateL=0;
var xwinCreateT=0;
var xwinZIndex=100;

// constantes de redimensionamiento
var xwinRESLEFT=1;
var xwinRESRIGHT=2;
var xwinRESTOP=3;
var xwinRESBOTTOM=4;
var xwinRESTOPLEFT=5;
var xwinRESTOPRIGHT=6;
var xwinRESBOTTOMLEFT=7;
var xwinRESBOTTOMRIGHT=8;

// constantes de tÃ­tulos
var xwinTMINIMIZE="Minimizar";
var xwinTRESTORE="Restaurar";
var xwinTMAXIMIZE="Maximizar";
var xwinTCLOSE="Cerrar";

// cachÃ© de imÃ¡genes
var xwinImageCache=false;

// varios iniciales
var xwinCapturedEvents=false;

// traer una ventana al frente
function xwinFocus(wid) {
	xwinForeground=wid;
	for (i=1;i<=xwinMax;i++) {
		if (xwin[i] && i!=wid) {
			if (xwin[i].xwinMain.className!="xwinmain xwinmaindisabled") xwin[i].xwinMain.className="xwinmain xwinmaindisabled";
			if (xwin[i].xwinTitle.className!="xwintitle xwintitledisabled") xwin[i].xwinTitle.className="xwintitle xwintitledisabled";
			if (xwin[i].onblur) eval(xwin[i].onblur);
		}
	}
	if (!xwin[wid]) return;
	xwin[wid].xwin.style.zIndex=++xwinZIndex;
	xwin[wid].xwinShadow.style.zIndex=++xwinZIndex;
	xwin[wid].xwinMain.style.zIndex=++xwinZIndex;
	if (!xwin[wid].disabled) {
		xwin[wid].xwinMain.className="xwinmain";
		xwin[wid].xwinTitle.className="xwintitle";
		xwinActive=wid;
	}
	for (i=1;i<=xwinMax;i++) {
		if (xwin[i]) {
			if (xwin[i].ontop) {
				xwin[i].xwin.style.zIndex=++xwinZIndex;
				xwin[i].xwinShadow.style.zIndex=++xwinZIndex;
				xwin[i].xwinMain.style.zIndex=++xwinZIndex;
			}
		}
	}
}

// comprobar si el ratÃ³n se encuentra en los bordes
// y actuar en caso de estar en un borde de cambio de tamaÃ±o
function xwinMouseMoveCheck(e) {
	var x,y,wid=xwinActive;
	if (!wid) return;
	if (!xwin[wid] || xwinResizing || xwinMoving) return;
	if (xwin[wid].xwinMaximized || xwin[wid].xwinMinimized || xwin[wid].disabled) return;
	if (!e) e=window.event;

	xwinResizeAction=0;

	if (e.clientX>=parseInt(xwin[wid].xwinMain.style.left)
		&& e.clientX<=(parseInt(xwin[wid].xwinMain.style.left)+parseInt(xwin[wid].xwinMain.style.width))
		&& e.clientY>=parseInt(xwin[wid].xwinMain.style.top)
		&& e.clientY<=(parseInt(xwin[wid].xwinMain.style.top)+parseInt(xwin[wid].xwinMain.style.height))
		) {
		if (!xwin[wid].noresize) {

		  var sx=scrollLeft();
			var sy=scrollTop();

			x1=(e.clientX-parseInt(xwin[wid].xwinMain.style.left))-sx;
			x2=-(e.clientX-parseInt(xwin[wid].xwinMain.style.left)-parseInt(xwin[wid].xwinMain.style.width))+1-sx;
			y1=(e.clientY-parseInt(xwin[wid].xwinMain.style.top))-sy;
			y2=-(e.clientY-parseInt(xwin[wid].xwinMain.style.top)-parseInt(xwin[wid].xwinMain.style.height))+1-sy;

			if (x1>=0 && x1<=xwinBorderSize+2) xwinResizeAction=xwinRESLEFT;
			if (x2>=0 && x2<=xwinBorderSize+4) xwinResizeAction=xwinRESRIGHT;
			if (y1>=0 && y1<=xwinBorderSize+2) xwinResizeAction=xwinRESTOP;
			if (y2>=0 && y2<=xwinBorderSize+4) xwinResizeAction=xwinRESBOTTOM;

			if (x1>=0 && x1<=xwinBorderResize && y1>=0 && y1<=xwinBorderResize) xwinResizeAction=xwinRESTOPLEFT;
			if (x2>=0 && x2<=xwinBorderResize && y1>=0 && y1<=xwinBorderResize) xwinResizeAction=xwinRESTOPRIGHT;
			if (x1>=0 && x1<=xwinBorderResize && y2>=0 && y2<=xwinBorderResize) xwinResizeAction=xwinRESBOTTOMLEFT;
			if (x2>=0 && x2<=xwinBorderResize && y2>=0 && y2<=xwinBorderResize) xwinResizeAction=xwinRESBOTTOMRIGHT;

			if (xwinResizeAction) {
				switch (xwinResizeAction) {
				case xwinRESTOPLEFT: xwin[wid].xwinTitle.style.cursor="NW-resize"; break;
				case xwinRESTOPRIGHT: xwin[wid].xwinTitle.style.cursor="NE-resize"; break;
				case xwinRESBOTTOMRIGHT: xwin[wid].xwinMain.style.cursor="NW-resize"; break;
				case xwinRESBOTTOMLEFT: xwin[wid].xwinMain.style.cursor="NE-resize"; break;
				case xwinRESLEFT: xwin[wid].xwinMain.style.cursor="E-resize"; break;
				case xwinRESRIGHT: xwin[wid].xwinMain.style.cursor="E-resize"; break;
				case xwinRESTOP: xwin[wid].xwinTitle.style.cursor="N-resize";	break;
				case xwinRESBOTTOM: xwin[wid].xwinMain.style.cursor="N-resize";	break;
				}
				return(false);
			}
		}
	}
	
	xwin[wid].xwinMain.style.cursor="default";
	xwin[wid].xwinTitle.style.cursor="default";
	
}

// hacer click con el ratÃ³n... Â¿mover? Â¿redimensionar?
function xwinMouseDown(e) {
	var wid=xwinActive;

	// comprobar si se ha especificado al sistema
	// que no se permita la selecciÃ³n de texto temporalmente
	if (xwinNoSelect) {
		xwinNoSelect=false;
		return(false);
	}

	// comprobar si hay una ventana seleccionada
	if (!wid) return;
	if (!xwin[wid] || xwinResizing) return;
	if (xwin[wid].disabled || xwin[wid].xwinMaximized) return;
	if (!e) e=window.event;

	xwinStartX=e.clientX;
	xwinStartY=e.clientY;
	xwinStartL=(parseInt(xwin[wid].xwinMain.style.left)!=NaN?parseInt(xwin[wid].xwinMain.style.left):0);
	xwinStartT=(parseInt(xwin[wid].xwinMain.style.top)!=NaN?parseInt(xwin[wid].xwinMain.style.top):0);

	// comprobar si se estÃ¡ moviendo la ventana
	if (xwinIsTitle && !xwinResizeAction && !xwin[wid].nomobile) {
		xwinActiveAction=wid;
		xwinMoving=true;
		xwinMoveMinSizeReached=false;
		selectionEnabled(document.body,false); // deshabilitar selecciÃ³n
		return(false);
	}

	// comprobar si se estÃ¡ cambiando el tamaÃ±o
	if ((xwinIsMain || xwinIsTitle) && xwinResizeAction) {
		xwinActiveAction=wid;
		xwinStartW=xwin[wid].xwinMain.offsetWidth;
		xwinStartH=xwin[wid].xwinMain.offsetHeight;
		xwinResizing=true;
		selectionEnabled(document.body,false); // deshabilitar selecciÃ³n
		return(false);	
	}

	// comprobar si estÃ¡ dentro de una ventana
	if (!xwinIsMain && !xwinIsTitle) {
		xwinFocus(0);
	}

}

// desplazar el ratÃ³n... Â¿moviendo? Â¿redimensionando?
function xwinMouseMove(e) {
	var wid=xwinActiveAction;
	if (!e) e=window.event;

	// si se estÃ¡ moviendo la ventana
	if (xwinMoving) {
		var x=(e.clientX-xwinStartX);
		var y=(e.clientY-xwinStartY);
		if (xwinMoveMinSizeReached || x>xwinMoveMinSize || y>xwinMoveMinSize || x<-xwinMoveMinSize || y<-xwinMoveMinSize) {
			xwinMoveMinSizeReached=true;
			var newL=(xwinStartL+x),newT=(xwinStartT+y);
			xwin[wid].xwinMain.style.left=newL+"px";
			xwin[wid].xwinMain.style.top=(newT>0?newT:0)+"px";
			xwinUpdate(wid);
			xwinMouseMoveCheck(e);
		}
		return(false);
	}

	// si cambiando el tamaÃ±o
	if (xwinResizing) {
		var newT=0;
		var minL=0,minT=0;
		var newW=0,newH=0;
		switch (xwinResizeAction) {
		case xwinRESTOPLEFT:
			newL=xwinStartL+(e.clientX-xwinStartX);
			newW=xwinStartW-(e.clientX-xwinStartX);
			newT=xwinStartT+(e.clientY-xwinStartY);
			newH=xwinStartH-(e.clientY-xwinStartY);
			break;
		case xwinRESTOPRIGHT:
			newW=xwinStartW+(e.clientX-xwinStartX);
			newT=xwinStartT+(e.clientY-xwinStartY);
			newH=xwinStartH-(e.clientY-xwinStartY);
			break;
		case xwinRESBOTTOMLEFT:
			newL=xwinStartL+(e.clientX-xwinStartX);
			newW=xwinStartW-(e.clientX-xwinStartX);
			newH=xwinStartH+(e.clientY-xwinStartY);
			break;
		case xwinRESBOTTOMRIGHT:
			newW=xwinStartW+(e.clientX-xwinStartX);
			newH=xwinStartH+(e.clientY-xwinStartY);
			break;
		case xwinRESLEFT:
			newL=xwinStartL+(e.clientX-xwinStartX);
			newW=xwinStartW-(e.clientX-xwinStartX);
			break;
		case xwinRESRIGHT:
			newW=xwinStartW+(e.clientX-xwinStartX);
			break;
		case xwinRESTOP:
			newT=xwinStartT+(e.clientY-xwinStartY);
			newH=xwinStartH-(e.clientY-xwinStartY);
			break;
		case xwinRESBOTTOM:
			newH=xwinStartH+(e.clientY-xwinStartY);
			break;
		}
		
		// hacer efectivas las nuevas posiciones
		if (newL) xwin[wid].xwinMain.style.left=newL+"px";
		if (newT) xwin[wid].xwinMain.style.top=(newT>minT?newT:minT)+"px";
		if (newW) {
			if (newW<xwinMinWidth) newW=xwinMinWidth;
			if (xwin[wid].minwidth && newW<xwin[wid].minwidth) newW=xwin[wid].minwidth;
			if (xwin[wid].maxwidth && newW>xwin[wid].maxwidth) newW=xwin[wid].maxwidth;
			xwin[wid].xwinMain.style.width=newW+"px";
		}
		if (newH) {
			if (newH<xwinMinHeight) newH=xwinMinHeight;
			if (xwin[wid].minheight && newH<xwin[wid].minheight) newH=xwin[wid].minheight;
			if (xwin[wid].maxheight && newH>xwin[wid].maxheight) newH=xwin[wid].maxheight;
			xwin[wid].xwinMain.style.height=newH+"px";
		}
		
		// actualizar las capas
		xwinUpdate(wid);
		return(false);
	}

}

// se ha soltado el ratÃ³n
function xwinMouseUp(e) {

	// habilitar selecciÃ³n de nuevo
	selectionEnabled(document.body,true);

	xwinActiveAction=0;
	xwinMoving=false;
	xwinResizing=false;
	xwinResizeAction=0;
}

// F4 cierra la ventana activa
function xwinOnKeyDown(e) {
	if (!e) e=window.event;
	if (e.keyCode==115) xwinClose(xwinForeground);
}

// actualizar las posiciones y tamaÃ±os de una ventana
function xwinUpdate(wid) {
	var xwinMainWidth=parseInt(xwin[wid].xwinMain.style.width);
	var xwinMainHeight=parseInt(xwin[wid].xwinMain.style.height);

	// barra de tÃ­tulo
	xwin[wid].xwinCaption.style.width=xwinMainWidth-xwin[wid].xwinButtons.offsetWidth-(isie()?2:0)+"px";

	// sombra
	if (!xwin[wid].xwinMaximized) {
		xwin[wid].xwinShadow.style.left=(parseInt(xwin[wid].xwinMain.style.left)+xwinShadowSizeLeft)+"px";
		xwin[wid].xwinShadow.style.top=(parseInt(xwin[wid].xwinMain.style.top)+xwinShadowSizeTop)+"px";
		xwin[wid].xwinShadow.style.width=xwinMainWidth+"px";
		xwin[wid].xwinShadow.style.height=xwinMainHeight+"px";
	} else {
		xwin[wid].xwinShadow.style.visibility="hidden";
	}

	// contenido
	if (!xwin[wid].xwinMaximized && !xwin[wid].xwinMinimized) {
		var bodyW=(xwinMainWidth-xwinBorderSize*2);
		var bodyH=(xwinMainHeight-xwin[wid].xwinTitle.offsetHeight-xwinBorderSize*2);
		xwin[wid].xwinBody.style.left  =xwinBorderSize+"px";
		xwin[wid].xwinBody.style.top   ="0px";
		xwin[wid].xwinBody.style.width =(bodyW>1?bodyW:1)+"px";
		xwin[wid].xwinBody.style.height=(bodyH>1?bodyH+xwinBorderSize:1)+"px";
		xwin[wid].xwinShadow.style.visibility="visible";
	} else {
		var bodyW=(xwinMainWidth);
		var bodyH=(xwinMainHeight-xwin[wid].xwinTitle.offsetHeight-xwinBorderSize);
		xwin[wid].xwinBody.style.left  ="0px";
		xwin[wid].xwinBody.style.top   ="0px";
		xwin[wid].xwinBody.style.width =(bodyW>1?bodyW:1)+"px";
		xwin[wid].xwinBody.style.height=(bodyH>1?bodyH+xwinBorderSize:1)+"px";
		xwin[wid].xwinShadow.style.visibility="hidden";
	}
	if (bodyW<=1 || bodyH<=1) xwin[wid].xwinBody.style.visibility="hidden";
	else xwin[wid].xwinBody.style.visibility="visible";
	if (xwin[wid].disabled) {
		xwin[wid].xwinDisable.style.left  =xwin[wid].xwinBody.style.left;
		xwin[wid].xwinDisable.style.top   =xwin[wid].xwinBody.style.top;
		xwin[wid].xwinDisable.style.width =xwin[wid].xwinBody.style.width;
		xwin[wid].xwinDisable.style.height=xwin[wid].xwinBody.style.height;
		xwin[wid].xwinDisable.style.visibility="visible";
	} else {
		if (xwin[wid].xwinDisable.style.visibility!="hidden") xwin[wid].xwinDisable.style.visibility="hidden";
	}
}

// evento que mueve todas las ventanas si se desplaza la pÃ¡gina
function xwinScroll() {

	// nueva posiciÃ³n
	var scrX=ieTrueBody().scrollLeft;
	var scrY=ieTrueBody().scrollTop;

	// mover todas las ventanas afectadas
	for (wid=1;wid<=xwinMax;wid++) {
		if (gid('xwin'+wid)) {
			xwin[wid].xwinMain.style.left=(parseInt(xwin[wid].xwinMain.style.left)+(scrX-xwinLastScrollX))+"px";
			xwin[wid].xwinMain.style.top=(parseInt(xwin[wid].xwinMain.style.top)+(scrY-xwinLastScrollY))+"px";
			xwinUpdate(wid);
		}
	}

	// actualizar y restaurar variables
	xwinLastScrollX=scrX;
	xwinLastScrollY=scrY;

}

// comprobar cada 1ms en IE si se ha producido un desplazamiento
function xwinIEscrollTimer() {
	if (ieTrueBody().scrollLeft!=xwinLastScrollX || ieTrueBody().scrollTop!=xwinLastScrollY) xwinScroll();
	setTimeout("xwinIEscrollTimer()",1);
}

// cerrar una ventana y destruir el objeto asociado
function xwinClose(wid) {
	if (!xwin[wid]) return;
	if (!xwin[wid].xwin) return;
	xwin[wid].xwin.parentNode.removeChild(xwin[wid].xwin);
	xwin[wid]=false;
	xwinIsTitle=false;
	xwinIsMain=false;
}

// obtener el HTML del contenedor de la ventana
function xwinGetBody(wid) {
	return(gid('xwin'+wid+'body').innerHTML);
}

// definir el HTML del contenedor de la ventana
function xwinSetBody(wid,html) {
	var cmds="";
	for (var i in xwin[wid].buttons) {
		cmds+="<input class='cmd' type='button' value='"+xwin[wid].buttons[i].caption+"' onClick=\""+(xwin[wid].buttons[i].action?xwin[wid].buttons[i].action:"xwinClose("+wid+")")+"\" style='margin-left:9px;' />";
	}
	gid('xwin'+wid+'body').innerHTML=(cmds
		?"<table cellpadding='0' cellspacing='0' width='100%' height='100%'>"
			+"<tr><td>"+html+"</td></tr>"
			+"<tr height='1%'><td style='text-align:right;padding: 0px 9px 9px 9px;'>"+cmds+"</td></tr>"
		+"</table>"
		:html
	);
}

// minimizar una ventana
function xwinMin(wid) {
	var l,t,w,h;
	var xw=xwin[wid].xwin;
	
	// comprobar si estÃ¡ minimizada o no
	if (!xwin[wid].xwinMinimized) {
		xwin[wid].xwinMinimized=true;
		if (!xwin[wid].xwinMaximized) {
			xwin[wid].oldpos={
				"left":parseInt(xwin[wid].xwinMain.style.left),
				"top":parseInt(xwin[wid].xwinMain.style.top),
				"width":parseInt(xwin[wid].xwinMain.style.width),
				"height":parseInt(xwin[wid].xwinMain.style.height)
				};
		}
	  l=parseInt(xwin[wid].xwinMain.style.left);
		t=parseInt(xwin[wid].xwinMain.style.top);
	  w=xwinMinWidth;
	  h=xwin[wid].xwinTitle.offsetHeight+xwinBorderSize;
		if (gid('xwin'+wid+'bmaxi')) gid('xwin'+wid+'bmaxi').src=xwinImagePath+xwinImageRestore;
		if (gid('xwin'+wid+'bmaxa')) gid('xwin'+wid+'bmaxa').title=xwinTRESTORE;
		if (gid('xwin'+wid+'bmina')) gid('xwin'+wid+'bmina').style.display="none";
		eval("xwin["+wid+"].xwinCaption.ondblclick=function(){xwinMin("+wid+");}");
	} else {
		xwin[wid].xwinMinimized=false;
		if (gid('xwin'+wid+'bmina')) gid('xwin'+wid+'bmina').style.display="inline";
		if (!xwin[wid].xwinMaximized) {
			l=xwin[wid].oldpos.left;
			t=xwin[wid].oldpos.top;
			w=xwin[wid].oldpos.width;
			h=xwin[wid].oldpos.height;
			if (gid('xwin'+wid+'bmaxi')) gid('xwin'+wid+'bmaxi').src=xwinImagePath+xwinImageMax;
			if (gid('xwin'+wid+'bmaxa')) gid('xwin'+wid+'bmaxa').title=xwinTMAXIMIZE;
		} else {
			xwin[wid].xwinMaxFromMin=true;
			xwinRestore(wid);
		}
		eval("xwin["+wid+"].xwinCaption.ondblclick=function(){xwinRestore("+wid+");}");
	}
	
	// aplicar valores de posiciÃ³n y tamaÃ±o si procede
	if (!xwin[wid].xwinMaxFromMin) {
		xwin[wid].xwinMain.style.left=l+"px";
		xwin[wid].xwinMain.style.top=t+"px";
		xwin[wid].xwinMain.style.width=w+"px";
		xwin[wid].xwinMain.style.height=h+"px";
		xwinUpdate(wid);
	} else {
		xwin[wid].xwinMaxFromMin=false;
	}
}

// maximizar o restaurar el tamaÃ±o de una ventana
function xwinRestore(wid) {
	var l,t,w,h;
	var xw=xwin[wid].xwin;
	
	// si estÃ¡ minimizada, tratar por xwinMin
	if (xwin[wid].xwinMinimized) {
		xwinMin(wid);
		return;
	}
	
	// no se puede maximizar ni restaurar, no hay botÃ³n
	if (!gid('xwin'+wid+'bmaxi')) return
	
	// comprobar si estÃ¡ maximizada o no
	if (!xwin[wid].xwinMaximized || xwin[wid].xwinMaxFromMin) {
		xwin[wid].xwinMaximized=true;
		if (!xwin[wid].xwinMaxFromMin) {
			xwin[wid].oldpos={
				"left":parseInt(xwin[wid].xwinMain.style.left),
				"top":parseInt(xwin[wid].xwinMain.style.top),
				"width":parseInt(xwin[wid].xwinMain.style.width),
				"height":parseInt(xwin[wid].xwinMain.style.height)
				};
		}
	  var l=scrollLeft(); xwinLastScrollX=l;
		var t=scrollTop(); xwinLastScrollY=t;
	  var w=windowWidth();
	  var h=windowHeight();
		gid('xwin'+wid+'bmaxi').src=xwinImagePath+xwinImageRestore;
		gid('xwin'+wid+'bmaxa').title=xwinTRESTORE;
	} else {
		xwin[wid].xwinMaximized=false;
		l=parseInt(xwin[wid].oldpos.left);
		t=parseInt(xwin[wid].oldpos.top);
		w=parseInt(xwin[wid].oldpos.width);
		h=parseInt(xwin[wid].oldpos.height);
		gid('xwin'+wid+'bmaxi').src=xwinImagePath+xwinImageMax;
		gid('xwin'+wid+'bmaxa').title=xwinTMAXIMIZE;
	}
	
	// aplicar valores de posiciÃ³n y tamaÃ±o
	xwin[wid].xwinMain.style.left=l+"px";
	xwin[wid].xwinMain.style.top=t+"px";
	xwin[wid].xwinMain.style.width=w+"px";
	xwin[wid].xwinMain.style.height=h+"px";
	xwinUpdate(wid);
}

// poner mezcla alpha a las sombras de las ventanas
function xwinSetAlphaShadow(wid) {
	xwinAlphaShadow=true;
	for (i=(wid?wid:1);i<=(wid?wid:xwinMax);i++) {
		if (xwin[i].xwin) {
			if (isie()) xwin[i].xwinShadow.style.filter="alpha(opacity=50);";
			else xwin[i].xwinShadow.style.opacity=0.5;
		}
	}
}

// quitar mezcla alpha a las sombras de las ventanas
function xwinUnSetAlphaShadow() {
	xwinAlphaShadow=false;
	for (i=1;i<=xwinMax;i++) {
		if (xwin[i].xwin) {
			if (isie()) xwin[i].xwinShadow.style.filter="";
			else xwin[i].xwinShadow.style.opacity=1;
		}
	}
}

// poner sombras a las ventanas a unas distancias definidas por left y top
// si son 0 y 0 respectiamente se quitan las sombras
function xwinSetShadows(left,top) {
	xwinShadowSizeLeft=left;
	xwinShadowSizeTop=top;
	xwinAlphaShadow=false;
	for (i=1;i<=xwinMax;i++) {
		if (xwin[i].xwin) {
			xwinUpdate(i);
			xwin[i].xwinShadow.style.visibility=(xwinShadowSizeLeft||xwinShadowSizeTop?"visible":"hidden");
		}
	}
}

// poner una ventana siempre encima de las otras
function xwinSetOntop(wid) {
	xwin[wid].ontop=true;
	xwinFocus(xwinForeground);
}

// quitar una ventana de estar siempre encima de las otras
function xwinUnSetOntop(wid) {
	xwin[wid].ontop=false;
	xwinFocus(xwinForeground);
}

// habilitar redimensionaiento de una ventana
function xwinResize(wid) {
	xwin[wid].noresize=false;
}

// deshabilitar redimensionaiento de una ventana
function xwinNoResize(wid) {
	xwin[wid].noresize=true;
}

// habilitar el desplazamiento de una ventana
function xwinMobile(wid) {
	xwin[wid].nomobile=false;
}

// deshabilitar el desplazamiento de una ventana
function xwinNoMobile(wid) {
	xwin[wid].nomobile=true;
}

// mover una ventana y cambiar su tamaÃ±o si se especificase
// (todos los parÃ¡metros son opcionales excepto la ventana)
function xwinMove(wid,left,top,width,height) {
	xwinLeft(wid,left,true);
	xwinTop(wid,top,true);
	xwinWidth(wid,width,true);
	xwinHeight(wid,height,true);
	xwinUpdate(wid);
}

// cambiar el tamaÃ±o de una ventana
function xwinGeometry(wid,width,height) {
	xwinWidth(wid,width,true);
	xwinHeight(wid,height,true);
	xwinUpdate(wid);
}

// cambiar la posiciÃ³n horizontal de una ventana
function xwinLeft(wid,left,noupdate) {
	if (left!=undefined) xwin[wid].xwinMain.style.left=left;
	if (!noupdate) xwinUpdate(wid);
}

// cambiar la posiciÃ³n vertical de una ventana
function xwinTop(wid,top,noupdate) {
	if (top!=undefined) xwin[wid].xwinMain.style.top=top;
	if (!noupdate) xwinUpdate(wid);
}

// cambiar el ancho de una ventana
function xwinWidth(wid,width,noupdate) {
	if (width!=undefined) xwin[wid].xwinMain.style.width=width;
	if (!noupdate) xwinUpdate(wid);
}

// cambiar el alto de una ventana
function xwinHeight(wid,height,noupdate) {
	if (height!=undefined) xwin[wid].xwinMain.style.height=height;
	if (!noupdate) xwinUpdate(wid);
}

// deshabilitar una ventana
function xwinEnable(wid) {
	xwin[wid].disabled=false;
	xwinUpdate(wid);
}

// deshabilitar una ventana
function xwinDisable(wid) {
	xwin[wid].disabled=true;
	xwinUpdate(wid);
}

// crear una nueva ventana
function xwinNew(p) {

	// comprobar si hay cachÃ© de imÃ¡genes, y en caso contrario inicializar
	if (!xwinImageCache) xwinInit();

	// crear nueva ventana y objetos asociados
	for (wid=1;wid<=xwinMax;wid++) {
		if (!gid('xwin'+wid)) break;
	}
	if (wid>xwinMax) xwinMax=wid;
	else {
		// purgar contador si hay ventanas destruidas
		for (i=xwinMax;i>wid;i--) {
			if (gid('xwin'+i)) break;
		}
		xwinMax=i;
	}
	
	// crear un objeto y copiar los parÃ¡metros en el objeto (si se especifican)
	xwin[wid]=new Object();
	if (p) xwin[wid]=p;
	
	if (p.noresize) {
		if (p.nomax==undefined) p.nomax=true;
	}

	// contenido de la ventana
	var w="";
	w+="<div id=xwin"+wid+"shadow class=xwinshadow></div>"
		+"<div id=xwin"+wid+"main class='xwinmain'>"
			+"<div id=xwin"+wid+"title class='xwintitle' onMouseDown='javascript:return(false);'>"
				+"<table cellpadding='0' cellspacing='0'><tr>"
					+"<td><div class='xwincaptioncontainer'><div class='xwincaption' id='xwin"+wid+"caption' onDblClick='javascript:if(!xwin["+wid+"].disabled)xwinRestore("+wid+");' title='"+(p.caption?p.caption:"")+"'"+(isie()?" style='text-overflow:ellipsis;'":"")+">"
						+(p.icon==undefined?"&nbsp; ":"<a href='javascript:void(0)' onDblClick='javascript:"+(p.noclose?"":"if(!xwin["+wid+"].disabled)"+(p.onclose?p.onclose:"xwinClose("+wid+");"))+"'><img src='"+(p.icon!=""?p.icon:xwinImagePath+xwinImageGenIcon)+"' alt='' width='16' height='16' align='top' style='position:relative;top:0px;' /></a> ")
						+(p.caption?p.caption:"&nbsp;")
					+"</div></div></td>"
					+"<td id='xwin"+wid+"buttons' class='xwinbuttons'>"
						+(p.nomin?"":"<a id='xwin"+wid+"bmina' href='javascript:void(0)' onClick='if(!xwin["+wid+"].disabled)xwinMin("+wid+");' title='"+xwinTMINIMIZE+"'><img id='xwin"+wid+"bmini' src='"+xwinImagePath+xwinImageMin+"' width='16' height='16' alt='_' /></a>")
						+(p.nomax?"":"<a id='xwin"+wid+"bmaxa' href='javascript:void(0)' onClick='if(!xwin["+wid+"].disabled)xwinRestore("+wid+");' title='"+xwinTMAXIMIZE+"'><img id='xwin"+wid+"bmaxi' src='"+xwinImagePath+xwinImageMax+"' width='16' height='16' alt='[]' /></a>")
						+(p.noclose?"":"<a id='xwin"+wid+"bclosea' href='javascript:void(0)' onClick='if(!xwin["+wid+"].disabled)"+(p.onclose?p.onclose:"xwinClose("+wid+");")+"' title='"+xwinTCLOSE+"'><img id='xwin"+wid+"bclosei' src='"+xwinImagePath+xwinImageClose+"' width='16' height='16' alt='X' /></a>")
					+"</td>"
				+"</tr></table>"
			+"</div>"
			+"<div class='xwindisable'><div id='xwin"+wid+"disable' style=\"background-image:url('"+xwinImagePath+xwinImageTrans+"');\"></div></div>"
			+"<div id='xwin"+wid+"body' class='xwinbody'></div>"
		+"</div>";

	// crear ventana en el documento
	var win=document.createElement("div");
	win.setAttribute("id","xwin"+wid);
	win.setAttribute("class","xwin");
	win.innerHTML=w;
	document.getElementsByTagName("body")[0].appendChild(win);

	// definir las referencias y variables de esta ventana
	xwin[wid].xwin=gid('xwin'+wid);
	xwin[wid].xwinMain=gid('xwin'+wid+'main');
	xwin[wid].xwinShadow=gid('xwin'+wid+'shadow');
	xwin[wid].xwinCaption=gid('xwin'+wid+'caption');
	xwin[wid].xwinTitle=gid('xwin'+wid+'title');
	xwin[wid].xwinBody=gid('xwin'+wid+'body');
	xwin[wid].xwinDisable=gid('xwin'+wid+'disable');
	xwin[wid].xwinButtons=gid('xwin'+wid+'buttons');
	xwin[wid].xwinMinimized=false;
	xwin[wid].xwinMaximized=false;

	// si solicitado, aÃ±adir botÃ³n de cierre
	if (xwin[wid].close) { xwin[wid].buttons=[{"caption":"Cerrar","action":null}]; }

	// definir eventos de la ventana
	eval("xwin["+wid+"].xwinTitle.onmouseover=function(){xwinIsTitle=true;xwinActive="+wid+";}");
	eval("xwin["+wid+"].xwinTitle.onmouseout=function(){xwinIsTitle=false;}");
	eval("xwin["+wid+"].xwinMain.onmouseover=function(){xwinIsMain=true;xwinActive="+wid+";}");
	eval("xwin["+wid+"].xwinMain.onmouseout=function(){xwinIsMain=false;}");
	eval("xwin["+wid+"].xwinMain.onmousedown=function(){if(!xwin["+wid+"].disabled && xwinForeground!="+wid+")xwinFocus("+wid+");}");
	eval("xwin["+wid+"].xwinMain.onmousemove=xwinMouseMoveCheck;");
	eval("xwin["+wid+"].xwinTitle.onmousemove=xwinMouseMoveCheck;");

  var scrX=scrollLeft(); xwinLastScrollX=0;
	var scrY=scrollTop(); xwinLastScrollY=0;
  var maxW=windowWidth();
  var maxH=windowHeight();

	// tamaÃ±o y posiciÃ³n inicial
	xwin[wid].xwinMain.style.width =(p.width ?p.width :xwin[wid].xwinMain.offsetWidth)+"px";
	xwin[wid].xwinMain.style.height=(p.height?p.height:xwin[wid].xwinMain.offsetHeight)+"px";

	// tamaÃ±o y posiciÃ³n iniciales
	xwin[wid].xwinMain.style.left=((p.left?p.left:xwinCreateL=(xwinCreateL+24)%200)+scrX)+"px";
	xwin[wid].xwinMain.style.top =((p.top ?p.top :xwinCreateT=(xwinCreateT+24)%200)+scrY)+"px";
	if (p.center) {
		if (!p.left) xwin[wid].xwinMain.style.left=((maxW-xwin[wid].xwinMain.offsetWidth)/2+scrX)+"px";
		if (!p.top) xwin[wid].xwinMain.style.top =((maxH-xwin[wid].xwinMain.offsetHeight)/2+scrY)+"px";
	}
	
	// actualizar tamaÃ±os de la ventana
	xwinUpdate(wid);

	// si hay contenido, cambiar
	if (p.body) xwinSetBody(wid,p.body);

	// mostrar ventana y su sombra (si procede)
	if (xwinShadowSizeLeft || xwinShadowSizeTop) {
		xwin[wid].xwinShadow.style.visibility="visible";
		if (xwinAlphaShadow) xwinSetAlphaShadow(wid);
	}
	xwin[wid].xwinMain.style.visibility="visible";

	// traer al frente
	xwinFocus(wid);

	// comprobar si se inicia maximizada
	if (p.maximized) xwinRestore(wid);

	// actualizar todo
	xwinUpdateAll();

	// devolver el identificador de ventana
	return(wid);

}

// limpieza de todas las ventanas y variables
function xwinClean() {
	
	// cerrar todas las ventanas abiertas
	for (i=1;i<=xwinMax;i++) {
		if (xwin[i].xwin) xwinClose(i);
	}
	
	// limpiar variables
	xwin=new Array();
	xwinMax=0;
	xwinCreateL=0;
	xwinCreateT=0;
	xwinZIndex=100;
	xwinImageCache=new Array();

}

// inicializaciÃ³n de las ventanas
// no es necesario llamar a esta funciÃ³n, pero cuanto antes se llame a la misma,
// antes estarÃ¡n disponibles las imÃ¡genes para los botones de las ventanas
function xwinInit() {

	// limpiar variables
	xwinClean();
	
	// precarga de todas las imÃ¡genes
	var imageList=Array(xwinImageGenIcon,xwinImageMin,xwinImageMax,xwinImageRestore,xwinImageClose);
	xwinImageCache=new Array();
	for (i=0;i<imageList.length;i++) {
		xwinImageCache[i]=new Image();
		xwinImageCache[i].src=xwinImagePath+imageList[i];
	}

	// activar timer para Internet Explorer que no tiene el evento onscroll
	if (isie()) xwinIEscrollTimer();

	// primera inicializaciÃ³n
	xwinUpdateAll();

}

// inicializaciÃ³n de las variables y eventos
function xwinUpdateAll() {

	// inicializar variables
	xwinIsTitle=false;
	xwinIsMain=false;
	xwinMoving=false;
	xwinResizing=false;
	xwinMaximized=false;
	xwinMoveMinSizeReached=false;

	// declarar los eventos	necesarios
	// (requiere common.js)
	if (!xwinCapturedEvents) {
		mouseup(xwinMouseUp);
		mousedown(xwinMouseDown);
		mousemove(xwinMouseMove);
		scroll(xwinScroll);
		keydown(xwinOnKeyDown);
		xwinCapturedEvents=true;
	}

}

