/*
	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/
	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 397 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_igen.gif";
var xwinImageTrans="xwin_trans.gif";

// opciones por defecto
var xwinBorderSize=4;
var xwinBorderResize=10;
var xwinShadowSizeLeft=5;
var xwinShadowSizeTop=9;
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 xwinAlphaShadow=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;


// 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=ietruebody().scrollLeft;
			var sy=ietruebody().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) xwinResizeAction=xwinRESLEFT;
			if (x2>=0 && x2<=xwinBorderSize) xwinResizeAction=xwinRESRIGHT;
			if (y1>=0 && y1<=xwinBorderSize) xwinResizeAction=xwinRESTOP;
			if (y2>=0 && y2<=xwinBorderSize) 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;
		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;
		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;
			xwin[wid].xwinMain.style.top=(newT>0?newT:0);
			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;
		if (newT) xwin[wid].xwinMain.style.top=(newT>minT?newT:minT);
		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;
		}
		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;
		}
		
		// actualizar las capas
		xwinUpdate(wid);
		return(false);
	}

}

// se ha soltado el ratón
function xwinMouseUp(e) {
	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);

	// sombra
	if (!xwin[wid].xwinMaximized) {
		xwin[wid].xwinShadow.style.left=parseInt(xwin[wid].xwinMain.style.left)+xwinShadowSizeLeft;
		xwin[wid].xwinShadow.style.top=parseInt(xwin[wid].xwinMain.style.top)+xwinShadowSizeTop;
		xwin[wid].xwinShadow.style.width=xwinMainWidth;
		xwin[wid].xwinShadow.style.height=xwinMainHeight;
	} 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;
		xwin[wid].xwinBody.style.top   =xwinBorderSize;
		xwin[wid].xwinBody.style.width =(bodyW>1?bodyW:1);
		xwin[wid].xwinBody.style.height=(bodyH>1?bodyH:1);
		xwin[wid].xwinShadow.style.visibility="visible";
	} else {
		var bodyW=(xwinMainWidth);
		var bodyH=(xwinMainHeight-xwin[wid].xwinTitle.offsetHeight-xwinBorderSize);
		xwin[wid].xwinBody.style.left  =0;
		xwin[wid].xwinBody.style.top   =xwinBorderSize;
		xwin[wid].xwinBody.style.width =(bodyW>1?bodyW:1);
		xwin[wid].xwinBody.style.height=(bodyH>1?bodyH:1);
		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);
			xwin[wid].xwinMain.style.top=parseInt(xwin[wid].xwinMain.style.top)+(scrY-xwinLastScrollY);
			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) {
	xwin[wid].xwin.parentNode.removeChild(xwin[wid].xwin);
	xwin[wid]=false;
	xwinIsTitle=false;
	xwinIsMain=false;
}

// definir el HTML del contenedor de la ventana
function xwinSetBody(wid,html) {
	gid('xwin'+wid+'body').innerHTML=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":xwin[wid].xwinMain.style.left,
				"top":xwin[wid].xwinMain.style.top,
				"width":xwin[wid].xwinMain.style.width,
				"height":xwin[wid].xwinMain.style.height
				};
		}
	  l=xwin[wid].xwinMain.style.left;
		t=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;
		xwin[wid].xwinMain.style.top=t;
		xwin[wid].xwinMain.style.width=w;
		xwin[wid].xwinMain.style.height=h;
		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":xwin[wid].xwinMain.style.left,
				"top":xwin[wid].xwinMain.style.top,
				"width":xwin[wid].xwinMain.style.width,
				"height":xwin[wid].xwinMain.style.height
				};
		}
	  var l=ietruebody().scrollLeft; xwinLastScrollX=l;
		var t=ietruebody().scrollTop; xwinLastScrollY=t;
	  var w=(document.all?ietruebody().clientWidth:document.body.clientWidth);
	  var h=(document.all?ietruebody().clientHeight:document.body.clientHeight);
		gid('xwin'+wid+'bmaxi').src=xwinImagePath+xwinImageRestore;
		gid('xwin'+wid+'bmaxa').title=xwinTRESTORE;
	} else {
		xwin[wid].xwinMaximized=false;
		l=xwin[wid].oldpos.left;
		t=xwin[wid].oldpos.top;
		w=xwin[wid].oldpos.width;
		h=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;
	xwin[wid].xwinMain.style.top=t;
	xwin[wid].xwinMain.style.width=w;
	xwin[wid].xwinMain.style.height=h;
	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><tr>"
				+"<td><div class=xwincaption><div 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:if(!xwin["+wid+"].disabled)xwinClose("+wid+");'><img src='"+(p.icon!=""?p.icon:xwinImagePath+xwinImageGenIcon)+"' alt='' width=16 height=16 /></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: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: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: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;

	// 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=ietruebody().scrollLeft; xwinLastScrollX=0;
	var scrY=ietruebody().scrollTop; xwinLastScrollY=0;
  var maxW=(document.all?ietruebody().clientWidth:document.body.clientWidth);
  var maxH=(document.all?ietruebody().clientHeight:document.body.clientHeight);

	// tamaño y posición inicial
	xwin[wid].xwinMain.style.width =(p.width ?p.width :xwin[wid].xwinMain.offsetWidth);
	xwin[wid].xwinMain.style.height=(p.height?p.height:xwin[wid].xwinMain.offsetHeight);

	// tamaño y posición iniciales
	xwin[wid].xwinMain.style.left=(p.left?p.left:xwinCreateL=(xwinCreateL+24)%200)+scrX;
	xwin[wid].xwinMain.style.top =(p.top ?p.top :xwinCreateT=(xwinCreateT+24)%200)+scrY;
	if (p.center) {
		if (!p.left) xwin[wid].xwinMain.style.left=((maxW-xwin[wid].xwinMain.offsetWidth)/2+scrX);
		if (!p.top) xwin[wid].xwinMain.style.top =((maxH-xwin[wid].xwinMain.offsetHeight)/2+scrY);
	}
	
	// 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
	document.onmouseup=xwinMouseUp;
	document.onmousedown=xwinMouseDown;
	document.onmousemove=xwinMouseMove;
	document.onscroll=xwinScroll;
	document.onkeydown=xwinOnKeyDown;

}function addComboOption(onSelect, sText, sVal, sSel, sBold) {

	var selOpcion=new Option(sText, sVal);
	var i;

	selOpcion.id=sVal;
	selOpcion.selected=sSel;

	try {

		if (navigator.appName=="Microsoft Internet Explorer") onSelect.add(selOpcion);
		else onSelect.add(selOpcion,null);

		document.getElementById(sVal).style.fontWeight=(sBold?"bold":"normal");

		if (sSel) {
			for (i=0; i<onSelect.length; i++) {
				if (onSelect.options[i].selected) onSelect.selectedItem=i;
			}
		}

	} catch(e) {
		alert(e+"\nError al agregar la opción ("+sVal+") - "+sText);
		return(false);
	}

	return(true);

}

function clearCombo(combo) {
	combo.length=0;
}

function comboValue(xCombo) {
	if (xCombo.selectedIndex<0) return(false);
	return(xCombo.options[xCombo.selectedIndex].value);
}

function comboText(xCombo) {
	if (xCombo.selectedIndex<0) return(false);
	return(xCombo.options[xCombo.selectedIndex].text);
}

function fillCombo(combo,lista,valorActual,formaMostrar,indiceValor,indiceTexto,filtro) {

	if (!indiceValor) indiceValor="i";
	if (!indiceTexto) indiceTexto="lista[i]";
	if (!formaMostrar) formaMostrar="lista[i]["+indiceTexto+"]";
	if (!filtro) filtro="";

	eval // es más eficiente meter el bucle for dentro que fuera, aunque el código quede más sucio
		("for (i=0; i<lista.length; i++) {"
		+"	"+(filtro?"if("+filtro+")":"")+"addComboOption(combo,"+formaMostrar+","+indiceValor+",(valorActual=="+indiceValor+"?true:false),(valorActual=="+indiceValor+"?true:false));"
		+"}");
}
var calertid=0;

function hideSelects(hidden) {
	if (!isie()) return;
	selects=document.getElementsByTagName("select");
	for (i=0;i<selects.length;i++)
		selects[i].style.visibility=(hidden?"hidden":"visible");
}

function wbox() {

	this.createDIV=function() {
		var w=40,h=20;
		var d=document.createElement("div");
		calertid++;
		d.id="ca"+calertid;
		d.className="alert";
		d.style.display="none";
		d.style.position="absolute";
		d.style.zIndex=500;
		d.style.width=w+"px";
		d.style.height=h+"px";
		document.body.appendChild(d);
		return(d.id);
	}

	this.id=this.createDIV();
	this.d=gid(this.id);
	this.widthSet=false;
	this.heightSet=false;

	this.center=function() {
		this.d.style.left=Math.floor(scrollLeft()+(windowWidth()-parseInt(this.d.style.width))/2)+"px";
		this.d.style.top=Math.floor(scrollTop()+(windowHeight()-parseInt(this.d.style.height))/2)+"px";
	}

	this.width=function(w) {
		this.widthSet=true;
		this.d.style.width=w+"px";
		this.center();
	}

	this.height=function(h) {
		this.heightSet=true;
		this.d.style.height=h+"px";
		this.center();
	}

	this.size=function(w,h) {
		this.width(w);
		this.height(h);
	}

	this.get=function(){
		return(this.d.innerHTML);
	}

	this.set=function(html){
		this.d.innerHTML=html;
	}

	this.show=function(){
		if (!this.widthSet) this.width(300);
		if (!this.heightSet) this.width(180);
		this.center();
		this.d.style.display="block";
		hideSelects(true);
	}

	this.hide=function(){
		this.d.style.display="none";
		hideSelects(false);
	}

	this.del=function() {
		wboxdel(this.id);
	}

}

function wboxdel(id) {
	hideSelects(false);
	if (gid(id)) giddel(id);
}

function walert(html,w,h) {
	var win=new wbox();
	win.width(w?w:400);
	win.height(h?h:120);
	win.set
		("<table width='100%' height='100%'>"
		+"<tr height='99%'><td valign=top>"+html+"</td></tr>"
		+"<tr height='1%'><td align=right><input class=cmd type=button value='Cerrar' onClick='javascript:wboxdel(\""+win.id+"\")' /></td></tr>"
		+"</table>");
	win.show();
}window.onload=function(){ try { init(); } catch(e) {} }
window.onunload=function(){ try { unload(); } catch(e) {} }
// pequeñas macros para reducir código
function gid(id) {
	try {
		return(document.getElementById(id));
	} catch(e) {
		return(false);
	}
}
function gidget(id) { return(gid(id).innerHTML); }
function gidset(id,html) { gid(id).innerHTML=html; }
function gidval(id,data) { if (data!=null) gid(id).value=data; else return(gid(id).value); }
function giddel(id) { var d=gid(id); d.parentNode.removeChild(d); }
function gmove(id_org,id_dst) { gid(id_dst).innerHTML=gid(id_org).innerHTML; gid(id_org).innerHTML=""; }
function show(id) { gid(id).style.display="block"; }
function hide(id) { gid(id).style.display="none"; }
function view(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 isfunction(cfunction) { return((typeof cfunction)=='function'?true:false); }

// propiedades del documento y ventana
function ietruebody() { return((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.all?ietruebody().clientWidth:document.body.clientWidth); }
function documentHeight() { return(document.all?ietruebody().clientHeight:document.body.clientHeight); }

// almacenar cookie
function setCookie(name,value,days) {
	var expires="";
	if (days) {
		var date=new Date();
		date.setTime(date.getTime()+(days*86400000));
		expires="; expires="+date.toGMTString();
	}
	document.cookie=name+"="+value+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));
	}
	return("");
}

// borrar cookie
function delCookie(name) {
	setCookie(name,"",-1);
}

// es internet explorer?
function isie() {
	var ag="ua: "+navigator.userAgent;
	if (ag.indexOf("MSIE")>0) return(true);
	else return(false);
}

// es mozilla firefox?
function ismoz() {
	var ag="ua: "+navigator.userAgent;
	if (ag.indexOf("Firefox")>0) return(true);
	else return(false);
}

// Parche al único fallo del FireFox que siguen sin solucionar
// al cambiar el tamaño de un table con height especificado,
// este no se autoredimensiona al disminuir su contenido.
// este problema suele aparecer al desarrollar aplicaciones AJAX.
function fffix(id) {
	gid(id).height="99%";
	setTimeout('gid("'+id+'").height="100%";',1);
}

// ancho sin los márgenes
function crossInnerWidth(element) {
	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 sin los márgenes
function crossInnerHeight(element) {
	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));
	}
}

// ancho del scroll vertical
function scrollWidth() {

	// thanks to Alexandre Gomes (Portugal) http://www.alexandre-gomes.com/?p=115
	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);
}

// 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);
}
/**

	Título..: VeryTinyAJAX 0.4b, Wrapper JavaScript simple a funciones XMLHTTP para AJAX
  Licencia: GPL (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.

*/


