/* ********************** SCRIPTS PARA LIBRARIUM ************************** */
/* (c) Juan Antonio Fernandez Madrigal, 2006-2007 */

		/* --------------- funciones auxiliares --------------- */

		function cambiacontenidodivision(divisi,nuevocont)
		/* cambia el contenido de la division de nombre DIVIS por el dado */
		{
			var divis=document.getElementById(divisi);
			if (divis==undefined) return;
			divis.innerHTML=nuevocont;
		}

		function ponalturadivision(divisi,altura)
		/* Situa la division dada con la altura dada */
		{	
			var divis=document.getElementById(divisi);
			if (divis==undefined) return;
			divis.style.height=altura+'px';
		}

		function despliegadivision(divis,paso,retardo,sentido,tope,divisioncompa,divcompa2)
		/* Despliega lentamente una division en pasos de PASO pixeles con retardo en cada paso de
		RETARDO milisegundos. Si SENTIDO es TRUE, aumenta la altura de la division desde su posicion actual
		hasta TOPE. Si es FALSE, la disminuye hasta alcanzar TOPE.
		Si DIVISIONCOMPA no esta vacio, hace que esa otra division acompaņe a la primera */
		{
			var rollo=document.getElementById(divis);
			if (rollo==undefined) return;
			var altu=rollo.style.height;
			if ((altu=='')||(altu==undefined)||(altu=='0px')) 
			{
				if (sentido==true) desplh=paso;
				else desplh=0;
			}
			else 
			{
				var pospx=altu.indexOf('px',0);
				if (pospx==-1) return;
				desplh=Number(altu.substr(0,pospx));
				if (sentido==true) desplh=desplh+paso;
				else desplh=desplh-paso;
			}
			var fin=false;
			if ( ((sentido)&&(desplh>=tope))||
			     ((!sentido)&&(desplh<=tope)) ) 
			{
				desplh=tope;
				fin=true;
			}
			rollo.style.height=desplh+'px';
			if ((divisioncompa!='')&&(divisioncompa!=undefined))
			{
				var rollo=document.getElementById(divisioncompa);
				if (rollo!=undefined) rollo.style.height=desplh+'px';
			}
			if ((divcompa2!='')&&(divcompa2!=undefined))
			{
				var rollo=document.getElementById(divcompa2);
				if (rollo!=undefined) rollo.style.height=desplh+'px';
			}
			if (!fin) setTimeout("despliegadivision('"+divis+"',"+paso+","+retardo+","+sentido+","+tope+",'"+divisioncompa+"')",retardo);
		}

		function iluminatexto(tag,color)
		/* Cambia el color del texto encerrado en el tag dado por uno dado */
		{
			var divis=document.getElementById(tag);
			if (divis==undefined) return;
			divis.style.color=color;
		}

		function ocultaelemento(tag)
		/* Oculta el elemento dado */
		{
			var divis=document.getElementById(tag);
			if (divis==undefined) return;
			divis.style.visibility='hidden';
		}

		function muestraelemento(tag)
		/* Muestra un elemento dado */
		{
			var divis=document.getElementById(tag);
			if (divis==undefined) return;
			divis.style.visibility='visible';
		}
		
		function ponmensajeglobal(mensaje)
		/* Muestra la division de mensaje global con el mensaje dado */
		{
			cambiacontenidodivision("textomensaje",mensaje);
		    muestraelemento("mensaje");
		}
		
		function quitamensajeglobal()
		/* Oculta el mensaje global */
		{
		 	 ocultaelemento("mensaje");
		}
		
		var navegador=0; // Guarda el navegador
		function detectanavegador()
		/* Detecta el navegador del cliente:
             0-> Netscape/Firefox/Mozilla
             1-> Microsoft explorer
             2-> Otro
        */
		{
             if (navigator.appName=='Netscape') navegador=0;
             else if (navigator.appName=='Microsoft Internet Explorer') navegador=1;
             else navegador=2;
		}

		/* ------------ Fades Simples ------------- */
		
		function pontransparencia(division,porc)
		// cambia la transparencia de la division dada a PORC (100-nada transparente, es decir, que se ve por completo, 0- totalmente transparente, es decir, que no se ve)
		{
			if ((porc<0)||(porc>100)) return;
			var fd=document.getElementById(division);
			if (fd==undefined) return;
			if (fd.style.MozOpacity!=null) 			// Mozilla
			{
				fd.style.MozOpacity = porc/100;
			}
			else if (fd.style.filter!=null) // IE
			{
			 /* IE no hace las transparencias si el elemento no tiene layout, una propiedad propia de Microsoft; 
				una forma de ponerle layout es ponerle anchura o altura, por ejemplo

							if ((fd.style.width=='')&&(fd.style.height=='')) fd.style.width='100%';
							fd.style.filter = "alpha(opacity="+Math.round(porc.toString())+")";

			  pero eso da problemas en los tags empotrados (no-bloques). Asi que en IE, no hay transparencias si no tiene layout y ya esta. */
				if (porc==0) fd.innerHTML=''; // Si desaparece, se elimina; si no, se deja
			}
		}
    
		function pontransparenciadivisiones(arraydivs,numdivs,indexsel)
		// Pone todas las divisiones del array opacas menos la del indice dado que la pone semitransparente
		// Si el indice es -1, pone todas opacas
		{
			if (navegador==0) // no se hace en IE por el motivo explicado en pontransparenciadivision
				for (f=0; f<numdivs; f++)
					pontransparencia(arraydivs[f],(f==indexsel?100:50));
		}

		/* ------------ Fades concurrentes y en varios pasos ------------- */
    
		function FadeData() // Objeto que representa un fade en varios pasos
		{
			this.division=''; // Division sobre la que se esta haciendo
			this.direcc=0;	  // Direccion: 0-> desaparecer, 1->aparecer
			this.porcact=100; // Porcentaje de transparencia actual: 100 -> se ve completo, 0 -> ha desaparecido
			this.pausa=20;	  // Pausa en milisegundos entre pasos del fade
			this.paso=10;	  // Paso de transparencia para cada incremento
			this.handler=0;	  // handler unico para este fade
		}
		
		var fadeh=0;	// Indice de handler unico de fade
		var listafades=new Array; // array de fades en curso; cada elemento es un objeto FadeData

		function posicionfadeenlista(division)
		// Devuelve la primera posicion en la lista de fades de un fade sobre la division dada, o -1 si no esta
		{
			var n=listafades.length;
			if (n>0)
			{
				var f;
				for (f=0; f<n; f++)
					if (listafades[f].division==division) return(f);
			}
			return(-1);
		}

		function handlerusadoenlista(h)
		// Devuelve la posicion en la lista del fade que usa H si ya ha sido usado en la lista de fades, o -1 si no
		{
			var n=listafades.length;
			if (n>0)
			{
				var f;
				for (f=0; f<n; f++)
					if (listafades[f].handler==h) return(f);
			}
			return(-1);
		}

		function eliminafadedelista(pos)
		// Elimina de la lista el elemento con esa posicion
		{
			var n=listafades.length;
			if ((pos<0)||(pos>=n)) return;
			delete listafades[pos];
			if (n==1) 
			{
				delete listafades;
				listafades=new Array;
			}
			else
			{
				if (pos==0)
					listafades=listafades.slice(1); // Se queda con todos los elementos salvo el primero: slice no los copia en profundidad porque son referencias a objetos
				else
				{
					if (pos==n-1) listafades.pop(); // Elimina el ultimo
					else
					{
						var nl1=listafades.slice(0,pos); // todos hasta el eliminado, menos el mismo
						var nl2=listafades.slice(pos+1); // todos desde el eliminado, menos el mismo
						listafades=nl1.concat(nl2); // el antiguo contenido de listafades es eliminado, y obtiene las referencias que tenia menos el elemento borrado; nl1 y nl2 desaparecen al salir de la funcion
					}
				}
			}
//alert('Terminado fade #'+pos+' ('+listafades.length+')');
		}
		
		function fadediv(division,pausa,porc,dir,paso,inicio,handler)
		// Hace un fade gradual de una division; DIR=0,PORC=100 para desvanecer, DIR=1,PORC=0 para volver
		// PASO es la cantidad de porcentaje que cambia en la transparencia en cada paso
		// PAUSA son los milisegundos entre paso y paso
		// INICIO debe ser true al llamarla desde fuera, HANDLER puede ser cualquier cosa
		{
			var d=document.getElementById(division);
			if (d==undefined) return;
			var p;
//alert('paso fade A (inicio: '+inicio+', handler='+handler+')');

			if (inicio)  // Se ha solicitado un nuevo fade
			{
				if (((dir!=0)&&(dir!=1))||((dir==0)&&(porc!=100))||((dir==1)&&(porc!=0))) return; // datos erroneos

				// Se le asigna un nuevo handler unico
				while (handlerusadoenlista(fadeh)!=-1) fadeh++;
				handler=fadeh;
				fadeh++;

				// Se mete en la lista
				p=posicionfadeenlista(division);
				if (p==-1) 
				{
					var fadeobj=new FadeData();
					listafades.push(fadeobj);
					p=listafades.length-1;
				}	
				listafades[p].division=division;
				listafades[p].direcc=dir;
				listafades[p].porcact=porc;
				listafades[p].pausa=pausa;
				listafades[p].paso=paso;
				listafades[p].handler=handler; // si ya habia un fade sobre la misma division lo sustituye por este (por tanto ese sera abortado)

//alert('Nuevo fade #'+p+' con handler='+handler+' ('+listafades.length+')');
				// Si no es firefox o el contenido es demasiado grande, no lo hace: va al final del ciclo y ya esta
				if ((navegador!=0)||(d.innerHTML.length>10000)) 
				{
					if (dir==0) pontransparencia(division,0);
					else pontransparencia(division,100);
					eliminafadedelista(p);
					return; 
				}
			}
			else
			{
				p=handlerusadoenlista(handler);
				if (p==-1) return; // ha sido abortado

				if ((!inicio)&&((porc<=0)||(porc>=100))) // hemos recorrido todo el trayecto y hemos llegado al final o nos hemos pasado
				{
					if (porc<=0) pontransparencia(division,0);
					else pontransparencia(division,100);
					eliminafadedelista(p);
					return;
				}
			}
			
			// En ambos casos, debe dar el siguiente paso 
			pontransparencia(division,porc);
			if (dir==0) porc-=paso;
			else porc+=paso;
			listafades[p].porc=porc;
			setTimeout("fadediv('"+division+"',"+pausa+","+porc+","+dir+","+paso+",false,"+handler+")",pausa); 
		}

		function _desactivaOnClickEvents(di)
		/* Elimina el codigo de los scripts asociados a onclick de los elementos contenidos en el objeto di y en el propio di */
		{
			if (di.onclick!=undefined) di.onclick=function() { return(false); };			

			if (!di.hasChildNodes()) return;
			var nhs=di.childNodes.length;
			var f;
			for (f=0; f<nhs; f++)
			{
				var hi=di.childNodes[f];
				_desactivaOnClickEvents(hi);
			}			
		}

		function DesactivaOnClickEvents(d)
		/* Elimina el codigo de los scripts asociados a onclick de los elementos contenidos en la division d */
		{
			var di=document.getElementById(d);
			if (di==undefined) return;
			_desactivaOnClickEvents(di);
		}

    	/* ------------ AJAX -------------- */

		/* NOTAS GENERALES:

				-Se permiten peticiones concurrentes
		*/

		function PeticionAJAX()
		{
		 		this.activa=false;
				this.divisionacargar='';
				this.datosacargar='';
				this.peticiondedatos=null;
		}
		
		function abortapeticionAJAX(pet,quitamensaje)
		// Aborta la peticion PET (de tipo PeticionAJAX)
		{
		 	  if (!pet.activa) return;
		      try { pet.peticiondedatos.abort(); } catch(e) {};
              pontransparencia(pet.divisionacargar,0);
			  cambiacontenidodivision(pet.divisionacargar,'');
		      pontransparencia(pet.divisionacargar,100);
			  pet.activa=false;
			  pet.peticiondedatos=null;
			  if (quitamensaje)	quitamensajeglobal();
		}

		function sustituyedatos(pet)
		// Muestra los datos recibidos; no devuelve nada
		// PET es de tipo PeticionAJAX
		{
			if (pet.activa==false) return;
			pet.activa=false;
/*			if (fadesactivos>0)
			{
				setTimeout("sustituyedatos(pet)",20);
				return;
			}
*/
			// Si es una pagina especial que requiere ser cargada en pantalla completa (en el body), pero por algun motivo ha sido requerida sobre una division, la pasa al body
			var tagini='<body>';
			var tagfin='</body>';
			var posini=pet.peticiondedatos.responseText.indexOf(tagini,0);
			var posfin=pet.peticiondedatos.responseText.indexOf(tagfin,0);
			if ((posini>=0)&&(posfin>posini)) // es una pagina completa: se redirige a la pantalla completa (se pierden estilos y demas)
			{
				var tinil=tagini.length; 
				document.body.innerHTML=pet.peticiondedatos.responseText.substr(posini+tinil,posfin-(posini+tinil));
			}
			else 
			{
                pontransparencia(pet.divisionacargar,0);
				cambiacontenidodivision(pet.divisionacargar,pet.peticiondedatos.responseText);
               	fadediv(pet.divisionacargar,20,0,1,10,true,0);
				quitamensajeglobal();
				// Si comienza por '_' la division de destino, no fuerza el scroll de pagina hacia arriba
				if (pet.divisionacargar.charAt(0)!='_') document.location.href='#inicioarribaabsoluto';
			}
			pet.peticiondedatos=null;
		}

    	function procesadatos(pet) 
    	// Se ejecuta cada vez que la carga cambia de estado; no devuelve nada
		// PET es de tipo PeticionAJAX, y es eliminada si hay error o si se termina correctamente la carga
		{
			try
			{
				if (!pet.activa) return; // La peticion no estaba activa
				var reads=pet.peticiondedatos.readyState;
				if (reads == 4) // Terminado de cargar
				{
					var stat=pet.peticiondedatos.status;
					if ((stat == 200)||(stat == 0)) // Carga OK		
					{
						sustituyedatos(pet);
						delete pet;
					}
					else  // error
					{
						abortapeticionAJAX(pet,false);
						delete pet;
						var erro='';
						switch (stat)
						{
							case 404: erro='No est&aacute;'; break;
							case 408: erro='<i>Timeout</i>'; break;
							default: erro='ERROR: '+String(stat);
						}
						ponmensajeglobal(erro);
						setTimeout("quitamensajeglobal()",400);  // No debe ponerse mucho para no dar tiempo al usuario a pedir otro mensaje
					}
				}
				else
				{
					switch (reads)
					{
						case 0: ms='Llamando'; break;
						case 1: ms='Procesando'; break;
						case 2: ms='Listo'; break;
						case 3: ms='Cargando'; break;
						case 4: ms='Terminado'; break;
						default: ms='Indefinido'; break;
					}
					ponmensajeglobal(ms+'...');
				}
			}
			catch (e)
			{
				abortapeticionAJAX(pet,false);
				delete pet;
				ponmensajeglobal("EXCEPCION");
				setTimeout("quitamensajeglobal()",400);  // No debe ponerse mucho para no dar tiempo al usuario a pedir otro mensaje
			}
		}
		   
		function traedatosdelservidorconparametros(urldatos,divisiondestino,datos) 
		// Hace la peticion al servidor para leer los datos producidos por el script URLDATOS y cargarlos en la DIVISIONDESTINO dada,
		// y le manda al script los parametros dados en DATOS por metodo post. Datos es un array de arrays; cada
		// array interno son dos valores: una cadena dando el nombre del dato y el propio dato
		// Si la division de destino comienza por '_', no fuerza a la pagina a hacer scroll hacia arriba
		// Tambien pueden cargarse paginas completas (con body y todo): cuando detecta que tienen body tag, las pone como paginas completas 
		// Devuelve FALSE si hay error, y un objeto PeticionAJAX con la peticion activa si no lo hay
		{
			if (datos!='')
			{
				var datosenc=URLencodeparameters(datos);
				if (datosenc==false) return(false);
			}
			quitamensajeglobal();
			var pet=new PeticionAJAX();  // Peticion AJAX en curso
			pet.divisionacargar=divisiondestino;
    		pet.datosacargar=urldatos;
			if (window.XMLHttpRequest)     // XMLHttpRequest nativo, curiosamente tambien para IE7
    		{
				ponmensajeglobal("Llamando...");
				fadediv(pet.divisionacargar,20,100,0,10,true,0);
    				
				pet.peticiondedatos = new XMLHttpRequest();
				pet.peticiondedatos.onreadystatechange = function() { procesadatos(pet); };
 				pet.activa=true;
				if (datos=='') 
				{
					pet.peticiondedatos.open("GET",urldatos,true);
             		pet.peticiondedatos.send(null);
				}
				else 
				{
					pet.peticiondedatos.open("POST",urldatos,true);
					pet.peticiondedatos.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
					pet.peticiondedatos.send(datosenc);
				}
    			return(pet);
    		}
    		else if (window.ActiveXObject)     // IE6/Windows ActiveX 
    		{
				pet.peticiondedatos=new ActiveXObject("Microsoft.XMLHTTP");
				if (pet.peticiondedatos) 
				{	
					ponmensajeglobal("Llamando...");
					fadediv(pet.divisionacargar,20,100,0,10,true,0);   

					pet.peticiondedatos.onreadystatechange = function() { procesadatos(pet); };
					pet.activa=true;
					if (datos=='') 
    				{
    					pet.peticiondedatos.open("GET",urldatos,true);
						pet.peticiondedatos.send();
    				}
					else 
					{
						pet.peticiondedatos.open("POST",urldatos,true);
						pet.peticiondedatos.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
						pet.peticiondedatos.send(datosenc);
					}
					return(pet);
				}
			}
    		// sin soporte xmlhttprequest
			delete pet;
			return(false);
		}
		
		function traedatosdelservidor(urldatos,divisiondestino) 
    	// Lo mismo que traedatosdelservidorconparametros, pero sin parametros post
		{
			return(traedatosdelservidorconparametros(urldatos,divisiondestino,''));
		}
		


	   /* --------------- funciones de busqueda en la web --------------- */

       function BuscaYahooPortadas(textobusq)
       /* Activa la funcion de yahoo para buscar portadas */
       {
           if (textobusq)
           {
			cambiacontenidodivision('yahooresultados','<i>Buscando...</i>');
            s = document.createElement('script');
            s.type ='text/javascript';
            s.charset ='utf-8';
            s.src = 'http://search.yahooapis.com/ImageSearchService/V1/imageSearch?appid=librarium&type=all&results=10&output=json&callback=pong&query=' + textobusq;
            document.getElementsByTagName('head')[0].appendChild(s);
            return(true);
           }
           else
           {
            alert('Debe introducir alg\xFAn t\xE9rmino de b\xFAsqueda');
            return(false);
           }
       }

       function pong(res)
       {
        var dest=document.getElementById('yahooresultados');
        var num=res.ResultSet.Result.length;
        if (num==1) dest.innerHTML='<i>1 imagen encontrada';
        else dest.innerHTML = '<i>'+String(num)+' im&aacute;genes encontradas';
        if (num==0) dest.innerHTML=dest.innerHTML+'.</i>';
        else dest.innerHTML=dest.innerHTML+':</i><br/>';
        for (var i = 0; i < num; i++)
        {
         var url=res.ResultSet.Result[i].Url;
         dest.innerHTML=dest.innerHTML+'<a href="'+url+'" target="_blank"><img title="Pulse para verla a tama&ntilde;o real" border="0" width="70" height="90" src="'+url+'"/></a> <input type="radio" name="portadas" onclick="javascript: var destvalue=document.getElementById(\'campoportada\'); destvalue.value='+"'"+url+"'"+'; return(true);"/> ';
        }
       }

	  /* --------------- funciones de formularios --------------- */

		function getElementsByName_iefix(tag, name) 
		{
			var elem = document.getElementsByTagName(tag);
     		var arr = new Array();
     		for (i = 0,iarr = 0; i < elem.length; i++) 
			{
          		att = elem[i].getAttribute("name");
          		if (att == name) 
				{
               		arr[iarr] = elem[i];
               		iarr++;
          		}
     		}
     		return arr;
		}
		
		function isNumber(txt)
		/* Devuelve true si txt contiene un numero entero */
		{
			var f;
			for (f=0; f<txt.length; f++)
				if ((txt.charAt(f)!='-')&&((txt.charCodeAt(f)<48)||(txt.charCodeAt(f)>48+9))) return(false);
			return(true);
		}
		
		function isVolume(txt)
		/* Devuelve true si TXT contiene un numero de volumen de un libro, en decimal o romano */
		{
			if (txt.length<=0) return(false);
			if (isNumber(txt))
			{
				if (parseInt(txt)<=0) return(false);
			}
			else
			{
				var v=txt.toUpperCase();
				var f;
				for (f=0; f<v.length; v++) 
				{
					switch (v.charAt(f))
					{
						case 'I': 
						case 'V':
						case 'X':
						case 'L':
						case 'C': break;
						default: return(false);
					}
				}
			}
			return(true);
		}

		function isURL(c)
		/* Devuelve true si C es una URL completa no vacia */
		{
			if ((allTrim(c)).length==0) return(false);
			var j=new RegExp();
			j.compile('http://[A-Za-z0-9-]+\.[A-Za-z0-9]+');
			if (!j.test(allTrim(c)))
			{
				delete j;
				return(false);
			}
			delete j;
			return(true);
		}

        function SeleccionaTodosSelectMultiple(selectm,sel)
        /* Selecciona todas las opciones del select multiple llamado SELECTM,
        si SEL= true, si es FALSE las deselecciona todas */
        {
         if (selectm==undefined) return(false);
		 if (selectm.disabled) return(true);
         var numopcs=selectm.length;
         for (f=0; f<numopcs; f++) selectm.options[f].selected=sel;
         return(true);
        }

		function CompactaSelect(selectm,letra)
		/* Devuelve un array con dos campos: el primero es el resultado de compactar todas las opciones seleccionadas en el select SELECTM, separadas por la letra LETRA, el segundo es el numero de opciones que estaban seleccionadas */
		{
			var numgeneros=selectm.length;
			var numsels=0;
			var textsels="";
			var f;
			for (f=0; f<numgeneros; f++)
    			if (selectm.options[f].selected)
    	        {
    	        	if (numsels>0) textsels=textsels+letra;
   					textsels=textsels+selectm.options[f].value;
    	           	numsels++;
    	   		}
			return(new Array(textsels,numsels));
		}

		function RecopilaSelect(selectm)
		/* Lo mismo que CompactaSelect pero devuelve un array con los elementos seleccionados, sin compactar */
		{
			var numgeneros=selectm.length;
			var numsels=0;
			var asels=new Array();
			var f;
			for (f=0; f<numgeneros; f++)
    			if (selectm.options[f].selected)
    	        {
   					asels[numsels]=selectm.options[f].value;
    	           	numsels++;
    	   		}
			return(asels);
		}

		function sustituyeComillas(txt)
		/* Cambia las comillas de un texto por caracteres que no son comillas */
		{
           var res='';
           n=txt.length;
           for (f=0; f<n; f++)
           {
              c=txt.charAt(f);
              if ((c=="'")||(c=='"')) res=res+'&quot;';
              else res=res+c;
           }
           return(res);
		}
		
		function desglosafecha(fecha,seaantigua,nomasde)
		/* dada una fecha en formato aaaa-mm-dd, devuelve un array con [0]-anio, [1]-mes, [2]-dia, o false si hubo error.
			Si SEAANTIGUA es true, comprueba que ademas sea anterior a la fecha actual
			Si NOMASDE es un numero positivo, indica el numero maximo de anios en el pasado en que puede estar la fecha. Solo se usa si SEAANTIGUA es true */
		{
            if (fecha.length==10)
			{
				var an=Number(fecha.substring(0,4));
				var me=Number(fecha.substring(5,7));
				var di=Number(fecha.substring(8));
				if ((me<1)||(me>12)||(di<1)||(di>31)) return(false);
				if (seaantigua)
				{
					var ah=new Date();
					var fe=new Date(an,me-1,di);
					if (fe>ah) return(false);
					if ((nomasde>=0)&&(an<ah.getFullYear()-nomasde)) return(false);
				}
				return(new Array(an,me,di));
			}
			return(false);
		}

		function glosafecha(anio,mes,dia,consep)
		/* Dado el resultado de desglosafecha, vuelve a formar un texto con ella. Si CONSEP es false, no mete los '-' */
		{
			if (anio<1000) return(false);
			var txt=''+anio;
			if (consep) txt=txt+'-';
			if (mes<10) txt=txt+'0';
			txt=txt+mes;
			if (consep) txt=txt+'-';
			if (dia<10) txt=txt+'0';
			txt=txt+dia;
			return(txt);			
		}

		function comparafechas(fecha1,fecha2)
		/* Dadas dos fechas en formato aaaa-mm-dd, devuelve 0 si fecha1 es anterior a fecha2, 1 si es al reves, 2 si son iguales, y -1 si hay error */
		{
			var f1=desglosafecha(fecha1,false,-1);
			var f2=desglosafecha(fecha2,false,-1);
			if ((f1==false)||(f2==false)) return(-1);
			var fa1=f1[0]*365+f1[1]*30+f1[0];
			var fa2=f2[0]*365+f2[1]*30+f2[0];
			if (fa1<fa2) return(0);
			if (fa1>fa2) return(1);
			return(2);
		}

        function desglosahora(hora)
        /* Devuelve un array con [0]-horas, [1]-minutos [2]-segundos de la hora
        especificada */
        {
          if (hora=='') return(false);
          var posant=0;
          var desgl=new Array(3);
          for (f=0; f<3; f++)
          {
              if (f<2)
              {
                var posfin=hora.indexOf(':',posant);
                if (posfin<=0) return(false);
                desgl[f]=Number(hora.substring(posant,posfin));
                posant=posfin+1;
              }
              else desgl[f]=Number(hora.substring(posant));
          }
          return(desgl);
        }
        		
		function leftTrim(sString)
		/* Quita espacios a la izquierda */
		{
			while ((sString.length>=1)&&(sString.substring(0,1) == ' '))
			{
				if (sString.length==1) sString='';
				else sString = sString.substring(1, sString.length);
			}
			return sString;
		}

		function rightTrim(sString)
		/* Quita espacios a la derecha */
		{
			while ((sString.length>=1)&&(sString.substring(sString.length-1, sString.length) == ' '))
			{
				if (sString.length==1) sString='';
				else sString = sString.substring(0,sString.length-1);
			}
			return sString;
		}

		function allTrim(sString)
		/* Quita espacios a izquierda y derecha */
		{
			return(leftTrim(rightTrim(sString)));
		}

		function inicialMayusculas(txt)
		/* Si puede, pone la primera letra en mayuscula y devuelve el texto; si no, lo devuelve sin cambiar. Primero aplica leftTrim */
		{
			var txt2=leftTrim(txt);
			if (txt2.length<=0) return(txt2);
			var prim=(txt2.substring(0,1)).toUpperCase();
			if (txt2.length==1) txt2=prim;
			else txt2=prim+txt2.substring(1,txt2.length);
			return(txt2);
		}

		/* --------------- funciones de las paginas --------------- */

        function numerodeopcionesmenuizda()
        /* Devuelve el numero de opciones del menu de la izda */
        {
           var n=0;
           if (document.getElementById('menuizdaopc0')!=undefined) n++;
           if (document.getElementById('menuizdaopc1')!=undefined) n++;
           if (document.getElementById('menuizdaopc2')!=undefined) n++;
           if (document.getElementById('menuizdaopc3')!=undefined) n++;
           var h;
           switch (n)
           {
                 case 1: h=290; break;
                 case 2: h=390; break;
                 case 3: h=460; break;
                 case 4: h=520; break;
                 default: h=170;
           }
           return(new Array(n,h));
        }

		function iniciapagina()
		/* Inicia la pagina */
		{
            var hs=numerodeopcionesmenuizda();
			ponalturadivision('rollodespl',0);
			muestraelemento('rollodespl');
			despliegadivision('rollodespl',5,10,true,hs[1],'','');

			quitamensajeglobal();
			
			detectanavegador();
		}
		
		function finpagina(destino)
		/* Cierra la pagina y va a destino */
		{
			pontransparencia('divcentro',0);						
			pontransparencia('divdcha',0);						
           var hs=numerodeopcionesmenuizda();
		 	despliegadivision('rollodespl',5,10,false,1,'','');
			setTimeout("testfinpagina('"+destino+"')",5*hs[1]);
		}
		
		function testfinpagina(destino)
		/* Companiera de FINPAGINA */
		{
		 document.location=destino;
		}

		function pliegaodespliegalibro(libro,asociada)
		/* Pliega o despliega el libro cuyo nombre es LIBRO (division con un nombre igual a 'libroID'), dependiendo de su estado actual. Las divisiones plegadas tienen una altura de 23 pixels */
		{
			var divis=document.getElementById(libro);
			if (divis==undefined) return;
			var divisasoc=document.getElementById(asociada);
			if (divisasoc==undefined) return;
			var altuestilo=divis.style.height;
			var altu=divis.clientHeight; 
			var altuestiloasoc=divisasoc.style.height;
			var altuasoc=divisasoc.clientHeight; 
			if (navegador==1) // IE a veces no da bien el clientHeight
			{
				if (altu==0) altu=divis.offsetHeight;
				if (altuasoc==0) altuasoc=divisasoc.offsetHeight;
			}
	
			var altudesplizda;
			var altudespldcha;
			var idlibro=libro.substr(5); // LIBRO debe tener el formato 'libroID'
			var datoalturadesplegadaizda='alturadesplegadaizda'+idlibro;
			var datoalturadesplegadadcha='alturadesplegadadcha'+idlibro;
			var divaltdesplizda=document.getElementById(datoalturadesplegadaizda);
			var divaltdespldcha=document.getElementById(datoalturadesplegadadcha);
			if ((divaltdesplizda==undefined)||(divaltdespldcha==undefined)) return; // la pagina no esta bien construida
			if ((altuestiloasoc=='')||(altuestiloasoc==undefined)||(altuestiloasoc==null)) // la primera vez que se llama: no hay altura calculada
			{
				divaltdesplizda.value=altu;
				divaltdespldcha.value=altuasoc;
				altudesplizda=altu;
				altudespldcha=altuasoc;
			}
			else
			{
				altudesplizda=Number(divaltdesplizda.value);
				altudespldcha=Number(divaltdespldcha.value);
				if ((altudesplizda<=0)||(altudespldcha<=0)) return; // la pagina no esta bien construida
			}

//alert('altu=['+altu+'],altuestilo=['+altuestilo+'],altuasoc=['+altuasoc+'],altuestiloasoc=['+altuestiloasoc+'] -- altdeplizda=['+altudesplizda+'],altdepldcha=['+altudespldcha+']');

            if (navegador!=0) // si no es Mozilla, no pliega ni despliega: lo hace de golpe
            {
			  if (altu==23) /* estaba plegado */
			  {
				ponalturadivision(libro,altudesplizda);
				ponalturadivision(asociada,altudespldcha);
              }
			  else /* estaba desplegado */
			  {
				ponalturadivision(libro,23);
				ponalturadivision(asociada,23);
              }
              return;
            }


			/* Rellena las alturas en los estilos, donde no tienen por que estar, para que la cojan de ahi las rutinas de plegado */
			ponalturadivision(libro,altu); 
			ponalturadivision(asociada,altuasoc); 
			if (altu==23) /* estaba plegado */
			{
				despliegadivision(libro,4,10,true,altudesplizda);
				despliegadivision(asociada,4,10,true,altudespldcha);
			}
			else /* estaba desplegado */
			{
				despliegadivision(libro,4,10,false,23);
				despliegadivision(asociada,4,10,false,23);
			}
		}