// declarar el objeto XML-HTTP global
var http;

// constantes para httpRequest
var hGET=0;
var hPOST=1;

// funciones auxiliares generales
function gid(id) { return(document.getElementById(id)); }
function gescape(torg) {
	var d=""+torg;
	try { var d=d.replace(/\?/gi,"%3F"); } catch(e) {}
	try { var d=d.replace(/&/gi,"%26"); } catch(e) {}
	try { var d=d.replace(/\+/gi,"%2B"); } catch(e) {}
	try { var d=d.replace(/\r/gi,"%0D"); } catch(e) {}
	try { var d=d.replace(/\n/gi,"%0A"); } catch(e) {}
	try { var d=d.replace(/ /gi,"+"); } catch(e) {}
	return(d);
}

// información de versión
function httpVersion() { return("VeryTinyAJAX/0.4b"); }

// crea el objeto XML-HTTP
function httpObject() {
	var xmlhttp;
	// comprobar que el navegador soporta XMLHttpRequest
	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);
}

// estado de la petición
function httpState() {
	try { return(http.readyState); }
	catch (e) { return(5); }
}

// cadena de estado de la petición
function httpStateString() {
	try { var rs=http.readyState; }
	catch (e) { var rs=5; }
	switch (rs) {
	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");
	}
}

// Indicar si se ha completado la operación
function httpComplete() {
	if (http.readyState==4) return(true);
	else return(false);
}

// Devolver los datos recibidos
function httpData() {
	return(http.responseText);
}

// Devolver los datos recibidos en formato documento XML
function httpXML() {
	return(http.responseXML);
}

// Devolver el estado del servidor
// Si se detecta error, el servidor no estará disponible
function httpStatus() {
	try { return(http.status); }
	catch(e) { return(0); }
}

// Comprobar que la respuesta del servidor es la 200 (HTTP OK)
function httpError() {
	if (http.readyState==4) {
		try { var ok=(http.status!=200); }
		catch(e) { return(true); }
		return(ok);
	}
}

// Muestra un mensaje de error dependiendo del tipo de error encontrado
function httpErrorShow() {
	if (httpError()) {
		if (httpStatus()) alert("Se ha encontrado el error "+httpStatus()+" en el servidor.");
		else alert("El servidor no responde a la petición!\nPruebe dentro de unos instantes.");
	}
}

// Realizar un envío de datos http
function httpSend(method, url, data, eventfunction) {
	var sdata=(data?data:"");
	var async=(eventfunction?true:false);
	http=httpObject();
	switch (method) {
	case 0: http.open("GET",url+"?"+sdata,async); sdata=null; break;
	case 1: http.open("POST",url,async); break;
	default: return(false);
	}
	if (async) http.onreadystatechange=eventfunction;
	http.setRequestHeader('Content-Type','application/x-www-form-urlencoded; charset=ISO-8859-1"');
	http.send(sdata);
	return(true);
}


// Devuelve todos los campos y datos
// de un formulario en forma campo1=dato1&campo2=dato2&...
function httpFormFields(formObject) {
	var fields="";
	for (i=0;i<formObject.length;i++) {
		if (!formObject[i].name) continue;
		if (formObject[i].type=="radio" && !formObject[i].checked) continue;
		fields+=(i>0?"&":"")+formObject[i].name+"="+gescape(httpGetObjectValue(formObject[i]));
	}
	return(fields);
}

// Habilitar o deshabilitar la posibilidad de introducción
// o modificación de datos de un formulario completo.
function httpFormFieldsEnabled(formObject,isEnabled) {
	for (x=0;x<formObject.length;x++) {
		try { formObject[x].disabled=!isEnabled; }
		catch(e) {}
	}
}

// Devuelve todos los campos y datos de un lista de identificadores
// tipo id1,id2,id3 en forma id1=dato1&id2=dato2&...
function httpGetFields(fieldNames) {
	var fn=fieldNames.split(",");
	var fields="";
	var formObject;
	for (i=0;i<fn.length;i++) {
		formObject=gid(fn[i]);
		if (!formObject) continue;
		if (formObject.type=="radio" && !formObject.checked) continue;
		fields+=(i>0?"&":"")+fn[i]+"="+gescape(httpGetObjectValue(formObject));
	}
	return(fields);
}

// Devuelve un valor de un campo
function httpGetObjectValue(formObject) {
	switch (formObject.type) {
	case "checkbox": return(formObject.checked?"1":"0");
	case "radio": case "button": case "select-one": case "text": case "textarea": default: return(formObject.value);
	}
}

// Devuelve un objeto con el número de variables
// creadas con la función aset(nombre,valor,es_array);
function aget(fullData) {
	var d=fullData;
	var o=new Object();
	var n=0;
	var p0,p1,p2,isa;
	while (true) {
		try {
			p0=d.indexOf("="); if (!p0) break;
			p1=d.indexOf("("); if (!p1) break;
			p2=d.indexOf(")"); if (!p2) break;
			isa=d.substring(p2+1,p2+2); if (!isa) break;
			isa=(isa=="$"?true:false);
			name=d.substring(0,p1); if (!name) break;
			plength=parseInt(d.substring(p1+1,p2));
			data=d.substring(p0+1,p0+plength+1);
			if (!isa) eval("o."+name+"=data;");
			else eval("o."+name+"="+data+";");
			d=d.substring(p0+plength+2);
		} catch(e) {
			return(false);
		}
	}
	return(o);
}

// Función auxiliar para crear cadenas PHP sin caracteres de control
function aescape(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);
}

// Devuelve un cadena con el objeto serializado a PHP
// ATENCIÓN: Debe ser saneado por la función verifyArray(cadena)
//           para evitar inyecciones de código a PHP.
function aput(data,level,human_readable) {
	var i,j,k,n=(level?level:0),r="",s="";
	if (human_readable) { s="\n"; for (i=0;i<n;i++) s+="\t"; }
	if (data==null) return("null");
	if (typeof data=="object") {
		if (data.constructor.toString().indexOf("Array")!=-1) {
			j=0;
			r+=s+"Array(";
			for (i in data) {
				if (typeof data[i]!="function") {
					if (j) r+=s+","; j++;
					r+=aput(data[i],n+1,human_readable);
				}
			}
			r+=s+")";
		} else {
			k=0;
			for (i in data) {
				k++;
				if (k>1) {
					r+=s+'Array(';
					break;
				}
			}
			j=0;
			for (i in data) {
				if (typeof data[i]!="function") {
					if (j) r+=","; j++;
					r+=s+'"'+i+'"=>'+aput(data[i]);
				}
			}
			if (k>1) r+=s+')';
		}
	} else {
		r+=(typeof data=="number"?data:'"'+data+'"');
	}
	return(r);
}
/*
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
	}

}

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 = {

	serialize : function(list) {
		var items = list.getElementsByTagName("li")
		var array = new Array()
		for (var i = 0, n = items.length; i < n; i++) {
			array.push(items[i]);
		}
		return array;
	},

	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) */

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])
			}
		}
	}
}
/* 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) */

/* 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"
	}
}
/* 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
			element.style.filter = 'alpha(opacity=' + (opacity * 100) + ')'
		})
		this.register('dragend', function(dragEvent) {
			var element = dragEvent.group.element
			element.style.opacity = originalOpacity
			element.style.filter = 'alpha(opacity=100)'
		})
	},

	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
		})
	},

	_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)

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)
	}
}

