/*
    json.js
    2006-04-28

    This file adds these methods to JavaScript:

        object.toJSONString()

            This method produces a JSON text from an object. The
            object must not contain any cyclical references.

        array.toJSONString()

            This method produces a JSON text from an array. The
            array must not contain any cyclical references.

        string.parseJSON()

            This method parses a JSON text to produce an object or
            array. It will return false if there is an error.
*/
(function () {
    var m = {
            '\b': '\\b',
            '\t': '\\t',
            '\n': '\\n',
            '\f': '\\f',
            '\r': '\\r',
            '"' : '\\"',
            '\\': '\\\\'
        },
        s = {
            array: function (x) {
                var a = ['['], b, f, i, l = x.length, v;
                for (i = 0; i < l; i += 1) {
                    v = x[i];
                    f = s[typeof v];
                    if (f) {
                        v = f(v);
                        if (typeof v == 'string') {
                            if (b) {
                                a[a.length] = ',';
                            }
                            a[a.length] = v;
                            b = true;
                        }
                    }
                }
                a[a.length] = ']';
                return a.join('');
            },
            'boolean': function (x) {
                return String(x);
            },
            'null': function (x) {
                return "null";
            },
            number: function (x) {
                return isFinite(x) ? String(x) : 'null';
            },
            object: function (x) {
                if (x) {
                    if (x instanceof Array) {
                        return s.array(x);
                    }
                    var a = ['{'], b, f, i, v;
                    for (i in x) {
                        v = x[i];
                        f = s[typeof v];
                        if (f) {
                            v = f(v);
                            if (typeof v == 'string') {
                                if (b) {
                                    a[a.length] = ',';
                                }
                                a.push(s.string(i), ':', v);
                                b = true;
                            }
                        }
                    }
                    a[a.length] = '}';
                    return a.join('');
                }
                return 'null';
            },
            string: function (x) {
                if (/["\\\x00-\x1f]/.test(x)) {
                    x = x.replace(/([\x00-\x1f\\"])/g, function(a, b) {
                        var c = m[b];
                        if (c) {
                            return c;
                        }
                        c = b.charCodeAt();
                        return '\\u00' +
                            Math.floor(c / 16).toString(16) +
                            (c % 16).toString(16);
                    });
                }
                return '"' + x + '"';
            }
        };

   /*Object.prototype.toJSONString = function () {
        return s.object(this);
    };

    Array.prototype.toJSONString = function () {
        return s.array(this);
    };*/
})();

String.prototype.parseJSON = function () {
    try {
        return !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(
                this.replace(/"(\\.|[^"\\])*/g, ''))) &&
            eval('(' + this + ')');
    } catch (e) {
        return false;
    }
};
	function autocompletar(idObjeto,textFieldName,divListName,tipoBusqueda,textFieldPais,textFieldEstado){
		this.id=idObjeto;
		this.lista=document.getElementById(divListName);
		this.textField=document.getElementById(textFieldName);

		this.elementoSeleccionado = -1;
		this.sugerencias = new Array();
		
		this.texto="";
		this.textoAnt="";
		
		this.url="./includes/paises.php";
		
		if(!tipoBusqueda){
			this.tipoBusqueda=1;
		}else{
			this.tipoBusqueda=tipoBusqueda;
		}
		
		if(!textFieldPais ){
			this.textFieldPais="";
		}else{
			this.textFieldPais=textFieldPais;
		}
		
		if(!textFieldEstado){
			this.textFieldEstado="";
		}else{
			this.textFieldEstado=textFieldEstado;
		}
		
		// funcion para crear el objeto HttpRequest (Ajax)
		this.xmlHttp = function() {
			var httpRequest;
			if(window.XMLHttpRequest) {  // Navegadores que siguen los estándares
				httpRequest = new XMLHttpRequest();
			}else if(window.ActiveXObject) {  // Navegadores obsoletos
				httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
			}
			return httpRequest;
		};
		
		// Muestra las coincidencias en la lista
		this.inputUpdated = function(evt) {
			
			var key = "";
			
			// Almaceno la tecla presionada en el teclado
			if(window.event){// si es Internet Explorer
				key = evt.keyCode;
			}else if(evt.which){// si es Netscape/Firefox/Opera
				key = evt.which;
			}
			
			// se obtiene lo que esta escrito en el campo de texto
			this.texto = this.textField.value;

			// Si el string posee mas de 2 letras y es distinto del utilizado para la ultima busqueda
			if (this.texto.length>1 && this.texto.toLowerCase()!=this.textoAnt.toLowerCase()){
				// Se llama a la funcion para llenar la lista de sugerencias
				this.cargarLista(this.texto, this);
				// se almacena el ultimo string utilizado para la busqueda
				this.textoAnt = this.texto;
			}
			
			// si la lista esta desplegada y el tamaño del texto baja de 1 se deja de mostrar
			if (this.texto.length<=1 && (this.sugerencias.length!=0 || this.lista.style.display == "block")){
				this.sugerencias = new Array();
				this.lista.style.display = "none";
				this.elementoSeleccionado=-1;
				this.textoAnt = this.texto;
			}
			
			// se verifica la tecla presionada
			if (key == 37) { // Izquierda
				// No hago nada
			} else if (key == 38) { // Arriba
				// Subo la posicion en la lista desplegable una posición
				if (this.elementoSeleccionado > 0) {
					this.seleccionarFilling(this.elementoSeleccionado-1);
				}else if (this.elementoSeleccionado == 0 && this.sugerencias.length!=0) {
					this.seleccionarFilling(this.elementoSeleccionado+(this.sugerencias.length-1));
				}
				
			} else if (key == 39) { // Derecha
				// No hago nada
			} else if (key == 40) { // Abajo
				// Subo la posicion en la lista desplegable una posición
				if (this.sugerencias.length != 0 && (this.elementoSeleccionado < this.sugerencias.length-1)) {
					this.seleccionarFilling(this.elementoSeleccionado+1);
				}else if (this.elementoSeleccionado == this.sugerencias.length-1 && this.sugerencias.length!=0) {
					this.seleccionarFilling(this.elementoSeleccionado-(this.sugerencias.length-1));
				}
			} else if (key == 8) { // Borrar <-
				// No hago nada
			} else if (key == 13) { // Enter
				if (this.sugerencias.length != 0 && (this.elementoSeleccionado!=-1)) {
					this.seleccionarTextoFilling(this.elementoSeleccionado);
				}
			} else {
				// En otro caso
				// No hago nada
			}	
			
			return true;
		};
		
		this.cargarLista = function (txt,obj) {
			httpRequest = this.xmlHttp();
			httpRequest.open("GET", this.url+"?texto="+txt+"&tipo="+this.tipoBusqueda+this.getPais()+this.getEstado(), true);
			httpRequest.onreadystatechange=function() {
				if (httpRequest.readyState==4) {
					var datos = httpRequest.responseXML;
					var nombreDato = datos.getElementsByTagName("nombre");
					obj.sugerencias = new Array();
					if (nombreDato) {
						for (var i=0; i<nombreDato.length; i++) {
							obj.sugerencias[i] = nombreDato[i].firstChild.data;
						}
					}
					obj.rellenarLista();
				}
			};
			httpRequest.send(null);
		};	
		
		this.rellenarLista = function () {
			var html = "";
			this.elementoSeleccionado=0;
			
			if (this.sugerencias.length == 0) {
				// Si la lista de sugerencias es vacia no la mostramos
				this.lista.style.display = "none";
				this.elementoSeleccionado=-1;
			} else {
				// Creamos una tabla con todos los elementos encontrados
				this.lista.style.display = "block";
				var html='<table cellspacing="0" cellpadding="0" border="0" width="100%">';
				for (var i=0; i<this.sugerencias.length; i++) {
					html += '<tr id="'+this.id+i+'" '+(this.elementoSeleccionado == i?' class="seleccionado" ': ' class="deseleccionado"')+
						' onmouseover="'+this.id+'.seleccionarFilling('+i+',true);" onmousedown="'+this.id+'.seleccionarTextoFilling('+i+')">';
					html += '<td>'+this.sugerencias[i]+'</td></tr>';
				}
				html += '</table>';
			}

			// Escribimos la lista
			this.lista.innerHTML = html;
			this.lista.scrollTop = this.elementoSeleccionado*14;
		};
	  
		/*
		 *Cambia el estilo de la palabra seleccionada de la lista
		 */
		this.seleccionarFilling = function (n,mouse) {
			document.getElementById(this.id+this.elementoSeleccionado).className = "deseleccionado";
			document.getElementById(this.id+n).className = "seleccionado";
			this.elementoSeleccionado = n;
			if(!mouse){
				this.lista.scrollTop = this.elementoSeleccionado*14;
			}
		};
	  
		// Pasa el texto de la lista al campo de texto
		this.seleccionarTextoFilling = function (n) {
			this.textoAnt = this.textField.value = document.getElementById(this.id+n).firstChild.innerHTML;
			this.elementoSeleccionado = -1;
			this.sugerencias = new Array();
			this.lista.style.display = "none";
		};
		
		this.getPais=function(){
			if(this.textFieldPais=="" || document.getElementById(this.textFieldPais).value==""){
				return "";
			}else{
				return "&pais="+document.getElementById(this.textFieldPais).value;
			}
		};
		
		this.getEstado=function(){
			if(this.textFieldEstado=="" || document.getElementById(this.textFieldEstado).value==""){
				return "";
			}else{
				return "&estado="+document.getElementById(this.textFieldEstado).value;
			}
		};	
	}	  var actualMap;
  var addCustomMarkerEnabled=false;
  var autocompletarPais;
  var autocompletarEstado;	
  var autocompletarVehiculo;
  var clickButton;
  var connectionTimeout;
  var currentZoom = 0;
  var cursorType = 'Default';  
  var customMarkerArray = new Array();
  var distanceEnabled = false;
  var distanceVehicleEnabled = false;
  var doubleClickPos;
  var draggingDisabled = true;
  
  // icono de fin de distancia
  var end_icon = 'http://maps.google.com/mapfiles/dd-end.png';
  var endPos;
  var eventListOpen = false;
  var free_location = true;
  var geo = new GClientGeocoder();
  var idNearestVehicle;
  var imagenCustomMarker="";
  var index2 = false;
  //var infoWindowsArray = new Array();
  var latlon;
  var localOffset;
  var minZoomLevel;
  var maxZoomLevel;
  var mapBounds;
  var mapCreated = false;
  var mapHeight = 0;
  var mapLatitude = 0;
  var mapLongitude = 0;
  var mapWidth = 0;
  var markerImagesUrl= new Array();
  var menuBar = null;
  var minClusterZoom = 8;
  var minClusterZoomYahoo = 10;
  var mouseMovePos;
  var nombreCustomMarker;
  var posAccuracy = 3;
  var previousCursor;
  var publicVehiclesArray = new Array();
  
  // arreglo para mensajes de error
  var reasons=[]; 
  reasons[G_GEO_SUCCESS]            = i18n["msg_address_search_success"];
  reasons[G_GEO_MISSING_ADDRESS]    = i18n["msg_missing_address"];
  reasons[G_GEO_UNKNOWN_ADDRESS]    = i18n["msg_unknown_address"];
  reasons[G_GEO_UNAVAILABLE_ADDRESS]= i18n["msg_unavailable_address"];
  reasons[G_GEO_BAD_KEY]            = i18n["msg_bad_key"];
  reasons[G_GEO_TOO_MANY_QUERIES]   = i18n["msg_too_many_queries"];
  reasons[G_GEO_SERVER_ERROR]       = i18n["msg_server_error"];
  
  var screenX, screenY;
  var selectedMap='google';
  var selectedMapItemIndex=1011;
  var selectedMapType='Normal';
  var selectedMapTypeIndex=1021;
  var selectedOption = 1;
  var shiftPressed;
  // icono de comienzo de distancia	
  var start_icon = 'http://maps.google.com/mapfiles/dd-start.png';
  var startPos;
   
  /*
   * Arreglo que coloca el zoom apropiado segun el accuracy
   * retornado por el Geocoder luego de efectuar una busqueda
   */ 
  var tabAccuracy = new Array(4,5,7,9,10,13,16,16,17,17);
   
  /* valor posicion tabAccuracy
   * posicion	Significado
   * 	0 		Unknown location.
   * 	1 		Country level accuracy.
   * 	2 		Region (state, province, prefecture, etc.) level accuracy.
   * 	3 		Sub-region (county, municipality, etc.) level accuracy.
   * 	4 		Town (city, village) level accuracy.
   * 	5 		Post code (zip code) level accuracy.
   * 	6 		Street level accuracy.
   * 	7 		Intersection level accuracy.
   * 	8 		Address level accuracy. 
   * 	9		Premise (building name, property name, shopping center, etc.) level accuracy
   */
  
  var tOutSet = true;
  var tOut; 
  var tmpClustersArray = new Array();
  var tmpOverlay; 
  var updateFrequency = 2000;
  var updateMenuFrequency = 50000;
  var updateTimeOut;
  var userCountry;
  var userLoggedIn = false;
  var userMapLat = 0;
  var userMapLong = 0;
  var vehicleDetailsOpen = false;
  var vehicleRadiusKm=new Array(1250,650,350,200,100,50,25,12.5,6.25,3,1.5,0.75,0.35,0.17,0.08,0.04,0.02,0.01,0.005,0.0025,0.0012);
  var vehiclesArray=new Array();

  var zoom = 2;
  var zoomInActive=false;
  var zoomOutActive=false;

  /*
   * Funcion para anadir una nueva zona
   */	
  function addActualZone() {
   var res = getResolutionCode();
  	var width = 400;
  	var height = 150;
  	if(res == 2) {
  		width = 370;
  		height = 150;
  	}
  	if(res == 3) {
  		width = 340;
  		height = 150;
  	}
  
  	var strParams = parent.callMapFunction('getBounds_', null);
  	var url = "./add_edit_zone.php?cmdtype=add&"+strParams;
	openPopupWindow(url,i18n['title_window_add_zones'],true, false,width,height);
  }
  
  /*
   * Funcion para anadir una nuevo Custom Marker
   */	
  function addCustomMarker(x,y) {
  	var res = getResolutionCode();
  	var width = 390;
  	var height = 290;
  	if(res == 2) {
  		width = 390;
  		height = 270;
  	}
  	if(res == 3) {
  		width = 370;
  		height = 270;
  	}
  	
  	if(!x)
  		x=0;
  	if(!y)
  		y=0;
  	var strParams = "x="+x+"&y="+y;
  	var url = "./custom_markers_service.php?cmdtype=add&"+strParams;
  	disableAllFunctions();
	openPopupWindow(url,i18n['title_window_add_custom_marker'],true, false,width,height);
	win.setCloseCallback(function(){
  		changeCursor('default');
  		win.destroy();
  		win=null;
	 });
  }
  
  /*
   * Funcion para anadir una nueva Entidad
   */	
  function addEntity() {
   var res = getResolutionCode();
  	var width = 450;
  	var height = 400;
  	if(res == 2) {
  		width = 450;
  		height = 400;
  	}
  	if(res == 3) {
  		width = 440;
  		height = 260;
  	}
  	var url = "./add_edit_entity.php?cmdtype=add";
	openPopupWindow(url,i18n['title_window_add_entity'],true, false,width,height);
  }
  
  /*
  *
  */
  function addItems(selectFrom, selectTo) {
	var deleteIndexList = new Array(); 
	for(var i=selectFrom.options.length; i<1; i--) {
		if(selectFrom.options[i-1].selected) {
			addOption(selectTo, selectFrom.options[i-1].value, selectFrom.options[i-1].text);
			deleteIndexList.push(i-1);
		}		
	}	
	for(var i=0; i<deleteIndexList.length; i++) {
		selectFrom.remove(deleteIndexList[i]);
	}
  }
  
   /*
   * Funcion para agregar opciones de menu dinamicamente
   */
  function addMenuItem(id,label,parent,jsFunction) {
  	var model = new DHTMLSuite.menuModel();								
	model.addItem(id,label,'','',parent,'',jsFunction);
	//model.init();
	menuBar.appendMenuItems(parent,model);
  }
  
   /*
   * Funcion para agregar opciones a un select
   */
  function addOption(select, value, text) {
  	var newoption = document.createElement('option');
    newoption.text = text;
  	newoption.value = value;
	try {
		select.add(newoption, null); // standards compliant; doesn't work in IE
	}
	catch(ex) {
		select.add(newoption); // IE only
	}  	
  }
  
  /*
   * Funcion que se encarga de calcular la distancia de un pto a cada vehiculo
   */
  function calculeDistanceVehicle(event) {
  	var count=0;

    doubleClickPos = getPosition(event);
  	var point = callMapFunction('getPointLatLon_', 'doubleClickPos');
    var result = new Array();
  	for(var vehicle in vehiclesArray){
		var vehicleObj=vehiclesArray[vehicle];
		if(vehicleObj["ejeY"]){
			var actualDistance=Math.round(point.distanceFrom(new GLatLng(vehicleObj["ejeY"], vehicleObj["ejeX"]))/10)/100;
			
			result[count] = new distanceResult(vehicleObj["nombre"], actualDistance);
			++count;
		}
	}
	
	result.sort(sortByDistance);
	
	var str = "<table width=\"100%\" class=\"list\" cellpadding=\"0\" cellspacing=\"0\">"+
  					"<tr height=\"10\">"+
  						"<td colspan=\"2\"><hr></td>" +
  					"</tr>"+
  					"<tr class=\"header\">"+
						"<td align=\"center\">"+i18n["lbl_vehicle_name"]+"</td>"+
						"<td align=\"center\">"+i18n["lbl_distance"]+"</td>"+
					"</tr>";
  			  

  	for(var i=0; i<result.length; i++) {
  		if((i % 2)==0)
			str +=  "<tr class=\"text\" bgcolor=\"#E8E8E8\">";
		else
			str += "<tr class=\"text\" bgcolor=\"#B8D5E2\">";
  	
  		str += "<td>"+result[i].carName+"</td>"+
  			   "<td align=\"right\">"+result[i].distance+" kms.</td></tr>";
  		
  	}
  	if(result.length ==0) {
  		str+= "<tr class=\"text\" bgcolor=\"#E8E8E8\">";
  		str += "<td align='center' colspan='2'>"+i18n['msg_no_vehicle']+"</td></tr>";
  	}
  	
  	str+= "<tr><td colspan='2' height='7'><img src='img/spacer.png'></td></tr>"+
  		  "<tr><td colspan='2' align='center'>"+
  				"<input class='button' type='button' id='close' name='close' value='"+i18n["btn_close"]+"' onclick='parent.win.close();'>"+
  		  "</td></tr>";
  	var res = getResolutionCode();
  	var width = 350;
  	var height = 150;
  	if(res == 2) {
  		width = 330;
  		height = 130;
  	}
  	if(res == 3) {
  		width = 320;
  		height = 120;
  	}
  	
  	showResultsPopupWindow(str,i18n["title_window_vehicle_distance"],true, false,width,height);
  }

  /*
   * Funcion que llama a una funcion considerando el mapa
   * seleccionado. 
   */	
  function callMapFunction(functionName, strParams) {
  	var selectedMap = actualMap;
  	if(!selectedMap) selectedMap = getSelectedMap();

  	var initStr = 'document.getElementById(\'map_container\').contentWindow.';
  	
  	if(strParams == null)
  		initStr += functionName+selectedMap+'()';
  	else{
  		/* 
	  	 * El String ###replaceWhithSingleQuote### viene en los casos que se ha reemplazado un submenu dinamicamente
	  	 * se utiliza de esta forma dado que el menu llama a la funcion eval al momento de ejecutar la funcion y esta elimina las 
	  	 * comillas que hacen que el javascript lo interprete como un string generando asi un error en tiempo de ejecucion.
	  	 */
	  	strParams=strParams.replace(/###replaceWhithSingleQuote###/gi, "'");
  		initStr += functionName+selectedMap+'('+strParams+')';
  	}

  	return eval(initStr);  
  }
  
  /*
  *  
  */
  function centerMapLocalizable(id){
  	 getEntityPositionAndZoom(id);
  	 updateVisibilityVehicle(id);
  	 showInfoWindow(id, true, false);
  }
  
  /*
  * Funcion que cambia el estado del usuario en la bd 
  */
  function changeUserStatus(newStatus){
  		var data = "changeStatus=1";
  		if (newStatus && newStatus != "") data = data+"&newStatus="+newStatus;
  		
  		var http_request = makeRequest();
	  	http_request.onreadystatechange = function () {
	  		if (http_request.readyState == 4) {
				if (http_request.status == 200) {
					var result = http_request.responseText.parseJSON();
					if(result.userTip){
						document.getElementById("user_tips_td").innerHTML = result.userTip;  
					}
				}
			}
	  	}
	  	
		http_request.open("POST", "./user_tips.php", true);
		http_request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
		http_request.send(data);
  }  
  
  /*
   * Funcion que chequea si el ano es bisiesto
   */
  function checkBisiesto(year) {
  	if(year !=0 ) {
	  	if ((year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0)))
			return true;
		else 
			return false;
	}
	else return true;
  } 

  /*
   * Funcion que verifica que la fecha que se ingresa en los selects es valida
   */
  function checkDate(doc,idObjDay, idObjMonth, idObjYear) {
  	var selectDay = doc.getElementById(idObjDay);
  	var day = selectDay.selectedIndex;

  	var selectMonth = doc.getElementById(idObjMonth);
  	var month = selectMonth.selectedIndex;

  	if(month != 0) {
  		if((month==4) || (month==6) || (month==9) || (month==10)) {
  			if(selectDay.options.length < 31) {
  				while(selectDay.options.length < 31) {
  					addOption(selectDay,selectDay.options.length, selectDay.options.length);					
  				}
  			}
  			else {
  				if(selectDay.options.length > 31) 
  					selectDay.remove(31);
  			}
  				
  			if(day > 30) selectDay.selectedIndex = 0;  				
  		}
  			
  		if((month==1) || (month==3) || (month==5) || (month==7) || (month==8) || (month==10) || (month==12)) {
  			if(selectDay.options.length < 32) {
  				while(selectDay.options.length < 32) {
  					addDay(selectDay, selectDay.options.length, selectDay.options.length);					
  				}
  			}
  		}
  			
  		if(month==2) {
  			var selectYear = doc.getElementById(idObjYear);
  			var year = selectYear.options[selectYear.selectedIndex].value;
  				
  			if(checkBisiesto(year)) {
  				if(selectDay.options.length < 30) {
  					while(selectDay.options.length < 30) {
  						addOption(selectDay,selectDay.options.length, selectDay.options.length);					
  					}
  				}
  				else {
  					if(selectDay.options.length > 30) {
  						while(selectDay.options.length > 30) {
  							selectDay.remove(selectDay.options.length-1);
  						}
  					}
  				}
  						
  				if(day > 29) selectDay.selectedIndex = 0;
  			}
  			else {
  				if(selectDay.options.length > 29) {
  					while(selectDay.options.length > 29) {
  						selectDay.remove(selectDay.options.length-1);
  					}
  				}
  				if(day > 28) selectDay.selectedIndex = 0;
  			}
  		}  				
  	}  			  			
  }
  
  /*
  * Función que muestra los mensajes que le han sido enviados al usuario.
  */
  function checkRequests(){
   	var res = getResolutionCode();
  	var width = 350;
  	var height = 320;
  	if(res == 2) {
  		width = 320;
  		height = 270;
  	}
  	if(res == 3) {
  		width = 320;
  		height = 270;
  	}
  	openPopupWindow('./messages.php',i18n['menu_requests'],true, false,width,height);
  }
  
   /*
   * Funcion que se encarga de eliminar un customMarker del menu 
   */
  function deleteCustomMarker(id){
  	removeCustomMarker(id);
	menuBar.deleteMenuItems("12"+id,true);
  }
  

  
   /*
   * Funcion que muestra mensaje de problemas de conexion
   */	
  function showConnectionError() {
  	 connectionTimeout=30;
  	 
   	 Dialog.info(i18n['connection_error'].replace(/XX/g, connectionTimeout),
               {className:"alphacube", width:250, height:100, showProgress: true});
   	 clearTimeout(tOut);
  	 tOut = setTimeout(checkRetryConnection, 1000);   	 
  }
  
  /*
   * Funcion que se encarga de chequear si debe intentar una reconexion
   */
  function checkRetryConnection() {
   	connectionTimeout--;
  	if (connectionTimeout >0) {
    	Dialog.setInfoMessage(i18n['connection_error'].replace(/XX/g, connectionTimeout));
    	clearTimeout(tOut);
    	tOut = setTimeout(checkRetryConnection, 1000)
 	}
 	else {
  		Dialog.closeInfo();
  		clearTimeout(tOut);
   		updateVehicles();
   	}
  }	

  /*
   * Funcion para mostrar los campos correctos en la busqueda de coordenadas
   */
   function changeCoordType() {
   		var selectedIndex = document.getElementById('coord_type').options.selectedIndex;
   		var type = document.getElementById('coord_type').options[selectedIndex].value;
   		
   		if(type=='gms') {
   			document.getElementById('lat-gms').style.display='block';
   			document.getElementById('lon-gms').style.display='block';
   			document.getElementById('lat-decimal').style.display='none';
   			document.getElementById('lon-decimal').style.display='none';
   			document.getElementById('lat_grades').focus();
   		}
   		else {
   			document.getElementById('lat-gms').style.display='none';
   			document.getElementById('lon-gms').style.display='none';
   			document.getElementById('lat-decimal').style.display='block';
   			document.getElementById('lon-decimal').style.display='block';
   			document.getElementById('latitude').focus();
   		}
   }
    
 /*
  * Funcion que cambia el cursor del mapa
  */
  function changeCursor(type) {
  	var div = document.getElementById("map_container").contentWindow.document.getElementById('over_map');
  	if(type=='zoomIn') {
  		div.style.cursor = 'url(../img/zoom_in.cur),default';
  	}
  	if(type=='zoomOut') {
  		div.style.cursor = 'url(../img/zoom_out.cur),default';
  	}
  	if(type=='drag') {
  		div.style.cursor = 'move';
  	}
  	if(type=='distance') {
  		div.style.cursor = 'crosshair';
  	}  
  	if(type=='default') {
  		div.style.cursor = 'default';
  	}  
  }
  
  /*
  * Funcion que cambia el idioma en el que el usuario ve la aplicacion
  */
  function changeLanguage(newLang, newPage){	
		var data = "newLang="+newLang;
		var http_request = makeRequest();
	  	
	  	http_request.onreadystatechange = function () {
	  		if (http_request.readyState == 4) {
				if (http_request.status == 200) {
					var result = http_request.responseText.parseJSON();
					if(result != false) {
						if (result.languageChanged){
							refreshParenti18n(result.i18n);
							window.open(newPage, "_self");
						}
					}
				}
			}
	  	}
	  	
		http_request.open("POST", "./change_language.php", true);
		http_request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
		http_request.send(data);
  }

  /*
   * Funcion que se encarga del manejo de las vistas en la seccion preferencias   
   */
  function changeView(type) {
  
  	// pais, zona y vehiculo
  	if((type==1) || (type==2) || (type == 4)) {
  		var strType = "";
  		if(type==1)
  			strType = 'country';
  		if(type==2)
  			strType = 'zone';
  		if(type==4)
  			strType = 'vehicles';		
  			
  		var objSelect =	win.getContent().contentWindow.document.getElementById("dependant");
  		loadDependantSelect(objSelect,strType,'');
	  	win.getContent().contentWindow.document.getElementById("label").innerHTML = i18n['lbl_default_view_'+type]+":";
	  	win.getContent().contentWindow.document.getElementById("dependant_tr_1").style.display=""; 
	  	win.getContent().contentWindow.document.getElementById("dependant_tr_2").style.display="none"; 
	  	win.getContent().contentWindow.document.getElementById("dependant_tr_3").style.display="none";
	  	win.getContent().contentWindow.document.getElementById("dependant_td_1").innerHTML = '<img src="img/help.gif" onMouseover="ddrivetip(\''+i18n['tooltip_location_default_view_'+type]+'\');" onMouseout="hideddrivetip();">'; 
	} 
	
	// automatico
	if(type==0) {
		win.getContent().contentWindow.document.getElementById("dependant_tr_1").style.display="none"; 
	  	win.getContent().contentWindow.document.getElementById("dependant_tr_2").style.display="none"; 
	  	win.getContent().contentWindow.document.getElementById("dependant_tr_3").style.display="none";
	}	 	
  	
  	// lugar de residencia
  	if(type==3) {
  		setResidenceText(); 
  		win.getContent().contentWindow.document.getElementById("dependant_tr_1").style.display="none"; 
	  	win.getContent().contentWindow.document.getElementById("dependant_tr_2").style.display="";
	  	win.getContent().contentWindow.document.getElementById("dependant_tr_3").style.display="none";
	  	win.getContent().contentWindow.document.getElementById("dependant_td_2").innerHTML = '<img src="img/help.gif" onMouseover="ddrivetip(\''+i18n['tooltip_location_default_view_'+type]+'\');" onMouseout="hideddrivetip();">';
  	}
  	
  	// grupo de vehiculos
  	if(type==5) {	
  		win.getContent().contentWindow.document.getElementById("dependant_tr_1").style.display="none"; 
	  	win.getContent().contentWindow.document.getElementById("dependant_tr_2").style.display="none";
	  	win.getContent().contentWindow.document.getElementById("dependant_tr_3").style.display="";
	  	win.getContent().contentWindow.document.getElementById("dependant_td_3").innerHTML = '<img src="img/help.gif" onMouseover="ddrivetip(\''+i18n['tooltip_location_default_view_'+type]+'\');" onMouseout="hideddrivetip();">'; 
  	}
  }	

  /*
   * Funcion que se encarga de cargar un select dependiente
   */  	
  function loadDependantSelect(select, type, condition) {
  	var data="type="+type+"&condition="+condition;
  	
  	var http_request = makeRequest();
  	
  	http_request.onreadystatechange = function () {
  		if (http_request.readyState == 4) {
			if (http_request.status == 200) {
				var options = http_request.responseText.parseJSON();
	
				if(options != false) {			
					select.options.length = 0;
					for(i=0; i<options.length; i++) {						
						addOption(select,options[i].id,options[i].nombre);
					}	
					// establece coordenadas de pais para primer elemento seleccionado
					setCountryCoords();
				} 
			} 
		}
  	}
  	
	http_request.open("POST", "./includes/dependant_select.php", true);
	http_request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
	http_request.send(data);
  }	

  /*
   * Funcion para convertir a coordenadas decimales
   */	
   function convertToDecimal(grades, minutes, seconds) {
   		return ((grades + (minutes/60)) + (seconds/3600));   		
   }

  /*
   *  Funcion que borra la cookie de session al hacer logout a trabes del boton del menu
   */
  function deleteCookieIfExist(){
	if (document.cookie.length>0){
		var exdate=new Date();
		exdate.setDate(exdate.getDate()-365);
		document.cookie="usr='';expires="+exdate.toGMTString();
		document.cookie="usr_pass='';expires="+exdate.toGMTString();
		document.cookie="usr_lang='';expires="+exdate.toGMTString();
	  }
	return "";
  }

  /*
   * Funcion que deshabilita la funcion que este habilitada sobre el mapa
   */  
  function disableAllFunctions(itemIndex) {
  	if(itemIndex) 
  		setOptionSelected(itemIndex);
  	else
  		setOptionSelected(1);
  	if(zoomInActive){
  		zoomIn();
  	}
  	if(zoomOutActive){
  		zoomOut();
  	}
  	if(distanceEnabled){
  		onOffCalculateDistance();
  	}
  	if(!draggingDisabled){
  		onOffDragging();
  	}
  	if(distanceVehicleEnabled){
  		onOffCalcDistVehicle();
  	}
  	if(addCustomMarkerEnabled){
  		addCustomMarkerEnabled=false;
  	}
  }
  
  /*
   * Objeto donde se guarda el calculo de distancia a un vehiculo
   */
  function distanceResult(carName, distance) {
  	this.carName = carName;
  	this.distance = distance;
  }
  
   /*
   * Funcion que maneja las acciones a relizarse con un doble click
   */
   function doubleClickAction(event){
	   	var agt = navigator.userAgent.toLowerCase();		
	  	if(isAllDisabled() && ((event.button==0) || ((agt.indexOf("msie") != -1) && (event.button==1)))) {  		
	  		doubleClickPos = getPosition(event);  		
	  		latlon = callMapFunction('getPointLatLon_', 'doubleClickPos');
	  		screenX = event.clientX + document.getElementById('map_container').offsetLeft;
	  		screenY = event.clientY + document.getElementById('map_container').offsetTop;
	  		
	  		getNearestVehicle();
			disableAllFunctions();

	  		if(idNearestVehicle && (idNearestVehicle !=0)){
	  			var data="check=1&id="+idNearestVehicle;
			  	var http_request = makeRequest();
			  	
			  	http_request.onreadystatechange = function () {
			  		if (http_request.readyState == 4) {
						if (http_request.status == 200) {
							var result = http_request.responseText.parseJSON();
							if(result != false) {		
								if (!result.empty){ 
									openPopupWindow('./vehicle_details.php?id='+idNearestVehicle+'&check=0',i18n['title_window_vehicle_details'],true, false,400,445);
									win.setLocation(((screen.height)/2)-(430/2)-100,0);
									vehicleDetailsOpen = true;
								  	win.setCloseCallback(function(){
								  		vehicleDetailsOpen = false;
								  		win.destroy();
								  		win=null;
									 });
								}
							} 
						} 
					}
			  	}
			  	
				http_request.open("POST", "./vehicle_details.php", true);
				http_request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
				http_request.send(data);
	  		}
	  	}
   }

  /*
   * Funcion que dibuja cuadro de zoom
   */
  function drawRectangle() {
	var rentangleWidth = endPos.x - startPos.x;
	var rectangleHeight = endPos.y - startPos.y;
	document.getElementById('map_container').contentWindow.document.getElementById('rectangle').style.display = 'inline';	
	document.getElementById('map_container').contentWindow.document.getElementById('rectangle').style.left = startPos.x;
	document.getElementById('map_container').contentWindow.document.getElementById('rectangle').style.top = startPos.y;
		
	// caso de que el rectangulo se dibuje de derecha a izquierda
	if(rentangleWidth < 0) {
		rentangleWidth =  startPos.x - endPos.x;			
		document.getElementById('map_container').contentWindow.document.getElementById('rectangle').style.left = endPos.x;
	}
		
	// caso de que el rectangulo se dibuja de abajo hacia a arriba
	if(rectangleHeight < 0) {
		rectangleHeight = startPos.y - endPos.y;			
		document.getElementById('map_container').contentWindow.document.getElementById('rectangle').style.top = endPos.y;
	}
		
	document.getElementById('map_container').contentWindow.document.getElementById('rectangle').style.width = rentangleWidth;
    document.getElementById('map_container').contentWindow.document.getElementById('rectangle').style.height = rectangleHeight;
  }  

  /*
   * funcion que hace login al presionar enter
   */	
  function enterLogin(e) {
  	var key;
  	if (window.event)
  		key = window.event.keyCode;
  	else 
  		key = e.which;
	
	if(key == 13)
		login();	
  }
  	
  /*
   * Funcion que busca una direccion. Se esta usando la busqueda de google para todos los mapas
   */ 
  function findAddress() { 
  	var search = getSearchString();
  	
  	if (search == ""){
  	 	searchAddress("error", i18n['msg_some_fields_required']);
  	}
  	else geo.getLocations(search, processResult);
  }
  
  /*
   * funcion que se encarga de la busqueda por coordenadas
   */
  function findCoord() {
  	var selectedIndex = document.getElementById('coord_type').options.selectedIndex;
   	var type = document.getElementById('coord_type').options[selectedIndex].value;

   	var latitude, longitude;	
   	// si el tipo de coordenada es grados minutos y segundos
   	if(type=='gms') {
   		 var lat_grades = new Number(document.getElementById('lat_grades').value);
   		 var lat_minutes = new Number(document.getElementById('lat_minutes').value);
   		 var lat_seconds = new Number(document.getElementById('lat_seconds').value);

   		 // se valida que haya ingresado valores correctos en los campos de latitud
   		 var valid = validateCoords(lat_grades,lat_minutes,lat_seconds,'lat');
   		 if(valid=='ok') {
   		 	latitude = convertToDecimal(lat_grades, lat_minutes, lat_seconds);   		 
   		 
   		 	var lon_grades = new Number(document.getElementById('lon_grades').value);
   		 	var lon_minutes = new Number(document.getElementById('lon_minutes').value);
   		 	var lon_seconds = new Number(document.getElementById('lon_seconds').value);
   		 	
   		 	// se valida que haya ingresado valores correctos en los campos de longitud
   		 	valid = validateCoords(lon_grades,lon_minutes,lon_seconds,'lon');
   		 	if(valid=='ok') 
   		 		longitude = convertToDecimal(lon_grades, lon_minutes, lon_seconds);	
   		 	else {
   		 		document.getElementById('msg_coord').innerHTML=valid;
   		 		document.getElementById('msg_coord_tr').style.display='';
   		 		return;
   		 	}		
   		 }
   		 else {
   		 	document.getElementById('msg_coord').innerHTML=valid;
   		 	document.getElementById('msg_coord_tr').style.display='';
   		 	return;
   		 } 
   	}
   	// si introdujo coordenadas decimales
   	else {
   		decimal_lat = new Number(document.getElementById('latitude').value);
   		decimal_lon = new Number(document.getElementById('longitude').value);   
   		
   		if(!isNaN(decimal_lat))
   			latitude = decimal_lat;
   		else {
   			document.getElementById('msg_coord').innerHTML=i18n['msg_coords_latitude'];
   		 	document.getElementById('msg_coord_tr').style.display='';
   		 	return;
   		}
   		
   		if(!isNaN(decimal_lon))
   			longitude = decimal_lon;
   		else {
   			document.getElementById('msg_coord').innerHTML=i18n['msg_coords_longitude'];
   		 	document.getElementById('msg_coord_tr').style.display='';
   		 	return;
   		}		
   	}

   	// si los valores ingresados son validos se muestra la ubicacion

   	var params = latitude+","+longitude;
   	callMapFunction('findCoord_', params);
   	document.getElementById('msg_coord_tr').style.display='none';
   	if (win) win.setLocation(((screen.height)/2 - 35),0);
  } 

  /*
   * Funcion para disparar un evento sobre un objeto
   */
  function fireEvent(element,event, evt){
  	if(evt) {
  		if (document.createEventObject) {
  			var evn = document.createEventObject(evt);
  			evn.button = 1;
  			return element.fireEvent('on'+event,evn);
  		}
  		else {
  			var evn = document.createEvent("MouseEvents");
			evn.initMouseEvent(event, evt.bubbles, evt.cancelable, evt.view, evt.detail, evt.screenX, evt.screenY, evt.clientX, 
							   evt.clientY, evt.ctrlKey, evt.altKey, evt.shiftKey, evt.metaKey, event.button, null);
			return element.dispatchEvent(evn);
  		}
  	}
  	else {
	    if (document.createEventObject){
	        // dispatch for IE
	        var evt = document.createEventObject();
	        return element.fireEvent('on'+event,evt);
	    }
	    else{
	        // dispatch for firefox + others
	        var evt = document.createEvent("HTMLEvents");
	        evt.initEvent(event, true, true ); // event type,bubbling,cancelable
	        return !element.dispatchEvent(evt);
	    }
	}
  } 

  /*
   * Funcion que retorna el valor de una cookie dado su nombre 
   */
  function getCookie(c_name){
	if (document.cookie.length>0){
	  c_start=document.cookie.indexOf(c_name + "=");
	  if (c_start!=-1)
	    { 
	    c_start=c_start + c_name.length+1; 
	    c_end=document.cookie.indexOf(";",c_start);
	    if (c_end==-1) c_end=document.cookie.length;
	    return unescape(document.cookie.substring(c_start,c_end));
	    } 
	  }
	return "";
  }

  /*
   *
   */ 	
  function getGLatLon(marker) {
 	if(selectedMap == 'google') 
 		return marker.getLatLng();
 	
 	if(selectedMap == 'yahoo') 
 		return new GLatLng(marker.YGeoPoint.Lat, marker.YGeoPoint.Lon);
  }
  
  /* 
   * Funcion que obtiene la posicion x,y del mouse en un evento dado
   */
  function getPosition(event) {
  	var posX = event.clientX;
 	var posY = event.clientY;

 	return new position(posX,posY);
  } 
  
  /*
   * Funcion que obtiene los valores del formulario Perferencias - Perfil
   */ 
  function getProfilePreferences() {
  	// obtiene la data del tab perfil
  	var language = win.getContent().contentWindow.document.getElementById("language").value;
  	var name = win.getContent().contentWindow.document.getElementById("name").value;
  	var lastname = win.getContent().contentWindow.document.getElementById("lastname").value;
  	var city = win.getContent().contentWindow.document.getElementById("input-ciudad").value;
  	var country = win.getContent().contentWindow.document.getElementById("input-pais").value;
  	var sex = win.getContent().contentWindow.document.getElementById("sex").value;
  	var instruction = win.getContent().contentWindow.document.getElementById("instruction").value;
  	var date = win.getContent().contentWindow.document.getElementById("year").value + '-' +
  			   win.getContent().contentWindow.document.getElementById("month").value + '-' +
  			   win.getContent().contentWindow.document.getElementById("day").value;
  			   
  	var data_profile = "language="+language+"&name="+name+"&lastname="+lastname+"&city="+city+"&country="+country+	
  					   "&sex="+sex+"&instruction="+instruction+"&birthdate="+date;	

 	return data_profile;
  }
  
  /*
  *	Funcion que busca la posicion actual de un ubicable y centra el mapa en ella al zoom seleccionado por el usuario
  */
  function getEntityPositionAndZoom(id){
  		var currentEntity = vehiclesArray[id];
  		//alert(currentEntity['ejeY']+','+currentEntity['ejeX']+','+currentEntity['zoom']);
  		callMapFunction('place_',currentEntity['ejeY']+','+currentEntity['ejeX']+','+currentEntity['zoom']);
  }
  
   /*
   * Funcion que obtiene los valores del formulario Perferencias - Visibilidad
   */ 
  function getVisibilityPreferences(){
		var data_visibility = "";
  		var entitiesSelect = win.getContent().contentWindow.document.getElementById("entities_added");
  		var entities = "";

  		for(var i=0; i<entitiesSelect.options.length; i++) {
			entities+= entitiesSelect.options[i].value + ",";
  		}
  		entities = entities.substring(0,entities.length - 1);
  		data_visibility = "&entities="+entities;
  		return data_visibility;
  }
  
  /*
   * funcion que devuelve un string dado resultado de la verificacion de los campos de busqueda de direccion
   */
  function getSearchString(){
  	var str="";
  	var prev=0;
  	
  	if(document.getElementById('input-pais').value!=""){
  		prev = 1;
  		str += document.getElementById('input-pais').value;
  	}
	
	if(document.getElementById('input-estado').value!=""){
  		if(prev==1){
  			str +=", "+document.getElementById('input-estado').value;
  		}else{
  			prev = 1;
  			str +=document.getElementById('input-estado').value;
  		}
  	}
	
	if(document.getElementById('input-ciudad').value!=""){
  		if(prev==1){
  			str +=", "+document.getElementById('input-ciudad').value;
  		}else{
  			prev = 1;
  			str +=document.getElementById('input-ciudad').value;
  		}
  	}
  	
  	if(document.getElementById('input-urban').value!=""){
  		if(prev==1){
  			str +=", "+document.getElementById('input-urban').value;
  		}else{
  			prev = 1;
  			str +=document.getElementById('input-urban').value;
  		}
  	}
  	
  	if(document.getElementById('input-calle').value!=""){
  		if(prev==1){
  			str +=", "+document.getElementById('input-calle').value;
  		}else{
  			prev = 1;
  			str +=document.getElementById('input-calle').value;
  		}
  	}
  	
  	if(document.getElementById('input-otros').value!=""){
  		if(prev==1){
  			str +=", "+document.getElementById('input-otros').value;
  		}else{
  			prev = 1;
  			str +=document.getElementById('input-otros').value;
  		}
  	}

  	return str;
  }
  
  /*
   * Funcion que retorna el mapa que se encuenta actualmente seleccionado en el menu
   * (google, yahoo, virtual earth)
   */
  function getSelectedMap() {
  	return selectedMap;
  }
  
  /*
   * Funcion que obtiene los valores del formulario Perferencias - Ubicacion
   */
  function getLocationPreferences() {
  	var view = win.getContent().contentWindow.document.getElementById("view").value;
  	var valueSelect = win.getContent().contentWindow.document.getElementById("dependant").value;
  	var data_location = "&view="+view;

  	// si es vista de pais
  	if((view == 1)||(view == 3)) {  	
  		if(view==1) data_location += "&valueSelect="+valueSelect;
  		
  		var latitud = win.getContent().contentWindow.document.getElementById("latitud").value;
  		var longitud = win.getContent().contentWindow.document.getElementById("longitud").value;
  		data_location +="&latitud=" + latitud + "&longitud=" + longitud;	   		        
  	}	
  	
  	if((view==2)||(view==4)) 
  		data_location += "&valueSelect="+valueSelect;
  	
  	if(view==5) {
  		var vehiclesSelect = win.getContent().contentWindow.document.getElementById("vehicles_added");
  		var vehicles = "";

  		for(var i=0; i<vehiclesSelect.options.length; i++) {
			vehicles+= vehiclesSelect.options[i].value + ",";
  		}
  		vehicles = vehicles.substring(0,vehicles.length - 1);
  		//data_location += "&valueSelect="+valueSelect+"&vehicles="+vehicles;
  		data_location += "&vehicles="+vehicles;
  	}
  	
  	return data_location;
  }
  
  /*
  *
  */
  function getOtherPreferences(){
  	var speed_unit = win.getContent().contentWindow.document.getElementById("speed_unit").value;
  			   
  	var others = "&speedunit="+speed_unit;	

 	return others;
  }
  
  /*
   * funcion que retorna el vehiculo mas cercano a un punto geografico segun el zoom del mapa
   */
  function getNearestVehicle(event) {
  	nearestVehicle=new Array();
   	if (latlon) {
   		var count=0;
   		var distance=0;
   		nearestVehicle["vehicleName"]="";

   		for(var vehicle in vehiclesArray){
   			var vehicleObj = vehiclesArray[vehicle];
   			
   			if(vehicleObj["nombre"]){
	   			var actualDistance=Math.round(latlon.distanceFrom(new GLatLng(vehicleObj["ejeY"], vehicleObj["ejeX"]))/10)/100;
	   			if(count==0 || (distance>actualDistance)){
		   				distance = actualDistance;
		   				idNearestVehicle = vehicle;	
	   			}
	   			++count;
	   		}
   		}
        if(distance>=vehicleRadiusKm[zoom-1])
        	idNearestVehicle=0;
	}
	return;
  }
  
  /*
   *
   */
  function gotoIndex() {
	Dialog.closeInfo();
	window.location.href="./logout.php";
  }
  
  /*
   * Funcion para ocultar la informacion de direccion
   */
  function hideAddress() {
	document.getElementById('bubble_tooltip').style.display = 'none';	
  }
  
  /*
   * Funcion que oculta un custom marker 
   */
  function hideCustomMarker(id){
	var i=0;
  	for(i=0;i<customMarkerArray.size();i++){
  		var markerInfo = customMarkerArray[i];
    	if(markerInfo['id']==id){
    		callMapFunction('hideOverlay_',('customMarkerArray['+i+'][\"overlay\"]')); 
		}
  	}
  	return;
  }

  /*
  * Esconde los user tips una vez que el usuario ha agregado una entidad con dispositivo GPS
  */
  function hideUserTips(newDisplay){
	document.getElementById("user_tips_tr").style.display = newDisplay;
  }
  
  /*
   * Funcion que establece cual es el mapa actual
   */ 
  function initActualMap() {
  	 actualMap = getSelectedMap();
  }
  
  /*
   * Funcion para inicializar evento de rueda de mouse
   */
  function initWheelEvent() {
  	if (document.getElementById('map_container').contentWindow.addEventListener)         
  		document.getElementById('map_container').contentWindow.addEventListener('DOMMouseScroll', wheel, false); 

	document.getElementById('map_container').contentWindow.onmousewheel = document.getElementById('map_container').contentWindow.document.onmousewheel = wheel; 
  } 

  /*
   * Funcion que determina si es click izquierdo
   */
   function isLeftClick() {
   		var agt = navigator.userAgent.toLowerCase();
		
		if((clickButton==0) || ((agt.indexOf("msie") != -1) && (clickButton==1)))
			return true;
		else 
			return false;			
   }
   
  /*
   * Funcion para verificar si todas las funciones estan deshabilitadas
   */ 
  function isAllDisabled() {
	if(!zoomInActive && !zoomOutActive && !distanceEnabled && draggingDisabled )
  		return true;
  	else 
  		return false;
   }
   
  /*
   * Funcion que carga la informacion de un usuario q ingreso a movilsat
   */ 
  function loadUserInfo(userId) {
  	
  	if(userId) {
 		var http_request = makeRequest();
  	
  		http_request.onreadystatechange = function () {
  			if (http_request.readyState == 4) {
				if (http_request.status == 200) {
					var result = http_request.responseText.parseJSON();
	
					if(result != false) {					
						if(result.success) {
							
							// agrega marcadores de vehiculos
							var vehiculos = result.vehiculos;
							for(i=0; i<vehiculos.length; i++) {
								var vehicle = new Array();
								vehicle['ejeY'] 	= vehiculos[i].ejeY;
								vehicle['ejeX'] 	= vehiculos[i].ejeX;
								vehicle['nombre'] 	= vehiculos[i].nombre;
								vehicle['imagen'] 	= "../"+vehiculos[i].imagen;
								vehicle['rotacion'] = vehiculos[i].rotacion;
								vehicle['zoom'] 	= vehiculos[i].zoom;
								vehicle['accuracy'] = vehiculos[i].accuracy;
								vehicle['radio'] 	= vehiculos[i].radio;
								vehicle['evento'] 	= vehiculos[i].evento;
								vehicle['velocidad']= vehiculos[i].velocidad;
								vehicle['reporte']	= vehiculos[i].reporte;									
								vehiclesArray[vehiculos[i].id]=vehicle;				
							}

							// agrega los custom marker
							var markers = result.customMarkers;
							for(i=0; i<markers.length; i++) {
								var markerInfo = new Array();
								markerInfo['id']=markers[i].id;
								markerInfo['ejeX']=markers[i].ejeX;
								markerInfo['ejeY']=markers[i].ejeY;
								markerInfo['nombre']=markers[i].nombre;
								markerInfo['imagen']="../"+markers[i].imagen;	    
								customMarkerArray.push(markerInfo);
							}
							callMapFunction("showAllMarkers_", null);
							
							//se muestra ultimo evento
							var lastevent = result.evento;						
							if(lastevent.success && lastevent.event_available) {
								var evento = lastevent.evento;
								updateEventTable(evento.tipo,evento.vehiculo,evento.time,evento.color);
							}
							
							if (!result.complete){
								openRegisterForm(true);
							}

							updateVehicles();
							updateMenu();
						}	
					} 
				} 
			}
	  	}

		http_request.open("POST", "./loadUserInfo.php", true);
		http_request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
		http_request.send(null);
  	}
  }

  /*
   * Funcion que se encarga de iniciar sesion via ajax
   */ 
  function login(email, password, rememberme) {
  	var autologin=true;
  	if(!email) {
  		email = document.getElementById('email').value;
  		password = document.getElementById('password').value;
  		rememberme = document.getElementById('rememberme').checked;
  		autologin=false;
  	}

  	var data = "email="+email+"&password="+password+'&localOffset='+localOffset;
	
	// mantiene o limpia los datos de inicio de sesion segun si esta o no marcada la casilla rememberme
	if(rememberme) data += "&rememberme="+rememberme;
	else {
		document.getElementById('email').value='';
		document.getElementById('password').value='';
	}
	
  	var http_request = makeRequest();
  	
  	http_request.onreadystatechange = function () {
  		if (http_request.readyState == 4) {
			if (http_request.status == 200) {
				var result = http_request.responseText.parseJSON();
	
				if(result != false) {					
					if(result.success) {
						userLoggedIn = true;
						
						if (free_location == true){ // se entró por el index 
							//oculta seccion de login
							//document.getElementById('login_tr').style.display = 'none';
							
							//actualiza menu
							refreshMenu();
							
							if (result.i18n){
								refreshParenti18n(result.i18n);
							}
							
							if (mapCreated){
								//callMapFunction('removeClusters_', null); // remueve los clusters
								callMapFunction('captureEvent_', null); // libera el evento que dispara la fabricacion de clusters y activa el de remover infoWindows
								//callMapFunction('releaseEvent_', null);

								//carga la informacion del usuario
								if(!autologin) loadUserInfo(result.userId);
								
								if (result.country){ // si se ubica al usuario por país
									var country = result.country;
									setLatLon(1);
									//callMapFunction('updateMapCenter_', mapLatitude+", "+mapLongitude);
								}
								else if (result.latitud && result.longitud){ // si se ubica por lugar de residencia o entidad
									mapLatitude = result.latitud;
									mapLongitude = result.longitud;
									zoom = 5;
									callMapFunction('updateMapCenter_', mapLatitude+", "+mapLongitude);
								}
								else if (result.dominio){ // se ubica por zona 
									callMapFunction('changeDomain_', '"'+result.dominio+'"');
								}
								else if (result.vehiculos){ // se ubica por grupo de entidades
									callMapFunction('setGroupCenter_', '"'+result.vehiculos+'"');
								}
								//document.getElementById('message_tr').style.display = 'none';
							}
							
							// Si se tiene el país del usuario se guardan sus coordenadas para posterior uso
							if (result.userCountry){ 
								userCountry = result.userCountry;
								setUserLatLon();
							}
							
							// Si contiene el correo electrónico del usuario, se muestra a la derecha de la pantalla
							if (result.email){
								document.getElementById('user_label').innerHTML = i18n['title_user']+":";
								document.getElementById('user_email').innerHTML = result.email;
								document.getElementById('user_id_tr').style.display = '';
							}
							
							// muestra los tips del usuario
							if (result.userTip){
								document.getElementById('user_tips_tr').style.display = '';
								document.getElementById('user_tips_td').innerHTML = result.userTip;
							}
							
							// Cambia el texto del banner de Movilsat Móvil por el del idioma del usuario
							//document.getElementById("mm_banner").innerHTML = i18n['lbl_download_movilsat_movil'];
							document.getElementById("antares_banner").innerHTML = i18n['lbl_get_gps_device'];
							
							// Si los datos del registro están incompletos se abre el formulario de registro para completarlo
							if (!result.complete){
								openRegisterForm(true);
							}
						}
						else { // se entró por el index2
							//document.getElementById('message_tr').style.display = 'none';
							//window.open("movilsat.php", "_self");
							window.location.href = "movilsat.php";
						}
					}
					else {
						if (!index2){
							window.open("index2.php?message="+escape(result.message), "_self");
						}
						else {
							document.getElementById('messageFileSeparator').style.display = '';
							document.getElementById('messageFile').style.display = '';
							document.getElementById('messageRow').innerHTML = "&nbsp;&nbsp;&nbsp;"+result.message;
							document.getElementById("email").focus();
						}
					}		
				} 
			} 
		}
  	}
  	
	http_request.open("POST", "./login.php", true);
	http_request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
	http_request.send(data);
  } 
  
   /*
   * Funcion que se encarga de cerrar sesion via ajax
   */ 
  function logout() {
  	var http_request = makeRequest();
  	
  	http_request.onreadystatechange = function () {
  		if (http_request.readyState == 4) {
			if (http_request.status == 200) {
				var result = http_request.responseText.parseJSON();
	
				if(result != false) {					
					if(result.success) {
						userLoggedIn = false;
						idNearestVehicle = 0;
						callMapFunction('releaseEvent_', null);
						
						//muestra seccion de login
						//document.getElementById('login_tr').style.display = '';
						
						// esconde el email del	usuario
						document.getElementById('user_id_tr').style.display = 'none';
						document.getElementById('user_email').innerHTML = '';
						document.getElementById('user_label').innerHTML = '';
						
						// esconde los tips
						document.getElementById('user_tips_tr').style.display = 'none';
						
						if(getCookie("usr")=="" && getCookie("usr_pass")==""){
							document.getElementById('email').value="";
							document.getElementById('password').value="";
							document.getElementById('rememberme').checked=false;
						}
						
						//actualiza menu
						refreshMenu();
						if (result.i18n){
							refreshParenti18n(result.i18n);
						}

						// Cambia el texto del banner de Movilsat Móvil por el del idioma del navegador
						//document.getElementById("mm_banner").innerHTML = i18n['lbl_download_movilsat_movil'];
						document.getElementById("antares_banner").innerHTML = i18n['lbl_get_gps_device'];
						
						// Setea el time out para el updateVehicles en caso de que el mismo no se encuentre seteado
						/*if (tOutSet == false){
							setTimeout("updateVehicles();",updateFrequency);
							tOutSet = true;
						}*/
						
						if (updateTimeOut) clearTimeout(updateTimeOut);
						
						adaptResolution();
												
						//se oculta ultimo evento
						document.getElementById('more_events').style.display = 'none';
						document.getElementById('event').style.display = 'none';	
						document.getElementById('title').innerHTML = '';
						
						// borra custom markers		
						for(var i=0;i<customMarkerArray.size();i++){
					  		var markerInfo = customMarkerArray[i];  		
					    	if(markerInfo['overlay']) {
						    	tmpOverlay = markerInfo['overlay'];
							    callMapFunction('removeOverlay_','tmpOverlay');
							}
					  	}
					  	customMarkerArray = new Array();
					  	
					  	// borra vehiculos
					  	// muestra vehiculos  	
					  	for(var key in vehiclesArray){
					  		var markerInfo = vehiclesArray[key];
					  		if(markerInfo['marker']) {
					  			tmpOverlay = markerInfo['marker'];
							    callMapFunction('removeOverlay_','tmpOverlay');
					  		}
					  		if(markerInfo['label']) {
					  			tmpOverlay = markerInfo['label'];
							    callMapFunction('removeOverlay_','tmpOverlay');
					  		}
					  		if(markerInfo['arrow']) {
					  			tmpOverlay = markerInfo['arrow'];
							    callMapFunction('removeOverlay_','tmpOverlay');
					  		}
					  		if(markerInfo['circle']) {
					  			tmpOverlay = markerInfo['circle'];
							    callMapFunction('removeOverlay_','tmpOverlay');
					  		}					
					  	}		
					  	vehiclesArray = new Array();
					  	if (win) win.close();
					  	/*hideInfoWindowOnMoveEvent();
					  	parent.getPublicVehicles();*/
					  	window.open("index.php", "_self");
					}		
				} 
			} 
		}
  	}

	http_request.open("POST", "./logout.php", true);
	http_request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
	http_request.send(null);
  } 
   
  /*
   * Funcion para abrir ventana de gestionar zonas
   */	
  function manageCustomMarkers() {  
  	var res = getResolutionCode();
  	var width = 450;
  	var height = 425;
  	if(res == 2) {
  		width = 380;
  		height = 370;
  	}
  	if(res == 3) {
  		width = 350;
  		height = 250;
  	}
  	openPopupWindow('./manage_custom_markers.php',i18n['title_window_manage_custom_marker'],true, false,width,height);
  }
  
  /*
   * Funcion para abrir ventana de gestionar vehiculos
   */	
  function manageVehicles() {
  	var res = getResolutionCode();
  	var width = 450;
  	var height = 425;
  	if(res == 2) {
  		width = 450;
  		height = 370;
  	}
  	if(res == 3) {
  		width = 320;
  		height = 270;
  	}
  	openPopupWindow('./manage_vehicles.php',i18n['title_window_manage_vehicles'],true, false,width,height);
  } 

  /*
   * Funcion para abrir ventana de gestionar zonas
   */	
  function manageZones() {
  	var res = getResolutionCode();
  	var width = 450;
  	var height = 440;
  	if(res == 2) {
  		width = 380;
  		height = 370;
  	}
  	if(res == 3) {
  		width = 320;
  		height = 250;
  	}
  	openPopupWindow('./manage_zones.php',i18n['title_window_manage_zones'],true, false,width,height);
  }

  /*
   * Funcion para crear objeto de conexion ajax
   */   	
  function makeRequest() {
	var http_request = false;

	if (window.XMLHttpRequest) { // Mozilla, Safari,...
		http_request = new XMLHttpRequest();
		if (http_request.overrideMimeType) {
			http_request.overrideMimeType('text/json');
		}
	} else if (window.ActiveXObject) { // IE
		try {
			http_request = new ActiveXObject("Microsoft.XMLHTTP");
		} catch (e) {
			try {
				http_request = new ActiveXObject("Msxml2.XMLHTTP");
			} catch (e) {}
		}
	}
	
	if (!http_request) {
		alert('Giving up :( Cannot create an XMLHTTP instance');
		return false;
	}
	
	return http_request;
  }

  /* 
   * Funcion que setea la posicion donde empieza un evento de mouse dado.
   */
  function mouseDownAction(event) {
  	//hideAddress();
  
  	var agt = navigator.userAgent.toLowerCase();
  	if(agt.indexOf("msie") == -1)
  		event.preventDefault();	
  		
 	startPos = getPosition(event);
 	clickButton = event.button;
 	shiftPressed = event.shiftKey;
 	previousCursor = document.getElementById("map_container").contentWindow.document.getElementById('over_map').style.cursor;
	setCursor(event);
	
	/* si el mapa es yahoo y la accion es click derecho o arrastrar mapa, disparo evento mousedown sobre el mapa yahoo.
	   Para el click derecho, si el dragging no esta activado hay que activarlo para poder arrastrar el mapa */
	if((getSelectedMap().indexOf("yahoo") != -1) && !event.shiftKey && ((clickButton ==2) || (!draggingDisabled))) {
		
		if((clickButton == 2) && (draggingDisabled)) {
			document.getElementById("map_container").contentWindow.map.enableDragMap();
		}
		fireEvent(document.getElementById("map_container").contentWindow.document.getElementById('map_yahoo'),'mousedown',event);
	}
  }
  
  /*
   * Funcion que define acciones a tomar mientras se mueve el mouse
   */
  function mouseMoveAction(event) {  
  
  	// si es explorer y no hay boton presionado limpiar los valores porq no disparo el onmouseup 	
  	var agt = navigator.userAgent.toLowerCase();
  	if((event.button==0)&&(agt.indexOf("msie") != -1)) {
  		endPos = null;
  		startPos = null;
  		clickButton = null;
  		shiftPressed = null;
  	}
  	
  	// actualiza la coordenada en la que esta el mouse
  	endPos = getPosition(event);		
  	document.getElementById('coordinates').innerHTML = i18n["msg_coordinates"]+': '+callMapFunction('coordToStr_', 'endPos');
	
	// Si la tecla shift está presionada
	if(shiftPressed) {
		// Si shift+click izquierdo
		if(isLeftClick()){
			drawRectangle();
			//if (userLoggedIn) hideInfoWindowOnMoveEvent();
		}
	}
	else {
		// si es click derecho se arrastra el mapa
		if(clickButton==2) {
			if (userLoggedIn)
				hideInfoWindowOnMoveEvent();
			
			// si el mapa es yahoo disparo evento mousemove sobre el mapa 
			if(getSelectedMap().indexOf("yahoo") != -1) {
				fireEvent(document.getElementById("map_container").contentWindow.document.getElementById('map_yahoo'),'mousemove',event);	
			}
			else
				callMapFunction('dragMap_', null);	
	  	} 
		else {
			// si es click izquierdo
			if(isLeftClick()) {
				// si esta activado el zoomIn y se esta haciendo clic izquierdo
				if(zoomInActive) 
	  				drawRectangle();
	  				
	  			// si esta activado el dragging y no es yahoo maps se hace drag del mapa
	  			if(!draggingDisabled) {
	  				if (userLoggedIn) 
	  					hideInfoWindowOnMoveEvent();
	  				
	  				if(getSelectedMap().indexOf("yahoo") != -1) 
	  					fireEvent(document.getElementById("map_container").contentWindow.document.getElementById('map_yahoo'),'mousemove',event);
	  				else
	  					callMapFunction('dragMap_', null);
	  			}
			}			
			else { // Sino está presionado ningún botón ni la tecla shift
				if (userLoggedIn){
					mouseMovePos = getPosition(event);
					latlon = callMapFunction('getPointLatLon_', 'mouseMovePos');
	  				
	  				getNearestVehicle();
	  				if(idNearestVehicle && (idNearestVehicle !=0)){
						showInfoWindow(idNearestVehicle);
	  				}
	  				else { hideInfoWindow();}
				}
			}
		}
	}
  }

  /*
   * Funcion que ejecuta acciones al soltar el boton del mouse
   */
  function mouseUpAction(event) {

	if(shiftPressed) {
	
		// si se hace shift + click derecho = zoom out
		if(clickButton == 2) {
			//if (userLoggedIn) hideInfoWindowOnMoveEvent();
			callMapFunction('zoomPoint_', 'startPos,false');
		}
		// si se hace shift + click izquierdo = zoom in
		else {
			if(isLeftClick()) {
				//if (userLoggedIn) hideInfoWindowOnMoveEvent();
				if((endPos == null)||((endPos.x==startPos.x) && (endPos.y==startPos.y))) 
					callMapFunction('zoomPoint_', 'startPos,true');
				else 
					zoomArea();
			}
		}
	}
	else {
		if(isLeftClick()) {	
		
			// cuando zoom in esta activo
			if(zoomInActive) {
				// si posicion final = posicion inicial hace zoom in sobre punto
				if((endPos == null)||((endPos.x==startPos.x) && (endPos.y==startPos.y))) {
					callMapFunction('zoomPoint_', 'startPos,true');
				}
				// si no, hacer zoom de area
				else {
					zoomArea();
				}
			}
	
			// si zoom out esta activo se hace zoom out
			if(zoomOutActive){
				// si posicion final = posicion inicial hace zoom out sobre punto
				if((endPos == null)||((endPos.x==startPos.x) && (endPos.y==startPos.y))) {
					callMapFunction('zoomPoint_', 'startPos,false');
				}
			}
			
			// si esta activo el boton de distancia
			if(distanceEnabled) {
				endPos = getPosition(event);
				callMapFunction('calculeDistance_', 'endPos');
			}
			
			// si esta activo el boton de distancia de vehiculo
			if(distanceVehicleEnabled) {
				calculeDistanceVehicle(event);
			}
			
			// si esta activo el boton de agregar custom marker
			if(addCustomMarkerEnabled) {
				doubleClickPos = getPosition(event);  		
  				callMapFunction('prepareCustomMarker_', 'doubleClickPos');
			}
		}	
		// si el dragging esta activado y el mapa es yahoo se finaliza el drag
		if((getSelectedMap().indexOf("yahoo") != -1) && (document.getElementById("map_container").contentWindow.document.getElementById('map_yahoo')!=null) && !event.shiftKey && ((clickButton ==2) || (!draggingDisabled))) {
			if((clickButton == 2) && (draggingDisabled))
				document.getElementById("map_container").contentWindow.map.disableDragMap();
			fireEvent(document.getElementById("map_container").contentWindow.document.getElementById('map_yahoo'),'mouseup');
		}
	}
	
	// resetea el valor de variable de posicion y boton presionado
  	document.getElementById("map_container").contentWindow.document.getElementById('over_map').style.cursor = previousCursor;  	
  	endPos = null;
  	startPos = null;
  	clickButton = null;
	shiftPressed = null;
  }
  
  /*
   * Funcion que se encarga de activar/desactivar la insercion de marcadores personalizados
   */
  function onAddCustomMarker(){
  	
  	if(win!=null){
    	win.close();
    }
	disableAllFunctions();
	addCustomMarkerEnabled=true;  
	changeCursor('distance');
  }
  
  /*
   * Funcion que se encarga de activar/desactivar el calculo de distancia
   */
  function onOffCalculateDistance(itemIndex){
    if(!itemIndex && distanceEnabled){
	  distanceEnabled = false;
	  changeCursor('default');
	}else{
		disableAllFunctions();
		distanceEnabled=true;
		changeCursor('distance');
	}  
	if(itemIndex) setOptionSelected(itemIndex);
  }
  
  /*
   * Funcion que se encarga de activar/desactivar el calculo de distancia de un pto a un vehiculo
   */
  function onOffCalcDistVehicle(itemIndex){
  	
  	if(!itemIndex && distanceVehicleEnabled){
	  distanceVehicleEnabled = false;
	  changeCursor('default');
	}else{
		if(win)
  			win.close();
		disableAllFunctions();
		distanceVehicleEnabled=true;
		changeCursor('distance');
	}
	
	if(itemIndex) setOptionSelected(itemIndex); 
  }

  /*
   * Funcion que se encarga de activar/desactivar el drangging
   */
  function onOffDragging(itemIndex){
  	
    if(!itemIndex && !draggingDisabled){
    	draggingDisabled = true;
	  	changeCursor('default');
	  	if(getSelectedMap() == 'yahoo') 
	  		document.getElementById("map_container").contentWindow.map.disableDragMap();
	  	
	}else{
		disableAllFunctions();
		draggingDisabled = false;
	  	changeCursor('drag');
	  	if(getSelectedMap() == 'yahoo') 
	  		document.getElementById("map_container").contentWindow.map.enableDragMap();
	}
	
	if(itemIndex) setOptionSelected(itemIndex);
  }  
  
  /*
  * Función para abrir la ventana de Acerca de...
  */
  function openAbout(){
  	var res = getResolutionCode();
  	var width = 300;
  	var height = 245;
  	if(res == 2) {
  		width = 280;
  		height = 245;
  	}
  	if(res == 3) {
  		width = 250;
  		height = 240;
  	}
  	openPopupWindow('./about.php',i18n["menu_help_about"],false, false, width,height);
  }
  
  /*
   * Funcion para abrir ventana de todos los eventos
   */
  function openAllEvents() {
  	var res = getResolutionCode();
  	var width = 450;
  	var height = 250;
  	if(res == 2) {
  		width = 420;
  		height = 220;
  	}
  	if(res == 3) {
  		width = 400;
  		height = 220;
  	}
  	openPopupWindow('./all_events.php',i18n["title_window_events"],false, false, width,height);
  	win.setLocation(((screen.height)/2)-(height/2)-100,0);
  	eventListOpen = true;
  	win.setCloseCallback(function(){
  		eventListOpen = false;
  		win.destroy();
  		win=null;
	 });
  }
  
  /*
  *	Funcion que muestra la lista de los dispositivos GPS que pueden usarse en Movilsat Free
  */
  function openAllowedDevices(){
  	  	var res = getResolutionCode();
	  	var width = 300;
	  	var height = 270;
	  	if(res == 2) {
	  		width = 300;
	  		height = 240;
	  	}
	  	if(res == 3) {
	  		width = 280;
	  		height = 230;
	  	}
	  	openPopupWindow('./allowed_devices.php',i18n['menu_allowed_devices'],true, false,width,height);
  }
  
   /*
   * Funcion para abrir el foro de la aplicacion
   */
  function openBoard() {
  	window.open('./forum_index.php');
  }
  
   /*
   * Funcion para abrir ventana de olvido de password
   */
  function openChangePassword() {
  	var res = getResolutionCode();
  	var width = 350;
  	var height = 210;
  	if(res == 2) {
  		width = 330;
  		height = 210;
  	}
  	if(res == 3) {
  		width = 300;
  		height = 200;
  	}
  	openPopupWindow('./change_password.php',i18n["menu_change_password"],false, false, width,height);
  }
  
  
  /*
   * Funcion para abrir ventana de FAQ
   */
  function openFAQ() {
  	var res = getResolutionCode();
  	var width = 450;
  	var height = 370;
  	if(res == 2) {
  		width = 430;
  		height = 360;
  	}
  	if(res == 3) {
  		width = 320;
  		height = 200;
  	}
  	openPopupWindow('./faq.php',i18n["title_faq"],false, true, width,height);
  }
  
  /*
   * Funcion para abrir ventana de olvido de password
   */
  function openForgotPassword() {
  	var res = getResolutionCode();
  	var width = 340;
  	var height = 190;
  	if(res == 2) {
  		width = 320;
  		height = 160;
  	}
  	if(res == 3) {
  		width = 290;
  		height = 160;
  	}
  	openPopupWindow('./forgotpassword.php', i18n["link_password_recovery"], false, false, width, height);
  }
  
  /*
  *	Funcion para abrir ventana para descargar los manuales de los dispositivos
  */
  function openGPSManuals(){
	  	var res = getResolutionCode();
		
	  	var width = 410;
	 	var height = 200;
	 	if(res == 2) {
	 		width = 410;
	 		height = 200;
	 	}
	 	if(res == 3) {
	 		width = 370;
	 		height = 200;
	 	}
		openPopupWindow('./gps_manual.php',i18n["menu_manuals"],false, false, width,height);
  }
  
   /*
   * Funcion para abrir ventana de invitar amigos
   */
  function openInviteFriends() {
	var res = getResolutionCode();
	var width = 500;
	var height = 390;
	if(res == 2) {
		width = 470;
		height = 390;
	}
	if(res == 3) {
		width = 470;
		height = 380;
	}
	openPopupWindow('./invite_friends_form.php',i18n["menu_invite_friends"],false, false, width,height);
  }
  
  /*
   * Funcion para abrir ventana de preferencias
   */
  function openPreferences() {
	var res = getResolutionCode();
	var width = 480;
	var height = 380;
	if(res == 2) {
		width = 450;
		height = 380;
	}
	if(res == 3) {
		width = 410;
		height = 370;
	}
	openPopupWindow('./preferences.php',i18n["menu_preferences"],false, false, width,height);
  }
  
  /*
   * Funcion para abrir ventana de olvido de password
   */
  function openRegisterForm(isRegistered) {
  	var res = getResolutionCode();

  	if (!isRegistered){
  		var width = 445;
	  	var height = 380;
	  	if(res == 2) {
	  		width = 440;
	  		height = 380;
	  	}
	  	if(res == 3) {
	  		width = 410;
	  		height = 370;
	  	}
  		openPopupWindow('./register.php',i18n["title_window_register_user"],false, false, width,height);
  	}
  	else {
  		var width = 445;
	  	var height = 400;
	  	if(res == 2) {
	  		width = 440;
	  		height = 400;
	  	}
	  	if(res == 3) {
	  		width = 410;
	  		height = 390;
	  	}
	  	disableAllFunctions();
  		createModalPopUpWindow('./register.php', i18n["title_window_register_user"], false, false, width, height, false);
  	}
  }
  
  /*
  *	 Funcion para abrir el formulario de envío de sugerencias
  */
  function openSuggestions(){
	var res = getResolutionCode();
	
  	var width = 430;
 	var height = 250;
 	if(res == 2) {
 		width = 425;
 		height = 250;
 	}
 	if(res == 3) {
 		width = 395;
 		height = 240;
 	}
	openPopupWindow('./suggestions.php',i18n["menu_suggestions"],false, false, width,height);
  }

  /*
   * Objeto que define una posicion x,y en el mapa
   */
  function position(x,y) {
  	this.x=x;
  	this.y=y;
  }

  /*
   * Funcion que procesa el resultado de busqueda obtenido 
   */
  function processResult(result) {
  	// inicializa pagina de resultado
  	var results = 			"<table class=\"list\" width=\"100%\" cellpadding=\"0\" cellspacing=\"0\">"+	
	  							"<tr>"+
									"<td colspan=\"2\" height=\"15\"><img src=\"img/spacer.png\"></td>"+
	  							"</tr>"+
	  							"<tr class=\"header\">"+
	  								"<td colspan=\"2\">"+i18n['title_window_search_address_results']+"</td>"+
	  							"</tr>";
	  							
  	if (result.Status.code == G_GEO_SUCCESS) {      
        // si hay mas de un resultado se listan en un pop up
        if (result.Placemark.length > 1) { 					
	  		for (var i=0; i<result.Placemark.length; i++) {
                var p = result.Placemark[i].Point.coordinates;
                
                var bgcolor = "bgcolor=\"#E8E8E8\"";
                if(i%2!=0)
                	bgcolor = "bgcolor=\"#B8D5E2\"";
                	
               	results += 		"<tr class=\"text\""+bgcolor+">"+
               						"<td align=\"center\">"+(i+1)+"</td>"+
               						"<td><a href=\"javascript:parent.callMapFunction(\'place_\',\'"+p[1]+","+p[0]+","+tabAccuracy[result.Placemark[i].AddressDetails.Accuracy]+
               						"\');parent.callMapFunction(\'addSearchMarker_\',\'"+p[1]+","+p[0]+"\')\">"+ result.Placemark[i].address+"</a></td>"+
               				 	"</tr>"
            }			
	  		results +=			"<tr>"+
									"<td colspan=\"2\" height=\"15\"><img src=\"img/spacer.png\"></td>"+
	  							"</tr>"+
	  							"<tr>"+
	  								"<td colspan=\"2\" align=\"right\"><a href=\"#\" onclick=\"document.getElementById('search_results').style.display = 'none';"+
	  																			"document.getElementById('search_form').style.display = 'block';\">"+
	  																			i18n['link_back_search']+"</a></td>"+
	  							"</tr>"+
	  						"</table>";	
        
        	document.getElementById("search_form").style.display = 'none';
        	document.getElementById("search_results").innerHTML = results;
        	document.getElementById("search_results").style.display = 'block';
  		}
  		//si hay solo un resultado se redirecciona al punto directamente
        else {
            var p = result.Placemark[0].Point.coordinates;
            var accuracy=result.Placemark[0].AddressDetails.Accuracy;
            parent.callMapFunction('place_',(p[1]+', '+p[0]+', '+tabAccuracy[accuracy]));  		
            parent.callMapFunction('addSearchMarker_',(p[1]+', '+p[0])); 	
  		}
  		if (win){
  			var res = getResolutionCode();
  			var height = 270;
		  	if(res == 2) height = 250;
		  	else if(res == 3) height = 240;
  			win.setLocation(((screen.height)/2)-(height/2)-100,0);
  		}
  	}
  	// no hay resultados
  	else {
  		var reason="Code "+result.Status.code;
        if (reasons[result.Status.code]) {
            reason = reasons[result.Status.code]
        } 
        var search = getSearchString();
  		
  		
  		results +=				"<tr bgcolor=\"#E8E8E8\" class=\"text\">"+
									'<td align="center">'+i18n["msg_address_not_found"]+' "'+search+ '". </td>'+
	  							"</tr>"+
  								"<tr>"+
									"<td colspan=\"2\" height=\"15\"><img src=\"img/spacer.png\"></td>"+
	  							"</tr>"+
	  							"<tr>"+
	  								"<td colspan=\"2\" align=\"right\"><a href=\"#\" onclick=\"document.getElementById('search_results').style.display = 'none';"+
	  																			"document.getElementById('search_form').style.display = 'block';\">"+
	  																			i18n['link_back_search']+"</a></td>"+
	  							"</tr>"+
	  						"</table>";	
	  	document.getElementById("search_form").style.display = 'none';
        document.getElementById("search_results").innerHTML = results;
        document.getElementById("search_results").style.display = 'block';
  	}
  }
  
  /*
  *
  */
  /*function refreshInfoWindows(infoWindows){
    var infoWindowsArray = new Array();
	var infoWindowData = infoWindows;
	for(i=0; i<infoWindowData.length; i++) {
		var infoWindowD = new Array();
		infoWindowD['ejeY'] 	= infoWindowData[i].ejeY;
		infoWindowD['ejeX'] 	= infoWindowData[i].ejeX;
		infoWindowD['nombre'] 	= infoWindowData[i].nombre;
		infoWindowD['evento'] 	= infoWindowData[i].evento;
		infoWindowD['velocidad']= infoWindowData[i].velocidad;
		infoWindowD['reporte']	= infoWindowData[i].reporte;
		infoWindowsArray[infoWindowData[i].id]=infoWindowD;	
	}
  }*/
  
  /*
  * Funcion para refrescar los marcadores luego de un cambio en las preferencias de visibilidad
  */
  function refreshMarkers(vehiculos){	
  	// Se remueven los marcadores existentes
	callMapFunction('removeAllMarkersVehicles_', '');
	
	var vehiclesArray = new Array();
	for(i=0; i<vehiculos.length; i++) {
		// Agrega el vehículo a vehiclesArray 
		var vehicle = new Array();
		vehicle['ejeY'] 	= vehiculos[i].ejeY;
		vehicle['ejeX'] 	= vehiculos[i].ejeX;
		vehicle['nombre'] 	= vehiculos[i].nombre;
		vehicle['imagen'] 	= "../"+vehiculos[i].imagen;
		vehicle['rotacion'] = vehiculos[i].rotacion;
		vehicle['zoom'] 	= vehiculos[i].zoom;
		vehicle['accuracy'] = vehiculos[i].accuracy;
		vehicle['radio'] 	= vehiculos[i].radio;
		vehicle['evento'] 	= vehiculos[i].evento;
		vehicle['velocidad']= vehiculos[i].velocidad;
		vehicle['reporte']	= vehiculos[i].reporte;
		vehiclesArray[vehiculos[i].id]=vehicle;	
		
		// ... y muestra el marcador
		var params = vehicle['ejeY']+','+vehicle['ejeX']+',"'+vehicle['nombre']+'","'+vehicle['imagen']+'",'+vehicle['rotacion']+','+vehiculos[i].id+
					 ','+vehicle['zoom']+','+vehicle['accuracy']+','+vehicle['radio']+',"'+vehicle['evento']+'","'+vehicle['velocidad']+'","'+
					 vehicle['reporte']+'"';
		callMapFunction('addMarker_',params);					
	}
  }
  
  /*
   * Funcion para actualizar el menu al iniciar sesion
   */
  function refreshMenu(loggedIn) {
  	document.getElementById('menu').innerHTML = "<img src='img/progress.gif' />";
  	
  	var http_request = makeRequest();
  	
  	http_request.onreadystatechange = function () {
  		if (http_request.readyState == 4) {
			if (http_request.status == 200) {
				var menu = document.getElementById('menu');
				menu.innerHTML = http_request.responseText;				
				http_request.responseText.evalScripts();
				if(loggedIn)
					document.getElementById('title').innerHTML = parent.i18n['title_last_event'];
			} 
		}
  	}
  	
	http_request.open("POST", "./menu.php", true);
	http_request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
	http_request.send(null);
  }
  
  /*
  * Funcion que reemplaza los valores del arreglo i18n
  */
  function refreshParenti18n(new_i18n){
	 	for(var key in new_i18n){
	  		i18n[key] = new_i18n[key];
		}		
  } 
  
  function removeCustomMarker(id){
  	var aux = new Array();
	var i=0;
  	for(i=0;i<customMarkerArray.size();i++){
  		var markerInfo = customMarkerArray[i];
    	if(markerInfo['id']==id){
    		callMapFunction('removeOverlay_',('customMarkerArray['+i+'][\"overlay\"]'));
    	    customMarkerArray.splice(i,1); 
		}else{
			aux.push(markerInfo);
		}
  	}
  	customMarkerArray=aux;
  	return;
  }
  
  /*
   * funcion para reemplazar las opciones de menu dinamicamente
   */
  function replaceMenuItem(id,menuModel_adds) {
  	document.getElementById("update_menu_div").innerHTML=menuModel_adds;
	var menuModel_add = new DHTMLSuite.menuModel();
	menuModel_add.addItemsFromMarkup('additionalModel');
	menuModel_add.init();
	
	menuBar.replaceMenuItems(id,menuModel_add);
  }	
  
  /*
   * Funcion que guarda todas las preferencias de usuario
   */
  function savePreferences() {
 	  					   
  	var http_request = makeRequest();
  	var data = getProfilePreferences()+getLocationPreferences()+getVisibilityPreferences()+getOtherPreferences();
  	
  	http_request.onreadystatechange = function () {
  		if (http_request.readyState == 4) {
			if (http_request.status == 200) {
				var result = http_request.responseText.parseJSON();
				
				if(result != false) {	
					var class_str = "";				
					if(result.success) {
						class_str ="success";
						
						// Si cambio el lenguaje
						if((result.languageChanged)) {
							refreshMenu(true);
							refreshParenti18n(result.i18n);
							//document.getElementById("mm_banner").innerHTML = i18n['lbl_download_movilsat_movil'];
							document.getElementById("antares_banner").innerHTML = i18n['lbl_get_gps_device'];
							document.getElementById('user_label').innerHTML = i18n['title_user']+":";
						}
						
						// Si cambiaron los ubicables visibles
						if (result.visibilityChanged){
							refreshMenu(true);
							refreshMarkers(result.vehiculos);
						}
						else if (result.speedUnit){ // Si cambió la unidad de velocidad
							alert("jdsjdfhsjfskdjfsjk");
							refreshMarkers(result.vehiculos);
						}
						
						win.close();
						var url = "./msg_activation.php?messageType=success&messageKey=msg_preferences_success&windowType=preferences";
						openPopupWindow(url,i18n['menu_preferences'],true, false,350,160);
					}	
					else {
						class_str ="error";
					
						win.getContent().contentWindow.document.getElementById('message').setAttribute("class", class_str);
					    win.getContent().contentWindow.document.getElementById('message').setAttribute("className", class_str);
						win.getContent().contentWindow.document.getElementById('message_tr').style.display = 'block';
						win.getContent().contentWindow.document.getElementById('message').innerHTML = result.message;
					}	
				} 
			} 
		}
  	}
  	
	http_request.open("POST", "./save_preferences.php", true);
	http_request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
	http_request.send(data);	   
  } 

  /*
   * Funcion que busca una direccion. Se esta usando la busqueda de google para todos los mapas
   */ 
  function searchAddress(messageType, message) { 
  	var res = getResolutionCode();
  	var width = 335;
  	var height = 280;
  	if(res == 2) {
  		width = 330;
  		height = 260;
  	}
  	if(res == 3) {
  		width = 320;
  		height = 240;
  	}
  	
  	var extra = '';
  	if ((messageType && message) && (messageType != "" && message != "")){
  		extra = '<tr><td class="'+messageType+'" colspan="2">'+message+'</td></tr>';
  	}
    var content = '<html><head>'+    				
					'<style>'+
						'body {'+
							'margin-left:5 px;'+
							'margin-right:5 px;'+
							'margin-top: 0 px;'+
						'}'+
					'</style>'+
					'</head>'+
					'<body>'+
						'<div id="search_form">'+
							'<table width="100%" cellpadding="0" cellspacing="0">'+
							  '<tr height="10">'+
							  		'<td colspan="3" ><hr></td>' +
							  '</tr>'+extra+
							  '<tr>'+
								'<td colspan="2" height="15"><img src="img/spacer.png"></td>'+
							  '</tr>'+
							  '<tr>'+
							  	'<td align="right" class="text">'+i18n["title_search_address_country"]+':&nbsp;</td>'+
								'<td>'+
									'<table cellpadding="0" cellspacing="0">'+
										'<tr>'+
											'<td><img src="img/izq_'+res+'.png" width="14"></td>'+
											'<td><input type="text" class="textbox" id="input-pais" autocomplete="off" size="25" '+
													   'onkeyup="parent.autocompletarPais.inputUpdated(event)" '+
													   'onblur="document.getElementById(\'listaPaises\').style.display=\'none\'"><div class="autocompletar" '+
													   'style="z-index:3"><div id="listaPaises" class="lista_autocompletar"></div>'+
												'</div></td>'+
											'<td><img src="img/der_'+res+'.png" width="8" ></td>'+
										'</tr>'+
									'</table>'+
								'</td>'+
							  '</tr>'+
							  '<tr>'+
								'<td colspan="2" height="10"><img src="img/spacer.png"></td>'+
							  '</tr>'+
							  '<tr>'+
							  	'<td align="right" class="text">'+i18n["title_search_address_state"]+':&nbsp;</td>'+
								'<td>'+
									'<table cellpadding="0" cellspacing="0">'+
										'<tr>'+
											'<td><img src="img/izq_'+res+'.png" width="14"></td>'+
											'<td><input type="text" class="textbox" id="input-estado" autocomplete="off" size="25" '+
													   'onkeyup="parent.autocompletarEstado.inputUpdated(event)"'+
													   'onblur="document.getElementById(\'listaEstados\').style.display=\'none\'"><div class="autocompletar" '+
													   'style="z-index:3"><div id="listaEstados" class="lista_autocompletar"></div>'+
												'</div></td>'+
											'<td><img src="img/der_'+res+'.png" width="8"></td>'+
										'</tr>'+
									'</table>'+
								'</td>'+
							  '</tr>'+
							  '<tr>'+
								'<td colspan="2" height="10"><img src="img/spacer.png"></td>'+
							  '</tr>'+
							  '<tr>'+
							  	'<td align="right" class="text">'+i18n["title_search_address_city"]+':&nbsp;</td>'+
								'<td>'+
									'<table cellpadding="0" cellspacing="0">'+
										'<tr>'+
											'<td><img src="img/izq_'+res+'.png" width="14"></td>'+
											'<td><input type="text" class="textbox" id="input-ciudad" autocomplete="off" size="25" '+
													    'onkeyup="parent.autocompletarCiudad.inputUpdated(event)" '+
													    'onblur="document.getElementById(\'listaCiudades\').style.display=\'none\'"><div class="autocompletar" '+
													    'style="z-index:3"><div id="listaCiudades" class="lista_autocompletar"></div>'+
												'</div></td>'+
											'<td><img src="img/der_'+res+'.png" width="8"></td>'+
										'</tr>'+
									'</table>'+
								'</td>'+
							  '</tr>'+
							  '<tr>'+
								'<td colspan="2" height="10"><img src="img/spacer.png"></td>'+
							  '</tr>'+
							  '<tr>'+
							  	'<td align="right" class="text">'+i18n["title_search_address_neighborhood"]+':&nbsp;</td>'+
								'<td>'+
									'<table cellpadding="0" cellspacing="0">'+
										'<tr>'+
											'<td><img src="img/izq_'+res+'.png" width="14"></td>'+
											'<td><input class="textbox" type="text" id="input-urban" autocomplete="off" size="25"></td>'+
											'<td><img src="img/der_'+res+'.png" width="8"></td>'+
										'</tr>'+
									'</table>'+
								'</td>'+
							  '</tr>'+
							  '<tr>'+
								'<td colspan="2" height="10"><img src="img/spacer.png"></td>'+
							  '</tr>'+
							  '<tr>'+
							  	'<td align="right" class="text">'+i18n["title_search_address_street"]+':&nbsp;</td>'+
								'<td>'+
									'<table cellpadding="0" cellspacing="0">'+
										'<tr>'+
											'<td><img src="img/izq_'+res+'.png" width="14"></td>'+
											'<td><input class="textbox" type="text" id="input-calle" autocomplete="off" size="25"></td>'+
											'<td><img src="img/der_'+res+'.png" width="8"></td>'+
										'</tr>'+
									'</table>'+
								'</td>'+
							  '</tr>'+
							  '<tr>'+
								'<td colspan="2" height="10"><img src="img/spacer.png"></td>'+
							  '</tr>'+
							  '<tr>'+
							  	'<td align="right" class="text">'+i18n["title_search_address_other"]+':&nbsp;</td>'+
								'<td>'+
									'<table cellpadding="0" cellspacing="0">'+
										'<tr>'+
											'<td><img src="img/izq_'+res+'.png" width="14"></td>'+
											'<td><input class="textbox" type="text" id="input-otros" autocomplete="off" size="25"></td>'+
											'<td><img src="img/der_'+res+'.png" width="8"></td>'+
										'</tr>'+
									'</table>'+
								'</td>'+
							  '</tr>'+
							  '<tr>'+
								'<td colspan="2" height="10"><img src="img/spacer.png"></td>'+
							  '</tr>'+
							  '<tr>'+
								'<!--<td class="text" align="right">&nbsp;</td>-->'+
								'<td class="text" valign="middle" align="center" colspan="2">&nbsp;&nbsp;'+
									'<input id="search" name="search" type="button" value="'+i18n["btn_accept"]+'" class="button" onclick="findAddress()">'+
									'<input id="cancel" name="cancel" type="button" value="'+i18n["btn_cancel"]+'" class="button" onclick="parent.win.close()">'+						
								'</td>'+
							  '</tr>'+
							'</table>'+
						'</div>'+
						'<div id="search_results"></div>'+
						'</body>'+
					'</html>';
   
    showResultsPopupWindow(content,i18n["title_window_search_address"],false, false,width,height);
    autocompletarPais=new autocompletar('autocompletarPais','input-pais','listaPaises',1);
	autocompletarEstado=new autocompletar('autocompletarEstado','input-estado','listaEstados',2,'input-pais');
	autocompletarCiudad=new autocompletar('autocompletarCiudad','input-ciudad','listaCiudades',3,'input-pais','input-estado');
	document.getElementById('input-pais').focus();
  }

function searchCoordinates() { 
  	var res = getResolutionCode();
  	var width = 280;
  	var height = 170;
  	if(res == 2) {
  		width = 250;
  		height = 160;
  	}
  	if(res == 3) {
  		width = 240;
  		height = 150;
  	}  
  	
  	  	var content = '<html><head></head><body>'+
					'<div id="search_form">'+
						'<table width="100%" cellpadding="0" cellspacing="0">'+
	  						'<tr height="10">'+
	  							'<td colspan="2" ><hr></td>'+ 
	  						'</tr>'+  
	  						'<tr id="msg_coord_tr" style="display:none">'+
								'<td colspan="2" align="center" class="error" id="msg_coord">&nbsp;aaa</td>'+
							'</tr>'+
	  						'<tr>'+
	  							'<td align="right" class="text">'+i18n['lbl_type']+':&nbsp;</td>'+
								'<td>'+
									'&nbsp;&nbsp;<select id="coord_type" style="width: 130px" onchange="changeCoordType()">'+
										'<option value="decimal" selected>'+i18n['lbl_type_decimal']+'</option>'+
										'<option value="gms">'+i18n['lbl_type_gms']+'</option>'+
									'</select>'+
								'</td>'+
	  						'</tr>'+
	  						'<tr>'+
								'<td colspan="2" height="10"><img src="img/spacer.png"></td>'+
	  						'</tr>'+
	  						'<tr>'+
	  							'<td align="right" class="text">'+i18n["title_latitude"]+':&nbsp;</td>'+
								'<td>'+
									'<div id="lat-decimal" style="display:block">'+
										'<table cellpadding="0" cellspacing="0">'+										
											'<tr>'+
												'<td><img src="img/izq_'+res+'.png" width="14"></td>'+
												'<td><input class="textbox" type="text" name="latitudTxt" value="" id="latitude"/></td>'+
												'<td><img src="img/der_'+res+'.png" width="8"></td>'+
											'</tr>'+
										'</table>'+
									'</div>'+	
									'<div id="lat-gms" style="display:none">'+
										'<table cellpadding="0" cellspacing="0">'+										
											'<tr>'+
												'<td>'+
													'<table cellpadding="0" cellspacing="0">'+										
														'<tr>'+
															'<td><img src="img/izq_'+res+'.png" width="14"></td>'+
															'<td><input class="textbox" type="text" name="lat_grades" size="6" maxlength="6" value="" id="lat_grades"/></td>'+
															'<td><img src="img/der_'+res+'.png" width="8"></td>'+
															'<td>&deg;</td>'+
														'</tr>'+
													'</table>'+
												'</td>'+
												'<td>'+
													'<table cellpadding="0" cellspacing="0">'+										
														'<tr>'+
															'<td><img src="img/izq_'+res+'.png" width="14"></td>'+
															'<td><input class="textbox" type="text" name="lat_minutes" size="4" maxlength="4" value="" id="lat_minutes"/></td>'+
															'<td><img src="img/der_'+res+'.png" width="8"></td>'+
															'<td>&#039;</td>'+
														'</tr>'+
													'</table>'+
												'</td>'+
												'<td>'+	
													'<table cellpadding="0" cellspacing="0">'+										
														'<tr>'+
															'<td><img src="img/izq_'+res+'.png" width="14"></td>'+
															'<td><input class="textbox" type="text" name="lat_seconds" size="4" maxlength="4" value="" id="lat_seconds"/></td>'+
															'<td><img src="img/der_'+res+'.png" width="8"></td>'+
															'<td>&quot;</td>'+
														'</tr>'+
													'</table>'+
												'</td>'+
											'</tr>'+
										'</table>'+		
									'</div>'+	
								'</td>'+
	  						'</tr>'+
							'<tr>'+
								'<td colspan="2" height="10"><img src="img/spacer.png"></td>'+
							'</tr>'+
	  						'<tr>'+
	  							'<td align="right" class="text">'+i18n["title_longitude"]+':&nbsp;</td>'+
								'<td>'+
									'<div id="lon-decimal" style="display:block">'+
										'<table cellpadding="0" cellspacing="0">'+
											'<tr>'+
												'<td><img src="img/izq_'+res+'.png" width="14"></td>'+
												'<td><input class="textbox" type="text" name="longitud" value="" id="longitude"/></td>'+
												'<td><img src="img/der_'+res+'.png" width="8"></td>'+
											'</tr>'+
										'</table>'+
									'</div>'+	
									'<div id="lon-gms" style="display:none">'+
										'<table cellpadding="0" cellspacing="0">'+										
											'<tr>'+
												'<td>'+
													'<table cellpadding="0" cellspacing="0">'+										
														'<tr>'+
															'<td><img src="img/izq_'+res+'.png" width="14"></td>'+
															'<td><input class="textbox" type="text" name="lon_grades" size="6" maxlength="6" value="" id="lon_grades"/></td>'+
															'<td><img src="img/der_'+res+'.png" width="8"></td>'+
															'<td>&deg;</td>'+
														'</tr>'+
													'</table>'+
												'</td>'+
												'<td>'+
													'<table cellpadding="0" cellspacing="0">'+										
														'<tr>'+
															'<td><img src="img/izq_'+res+'.png" width="14"></td>'+
															'<td><input class="textbox" type="text" name="lon_minutes" size="4" maxlength="4" value="" id="lon_minutes"/></td>'+
															'<td><img src="img/der_'+res+'.png" width="8"></td>'+
															'<td>&#039;</td>'+
														'</tr>'+
													'</table>'+
												'</td>'+
												'<td>'+	
													'<table cellpadding="0" cellspacing="0">'+										
														'<tr>'+
															'<td><img src="img/izq_'+res+'.png" width="14"></td>'+
															'<td><input class="textbox" type="text" name="lon_seconds" size="4" maxlength="4" value="" id="lon_seconds"/></td>'+
															'<td><img src="img/der_'+res+'.png" width="8"></td>'+
															'<td>&quot;</td>'+
														'</tr>'+
													'</table>'+
												'</td>'+
											'</tr>'+
										'</table>'+		
									'</div>'+	
								'</td>'+
							  '</tr>'+
							  '<tr>'+
								'<td colspan="2" height="10"><img src="img/spacer.png"></td>'+
							  '</tr>'+
							  '<tr>'+
								'<td class="text" valign="middle" align="center" colspan="2">&nbsp;&nbsp;'+
									'<input id="search" name="search" type="button" value="'+i18n["btn_accept"]+'" class="button" onclick="parent.findCoord()">'+							
									'<input id="cancel" name="cancel" type="button" value="'+i18n["btn_cancel"]+'" class="button" onclick="parent.win.close()">'+
								'</td>'+
							  '</tr>'+
							'</table>'+
						'</div>'+
						'<div id="search_results"></div>'+
					'</body></html>';
  	showResultsPopupWindow(content,i18n["title_window_search_coords"],false, false,width,height);
    document.getElementById('latitude').focus();
  }

  /*
  * Busca entidades pertenecientes a otros usuarios
  */
  function searchEntity(){
  	var res = getResolutionCode();
  	var width = 350;
  	var height = 350;
  	if(res == 2) {
  		width = 330;
  		height = 330;
  	}
  	if(res == 3) {
  		width = 320;
  		height = 310;
  	}
  	
  	var url = "./search_entity.php?cmdtype=add";
	openPopupWindow(url,i18n['menu_search_vehicle'],true, false,width,height);
  }

  /*
   * Funcion que recupera el password
   */
   function sendPassword() {
   	 var email = document.getElementById('email').value;
   	 var url = "./forgotpassword.php?lostpass=yes&email="+email;
   	 parent.win.setURL(url);
   }

  /*
   * Funcion que establece el cursor segun la accion que se encuentra activada
   */
  function setActionCursor() {
  	if(zoomInActive) 
  		changeCursor('zoomIn');
  				
  	if(zoomOutActive) 
  		changeCursor('zoomOut');
  			
  	if(!draggingDisabled)
  		changeCursor('drag');
  				
  	if(distanceEnabled)
  		changeCursor('distance');
  }  
  
   /*
   * Funcion que retorna la direcion para un punto latitud, longitud dado.
   */
  function setAddress(lat,lon) {
  	var point = new GLatLng(lat,lon);
  	geo.getLocations(point, function(addresses) {
  								var addressStr="";
	          					if(addresses.Status.code != 200)
	          						addressStr = i18n["msg_geocoding_vehicle_not_found"];
	          					else {
	            					var address = addresses.Placemark[0];
	          						addressStr = address.address;          
	          					}   
	         					win.getContent().contentWindow.document.getElementById("address").innerHTML=addressStr;       
	        				});  	
  }

  /*
   * Funcion que establece las coordenadas para un pais seleccionado en Preferencias - Ubicacion
   */
  function setCountryCoords() {
   	var view = win.getContent().contentWindow.document.getElementById("view").value;
   	if(view == 1) {
   		var valueSelect = win.getContent().contentWindow.document.getElementById("dependant");
 		var address = valueSelect.options[valueSelect.selectedIndex].text;	  
 		
 		geo.getLatLng(address, function(point) {
  			if(point) {	
		  		win.getContent().contentWindow.document.getElementById("latitud").value = point.lat();
		  		win.getContent().contentWindow.document.getElementById("longitud").value = point.lng();
		  	}
		  	else {
		  		win.getContent().contentWindow.document.getElementById("latitud").value = "0";
		  		win.getContent().contentWindow.document.getElementById("longitud").value = "0";
		  	}
  		});		
   	}	
  }

  /*
   * Funcion que establece el cursor segun el evento que esta ocurriendo sobre el mapa
   */  
  function setCursor(event) {
  	if(event.shift) {
  		if(clickButton == 2) 
  			changeCursor('zoomOut');
  		if(isLeftClick())
  			changeCursor('zoomIn');
  	}
  	else {
  		if(clickButton == 2) 
  			changeCursor('drag');
  		else {
  			setActionCursor();
  		}
  	}
  }
  
  function setItemText(id,newText){
  	menuBar.setText(id,newText);
  }
  
  /*
   * Funcion que incluye en el frame el mapa selecionado
   */ 
  function setMap(map, mapIndex) {
  	var iframe = document.getElementById('map_container');
  	
  	// si se esta seleccionando un mapa
  	if(map) {
		
		//si selecciona un mapa nuevo (diferente al actual)  	
		if(map != selectedMap) {
			
			// se desmarca la opcion actual
			//menuBar.setMenuItemIcon(selectedMapItemIndex, '');
			menuBar.setIcon(selectedMapItemIndex, '');
			
			//se marca la opcion actual
			//menuBar.setMenuItemIcon(mapIndex, 'img/bullet.png');
			menuBar.setIcon(mapIndex, 'img/bullet.png');
			
			//se actualizan las variables globales
			selectedMap = map;
			selectedMapItemIndex = mapIndex;
			
			// se limpia el calculo de distancia
			document.getElementById('distance').innerHTML = "&nbsp;";
		
			// refresca el mapa
		  	if(selectedMap == 'google') 
		  		iframe.src = 'googlemap/index.php';
		  	
		  	if(selectedMap == 'yahoo') 
		  		iframe.src = 'yahoomap/index.php';
		  	
		  	if(selectedMap == 'virtualearth') 
				iframe.src = 'virtual_earth/index.php';
				
		  	/*if(selectedMap == 'openstreetmap') 
				iframe.src = 'openstreetmap/index.php';	*/				
		}
	}	
	else {
		// aqui solo entra cuando esta cargando la pagina
		iframe.src = 'googlemap/index.php';		
	}
  }	

  /*
   * Funcion que cambia tipo de mapa selecionado
   */
  function setMapType(mapType, mapTypeIndex) {

  	if(mapType != selectedMapType) {
  		// se desmarca la opcion actual
		//menuBar.setMenuItemIcon(selectedMapTypeIndex, '');
		menuBar.setIcon(selectedMapTypeIndex, '');
			
		//se marca la opcion actual
		//menuBar.setMenuItemIcon(mapTypeIndex, 'img/bullet.png');
		menuBar.setIcon(mapTypeIndex, 'img/bullet.png');
		
		//se actualizan las variables globales
		selectedMapType = mapType;
		selectedMapTypeIndex = mapTypeIndex;
		
		callMapFunction('setMapType_',null);
  	}
  }
  
  /*
   * Funcion que muestra el preview del custom marker si esta activa la ventana
   * al hacer un cambio del proveedor del mapa
   */	
  function showCustomMarkerPreviewOnLoadMap() {
  	
  	if(addCustomMarkerEnabled && win!=null){
  		changeCursor('distance');
  		var domPopup=win.getContent().contentWindow.document;
		if(domPopup.getElementById("x") && domPopup.getElementById("y")){
  			var ejeY = domPopup.getElementById("y").value;
  			var ejeX = domPopup.getElementById("x").value;
  			
  			var selectImg = domPopup.getElementById("image");
			var ruta="'../"+selectImg.options[selectImg.selectedIndex].id+"'";
			callMapFunction('previewCustomMarker_', ejeY+','+ejeX+','+ruta);
  		}
	}
  	
  }
  
  function showInvalidSessionError() {
  	menuBar.hideSubMenus();
  	Dialog.info(i18n['invalid_session_error'],
               {className:"alphacube", width:250, height:100, showProgress: false});
  }
  
  function showUserTip(userStatus){
  		if (userStatus && userStatus != ""){ 
  			var data = "userStatus="+userStatus;
  			var width; var height;
  			if (userStatus == 1){
  				width = 350;
  				height = 280;
  			}
  			else if (userStatus == 2){
  				width = 350;
  				height = 170;
  			}
  		}

  		var http_request = makeRequest();
	  	http_request.onreadystatechange = function () {
	  		if (http_request.readyState == 4) {
				if (http_request.status == 200) {
					var result = http_request.responseText.parseJSON();
		
					if(result != false) {
						if(result.userTip){
							showResultsPopupWindow(result.userTip, i18n['title_user_status_'+userStatus], true, false, width, height);
						}
					} 
				}
			}
	  	}
	  	
		http_request.open("POST", "./user_tips.php", true);
		http_request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
		http_request.send(data);
  }
  
  function getPublicVehicles(){
  	if (!userLoggedIn){
		var bounds = callMapFunction('getBounds_', null);
		currentZoom = callMapFunction('getZoom_', null); 
		var data = bounds+"&selectedMap="+selectedMap+"&currentZoom="+currentZoom;
	
	 	var http_request = makeRequest();
	  	
	  	http_request.onreadystatechange = function () {
	  		if (http_request.readyState == 4) {
				if (http_request.status == 200) {
					var result = http_request.responseText.parseJSON();
		
					if(result != false) {
						if (result.clusters){
							// Si hay posibles clusters 
							var clusters = result.clusters;
							var j = 0;
							for(i=0; i<clusters.length; i++) {
								var cluster = new Array();
								cluster['ejeY'] = clusters[i].ejeY;
								cluster['ejeX'] = clusters[i].ejeX;
								cluster['cantidad'] = clusters[i].cantidad;
								cluster['nombre'] = clusters[i].nombre;
								cluster['imagen'] = "../"+clusters[i].imagen;
								cluster['rotacion'] = clusters[i].rotacion;
								tmpClustersArray[j] = cluster;
								j = j+1;					
							}
							if (result.cantidad) var cantidad = result.cantidad;
							
							callMapFunction('markerClusterer_', cantidad);
							result.clusters = null;
						}
					} 
				}
			}
	  	}
	  	
		http_request.open("POST", "./public_vehicles.php", true);
		http_request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
		http_request.send(data);
	}
  }
    
  function setLatLon(setType) {
  	if(country && (country!='')){
  		geo.getLocations(country, function (result) {
  			if (result.Placemark.length == 1) {
  				 var p = result.Placemark[0].Point.coordinates;
            	 var accuracy=result.Placemark[0].AddressDetails.Accuracy;
            	 mapLatitude = p[1]; 
  				 mapLongitude = p[0];
  				 zoom = 6;
  				 if (setType) callMapFunction('updateMapCenter_', mapLatitude+", "+mapLongitude);
  			}  			
  		});
	}
  }
  
   function setUserLatLon() {
  	if(userCountry && (userCountry!='')) 
  		geo.getLocations(userCountry, function (result) {
  			if (result.Placemark.length == 1) {
  				 var p = result.Placemark[0].Point.coordinates;
            	 var accuracy=result.Placemark[0].AddressDetails.Accuracy;
            	 userMapLat = p[1]; 
  				 userMapLong = p[0]; 
  			}  			
  		});
  }
  	
  /**
   * setOnCloseEditCustonMarker
   * @param {Number} id 
   */
   function setOnCloseEditCustonMarker(id) {
   	 win.setCloseCallback(function(){
   	 	unhideCustomMarker(id);
		callMapFunction('removeOverlay_',null);
  		changeCursor('default');
  		addCustomMarkerEnabled=false;
  		win.destroy();
  		win=null;
	 });
   }
  	
  /*
   * Establece el valor del texto de lugar de residencia, 
   * en preferencias - ubicacion
   */
  function setResidenceText() {
  	var view = win.getContent().contentWindow.document.getElementById("view").value;
   	if(view == 3) {
	  	var address = win.getContent().contentWindow.document.getElementById("input-ciudad").value+", "+
	  			  win.getContent().contentWindow.document.getElementById("input-pais").value;
	  				  
	  	win.getContent().contentWindow.document.getElementById("residence_txt").innerHTML=address;
	  	
	  	geo.getLatLng(address, function(point) {
	  		if(point) {
	  			if (win.getContent().contentWindow.document.getElementById("latitud"))
		  			win.getContent().contentWindow.document.getElementById("latitud").value = point.lat();
		  		
		  		if (win.getContent().contentWindow.document.getElementById("longitud"))
		  			win.getContent().contentWindow.document.getElementById("longitud").value = point.lng();
		  	}
		  	else {
		  		win.getContent().contentWindow.document.getElementById("latitud").value = "0";
		  		win.getContent().contentWindow.document.getElementById("longitud").value = "0";
		  	}
	  	});
	 }
  }  
   
  /*
   * Funcion para establecer el boton presionado
   */
  function setOptionSelected(newIndex) {
  	if(newIndex != selectedOption) { 
	  	// cambia el status del previo seleccionado a no seleccionado	
	  	menuBar.setMenuItemState(selectedOption,'regular');
	  	
	  	// setea el nuevo boton seleccionado
	  	selectedOption = newIndex;
	  	menuBar.setMenuItemState(selectedOption,'active');
	 } 	
  }
  
  /*
   * Funcion que establece la opcion seleccionada en un campo dado
   */	
  function setSelectedOption(objSelect, optionValue) {
		for(var i=0; i<objSelect.options.length; i++) {
			var val = objSelect.options[i].value;
			if(val==optionValue)
				objSelect.selectedIndex = i;
		} 
  }
  
 /*
  * Funcion que ordena el arreglo de resultados de distancia a vehiculos
  */
  function sortByDistance(a, b) {
    var x = a.distance;
    var y = b.distance;
    return ((x < y) ? -1 : ((x > y) ? 1 : 0));
  }
  
  /*
   * Funcion que muestra un custom marker oculto
   */
  function unhideCustomMarker(id){
	var i=0;
  	for(i=0;i<customMarkerArray.size();i++){
  		var markerInfo = customMarkerArray[i];
    	if(markerInfo['id']==id){
    		callMapFunction('unhideOverlay_',('customMarkerArray['+i+'][\"overlay\"]')); 
		}
  	}
  	return;
  }

  /*
  * Funcion que coloca la creación del mapa en "false" mientras el mismo es creado por el nuevo proveedor
  */	
  function unsetMapCreated() {
  	 mapCreated = false;
  }

  /*
   * Funcion para actualizar la tabla de eventos
   */
  function updateEventTable(tipoEvento, nombreVehiculo, time, color) {
  	document.getElementById('title').innerHTML = i18n['title_last_event'];
  	document.getElementById('tipo_evento').innerHTML = tipoEvento;
	document.getElementById('nombre_vehiculo').innerHTML = nombreVehiculo;
	document.getElementById('time').innerHTML = time;
	document.getElementById('last_event').style.backgroundColor=color;
	document.getElementById('event').style.display = 'block';
	document.getElementById('more_events').style.display = 'block';
  }
  
   /*
   * Funcion que actualiza los datos que serán mostrados al hacer mousemove sobre el ubicable
   */
   /*function updateInfoWindowsArray(id, ejeY, ejeX, nombre, evento, velocidad, fecha){
		var infoWindowD 		= new Array();
		infoWindowD['ejeY'] 	= ejeY;
		infoWindowD['ejeX'] 	= ejeX;
		infoWindowD['nombre'] 	= nombre;
		infoWindowD['evento'] 	= evento;
		infoWindowD['velocidad']= velocidad;
		infoWindowD['reporte']	= fecha;
		infoWindowsArray[id]	= infoWindowD;
   }*/
  
  /*
  *	Funcion para actualizar el menú de solicitudes
  */
  function updateMenu(){
  	var http_request = makeRequest();
  	
  	http_request.onreadystatechange = function () {
	  		if (http_request.readyState == 4) {
				if (http_request.status == 200) {
					var result = http_request.responseText.parseJSON();
					
					if (result != false){
						var solicitudes = result.solicitudes;
						if (solicitudes != "") parent.setItemText(16, solicitudes);	
					}
					setTimeout("updateMenu();",updateMenuFrequency);
				} 
			}
	  	}
	  	
	http_request.open("POST", "./update_menu.php", true);
	http_request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
	http_request.send(null);
  }
  
  /*
   * Funcion para actualizar los vehiculos
   */
  function updateVehicles() {
  		tOutSet = false;				
	  	var http_request = makeRequest();
	  	
	  	http_request.onreadystatechange = function () {
	  		if (http_request.readyState == 4) {
				if (http_request.status == 200) {
					var result = http_request.responseText.parseJSON();
					
					if(result != false) {
						// si la sesion es valida
						if(result.isValidSession) {
							var vehiculos = result.vehiculos;
							if (vehiculos.length >= 1){
								for(i=0; i<vehiculos.length; i++) {
									var params = vehiculos[i].ejeY+','+vehiculos[i].ejeX+',"'+vehiculos[i].nombre+'","../'+vehiculos[i].imagen+'",'+
												vehiculos[i].rotacion+','+vehiculos[i].id+','+vehiculos[i].acercamiento+','+vehiculos[i].accuracy+
												','+vehiculos[i].radio+',"'+vehiculos[i].evento+'","'+vehiculos[i].velocidad+'","'+vehiculos[i].reporte+'"';
									
									updateEventTable(vehiculos[i].tipo, vehiculos[i].nombre, vehiculos[i].time,vehiculos[i].color);
									//updateInfoWindowsArray(vehiculos[i].id, vehiculos[i].ejeY, vehiculos[i].ejeX, vehiculos[i].nombre, vehiculos[i].evento, vehiculos[i].velocidad, vehiculos[i].reporte);
									//if (vehiclesArray){
										callMapFunction('updateMarkerVehicle_',params);
										checkInfoWindow(vehiculos[i].id);
									//}
									//updateEventTable(vehiculos[i].tipo, vehiculos[i].nombre, vehiculos[i].time,vehiculos[i].color);
									
									
									// Si la lista de detalles del vehículo está abierta
									if (vehicleDetailsOpen && vehiculos[i].id == idNearestVehicle){
										var tbody = win.getContent().contentWindow.document.getElementById("table_body");
										win.getContent().contentWindow.document.getElementById("list_table").removeChild(tbody);
										win.getContent().contentWindow.vehicle_events.load();
									}
								}
								
								// Si la lista de eventos se encuentra abierta, se actualizan los eventos en ella
								if (eventListOpen){
									var tbody = win.getContent().contentWindow.document.getElementById("table_body");
									win.getContent().contentWindow.document.getElementById("list_table").removeChild(tbody);
									win.getContent().contentWindow.all_events.load();
								}
							}
							updateTimeOut = setTimeout("updateVehicles();",updateFrequency);
							tOutSet = true;
						}
						// si la sesion no es valida
						else {
								showInvalidSessionError();
						}				
					} 
					else {
						updateTimeOut = setTimeout("updateVehicles();",updateFrequency);
						tOutSet = true;
					}
				} 
				else {
					// problemas de conexion
					showConnectionError();			
				}
			}
	  	}
	  	
		http_request.open("POST", "./update_events.php", true);
		http_request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
		http_request.send(null);
  } 
	
  /*
  *  Función que actualiza la visibilidad del marker en el mapa
  */	
	function updateVisibilityVehicle(id){
 		// borra el marker existente del vehículo en el mapa
 		callMapFunction('removeMarkerVehicle_',"'"+id+"'");
 		
		var data = "vehicleid="+id;
		var http_request = makeRequest();
	  	
	  	http_request.onreadystatechange = function () {
	  		if (http_request.readyState == 4) {
				if (http_request.status == 200) {
					var result = http_request.responseText.parseJSON();
					
					if(result != false) {
						var vehiculo = result.vehiculo;
						var params = vehiculo.ejeY+','+vehiculo.ejeX+',"'+vehiculo.nombre+'","../'+vehiculo.imagen+'",'+
									vehiculo.rotacion+','+vehiculo.id+','+vehiculo.acercamiento+','+vehiculo.accuracy+','+vehiculo.radio+',"'+
									vehiculo.evento+'","'+vehiculo.velocidad+'","'+vehiculo.reporte+'"';
						callMapFunction('addMarker_',params);		
					}
				}
			}
	  	}
	  	
		http_request.open("POST", "./update_markers.php", true);
		http_request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
		http_request.send(data);
	}	
	
  /*
   * Funcion q valida coordenadas del tipo grados, minutos, segundos
   */	
  function validateCoords(grades, minutes, seconds, type) {
  	if(isNaN(grades) || ((type=='lat')&&((grades < -90)||(grades > 90))))
  		return i18n['msg_coords_grades_lat'];
  	
  	if(isNaN(grades) || ((type=='lon')&&((grades < -90)||(grades > 90))))
  		return i18n['msg_coords_grades_lon'];
  	
  	if(isNaN(minutes) || (minutes < 0) || (minutes > 60))
  		return i18n['msg_coords_minutes'];
  		
  	if(isNaN(seconds) || (seconds < 0) || (seconds > 60))
  		return i18n['msg_coords_seconds'];	
  	
  	return 'ok';
  }
  

  /*
   * Funcion para manejar el evento de rueda de mouse
   */  
  function wheel(event){          
   	var delta = 0;   
  
   	if (!event) 
		event = document.getElementById('map_container').contentWindow.event;          
		
	if (event.wheelDelta) { 
		delta = event.wheelDelta/120;                                  
		if (document.getElementById('map_container').contentWindow.opera)                          
			delta = -delta;          
	} 
	else 
		if (event.detail) 
			delta = -event.detail/3;         
	
	if (delta)  {
		if(delta > 0)
			callMapFunction('zoomPoint_', 'null,true');
		else
			callMapFunction('zoomPoint_', 'null,false');
	}                
 	
  }

  /*
   * Funcion que hace zoom sobre un area 
   */
  function zoomArea() {	
	var tmpStartX = startPos.x;
	var tmpStartY = startPos.y;
	var tmpEndX = endPos.x;
	var tmpEndY = endPos.y;
	  	
	if((tmpEndX - tmpStartX) < 0) {
	  	startPos.x = endPos.x;
	  	endPos.x = tmpStartX
	} 
	  	
	if((tmpEndY - tmpStartY) < 0) {
	  	startPos.y = endPos.y;
	  	endPos.y = tmpStartY
	}
	  	
	document.getElementById('map_container').contentWindow.document.getElementById('rectangle').style.display = 'none';
	callMapFunction('zoomRectangle_','startPos, endPos');
  }

  /*
   * Funcion que se encarga de activa/desactivar el zoom in
   */  
  function zoomIn(itemIndex){
  	
	if(!itemIndex && zoomInActive){ 
		zoomInActive=false;
		changeCursor('default');
	}else{ 
		disableAllFunctions();
		zoomInActive=true;
		changeCursor('zoomIn');
	}
	
	if(itemIndex) setOptionSelected(itemIndex);
  }  	
  
  /*
   * Funcion que se encarga de activa/desactivar el zoom out
   */
  function zoomOut(itemIndex){
  	
    if(!itemIndex && zoomOutActive){ 
		zoomOutActive=false;
		changeCursor('default');
	}else{ 
		disableAllFunctions();
		zoomOutActive=true;
		changeCursor('zoomOut');
	}
	
	if(itemIndex) setOptionSelected(itemIndex);
  }  var win;
  
   /*
   * Funcion que cierra la ventana de pop-up
   */
  function closeWinResultIfExist(){
  	var win = Windows.getWindow("winResults");
	if(win != null)
		win.close();
  }
  
  
  /*
   * Funcion que crea un pop up para mostrar los resultados de busqueda
   */
  function createWindow(resize, minmax) {
	var window = new Window({id: "popup", className: "alphacube", resizable: resize, minimizable: minmax, maximizable: minmax, wiredDrag: true});
		
  	window.setDestroyOnClose();
  	window.setCloseCallback(function() {
  		win.destroy();
  		win=null;
	});

  	window.setZIndex(10);
  				
  	window.show();
  	window.toFront();
  	
  	return window;
  }
  
  /*
   * Funcion para abrir una ventana popup
   */
  function openPopupWindow(url,title,resizable, minmax,width,height) {  	
    if(!win){
    	win = createWindow(resizable, minmax);
    }else{
		win.close();
		win = createWindow(resizable, minmax);
	}
	
	if(url.indexOf("confirm_message.php")==-1 && url.indexOf("show_conf_steps.php")==-1){
		// estableciendo ubicacion de ventana  
	  	var left = ((screen.width)/2) - (width/2) ;
	  	var top = ((screen.height)/2 )- (height/2) - 100;
	  	win.setLocation(top, left);
  	}
  	else{
  		win.setLocation(40, 50);
  	}
  	
  	
    win.setURL(url);
    win.setTitle(title);
    win.setSize(width,height);
   }
   
    /*
   * Funcion para abrir una ventana mostrando el contenido dado
   */
  function showResultsPopupWindow(content,title,resizable, minmax,width,height) {
    if(!win)
    	win = createWindow(resizable, minmax);
    else{
		win.close();
		win = createWindow(resizable, minmax);
	}
	
	// estableciendo ubicacion de ventana  
  	var left = ((screen.width)/2) - (width/2) ;
  	var top = ((screen.height)/2)- (height/2) - 100;
  	win.setLocation(top, left);
	
    win.getContent().innerHTML=content;
    win.setTitle(title);
    win.setSize(width,height);

   }
   
   /*
   *	Funcion que crea un pop-up de tipo modal
   */
   function createModalPopUpWindow(url,title,resizable,minmax,width,height,close) {  	
	    if(!win){
	    	win = createModalWindow(resizable, minmax, close);
	    }else{
			win.close();
			win = createModalWindow(resizable, minmax, close);
		}
		
		if(url.indexOf("confirm_message.php")==-1 && url.indexOf("show_conf_steps.php")==-1){
			// estableciendo ubicacion de ventana  
		  	var left = ((screen.width)/2) - (width/2) ;
		  	var top = ((screen.height)/2 )- (height/2) - 100;
		  	win.setLocation(top, left);
	  	}else{
	  		win.setLocation(40, 50);
	  	}
	  	
	    win.setURL(url);
	    win.setTitle(title);
	    win.setSize(width,height);
   }
   
  /*
  *  Crea una ventana de tipo modal
  */
  function createModalWindow(resize, minmax, close) {
	var window = new Window({id: "popup", className: "alphacube", resizable: resize, minimizable: minmax, maximizable: minmax, wiredDrag: true, closable: close});
		
  	window.setDestroyOnClose();
  	window.setZIndex(10);
  				
  	window.show(true);
  	window.toFront();
  	
  	return window;
  }/*  Prototype JavaScript framework, version 1.5.1_rc3
 *  (c) 2005-2007 Sam Stephenson
 *
 *  Prototype is freely distributable under the terms of an MIT-style license.
 *  For details, see the Prototype web site: http://www.prototypejs.org/
 *
/*--------------------------------------------------------------------------*/

var Prototype = {
  Version: '1.5.1_rc3',

  Browser: {
    IE:     !!(window.attachEvent && !window.opera),
    Opera:  !!window.opera,
    WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1,
    Gecko:  navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1
  },

  BrowserFeatures: {
    XPath: !!document.evaluate,
    ElementExtensions: !!window.HTMLElement,
    SpecificElementExtensions:
      (document.createElement('div').__proto__ !==
       document.createElement('form').__proto__)
  },

  ScriptFragment: '<script[^>]*>([\u0001-\uFFFF]*?)</script>',
  JSONFilter: /^\/\*-secure-\s*(.*)\s*\*\/\s*$/,

  emptyFunction: function() { },
  K: function(x) { return x }
}

var Class = {
  create: function() {
    return function() {
      this.initialize.apply(this, arguments);
    }
  }
}

var Abstract = new Object();

Object.extend = function(destination, source) {
  for (var property in source) {
    destination[property] = source[property];
  }
  return destination;
}

Object.extend(Object, {
  inspect: function(object) {
    try {
      if (object === undefined) return 'undefined';
      if (object === null) return 'null';
      return object.inspect ? object.inspect() : object.toString();
    } catch (e) {
      if (e instanceof RangeError) return '...';
      throw e;
    }
  },

  toJSON: function(object) {
    var type = typeof object;
    switch(type) {
      case 'undefined':
      case 'function':
      case 'unknown': return;
      case 'boolean': return object.toString();
    }
    if (object === null) return 'null';
    if (object.toJSON) return object.toJSON();
    if (object.ownerDocument === document) return;
    var results = [];
    for (var property in object) {
      var value = Object.toJSON(object[property]);
      if (value !== undefined)
        results.push(property.toJSON() + ': ' + value);
    }
    return '{' + results.join(', ') + '}';
  },

  keys: function(object) {
    var keys = [];
    for (var property in object)
      keys.push(property);
    return keys;
  },

  values: function(object) {
    var values = [];
    for (var property in object)
      values.push(object[property]);
    return values;
  },

  clone: function(object) {
    return Object.extend({}, object);
  }
});

Function.prototype.bind = function() {
  var __method = this, args = $A(arguments), object = args.shift();
  return function() {
    return __method.apply(object, args.concat($A(arguments)));
  }
}

Function.prototype.bindAsEventListener = function(object) {
  var __method = this, args = $A(arguments), object = args.shift();
  return function(event) {
    return __method.apply(object, [( event || window.event)].concat(args).concat($A(arguments)));
  }
}

Object.extend(Number.prototype, {
  toColorPart: function() {
    return this.toPaddedString(2, 16);
  },

  succ: function() {
    return this + 1;
  },

  times: function(iterator) {
    $R(0, this, true).each(iterator);
    return this;
  },

  toPaddedString: function(length, radix) {
    var string = this.toString(radix || 10);
    return '0'.times(length - string.length) + string;
  },

  toJSON: function() {
    return isFinite(this) ? this.toString() : 'null';
  }
});

Date.prototype.toJSON = function() {
  return '"' + this.getFullYear() + '-' +
    (this.getMonth() + 1).toPaddedString(2) + '-' +
    this.getDate().toPaddedString(2) + 'T' +
    this.getHours().toPaddedString(2) + ':' +
    this.getMinutes().toPaddedString(2) + ':' +
    this.getSeconds().toPaddedString(2) + '"';
};

var Try = {
  these: function() {
    var returnValue;

    for (var i = 0, length = arguments.length; i < length; i++) {
      var lambda = arguments[i];
      try {
        returnValue = lambda();
        break;
      } catch (e) {}
    }

    return returnValue;
  }
}

/*--------------------------------------------------------------------------*/

var PeriodicalExecuter = Class.create();
PeriodicalExecuter.prototype = {
  initialize: function(callback, frequency) {
    this.callback = callback;
    this.frequency = frequency;
    this.currentlyExecuting = false;

    this.registerCallback();
  },

  registerCallback: function() {
    this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
  },

  stop: function() {
    if (!this.timer) return;
    clearInterval(this.timer);
    this.timer = null;
  },

  onTimerEvent: function() {
    if (!this.currentlyExecuting) {
      try {
        this.currentlyExecuting = true;
        this.callback(this);
      } finally {
        this.currentlyExecuting = false;
      }
    }
  }
}
Object.extend(String, {
  interpret: function(value) {
    return value == null ? '' : String(value);
  },
  specialChar: {
    '\b': '\\b',
    '\t': '\\t',
    '\n': '\\n',
    '\f': '\\f',
    '\r': '\\r',
    '\\': '\\\\'
  }
});

Object.extend(String.prototype, {
  gsub: function(pattern, replacement) {
    var result = '', source = this, match;
    replacement = arguments.callee.prepareReplacement(replacement);

    while (source.length > 0) {
      if (match = source.match(pattern)) {
        result += source.slice(0, match.index);
        result += String.interpret(replacement(match));
        source  = source.slice(match.index + match[0].length);
      } else {
        result += source, source = '';
      }
    }
    return result;
  },

  sub: function(pattern, replacement, count) {
    replacement = this.gsub.prepareReplacement(replacement);
    count = count === undefined ? 1 : count;

    return this.gsub(pattern, function(match) {
      if (--count < 0) return match[0];
      return replacement(match);
    });
  },

  scan: function(pattern, iterator) {
    this.gsub(pattern, iterator);
    return this;
  },

  truncate: function(length, truncation) {
    length = length || 30;
    truncation = truncation === undefined ? '...' : truncation;
    return this.length > length ?
      this.slice(0, length - truncation.length) + truncation : this;
  },

  strip: function() {
    return this.replace(/^\s+/, '').replace(/\s+$/, '');
  },

  stripTags: function() {
    return this.replace(/<\/?[^>]+>/gi, '');
  },

  stripScripts: function() {
    return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
  },

  extractScripts: function() {
    var matchAll = new RegExp(Prototype.ScriptFragment, 'img');
    var matchOne = new RegExp(Prototype.ScriptFragment, 'im');
    return (this.match(matchAll) || []).map(function(scriptTag) {
      return (scriptTag.match(matchOne) || ['', ''])[1];
    });
  },

  evalScripts: function() {
    return this.extractScripts().map(function(script) { return eval(script) });
  },

  escapeHTML: function() {
    var self = arguments.callee;
    self.text.data = this;
    return self.div.innerHTML;
  },

  unescapeHTML: function() {
    var div = document.createElement('div');
    div.innerHTML = this.stripTags();
    return div.childNodes[0] ? (div.childNodes.length > 1 ?
      $A(div.childNodes).inject('', function(memo, node) { return memo+node.nodeValue }) :
      div.childNodes[0].nodeValue) : '';
  },

  toQueryParams: function(separator) {
    var match = this.strip().match(/([^?#]*)(#.*)?$/);
    if (!match) return {};

    return match[1].split(separator || '&').inject({}, function(hash, pair) {
      if ((pair = pair.split('='))[0]) {
        var key = decodeURIComponent(pair.shift());
        var value = pair.length > 1 ? pair.join('=') : pair[0];
        if (value != undefined) value = decodeURIComponent(value);

        if (key in hash) {
          if (hash[key].constructor != Array) hash[key] = [hash[key]];
          hash[key].push(value);
        }
        else hash[key] = value;
      }
      return hash;
    });
  },

  toArray: function() {
    return this.split('');
  },

  succ: function() {
    return this.slice(0, this.length - 1) +
      String.fromCharCode(this.charCodeAt(this.length - 1) + 1);
  },

  times: function(count) {
    var result = '';
    for (var i = 0; i < count; i++) result += this;
    return result;
  },

  camelize: function() {
    var parts = this.split('-'), len = parts.length;
    if (len == 1) return parts[0];

    var camelized = this.charAt(0) == '-'
      ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1)
      : parts[0];

    for (var i = 1; i < len; i++)
      camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);

    return camelized;
  },

  capitalize: function() {
    return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
  },

  underscore: function() {
    return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase();
  },

  dasherize: function() {
    return this.gsub(/_/,'-');
  },

  inspect: function(useDoubleQuotes) {
    var escapedString = this.gsub(/[\x00-\x1f\\]/, function(match) {
      var character = String.specialChar[match[0]];
      return character ? character : '\\u00' + match[0].charCodeAt().toPaddedString(2, 16);
    });
    if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"';
    return "'" + escapedString.replace(/'/g, '\\\'') + "'";
  },

  toJSON: function() {
    return this.inspect(true);
  },

  unfilterJSON: function(filter) {
    return this.sub(filter || Prototype.JSONFilter, '#{1}');
  },

  evalJSON: function(sanitize) {
    var json = this.unfilterJSON();
    try {
      if (!sanitize || (/^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/.test(json)))
        return eval('(' + json + ')');
    } catch (e) { }
    throw new SyntaxError('Badly formed JSON string: ' + this.inspect());
  },

  include: function(pattern) {
    return this.indexOf(pattern) > -1;
  },

  startsWith: function(pattern) {
    return this.indexOf(pattern) === 0;
  },

  endsWith: function(pattern) {
    var d = this.length - pattern.length;
    return d >= 0 && this.lastIndexOf(pattern) === d;
  },

  empty: function() {
    return this == '';
  },

  blank: function() {
    return /^\s*$/.test(this);
  }
});

if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, {
  escapeHTML: function() {
    return this.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
  },
  unescapeHTML: function() {
    return this.replace(/&amp;/g,'&').replace(/&lt;/g,'<').replace(/&gt;/g,'>');
  }
});

String.prototype.gsub.prepareReplacement = function(replacement) {
  if (typeof replacement == 'function') return replacement;
  var template = new Template(replacement);
  return function(match) { return template.evaluate(match) };
}

String.prototype.parseQuery = String.prototype.toQueryParams;

Object.extend(String.prototype.escapeHTML, {
  div:  document.createElement('div'),
  text: document.createTextNode('')
});

with (String.prototype.escapeHTML) div.appendChild(text);

var Template = Class.create();
Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
Template.prototype = {
  initialize: function(template, pattern) {
    this.template = template.toString();
    this.pattern  = pattern || Template.Pattern;
  },

  evaluate: function(object) {
    return this.template.gsub(this.pattern, function(match) {
      var before = match[1];
      if (before == '\\') return match[2];
      return before + String.interpret(object[match[3]]);
    });
  }
}

var $break    = new Object();
var $continue = new Object();

var Enumerable = {
  each: function(iterator) {
    var index = 0;
    try {
      this._each(function(value) {
        iterator(value, index++);
      });
    } catch (e) {
      if (e != $break) throw e;
    }
    return this;
  },

  eachSlice: function(number, iterator) {
    var index = -number, slices = [], array = this.toArray();
    while ((index += number) < array.length)
      slices.push(array.slice(index, index+number));
    return slices.map(iterator);
  },

  all: function(iterator) {
    var result = true;
    this.each(function(value, index) {
      result = result && !!(iterator || Prototype.K)(value, index);
      if (!result) throw $break;
    });
    return result;
  },

  any: function(iterator) {
    var result = false;
    this.each(function(value, index) {
      if (result = !!(iterator || Prototype.K)(value, index))
        throw $break;
    });
    return result;
  },

  collect: function(iterator) {
    var results = [];
    this.each(function(value, index) {
      results.push((iterator || Prototype.K)(value, index));
    });
    return results;
  },

  detect: function(iterator) {
    var result;
    this.each(function(value, index) {
      if (iterator(value, index)) {
        result = value;
        throw $break;
      }
    });
    return result;
  },

  findAll: function(iterator) {
    var results = [];
    this.each(function(value, index) {
      if (iterator(value, index))
        results.push(value);
    });
    return results;
  },

  grep: function(pattern, iterator) {
    var results = [];
    this.each(function(value, index) {
      var stringValue = value.toString();
      if (stringValue.match(pattern))
        results.push((iterator || Prototype.K)(value, index));
    })
    return results;
  },

  include: function(object) {
    var found = false;
    this.each(function(value) {
      if (value == object) {
        found = true;
        throw $break;
      }
    });
    return found;
  },

  inGroupsOf: function(number, fillWith) {
    fillWith = fillWith === undefined ? null : fillWith;
    return this.eachSlice(number, function(slice) {
      while(slice.length < number) slice.push(fillWith);
      return slice;
    });
  },

  inject: function(memo, iterator) {
    this.each(function(value, index) {
      memo = iterator(memo, value, index);
    });
    return memo;
  },

  invoke: function(method) {
    var args = $A(arguments).slice(1);
    return this.map(function(value) {
      return value[method].apply(value, args);
    });
  },

  max: function(iterator) {
    var result;
    this.each(function(value, index) {
      value = (iterator || Prototype.K)(value, index);
      if (result == undefined || value >= result)
        result = value;
    });
    return result;
  },

  min: function(iterator) {
    var result;
    this.each(function(value, index) {
      value = (iterator || Prototype.K)(value, index);
      if (result == undefined || value < result)
        result = value;
    });
    return result;
  },

  partition: function(iterator) {
    var trues = [], falses = [];
    this.each(function(value, index) {
      ((iterator || Prototype.K)(value, index) ?
        trues : falses).push(value);
    });
    return [trues, falses];
  },

  pluck: function(property) {
    var results = [];
    this.each(function(value, index) {
      results.push(value[property]);
    });
    return results;
  },

  reject: function(iterator) {
    var results = [];
    this.each(function(value, index) {
      if (!iterator(value, index))
        results.push(value);
    });
    return results;
  },

  sortBy: function(iterator) {
    return this.map(function(value, index) {
      return {value: value, criteria: iterator(value, index)};
    }).sort(function(left, right) {
      var a = left.criteria, b = right.criteria;
      return a < b ? -1 : a > b ? 1 : 0;
    }).pluck('value');
  },

  toArray: function() {
    return this.map();
  },

  zip: function() {
    var iterator = Prototype.K, args = $A(arguments);
    if (typeof args.last() == 'function')
      iterator = args.pop();

    var collections = [this].concat(args).map($A);
    return this.map(function(value, index) {
      return iterator(collections.pluck(index));
    });
  },

  size: function() {
    return this.toArray().length;
  },

  inspect: function() {
    return '#<Enumerable:' + this.toArray().inspect() + '>';
  }
}

Object.extend(Enumerable, {
  map:     Enumerable.collect,
  find:    Enumerable.detect,
  select:  Enumerable.findAll,
  member:  Enumerable.include,
  entries: Enumerable.toArray
});
var $A = Array.from = function(iterable) {
  if (!iterable) return [];
  if (iterable.toArray) {
    return iterable.toArray();
  } else {
    var results = [];
    for (var i = 0, length = iterable.length; i < length; i++)
      results.push(iterable[i]);
    return results;
  }
}

if (Prototype.Browser.WebKit) {
  $A = Array.from = function(iterable) {
    if (!iterable) return [];
    if (!(typeof iterable == 'function' && iterable == '[object NodeList]') &&
      iterable.toArray) {
      return iterable.toArray();
    } else {
      var results = [];
      for (var i = 0, length = iterable.length; i < length; i++)
        results.push(iterable[i]);
      return results;
    }
  }
}

Object.extend(Array.prototype, Enumerable);

if (!Array.prototype._reverse)
  Array.prototype._reverse = Array.prototype.reverse;

Object.extend(Array.prototype, {
  _each: function(iterator) {
    for (var i = 0, length = this.length; i < length; i++)
      iterator(this[i]);
  },

  clear: function() {
    this.length = 0;
    return this;
  },

  first: function() {
    return this[0];
  },

  last: function() {
    return this[this.length - 1];
  },

  compact: function() {
    return this.select(function(value) {
      return value != null;
    });
  },

  flatten: function() {
    return this.inject([], function(array, value) {
      return array.concat(value && value.constructor == Array ?
        value.flatten() : [value]);
    });
  },

  without: function() {
    var values = $A(arguments);
    return this.select(function(value) {
      return !values.include(value);
    });
  },

  indexOf: function(object) {
    for (var i = 0, length = this.length; i < length; i++)
      if (this[i] == object) return i;
    return -1;
  },

  reverse: function(inline) {
    return (inline !== false ? this : this.toArray())._reverse();
  },

  reduce: function() {
    return this.length > 1 ? this : this[0];
  },

  uniq: function(sorted) {
    return this.inject([], function(array, value, index) {
      if (0 == index || (sorted ? array.last() != value : !array.include(value)))
        array.push(value);
      return array;
    });
  },

  clone: function() {
    return [].concat(this);
  },

  size: function() {
    return this.length;
  },

  inspect: function() {
    return '[' + this.map(Object.inspect).join(', ') + ']';
  },

  toJSON: function() {
    var results = [];
    this.each(function(object) {
      var value = Object.toJSON(object);
      if (value !== undefined) results.push(value);
    });
    return '[' + results.join(', ') + ']';
  }
});

Array.prototype.toArray = Array.prototype.clone;

function $w(string) {
  string = string.strip();
  return string ? string.split(/\s+/) : [];
}

if (Prototype.Browser.Opera){
  Array.prototype.concat = function() {
    var array = [];
    for (var i = 0, length = this.length; i < length; i++) array.push(this[i]);
    for (var i = 0, length = arguments.length; i < length; i++) {
      if (arguments[i].constructor == Array) {
        for (var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++)
          array.push(arguments[i][j]);
      } else {
        array.push(arguments[i]);
      }
    }
    return array;
  }
}
var Hash = function(object) {
  if (object instanceof Hash) this.merge(object);
  else Object.extend(this, object || {});
};

Object.extend(Hash, {
  toQueryString: function(obj) {
    var parts = [];
    parts.add = arguments.callee.addPair;

    this.prototype._each.call(obj, function(pair) {
      if (!pair.key) return;
      var value = pair.value;

      if (value && typeof value == 'object') {
        if (value.constructor == Array) value.each(function(value) {
          parts.add(pair.key, value);
        });
        return;
      }
      parts.add(pair.key, value);
    });

    return parts.join('&');
  },

  toJSON: function(object) {
    var results = [];
    this.prototype._each.call(object, function(pair) {
      var value = Object.toJSON(pair.value);
      if (value !== undefined) results.push(pair.key.toJSON() + ': ' + value);
    });
    return '{' + results.join(', ') + '}';
  }
});

Hash.toQueryString.addPair = function(key, value, prefix) {
  key = encodeURIComponent(key);
  if (value === undefined) this.push(key);
  else this.push(key + '=' + (value == null ? '' : encodeURIComponent(value)));
}

Object.extend(Hash.prototype, Enumerable);
Object.extend(Hash.prototype, {
  _each: function(iterator) {
    for (var key in this) {
      var value = this[key];
      if (value && value == Hash.prototype[key]) continue;

      var pair = [key, value];
      pair.key = key;
      pair.value = value;
      iterator(pair);
    }
  },

  keys: function() {
    return this.pluck('key');
  },

  values: function() {
    return this.pluck('value');
  },

  merge: function(hash) {
    return $H(hash).inject(this, function(mergedHash, pair) {
      mergedHash[pair.key] = pair.value;
      return mergedHash;
    });
  },

  remove: function() {
    var result;
    for(var i = 0, length = arguments.length; i < length; i++) {
      var value = this[arguments[i]];
      if (value !== undefined){
        if (result === undefined) result = value;
        else {
          if (result.constructor != Array) result = [result];
          result.push(value)
        }
      }
      delete this[arguments[i]];
    }
    return result;
  },

  toQueryString: function() {
    return Hash.toQueryString(this);
  },

  inspect: function() {
    return '#<Hash:{' + this.map(function(pair) {
      return pair.map(Object.inspect).join(': ');
    }).join(', ') + '}>';
  },

  toJSON: function() {
    return Hash.toJSON(this);
  }
});

function $H(object) {
  if (object instanceof Hash) return object;
  return new Hash(object);
};

// Safari iterates over shadowed properties
if (function() {
  var i = 0, Test = function(value) { this.key = value };
  Test.prototype.key = 'foo';
  for (var property in new Test('bar')) i++;
  return i > 1;
}()) Hash.prototype._each = function(iterator) {
  var cache = [];
  for (var key in this) {
    var value = this[key];
    if ((value && value == Hash.prototype[key]) || cache.include(key)) continue;
    cache.push(key);
    var pair = [key, value];
    pair.key = key;
    pair.value = value;
    iterator(pair);
  }
};
ObjectRange = Class.create();
Object.extend(ObjectRange.prototype, Enumerable);
Object.extend(ObjectRange.prototype, {
  initialize: function(start, end, exclusive) {
    this.start = start;
    this.end = end;
    this.exclusive = exclusive;
  },

  _each: function(iterator) {
    var value = this.start;
    while (this.include(value)) {
      iterator(value);
      value = value.succ();
    }
  },

  include: function(value) {
    if (value < this.start)
      return false;
    if (this.exclusive)
      return value < this.end;
    return value <= this.end;
  }
});

var $R = function(start, end, exclusive) {
  return new ObjectRange(start, end, exclusive);
}

var Ajax = {
  getTransport: function() {
    return Try.these(
      function() {return new XMLHttpRequest()},
      function() {return new ActiveXObject('Msxml2.XMLHTTP')},
      function() {return new ActiveXObject('Microsoft.XMLHTTP')}
    ) || false;
  },

  activeRequestCount: 0
}

Ajax.Responders = {
  responders: [],

  _each: function(iterator) {
    this.responders._each(iterator);
  },

  register: function(responder) {
    if (!this.include(responder))
      this.responders.push(responder);
  },

  unregister: function(responder) {
    this.responders = this.responders.without(responder);
  },

  dispatch: function(callback, request, transport, json) {
    this.each(function(responder) {
      if (typeof responder[callback] == 'function') {
        try {
          responder[callback].apply(responder, [request, transport, json]);
        } catch (e) {}
      }
    });
  }
};

Object.extend(Ajax.Responders, Enumerable);

Ajax.Responders.register({
  onCreate: function() {
    Ajax.activeRequestCount++;
  },
  onComplete: function() {
    Ajax.activeRequestCount--;
  }
});

Ajax.Base = function() {};
Ajax.Base.prototype = {
  setOptions: function(options) {
    this.options = {
      method:       'post',
      asynchronous: true,
      contentType:  'application/x-www-form-urlencoded',
      encoding:     'UTF-8',
      parameters:   ''
    }
    Object.extend(this.options, options || {});

    this.options.method = this.options.method.toLowerCase();
    if (typeof this.options.parameters == 'string')
      this.options.parameters = this.options.parameters.toQueryParams();
  }
}

Ajax.Request = Class.create();
Ajax.Request.Events =
  ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];

Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
  _complete: false,

  initialize: function(url, options) {
    this.transport = Ajax.getTransport();
    this.setOptions(options);
    this.request(url);
  },

  request: function(url) {
    this.url = url;
    this.method = this.options.method;
    var params = Object.clone(this.options.parameters);

    if (!['get', 'post'].include(this.method)) {
      // simulate other verbs over post
      params['_method'] = this.method;
      this.method = 'post';
    }

    this.parameters = params;

    if (params = Hash.toQueryString(params)) {
      // when GET, append parameters to URL
      if (this.method == 'get')
        this.url += (this.url.include('?') ? '&' : '?') + params;
      else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent))
        params += '&_=';
    }

    try {
      if (this.options.onCreate) this.options.onCreate(this.transport);
      Ajax.Responders.dispatch('onCreate', this, this.transport);

      this.transport.open(this.method.toUpperCase(), this.url,
        this.options.asynchronous);

      if (this.options.asynchronous)
        setTimeout(function() { this.respondToReadyState(1) }.bind(this), 10);

      this.transport.onreadystatechange = this.onStateChange.bind(this);
      this.setRequestHeaders();

      this.body = this.method == 'post' ? (this.options.postBody || params) : null;
      this.transport.send(this.body);

      /* Force Firefox to handle ready state 4 for synchronous requests */
      if (!this.options.asynchronous && this.transport.overrideMimeType)
        this.onStateChange();

    }
    catch (e) {
      this.dispatchException(e);
    }
  },

  onStateChange: function() {
    var readyState = this.transport.readyState;
    if (readyState > 1 && !((readyState == 4) && this._complete))
      this.respondToReadyState(this.transport.readyState);
  },

  setRequestHeaders: function() {
    var headers = {
      'X-Requested-With': 'XMLHttpRequest',
      'X-Prototype-Version': Prototype.Version,
      'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
    };

    if (this.method == 'post') {
      headers['Content-type'] = this.options.contentType +
        (this.options.encoding ? '; charset=' + this.options.encoding : '');

      /* Force "Connection: close" for older Mozilla browsers to work
       * around a bug where XMLHttpRequest sends an incorrect
       * Content-length header. See Mozilla Bugzilla #246651.
       */
      if (this.transport.overrideMimeType &&
          (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005)
            headers['Connection'] = 'close';
    }

    // user-defined headers
    if (typeof this.options.requestHeaders == 'object') {
      var extras = this.options.requestHeaders;

      if (typeof extras.push == 'function')
        for (var i = 0, length = extras.length; i < length; i += 2)
          headers[extras[i]] = extras[i+1];
      else
        $H(extras).each(function(pair) { headers[pair.key] = pair.value });
    }

    for (var name in headers)
      this.transport.setRequestHeader(name, headers[name]);
  },

  success: function() {
    return !this.transport.status
        || (this.transport.status >= 200 && this.transport.status < 300);
  },

  respondToReadyState: function(readyState) {
    var state = Ajax.Request.Events[readyState];
    var transport = this.transport, json = this.evalJSON();

    if (state == 'Complete') {
      try {
        this._complete = true;
        (this.options['on' + this.transport.status]
         || this.options['on' + (this.success() ? 'Success' : 'Failure')]
         || Prototype.emptyFunction)(transport, json);
      } catch (e) {
        this.dispatchException(e);
      }

      var contentType = this.getHeader('Content-type');
      if (contentType && contentType.strip().
        match(/^(text|application)\/(x-)?(java|ecma)script(;.*)?$/i))
          this.evalResponse();
    }

    try {
      (this.options['on' + state] || Prototype.emptyFunction)(transport, json);
      Ajax.Responders.dispatch('on' + state, this, transport, json);
    } catch (e) {
      this.dispatchException(e);
    }

    if (state == 'Complete') {
      // avoid memory leak in MSIE: clean up
      this.transport.onreadystatechange = Prototype.emptyFunction;
    }
  },

  getHeader: function(name) {
    try {
      return this.transport.getResponseHeader(name);
    } catch (e) { return null }
  },

  evalJSON: function() {
    try {
      var json = this.getHeader('X-JSON');
      return json ? json.evalJSON() : null;
    } catch (e) { return null }
  },

  evalResponse: function() {
    try {
      return eval((this.transport.responseText || '').unfilterJSON());
    } catch (e) {
      this.dispatchException(e);
    }
  },

  dispatchException: function(exception) {
    (this.options.onException || Prototype.emptyFunction)(this, exception);
    Ajax.Responders.dispatch('onException', this, exception);
  }
});

Ajax.Updater = Class.create();

Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {
  initialize: function(container, url, options) {
    this.container = {
      success: (container.success || container),
      failure: (container.failure || (container.success ? null : container))
    }

    this.transport = Ajax.getTransport();
    this.setOptions(options);

    var onComplete = this.options.onComplete || Prototype.emptyFunction;
    this.options.onComplete = (function(transport, param) {
      this.updateContent();
      onComplete(transport, param);
    }).bind(this);

    this.request(url);
  },

  updateContent: function() {
    var receiver = this.container[this.success() ? 'success' : 'failure'];
    var response = this.transport.responseText;

    if (!this.options.evalScripts) response = response.stripScripts();

    if (receiver = $(receiver)) {
      if (this.options.insertion)
        new this.options.insertion(receiver, response);
      else
        receiver.update(response);
    }

    if (this.success()) {
      if (this.onComplete)
        setTimeout(this.onComplete.bind(this), 10);
    }
  }
});

Ajax.PeriodicalUpdater = Class.create();
Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), {
  initialize: function(container, url, options) {
    this.setOptions(options);
    this.onComplete = this.options.onComplete;

    this.frequency = (this.options.frequency || 2);
    this.decay = (this.options.decay || 1);

    this.updater = {};
    this.container = container;
    this.url = url;

    this.start();
  },

  start: function() {
    this.options.onComplete = this.updateComplete.bind(this);
    this.onTimerEvent();
  },

  stop: function() {
    this.updater.options.onComplete = undefined;
    clearTimeout(this.timer);
    (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
  },

  updateComplete: function(request) {
    if (this.options.decay) {
      this.decay = (request.responseText == this.lastText ?
        this.decay * this.options.decay : 1);

      this.lastText = request.responseText;
    }
    this.timer = setTimeout(this.onTimerEvent.bind(this),
      this.decay * this.frequency * 1000);
  },

  onTimerEvent: function() {
    this.updater = new Ajax.Updater(this.container, this.url, this.options);
  }
});
function $(element) {
  if (arguments.length > 1) {
    for (var i = 0, elements = [], length = arguments.length; i < length; i++)
      elements.push($(arguments[i]));
    return elements;
  }
  if (typeof element == 'string')
    element = document.getElementById(element);
  return Element.extend(element);
}

if (Prototype.BrowserFeatures.XPath) {
  document._getElementsByXPath = function(expression, parentElement) {
    var results = [];
    var query = document.evaluate(expression, $(parentElement) || document,
      null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
    for (var i = 0, length = query.snapshotLength; i < length; i++)
      results.push(query.snapshotItem(i));
    return results;
  };

  document.getElementsByClassName = function(className, parentElement) {
    var q = ".//*[contains(concat(' ', @class, ' '), ' " + className + " ')]";
    return document._getElementsByXPath(q, parentElement);
  }

} else document.getElementsByClassName = function(className, parentElement) {
  var children = ($(parentElement) || document.body).getElementsByTagName('*');
  var elements = [], child;
  for (var i = 0, length = children.length; i < length; i++) {
    child = children[i];
    if (Element.hasClassName(child, className))
      elements.push(Element.extend(child));
  }
  return elements;
};

/*--------------------------------------------------------------------------*/

if (!window.Element) var Element = {};

Element.extend = function(element) {
  var F = Prototype.BrowserFeatures;
  if (!element || !element.tagName || element.nodeType == 3 ||
   element._extended || F.SpecificElementExtensions || element == window)
    return element;

  var methods = {}, tagName = element.tagName, cache = Element.extend.cache,
   T = Element.Methods.ByTag;

  // extend methods for all tags (Safari doesn't need this)
  if (!F.ElementExtensions) {
    Object.extend(methods, Element.Methods),
    Object.extend(methods, Element.Methods.Simulated);
  }

  // extend methods for specific tags
  if (T[tagName]) Object.extend(methods, T[tagName]);

  for (var property in methods) {
    var value = methods[property];
    if (typeof value == 'function' && !(property in element))
      element[property] = cache.findOrStore(value);
  }

  element._extended = Prototype.emptyFunction;
  return element;
};

Element.extend.cache = {
  findOrStore: function(value) {
    return this[value] = this[value] || function() {
      return value.apply(null, [this].concat($A(arguments)));
    }
  }
};

Element.Methods = {
  visible: function(element) {
    return $(element).style.display != 'none';
  },

  toggle: function(element) {
    element = $(element);
    Element[Element.visible(element) ? 'hide' : 'show'](element);
    return element;
  },

  hide: function(element) {
    $(element).style.display = 'none';
    return element;
  },

  show: function(element) {
    $(element).style.display = '';
    return element;
  },

  remove: function(element) {
    element = $(element);
    element.parentNode.removeChild(element);
    return element;
  },

  update: function(element, html) {
    html = typeof html == 'undefined' ? '' : html.toString();
    $(element).innerHTML = html.stripScripts();
    setTimeout(function() {html.evalScripts()}, 10);
    return element;
  },

  replace: function(element, html) {
    element = $(element);
    html = typeof html == 'undefined' ? '' : html.toString();
    if (element.outerHTML) {
      element.outerHTML = html.stripScripts();
    } else {
      var range = element.ownerDocument.createRange();
      range.selectNodeContents(element);
      element.parentNode.replaceChild(
        range.createContextualFragment(html.stripScripts()), element);
    }
    setTimeout(function() {html.evalScripts()}, 10);
    return element;
  },

  inspect: function(element) {
    element = $(element);
    var result = '<' + element.tagName.toLowerCase();
    $H({'id': 'id', 'className': 'class'}).each(function(pair) {
      var property = pair.first(), attribute = pair.last();
      var value = (element[property] || '').toString();
      if (value) result += ' ' + attribute + '=' + value.inspect(true);
    });
    return result + '>';
  },

  recursivelyCollect: function(element, property) {
    element = $(element);
    var elements = [];
    while (element = element[property])
      if (element.nodeType == 1)
        elements.push(Element.extend(element));
    return elements;
  },

  ancestors: function(element) {
    return $(element).recursivelyCollect('parentNode');
  },

  descendants: function(element) {
    return $A($(element).getElementsByTagName('*')).each(Element.extend);
  },

  firstDescendant: function(element) {
    element = $(element).firstChild;
    while (element && element.nodeType != 1) element = element.nextSibling;
    return $(element);
  },

  immediateDescendants: function(element) {
    if (!(element = $(element).firstChild)) return [];
    while (element && element.nodeType != 1) element = element.nextSibling;
    if (element) return [element].concat($(element).nextSiblings());
    return [];
  },

  previousSiblings: function(element) {
    return $(element).recursivelyCollect('previousSibling');
  },

  nextSiblings: function(element) {
    return $(element).recursivelyCollect('nextSibling');
  },

  siblings: function(element) {
    element = $(element);
    return element.previousSiblings().reverse().concat(element.nextSiblings());
  },

  match: function(element, selector) {
    if (typeof selector == 'string')
      selector = new Selector(selector);
    return selector.match($(element));
  },

  up: function(element, expression, index) {
    element = $(element);
    if (arguments.length == 1) return $(element.parentNode);
    var ancestors = element.ancestors();
    return expression ? Selector.findElement(ancestors, expression, index) :
      ancestors[index || 0];
  },

  down: function(element, expression, index) {
    element = $(element);
    if (arguments.length == 1) return element.firstDescendant();
    var descendants = element.descendants();
    return expression ? Selector.findElement(descendants, expression, index) :
      descendants[index || 0];
  },

  previous: function(element, expression, index) {
    element = $(element);
    if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element));
    var previousSiblings = element.previousSiblings();
    return expression ? Selector.findElement(previousSiblings, expression, index) :
      previousSiblings[index || 0];
  },

  next: function(element, expression, index) {
    element = $(element);
    if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element));
    var nextSiblings = element.nextSiblings();
    return expression ? Selector.findElement(nextSiblings, expression, index) :
      nextSiblings[index || 0];
  },

  getElementsBySelector: function() {
    var args = $A(arguments), element = $(args.shift());
    return Selector.findChildElements(element, args);
  },

  getElementsByClassName: function(element, className) {
    return document.getElementsByClassName(className, element);
  },

  readAttribute: function(element, name) {
    element = $(element);
    if (Prototype.Browser.IE) {
      if (!element.attributes) return null;
      var t = Element._attributeTranslations;
      if (t.values[name]) return t.values[name](element, name);
      if (t.names[name])  name = t.names[name];
      var attribute = element.attributes[name];
      return attribute ? attribute.nodeValue : null;
    }
    return element.getAttribute(name);
  },

  getHeight: function(element) {
    return $(element).getDimensions().height;
  },

  getWidth: function(element) {
    return $(element).getDimensions().width;
  },

  classNames: function(element) {
    return new Element.ClassNames(element);
  },

  hasClassName: function(element, className) {
    if (!(element = $(element))) return;
    var elementClassName = element.className;
    if (elementClassName.length == 0) return false;
    if (elementClassName == className ||
        elementClassName.match(new RegExp("(^|\\s)" + className + "(\\s|$)")))
      return true;
    return false;
  },

  addClassName: function(element, className) {
    if (!(element = $(element))) return;
    Element.classNames(element).add(className);
    return element;
  },

  removeClassName: function(element, className) {
    if (!(element = $(element))) return;
    Element.classNames(element).remove(className);
    return element;
  },

  toggleClassName: function(element, className) {
    if (!(element = $(element))) return;
    Element.classNames(element)[element.hasClassName(className) ? 'remove' : 'add'](className);
    return element;
  },

  observe: function() {
    Event.observe.apply(Event, arguments);
    return $A(arguments).first();
  },

  stopObserving: function() {
    Event.stopObserving.apply(Event, arguments);
    return $A(arguments).first();
  },

  // removes whitespace-only text node children
  cleanWhitespace: function(element) {
    element = $(element);
    var node = element.firstChild;
    while (node) {
      var nextNode = node.nextSibling;
      if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
        element.removeChild(node);
      node = nextNode;
    }
    return element;
  },

  empty: function(element) {
    return $(element).innerHTML.blank();
  },

  descendantOf: function(element, ancestor) {
    element = $(element), ancestor = $(ancestor);
    while (element = element.parentNode)
      if (element == ancestor) return true;
    return false;
  },

  scrollTo: function(element) {
    element = $(element);
    var pos = Position.cumulativeOffset(element);
    window.scrollTo(pos[0], pos[1]);
    return element;
  },

  getStyle: function(element, style) {
    element = $(element);
    style = style == 'float' ? 'cssFloat' : style.camelize();
    var value = element.style[style];
    if (!value) {
      var css = document.defaultView.getComputedStyle(element, null);
      value = css ? css[style] : null;
    }
    if (style == 'opacity') return value ? parseFloat(value) : 1.0;
    return value == 'auto' ? null : value;
  },

  getOpacity: function(element) {
    return $(element).getStyle('opacity');
  },

  setStyle: function(element, styles, camelized) {
    element = $(element);
    var elementStyle = element.style;

    for (var property in styles)
      if (property == 'opacity') element.setOpacity(styles[property])
      else
        elementStyle[(property == 'float' || property == 'cssFloat') ?
          (elementStyle.styleFloat === undefined ? 'cssFloat' : 'styleFloat') :
          (camelized ? property : property.camelize())] = styles[property];

    return element;
  },

  setOpacity: function(element, value) {
    element = $(element);
    element.style.opacity = (value == 1 || value === '') ? '' :
      (value < 0.00001) ? 0 : value;
    return element;
  },

  getDimensions: function(element) {
    element = $(element);
    var display = $(element).getStyle('display');
    if (display != 'none' && display != null) // Safari bug
      return {width: element.offsetWidth, height: element.offsetHeight};

    // All *Width and *Height properties give 0 on elements with display none,
    // so enable the element temporarily
    var els = element.style;
    var originalVisibility = els.visibility;
    var originalPosition = els.position;
    var originalDisplay = els.display;
    els.visibility = 'hidden';
    els.position = 'absolute';
    els.display = 'block';
    var originalWidth = element.clientWidth;
    var originalHeight = element.clientHeight;
    els.display = originalDisplay;
    els.position = originalPosition;
    els.visibility = originalVisibility;
    return {width: originalWidth, height: originalHeight};
  },

  makePositioned: function(element) {
    element = $(element);
    var pos = Element.getStyle(element, 'position');
    if (pos == 'static' || !pos) {
      element._madePositioned = true;
      element.style.position = 'relative';
      // Opera returns the offset relative to the positioning context, when an
      // element is position relative but top and left have not been defined
      if (window.opera) {
        element.style.top = 0;
        element.style.left = 0;
      }
    }
    return element;
  },

  undoPositioned: function(element) {
    element = $(element);
    if (element._madePositioned) {
      element._madePositioned = undefined;
      element.style.position =
        element.style.top =
        element.style.left =
        element.style.bottom =
        element.style.right = '';
    }
    return element;
  },

  makeClipping: function(element) {
    element = $(element);
    if (element._overflow) return element;
    element._overflow = element.style.overflow || 'auto';
    if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden')
      element.style.overflow = 'hidden';
    return element;
  },

  undoClipping: function(element) {
    element = $(element);
    if (!element._overflow) return element;
    element.style.overflow = element._overflow == 'auto' ? '' : element._overflow;
    element._overflow = null;
    return element;
  }
};

Object.extend(Element.Methods, {
  childOf: Element.Methods.descendantOf,
  childElements: Element.Methods.immediateDescendants
});

if (Prototype.Browser.Opera) {
  Element.Methods._getStyle = Element.Methods.getStyle;
  Element.Methods.getStyle = function(element, style) {
    switch(style) {
      case 'left':
      case 'top':
      case 'right':
      case 'bottom':
        if (Element._getStyle(element, 'position') == 'static') return null;
      default: return Element._getStyle(element, style);
    }
  };
}
else if (Prototype.Browser.IE) {
  Element.Methods.getStyle = function(element, style) {
    element = $(element);
    style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize();
    var value = element.style[style];
    if (!value && element.currentStyle) value = element.currentStyle[style];

    if (style == 'opacity') {
      if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/))
        if (value[1]) return parseFloat(value[1]) / 100;
      return 1.0;
    }

    if (value == 'auto') {
      if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none'))
        return element['offset'+style.capitalize()] + 'px';
      return null;
    }
    return value;
  };

  Element.Methods.setOpacity = function(element, value) {
    element = $(element);
    var style = element.style;

    if(/MSIE/.test(navigator.userAgent)) {
	    var filter = element.getStyle('filter');
	    if (value == 1 || value === '') {
	      style.filter = filter.replace(/alpha\([^\)]*\)/gi,'');
	      return element;
	    } else if (value < 0.00001) value = 0;
	    style.filter = filter.replace(/alpha\([^\)]*\)/gi, '') +
	      'alpha(opacity=' + (value * 100) + ')';
	      
	}
	else {
		if(value == 1 || value === '')
			style.MozOpacity = '' ;
	    else 
	    	style.MozOpacity = (value / 100) ;	
	}
    return element;
  };

  // IE is missing .innerHTML support for TABLE-related elements
  Element.Methods.update = function(element, html) {
    element = $(element);
    html = typeof html == 'undefined' ? '' : html.toString();
    var tagName = element.tagName.toUpperCase();
    if (['THEAD','TBODY','TR','TD'].include(tagName)) {
      var div = document.createElement('div');
      switch (tagName) {
        case 'THEAD':
        case 'TBODY':
          div.innerHTML = '<table><tbody>' +  html.stripScripts() + '</tbody></table>';
          depth = 2;
          break;
        case 'TR':
          div.innerHTML = '<table><tbody><tr>' +  html.stripScripts() + '</tr></tbody></table>';
          depth = 3;
          break;
        case 'TD':
          div.innerHTML = '<table><tbody><tr><td>' +  html.stripScripts() + '</td></tr></tbody></table>';
          depth = 4;
      }
      $A(element.childNodes).each(function(node) { element.removeChild(node) });
      depth.times(function() { div = div.firstChild });
      $A(div.childNodes).each(function(node) { element.appendChild(node) });
    } else {
      element.innerHTML = html.stripScripts();
    }
    setTimeout(function() { html.evalScripts() }, 10);
    return element;
  }
}
else if (Prototype.Browser.Gecko) {
  Element.Methods.setOpacity = function(element, value) {
    element = $(element);
    element.style.opacity = (value == 1) ? 0.999999 :
      (value === '') ? '' : (value < 0.00001) ? 0 : value;
    return element;
  };
}

Element._attributeTranslations = {
  names: {
    colspan:   "colSpan",
    rowspan:   "rowSpan",
    valign:    "vAlign",
    datetime:  "dateTime",
    accesskey: "accessKey",
    tabindex:  "tabIndex",
    enctype:   "encType",
    maxlength: "maxLength",
    readonly:  "readOnly",
    longdesc:  "longDesc"
  },
  values: {
    _getAttr: function(element, attribute) {
      return element.getAttribute(attribute, 2);
    },
    _flag: function(element, attribute) {
      return $(element).hasAttribute(attribute) ? attribute : null;
    },
    style: function(element) {
      return element.style.cssText.toLowerCase();
    },
    title: function(element) {
      var node = element.getAttributeNode('title');
      return node.specified ? node.nodeValue : null;
    }
  }
};

(function() {
  Object.extend(this, {
    href: this._getAttr,
    src:  this._getAttr,
    disabled: this._flag,
    checked:  this._flag,
    readonly: this._flag,
    multiple: this._flag
  });
}).call(Element._attributeTranslations.values);

Element.Methods.Simulated = {
  hasAttribute: function(element, attribute) {
    var t = Element._attributeTranslations, node;
    attribute = t.names[attribute] || attribute;
    node = $(element).getAttributeNode(attribute);
    return node && node.specified;
  }
};

Element.Methods.ByTag = {};

Object.extend(Element, Element.Methods);

if (!Prototype.BrowserFeatures.ElementExtensions &&
 document.createElement('div').__proto__) {
  window.HTMLElement = {};
  window.HTMLElement.prototype = document.createElement('div').__proto__;
  Prototype.BrowserFeatures.ElementExtensions = true;
}

Element.hasAttribute = function(element, attribute) {
  if (element.hasAttribute) return element.hasAttribute(attribute);
  return Element.Methods.Simulated.hasAttribute(element, attribute);
};

Element.addMethods = function(methods) {
  var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag;
  if (arguments.length == 2) {
    var tagName = methods;
    methods = arguments[1];
  }

  if (!tagName) Object.extend(Element.Methods, methods || {});
  else {
    if (tagName.constructor == Array) tagName.each(extend);
    else extend(tagName);
  }

  function extend(tagName) {
    tagName = tagName.toUpperCase();
    if (!Element.Methods.ByTag[tagName])
      Element.Methods.ByTag[tagName] = {};
    Object.extend(Element.Methods.ByTag[tagName], methods);
  }

  function copy(methods, destination, onlyIfAbsent) {
    onlyIfAbsent = onlyIfAbsent || false;
    var cache = Element.extend.cache;
    for (var property in methods) {
      var value = methods[property];
      if (!onlyIfAbsent || !(property in destination))
        destination[property] = cache.findOrStore(value);
    }
  }

  function findDOMClass(tagName) {
    var klass;
    var trans = {
      "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph",
      "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList",
      "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading",
      "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote",
      "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION":
      "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD":
      "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR":
      "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET":
      "FrameSet", "IFRAME": "IFrame"
    };
    if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element';
    if (window[klass]) return window[klass];
    klass = 'HTML' + tagName + 'Element';
    if (window[klass]) return window[klass];
    klass = 'HTML' + tagName.capitalize() + 'Element';
    if (window[klass]) return window[klass];

    window[klass] = {};
    window[klass].prototype = document.createElement(tagName).__proto__;
    return window[klass];
  }

  if (F.ElementExtensions) {
    copy(Element.Methods, HTMLElement.prototype);
    copy(Element.Methods.Simulated, HTMLElement.prototype, true);
  }

  if (F.SpecificElementExtensions) {
    for (var tag in Element.Methods.ByTag) {
      var klass = findDOMClass(tag);
      if (typeof klass == "undefined") continue;
      copy(T[tag], klass.prototype);
    }
  }

  Object.extend(Element, Element.Methods);
  delete Element.ByTag;
};

var Toggle = { display: Element.toggle };

/*--------------------------------------------------------------------------*/

Abstract.Insertion = function(adjacency) {
  this.adjacency = adjacency;
}

Abstract.Insertion.prototype = {
  initialize: function(element, content) {
    this.element = $(element);
    this.content = content.stripScripts();

    if (this.adjacency && this.element.insertAdjacentHTML) {
      try {
        this.element.insertAdjacentHTML(this.adjacency, this.content);
      } catch (e) {
        var tagName = this.element.tagName.toUpperCase();
        if (['TBODY', 'TR'].include(tagName)) {
          this.insertContent(this.contentFromAnonymousTable());
        } else {
          throw e;
        }
      }
    } else {
      this.range = this.element.ownerDocument.createRange();
      if (this.initializeRange) this.initializeRange();
      this.insertContent([this.range.createContextualFragment(this.content)]);
    }

    setTimeout(function() {content.evalScripts()}, 10);
  },

  contentFromAnonymousTable: function() {
    var div = document.createElement('div');
    div.innerHTML = '<table><tbody>' + this.content + '</tbody></table>';
    return $A(div.childNodes[0].childNodes[0].childNodes);
  }
}

var Insertion = new Object();

Insertion.Before = Class.create();
Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), {
  initializeRange: function() {
    this.range.setStartBefore(this.element);
  },

  insertContent: function(fragments) {
    fragments.each((function(fragment) {
      this.element.parentNode.insertBefore(fragment, this.element);
    }).bind(this));
  }
});

Insertion.Top = Class.create();
Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), {
  initializeRange: function() {
    this.range.selectNodeContents(this.element);
    this.range.collapse(true);
  },

  insertContent: function(fragments) {
    fragments.reverse(false).each((function(fragment) {
      this.element.insertBefore(fragment, this.element.firstChild);
    }).bind(this));
  }
});

Insertion.Bottom = Class.create();
Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), {
  initializeRange: function() {
    this.range.selectNodeContents(this.element);
    this.range.collapse(this.element);
  },

  insertContent: function(fragments) {
    fragments.each((function(fragment) {
      this.element.appendChild(fragment);
    }).bind(this));
  }
});

Insertion.After = Class.create();
Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), {
  initializeRange: function() {
    this.range.setStartAfter(this.element);
  },

  insertContent: function(fragments) {
    fragments.each((function(fragment) {
      this.element.parentNode.insertBefore(fragment,
        this.element.nextSibling);
    }).bind(this));
  }
});

/*--------------------------------------------------------------------------*/

Element.ClassNames = Class.create();
Element.ClassNames.prototype = {
  initialize: function(element) {
    this.element = $(element);
  },

  _each: function(iterator) {
    this.element.className.split(/\s+/).select(function(name) {
      return name.length > 0;
    })._each(iterator);
  },

  set: function(className) {
    this.element.className = className;
  },

  add: function(classNameToAdd) {
    if (this.include(classNameToAdd)) return;
    this.set($A(this).concat(classNameToAdd).join(' '));
  },

  remove: function(classNameToRemove) {
    if (!this.include(classNameToRemove)) return;
    this.set($A(this).without(classNameToRemove).join(' '));
  },

  toString: function() {
    return $A(this).join(' ');
  }
};

Object.extend(Element.ClassNames.prototype, Enumerable);
/* Portions of the Selector class are derived from Jack Slocumâ€™s DomQuery,
 * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style
 * license.  Please see http://www.yui-ext.com/ for more information. */

var Selector = Class.create();

Selector.prototype = {
  initialize: function(expression) {
    this.expression = expression.strip();
    this.compileMatcher();
  },

  compileMatcher: function() {
    // Selectors with namespaced attributes can't use the XPath version
    if (Prototype.BrowserFeatures.XPath && !(/\[[\w-]*?:/).test(this.expression))
      return this.compileXPathMatcher();

    var e = this.expression, ps = Selector.patterns, h = Selector.handlers,
        c = Selector.criteria, le, p, m;

    if (Selector._cache[e]) {
      this.matcher = Selector._cache[e]; return;
    }
    this.matcher = ["this.matcher = function(root) {",
                    "var r = root, h = Selector.handlers, c = false, n;"];

    while (e && le != e && (/\S/).test(e)) {
      le = e;
      for (var i in ps) {
        p = ps[i];
        if (m = e.match(p)) {
          this.matcher.push(typeof c[i] == 'function' ? c[i](m) :
    	      new Template(c[i]).evaluate(m));
          e = e.replace(m[0], '');
          break;
        }
      }
    }

    this.matcher.push("return h.unique(n);\n}");
    eval(this.matcher.join('\n'));
    Selector._cache[this.expression] = this.matcher;
  },

  compileXPathMatcher: function() {
    var e = this.expression, ps = Selector.patterns,
        x = Selector.xpath, le,  m;

    if (Selector._cache[e]) {
      this.xpath = Selector._cache[e]; return;
    }

    this.matcher = ['.//*'];
    while (e && le != e && (/\S/).test(e)) {
      le = e;
      for (var i in ps) {
        if (m = e.match(ps[i])) {
          this.matcher.push(typeof x[i] == 'function' ? x[i](m) :
            new Template(x[i]).evaluate(m));
          e = e.replace(m[0], '');
          break;
        }
      }
    }

    this.xpath = this.matcher.join('');
    Selector._cache[this.expression] = this.xpath;
  },

  findElements: function(root) {
    root = root || document;
    if (this.xpath) return document._getElementsByXPath(this.xpath, root);
    return this.matcher(root);
  },

  match: function(element) {
    return this.findElements(document).include(element);
  },

  toString: function() {
    return this.expression;
  },

  inspect: function() {
    return "#<Selector:" + this.expression.inspect() + ">";
  }
};

Object.extend(Selector, {
  _cache: {},

  xpath: {
    descendant:   "//*",
    child:        "/*",
    adjacent:     "/following-sibling::*[1]",
    laterSibling: '/following-sibling::*',
    tagName:      function(m) {
      if (m[1] == '*') return '';
      return "[local-name()='" + m[1].toLowerCase() +
             "' or local-name()='" + m[1].toUpperCase() + "']";
    },
    className:    "[contains(concat(' ', @class, ' '), ' #{1} ')]",
    id:           "[@id='#{1}']",
    attrPresence: "[@#{1}]",
    attr: function(m) {
      m[3] = m[5] || m[6];
      return new Template(Selector.xpath.operators[m[2]]).evaluate(m);
    },
    pseudo: function(m) {
      var h = Selector.xpath.pseudos[m[1]];
      if (!h) return '';
      if (typeof h === 'function') return h(m);
      return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m);
    },
    operators: {
      '=':  "[@#{1}='#{3}']",
      '!=': "[@#{1}!='#{3}']",
      '^=': "[starts-with(@#{1}, '#{3}')]",
      '$=': "[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']",
      '*=': "[contains(@#{1}, '#{3}')]",
      '~=': "[contains(concat(' ', @#{1}, ' '), ' #{3} ')]",
      '|=': "[contains(concat('-', @#{1}, '-'), '-#{3}-')]"
    },
    pseudos: {
      'first-child': '[not(preceding-sibling::*)]',
      'last-child':  '[not(following-sibling::*)]',
      'only-child':  '[not(preceding-sibling::* or following-sibling::*)]',
      'empty':       "[count(*) = 0 and (count(text()) = 0 or translate(text(), ' \t\r\n', '') = '')]",
      'checked':     "[@checked]",
      'disabled':    "[@disabled]",
      'enabled':     "[not(@disabled)]",
      'not': function(m) {
        var e = m[6], p = Selector.patterns,
            x = Selector.xpath, le, m, v;

        var exclusion = [];
        while (e && le != e && (/\S/).test(e)) {
          le = e;
          for (var i in p) {
            if (m = e.match(p[i])) {
              v = typeof x[i] == 'function' ? x[i](m) : new Template(x[i]).evaluate(m);
              exclusion.push("(" + v.substring(1, v.length - 1) + ")");
              e = e.replace(m[0], '');
              break;
            }
          }
        }
        return "[not(" + exclusion.join(" and ") + ")]";
      },
      'nth-child':      function(m) {
        return Selector.xpath.pseudos.nth("(count(./preceding-sibling::*) + 1) ", m);
      },
      'nth-last-child': function(m) {
        return Selector.xpath.pseudos.nth("(count(./following-sibling::*) + 1) ", m);
      },
      'nth-of-type':    function(m) {
        return Selector.xpath.pseudos.nth("position() ", m);
      },
      'nth-last-of-type': function(m) {
        return Selector.xpath.pseudos.nth("(last() + 1 - position()) ", m);
      },
      'first-of-type':  function(m) {
        m[6] = "1"; return Selector.xpath.pseudos['nth-of-type'](m);
      },
      'last-of-type':   function(m) {
        m[6] = "1"; return Selector.xpath.pseudos['nth-last-of-type'](m);
      },
      'only-of-type':   function(m) {
        var p = Selector.xpath.pseudos; return p['first-of-type'](m) + p['last-of-type'](m);
      },
      nth: function(fragment, m) {
        var mm, formula = m[6], predicate;
        if (formula == 'even') formula = '2n+0';
        if (formula == 'odd')  formula = '2n+1';
        if (mm = formula.match(/^(\d+)$/)) // digit only
          return '[' + fragment + "= " + mm[1] + ']';
        if (mm = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
          if (mm[1] == "-") mm[1] = -1;
          var a = mm[1] ? Number(mm[1]) : 1;
          var b = mm[2] ? Number(mm[2]) : 0;
          predicate = "[((#{fragment} - #{b}) mod #{a} = 0) and " +
          "((#{fragment} - #{b}) div #{a} >= 0)]";
          return new Template(predicate).evaluate({
            fragment: fragment, a: a, b: b });
        }
      }
    }
  },

  criteria: {
    tagName:      'n = h.tagName(n, r, "#{1}", c);   c = false;',
    className:    'n = h.className(n, r, "#{1}", c); c = false;',
    id:           'n = h.id(n, r, "#{1}", c);        c = false;',
    attrPresence: 'n = h.attrPresence(n, r, "#{1}"); c = false;',
    attr: function(m) {
      m[3] = (m[5] || m[6]);
      return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}"); c = false;').evaluate(m);
    },
    pseudo:       function(m) {
      if (m[6]) m[6] = m[6].replace(/"/g, '\\"');
      return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m);
    },
    descendant:   'c = "descendant";',
    child:        'c = "child";',
    adjacent:     'c = "adjacent";',
    laterSibling: 'c = "laterSibling";'
  },

  patterns: {
    // combinators must be listed first
    // (and descendant needs to be last combinator)
    laterSibling: /^\s*~\s*/,
    child:        /^\s*>\s*/,
    adjacent:     /^\s*\+\s*/,
    descendant:   /^\s/,

    // selectors follow
    tagName:      /^\s*(\*|[\w\-]+)(\b|$)?/,
    id:           /^#([\w\-\*]+)(\b|$)/,
    className:    /^\.([\w\-\*]+)(\b|$)/,
    pseudo:       /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|\s)/,
    attrPresence: /^\[([\w]+)\]/,
    attr:         /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\]]*?)\4|([^'"][^\]]*?)))?\]/
  },

  handlers: {
    // UTILITY FUNCTIONS
    // joins two collections
    concat: function(a, b) {
      for (var i = 0, node; node = b[i]; i++)
        a.push(node);
      return a;
    },

    // marks an array of nodes for counting
    mark: function(nodes) {
      for (var i = 0, node; node = nodes[i]; i++)
        node._counted = true;
      return nodes;
    },

    unmark: function(nodes) {
      for (var i = 0, node; node = nodes[i]; i++)
        node._counted = undefined;
      return nodes;
    },

    // mark each child node with its position (for nth calls)
    // "ofType" flag indicates whether we're indexing for nth-of-type
    // rather than nth-child
    index: function(parentNode, reverse, ofType) {
      parentNode._counted = true;
      if (reverse) {
        for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) {
          node = nodes[i];
          if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++;
        }
      } else {
        for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++)
          if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++;
      }
    },

    // filters out duplicates and extends all nodes
    unique: function(nodes) {
      if (nodes.length == 0) return nodes;
      var results = [], n;
      for (var i = 0, l = nodes.length; i < l; i++)
        if (!(n = nodes[i])._counted) {
          n._counted = true;
          results.push(Element.extend(n));
        }
      return Selector.handlers.unmark(results);
    },

    // COMBINATOR FUNCTIONS
    descendant: function(nodes) {
      var h = Selector.handlers;
      for (var i = 0, results = [], node; node = nodes[i]; i++)
        h.concat(results, node.getElementsByTagName('*'));
      return results;
    },

    child: function(nodes) {
      var h = Selector.handlers;
      for (var i = 0, results = [], node; node = nodes[i]; i++) {
        for (var j = 0, children = [], child; child = node.childNodes[j]; j++)
          if (child.nodeType == 1 && child.tagName != '!') results.push(child);
      }
      return results;
    },

    adjacent: function(nodes) {
      for (var i = 0, results = [], node; node = nodes[i]; i++) {
        var next = this.nextElementSibling(node);
        if (next) results.push(next);
      }
      return results;
    },

    laterSibling: function(nodes) {
      var h = Selector.handlers;
      for (var i = 0, results = [], node; node = nodes[i]; i++)
        h.concat(results, Element.nextSiblings(node));
      return results;
    },

    nextElementSibling: function(node) {
      while (node = node.nextSibling)
	      if (node.nodeType == 1) return node;
      return null;
    },

    previousElementSibling: function(node) {
      while (node = node.previousSibling)
        if (node.nodeType == 1) return node;
      return null;
    },

    // TOKEN FUNCTIONS
    tagName: function(nodes, root, tagName, combinator) {
      tagName = tagName.toUpperCase();
      var results = [], h = Selector.handlers;
      if (nodes) {
        if (combinator) {
          // fastlane for ordinary descendant combinators
          if (combinator == "descendant") {
            for (var i = 0, node; node = nodes[i]; i++)
              h.concat(results, node.getElementsByTagName(tagName));
            return results;
          } else nodes = this[combinator](nodes);
          if (tagName == "*") return nodes;
        }
        for (var i = 0, node; node = nodes[i]; i++)
          if (node.tagName.toUpperCase() == tagName) results.push(node);
        return results;
      } else return root.getElementsByTagName(tagName);
    },

    id: function(nodes, root, id, combinator) {
      var targetNode = $(id), h = Selector.handlers;
      if (!nodes && root == document) return targetNode ? [targetNode] : [];
      if (nodes) {
        if (combinator) {
          if (combinator == 'child') {
            for (var i = 0, node; node = nodes[i]; i++)
              if (targetNode.parentNode == node) return [targetNode];
          } else if (combinator == 'descendant') {
            for (var i = 0, node; node = nodes[i]; i++)
              if (Element.descendantOf(targetNode, node)) return [targetNode];
          } else if (combinator == 'adjacent') {
            for (var i = 0, node; node = nodes[i]; i++)
              if (Selector.handlers.previousElementSibling(targetNode) == node)
                return [targetNode];
          } else nodes = h[combinator](nodes);
        }
        for (var i = 0, node; node = nodes[i]; i++)
          if (node == targetNode) return [targetNode];
        return [];
      }
      return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : [];
    },

    className: function(nodes, root, className, combinator) {
      if (nodes && combinator) nodes = this[combinator](nodes);
      return Selector.handlers.byClassName(nodes, root, className);
    },

    byClassName: function(nodes, root, className) {
      if (!nodes) nodes = Selector.handlers.descendant([root]);
      var needle = ' ' + className + ' ';
      for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) {
        nodeClassName = node.className;
        if (nodeClassName.length == 0) continue;
        if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle))
          results.push(node);
      }
      return results;
    },

    attrPresence: function(nodes, root, attr) {
      var results = [];
      for (var i = 0, node; node = nodes[i]; i++)
        if (Element.hasAttribute(node, attr)) results.push(node);
      return results;
    },

    attr: function(nodes, root, attr, value, operator) {
      if (!nodes) nodes = root.getElementsByTagName("*");
      var handler = Selector.operators[operator], results = [];
      for (var i = 0, node; node = nodes[i]; i++) {
        var nodeValue = Element.readAttribute(node, attr);
        if (nodeValue === null) continue;
        if (handler(nodeValue, value)) results.push(node);
      }
      return results;
    },

    pseudo: function(nodes, name, value, root, combinator) {
      if (nodes && combinator) nodes = this[combinator](nodes);
      if (!nodes) nodes = root.getElementsByTagName("*");
      return Selector.pseudos[name](nodes, value, root);
    }
  },

  pseudos: {
    'first-child': function(nodes, value, root) {
      for (var i = 0, results = [], node; node = nodes[i]; i++) {
        if (Selector.handlers.previousElementSibling(node)) continue;
          results.push(node);
      }
      return results;
    },
    'last-child': function(nodes, value, root) {
      for (var i = 0, results = [], node; node = nodes[i]; i++) {
        if (Selector.handlers.nextElementSibling(node)) continue;
          results.push(node);
      }
      return results;
    },
    'only-child': function(nodes, value, root) {
      var h = Selector.handlers;
      for (var i = 0, results = [], node; node = nodes[i]; i++)
        if (!h.previousElementSibling(node) && !h.nextElementSibling(node))
          results.push(node);
      return results;
    },
    'nth-child':        function(nodes, formula, root) {
      return Selector.pseudos.nth(nodes, formula, root);
    },
    'nth-last-child':   function(nodes, formula, root) {
      return Selector.pseudos.nth(nodes, formula, root, true);
    },
    'nth-of-type':      function(nodes, formula, root) {
      return Selector.pseudos.nth(nodes, formula, root, false, true);
    },
    'nth-last-of-type': function(nodes, formula, root) {
      return Selector.pseudos.nth(nodes, formula, root, true, true);
    },
    'first-of-type':    function(nodes, formula, root) {
      return Selector.pseudos.nth(nodes, "1", root, false, true);
    },
    'last-of-type':     function(nodes, formula, root) {
      return Selector.pseudos.nth(nodes, "1", root, true, true);
    },
    'only-of-type':     function(nodes, formula, root) {
      var p = Selector.pseudos;
      return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root);
    },

    // handles the an+b logic
    getIndices: function(a, b, total) {
      if (a == 0) return b > 0 ? [b] : [];
      return $R(1, total).inject([], function(memo, i) {
        if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i);
        return memo;
      });
    },

    // handles nth(-last)-child, nth(-last)-of-type, and (first|last)-of-type
    nth: function(nodes, formula, root, reverse, ofType) {
      if (nodes.length == 0) return [];
      if (formula == 'even') formula = '2n+0';
      if (formula == 'odd')  formula = '2n+1';
      var h = Selector.handlers, results = [], indexed = [], m;
      h.mark(nodes);
      for (var i = 0, node; node = nodes[i]; i++) {
        if (!node.parentNode._counted) {
          h.index(node.parentNode, reverse, ofType);
          indexed.push(node.parentNode);
        }
      }
      if (formula.match(/^\d+$/)) { // just a number
        formula = Number(formula);
        for (var i = 0, node; node = nodes[i]; i++)
          if (node.nodeIndex == formula) results.push(node);
      } else if (m = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
        if (m[1] == "-") m[1] = -1;
        var a = m[1] ? Number(m[1]) : 1;
        var b = m[2] ? Number(m[2]) : 0;
        var indices = Selector.pseudos.getIndices(a, b, nodes.length);
        for (var i = 0, node, l = indices.length; node = nodes[i]; i++) {
          for (var j = 0; j < l; j++)
            if (node.nodeIndex == indices[j]) results.push(node);
        }
      }
      h.unmark(nodes);
      h.unmark(indexed);
      return results;
    },

    'empty': function(nodes, value, root) {
      for (var i = 0, results = [], node; node = nodes[i]; i++) {
        // IE treats comments as element nodes
        if (node.tagName == '!' || (node.firstChild && !node.innerHTML.match(/^\s*$/))) continue;
        results.push(node);
      }
      return results;
    },

    'not': function(nodes, selector, root) {
      var h = Selector.handlers, selectorType, m;
      var exclusions = new Selector(selector).findElements(root);
      h.mark(exclusions);
      for (var i = 0, results = [], node; node = nodes[i]; i++)
        if (!node._counted) results.push(node);
      h.unmark(exclusions);
      return results;
    },

    'enabled': function(nodes, value, root) {
      for (var i = 0, results = [], node; node = nodes[i]; i++)
        if (!node.disabled) results.push(node);
      return results;
    },

    'disabled': function(nodes, value, root) {
      for (var i = 0, results = [], node; node = nodes[i]; i++)
        if (node.disabled) results.push(node);
      return results;
    },

    'checked': function(nodes, value, root) {
      for (var i = 0, results = [], node; node = nodes[i]; i++)
        if (node.checked) results.push(node);
      return results;
    }
  },

  operators: {
    '=':  function(nv, v) { return nv == v; },
    '!=': function(nv, v) { return nv != v; },
    '^=': function(nv, v) { return nv.startsWith(v); },
    '$=': function(nv, v) { return nv.endsWith(v); },
    '*=': function(nv, v) { return nv.include(v); },
    '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); },
    '|=': function(nv, v) { return ('-' + nv.toUpperCase() + '-').include('-' + v.toUpperCase() + '-'); }
  },

  matchElements: function(elements, expression) {
    var matches = new Selector(expression).findElements(), h = Selector.handlers;
    h.mark(matches);
    for (var i = 0, results = [], element; element = elements[i]; i++)
      if (element._counted) results.push(element);
    h.unmark(matches);
    return results;
  },

  findElement: function(elements, expression, index) {
    if (typeof expression == 'number') {
      index = expression; expression = false;
    }
    return Selector.matchElements(elements, expression || '*')[index || 0];
  },

  findChildElements: function(element, expressions) {
    var exprs = expressions.join(','), expressions = [];
    exprs.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) {
      expressions.push(m[1].strip());
    });
    var results = [], h = Selector.handlers;
    for (var i = 0, l = expressions.length, selector; i < l; i++) {
      selector = new Selector(expressions[i].strip());
      h.concat(results, selector.findElements(element));
    }
    return (l > 1) ? h.unique(results) : results;
  }
});

function $$() {
  return Selector.findChildElements(document, $A(arguments));
}
var Form = {
  reset: function(form) {
    $(form).reset();
    return form;
  },

  serializeElements: function(elements, getHash) {
    var data = elements.inject({}, function(result, element) {
      if (!element.disabled && element.name) {
        var key = element.name, value = $(element).getValue();
        if (value != null) {
         	if (key in result) {
            if (result[key].constructor != Array) result[key] = [result[key]];
            result[key].push(value);
          }
          else result[key] = value;
        }
      }
      return result;
    });

    return getHash ? data : Hash.toQueryString(data);
  }
};

Form.Methods = {
  serialize: function(form, getHash) {
    return Form.serializeElements(Form.getElements(form), getHash);
  },

  getElements: function(form) {
    return $A($(form).getElementsByTagName('*')).inject([],
      function(elements, child) {
        if (Form.Element.Serializers[child.tagName.toLowerCase()])
          elements.push(Element.extend(child));
        return elements;
      }
    );
  },

  getInputs: function(form, typeName, name) {
    form = $(form);
    var inputs = form.getElementsByTagName('input');

    if (!typeName && !name) return $A(inputs).map(Element.extend);

    for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) {
      var input = inputs[i];
      if ((typeName && input.type != typeName) || (name && input.name != name))
        continue;
      matchingInputs.push(Element.extend(input));
    }

    return matchingInputs;
  },

  disable: function(form) {
    form = $(form);
    Form.getElements(form).invoke('disable');
    return form;
  },

  enable: function(form) {
    form = $(form);
    Form.getElements(form).invoke('enable');
    return form;
  },

  findFirstElement: function(form) {
    return $(form).getElements().find(function(element) {
      return element.type != 'hidden' && !element.disabled &&
        ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
    });
  },

  focusFirstElement: function(form) {
    form = $(form);
    form.findFirstElement().activate();
    return form;
  },

  request: function(form, options) {
    form = $(form), options = Object.clone(options || {});

    var params = options.parameters;
    options.parameters = form.serialize(true);

    if (params) {
      if (typeof params == 'string') params = params.toQueryParams();
      Object.extend(options.parameters, params);
    }

    if (form.hasAttribute('method') && !options.method)
      options.method = form.method;

    return new Ajax.Request(form.readAttribute('action'), options);
  }
}

Object.extend(Form, Form.Methods);

/*--------------------------------------------------------------------------*/

Form.Element = {
  focus: function(element) {
    $(element).focus();
    return element;
  },

  select: function(element) {
    $(element).select();
    return element;
  }
}

Form.Element.Methods = {
  serialize: function(element) {
    element = $(element);
    if (!element.disabled && element.name) {
      var value = element.getValue();
      if (value != undefined) {
        var pair = {};
        pair[element.name] = value;
        return Hash.toQueryString(pair);
      }
    }
    return '';
  },

  getValue: function(element) {
    element = $(element);
    var method = element.tagName.toLowerCase();
    return Form.Element.Serializers[method](element);
  },

  clear: function(element) {
    $(element).value = '';
    return element;
  },

  present: function(element) {
    return $(element).value != '';
  },

  activate: function(element) {
    element = $(element);
    try {
      element.focus();
      if (element.select && (element.tagName.toLowerCase() != 'input' ||
        !['button', 'reset', 'submit'].include(element.type)))
        element.select();
    } catch (e) {}
    return element;
  },

  disable: function(element) {
    element = $(element);
    element.blur();
    element.disabled = true;
    return element;
  },

  enable: function(element) {
    element = $(element);
    element.disabled = false;
    return element;
  }
}

Object.extend(Form.Element, Form.Element.Methods);
Object.extend(Element.Methods.ByTag, {
  "FORM":     Object.clone(Form.Methods),
  "INPUT":    Object.clone(Form.Element.Methods),
  "SELECT":   Object.clone(Form.Element.Methods),
  "TEXTAREA": Object.clone(Form.Element.Methods)
});

/*--------------------------------------------------------------------------*/

var Field = Form.Element;
var $F = Form.Element.getValue;

/*--------------------------------------------------------------------------*/

Form.Element.Serializers = {
  input: function(element) {
    switch (element.type.toLowerCase()) {
      case 'checkbox':
      case 'radio':
        return Form.Element.Serializers.inputSelector(element);
      default:
        return Form.Element.Serializers.textarea(element);
    }
  },

  inputSelector: function(element) {
    return element.checked ? element.value : null;
  },

  textarea: function(element) {
    return element.value;
  },

  select: function(element) {
    return this[element.type == 'select-one' ?
      'selectOne' : 'selectMany'](element);
  },

  selectOne: function(element) {
    var index = element.selectedIndex;
    return index >= 0 ? this.optionValue(element.options[index]) : null;
  },

  selectMany: function(element) {
    var values, length = element.length;
    if (!length) return null;

    for (var i = 0, values = []; i < length; i++) {
      var opt = element.options[i];
      if (opt.selected) values.push(this.optionValue(opt));
    }
    return values;
  },

  optionValue: function(opt) {
    // extend element because hasAttribute may not be native
    return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text;
  }
}

/*--------------------------------------------------------------------------*/

Abstract.TimedObserver = function() {}
Abstract.TimedObserver.prototype = {
  initialize: function(element, frequency, callback) {
    this.frequency = frequency;
    this.element   = $(element);
    this.callback  = callback;

    this.lastValue = this.getValue();
    this.registerCallback();
  },

  registerCallback: function() {
    setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
  },

  onTimerEvent: function() {
    var value = this.getValue();
    var changed = ('string' == typeof this.lastValue && 'string' == typeof value
      ? this.lastValue != value : String(this.lastValue) != String(value));
    if (changed) {
      this.callback(this.element, value);
      this.lastValue = value;
    }
  }
}

Form.Element.Observer = Class.create();
Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
  getValue: function() {
    return Form.Element.getValue(this.element);
  }
});

Form.Observer = Class.create();
Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
  getValue: function() {
    return Form.serialize(this.element);
  }
});

/*--------------------------------------------------------------------------*/

Abstract.EventObserver = function() {}
Abstract.EventObserver.prototype = {
  initialize: function(element, callback) {
    this.element  = $(element);
    this.callback = callback;

    this.lastValue = this.getValue();
    if (this.element.tagName.toLowerCase() == 'form')
      this.registerFormCallbacks();
    else
      this.registerCallback(this.element);
  },

  onElementEvent: function() {
    var value = this.getValue();
    if (this.lastValue != value) {
      this.callback(this.element, value);
      this.lastValue = value;
    }
  },

  registerFormCallbacks: function() {
    Form.getElements(this.element).each(this.registerCallback.bind(this));
  },

  registerCallback: function(element) {
    if (element.type) {
      switch (element.type.toLowerCase()) {
        case 'checkbox':
        case 'radio':
          Event.observe(element, 'click', this.onElementEvent.bind(this));
          break;
        default:
          Event.observe(element, 'change', this.onElementEvent.bind(this));
          break;
      }
    }
  }
}

Form.Element.EventObserver = Class.create();
Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
  getValue: function() {
    return Form.Element.getValue(this.element);
  }
});

Form.EventObserver = Class.create();
Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
  getValue: function() {
    return Form.serialize(this.element);
  }
});
if (!window.Event) {
  var Event = new Object();
}

Object.extend(Event, {
  KEY_BACKSPACE: 8,
  KEY_TAB:       9,
  KEY_RETURN:   13,
  KEY_ESC:      27,
  KEY_LEFT:     37,
  KEY_UP:       38,
  KEY_RIGHT:    39,
  KEY_DOWN:     40,
  KEY_DELETE:   46,
  KEY_HOME:     36,
  KEY_END:      35,
  KEY_PAGEUP:   33,
  KEY_PAGEDOWN: 34,

  element: function(event) {
    return $(event.target || event.srcElement);
  },

  isLeftClick: function(event) {
    return (((event.which) && (event.which == 1)) ||
            ((event.button) && (event.button == 1)));
  },

  pointerX: function(event) {
    return event.pageX || (event.clientX +
      (document.documentElement.scrollLeft || document.body.scrollLeft));
  },

  pointerY: function(event) {
    return event.pageY || (event.clientY +
      (document.documentElement.scrollTop || document.body.scrollTop));
  },

  stop: function(event) {
    if (event.preventDefault) {
      event.preventDefault();
      event.stopPropagation();
    } else {
      event.returnValue = false;
      event.cancelBubble = true;
    }
  },

  // find the first node with the given tagName, starting from the
  // node the event was triggered on; traverses the DOM upwards
  findElement: function(event, tagName) {
    var element = Event.element(event);
    while (element.parentNode && (!element.tagName ||
        (element.tagName.toUpperCase() != tagName.toUpperCase())))
      element = element.parentNode;
    return element;
  },

  observers: false,

  _observeAndCache: function(element, name, observer, useCapture) {
    if (!this.observers) this.observers = [];
    if (element.addEventListener) {
      this.observers.push([element, name, observer, useCapture]);
      element.addEventListener(name, observer, useCapture);
    } else if (element.attachEvent) {
      this.observers.push([element, name, observer, useCapture]);
      element.attachEvent('on' + name, observer);
    }
  },

  unloadCache: function() {
    if (!Event.observers) return;
    for (var i = 0, length = Event.observers.length; i < length; i++) {
      Event.stopObserving.apply(this, Event.observers[i]);
      Event.observers[i][0] = null;
    }
    Event.observers = false;
  },

  observe: function(element, name, observer, useCapture) {
    element = $(element);
    useCapture = useCapture || false;

    if (name == 'keypress' &&
      (Prototype.Browser.WebKit || element.attachEvent))
      name = 'keydown';

    Event._observeAndCache(element, name, observer, useCapture);
  },

  stopObserving: function(element, name, observer, useCapture) {
    element = $(element);
    useCapture = useCapture || false;

    if (name == 'keypress' &&
        (Prototype.Browser.WebKit || element.attachEvent))
      name = 'keydown';

    if (element.removeEventListener) {
      element.removeEventListener(name, observer, useCapture);
    } else if (element.detachEvent) {
      try {
        element.detachEvent('on' + name, observer);
      } catch (e) {}
    }
  }
});

/* prevent memory leaks in IE */
if (Prototype.Browser.IE)
  Event.observe(window, 'unload', Event.unloadCache, false);
var Position = {
  // set to true if needed, warning: firefox performance problems
  // NOT neeeded for page scrolling, only if draggable contained in
  // scrollable elements
  includeScrollOffsets: false,

  // must be called before calling withinIncludingScrolloffset, every time the
  // page is scrolled
  prepare: function() {
    this.deltaX =  window.pageXOffset
                || document.documentElement.scrollLeft
                || document.body.scrollLeft
                || 0;
    this.deltaY =  window.pageYOffset
                || document.documentElement.scrollTop
                || document.body.scrollTop
                || 0;
  },

  realOffset: function(element) {
    var valueT = 0, valueL = 0;
    do {
      valueT += element.scrollTop  || 0;
      valueL += element.scrollLeft || 0;
      element = element.parentNode;
    } while (element);
    return [valueL, valueT];
  },

  cumulativeOffset: function(element) {
    var valueT = 0, valueL = 0;
    do {
      valueT += element.offsetTop  || 0;
      valueL += element.offsetLeft || 0;
      element = element.offsetParent;
    } while (element);
    return [valueL, valueT];
  },

  positionedOffset: function(element) {
    var valueT = 0, valueL = 0;
    do {
      valueT += element.offsetTop  || 0;
      valueL += element.offsetLeft || 0;
      element = element.offsetParent;
      if (element) {
        if(element.tagName=='BODY') break;
        var p = Element.getStyle(element, 'position');
        if (p == 'relative' || p == 'absolute') break;
      }
    } while (element);
    return [valueL, valueT];
  },

  offsetParent: function(element) {
    if (element.offsetParent) return element.offsetParent;
    if (element == document.body) return element;

    while ((element = element.parentNode) && element != document.body)
      if (Element.getStyle(element, 'position') != 'static')
        return element;

    return document.body;
  },

  // caches x/y coordinate pair to use with overlap
  within: function(element, x, y) {
    if (this.includeScrollOffsets)
      return this.withinIncludingScrolloffsets(element, x, y);
    this.xcomp = x;
    this.ycomp = y;
    this.offset = this.cumulativeOffset(element);

    return (y >= this.offset[1] &&
            y <  this.offset[1] + element.offsetHeight &&
            x >= this.offset[0] &&
            x <  this.offset[0] + element.offsetWidth);
  },

  withinIncludingScrolloffsets: function(element, x, y) {
    var offsetcache = this.realOffset(element);

    this.xcomp = x + offsetcache[0] - this.deltaX;
    this.ycomp = y + offsetcache[1] - this.deltaY;
    this.offset = this.cumulativeOffset(element);

    return (this.ycomp >= this.offset[1] &&
            this.ycomp <  this.offset[1] + element.offsetHeight &&
            this.xcomp >= this.offset[0] &&
            this.xcomp <  this.offset[0] + element.offsetWidth);
  },

  // within must be called directly before
  overlap: function(mode, element) {
    if (!mode) return 0;
    if (mode == 'vertical')
      return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
        element.offsetHeight;
    if (mode == 'horizontal')
      return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
        element.offsetWidth;
  },

  page: function(forElement) {
    var valueT = 0, valueL = 0;

    var element = forElement;
    do {
      valueT += element.offsetTop  || 0;
      valueL += element.offsetLeft || 0;

      // Safari fix
      if (element.offsetParent == document.body)
        if (Element.getStyle(element,'position')=='absolute') break;

    } while (element = element.offsetParent);

    element = forElement;
    do {
      if (!window.opera || element.tagName=='BODY') {
        valueT -= element.scrollTop  || 0;
        valueL -= element.scrollLeft || 0;
      }
    } while (element = element.parentNode);

    return [valueL, valueT];
  },

  clone: function(source, target) {
    var options = Object.extend({
      setLeft:    true,
      setTop:     true,
      setWidth:   true,
      setHeight:  true,
      offsetTop:  0,
      offsetLeft: 0
    }, arguments[2] || {})

    // find page position of source
    source = $(source);
    var p = Position.page(source);

    // find coordinate system to use
    target = $(target);
    var delta = [0, 0];
    var parent = null;
    // delta [0,0] will do fine with position: fixed elements,
    // position:absolute needs offsetParent deltas
    if (Element.getStyle(target,'position') == 'absolute') {
      parent = Position.offsetParent(target);
      delta = Position.page(parent);
    }

    // correct by body offsets (fixes Safari)
    if (parent == document.body) {
      delta[0] -= document.body.offsetLeft;
      delta[1] -= document.body.offsetTop;
    }

    // set position
    if(options.setLeft)   target.style.left  = (p[0] - delta[0] + options.offsetLeft) + 'px';
    if(options.setTop)    target.style.top   = (p[1] - delta[1] + options.offsetTop) + 'px';
    if(options.setWidth)  target.style.width = source.offsetWidth + 'px';
    if(options.setHeight) target.style.height = source.offsetHeight + 'px';
  },

  absolutize: function(element) {
    element = $(element);
    if (element.style.position == 'absolute') return;
    Position.prepare();

    var offsets = Position.positionedOffset(element);
    var top     = offsets[1];
    var left    = offsets[0];
    var width   = element.clientWidth;
    var height  = element.clientHeight;

    element._originalLeft   = left - parseFloat(element.style.left  || 0);
    element._originalTop    = top  - parseFloat(element.style.top || 0);
    element._originalWidth  = element.style.width;
    element._originalHeight = element.style.height;

    element.style.position = 'absolute';
    element.style.top    = top + 'px';
    element.style.left   = left + 'px';
    element.style.width  = width + 'px';
    element.style.height = height + 'px';
  },

  relativize: function(element) {
    element = $(element);
    if (element.style.position == 'relative') return;
    Position.prepare();

    element.style.position = 'relative';
    var top  = parseFloat(element.style.top  || 0) - (element._originalTop || 0);
    var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);

    element.style.top    = top + 'px';
    element.style.left   = left + 'px';
    element.style.height = element._originalHeight;
    element.style.width  = element._originalWidth;
  }
}

// Safari returns margins on body which is incorrect if the child is absolutely
// positioned.  For performance reasons, redefine Position.cumulativeOffset for
// KHTML/WebKit only.
if (Prototype.Browser.WebKit) {
  Position.cumulativeOffset = function(element) {
    var valueT = 0, valueL = 0;
    do {
      valueT += element.offsetTop  || 0;
      valueL += element.offsetLeft || 0;
      if (element.offsetParent == document.body)
        if (Element.getStyle(element, 'position') == 'absolute') break;

      element = element.offsetParent;
    } while (element);

    return [valueL, valueT];
  }
}

Element.addMethods();// Copyright (c) 2006 Sebastien Gruhier (http://xilinus.com, http://itseb.com)
// 
// 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.
//
// VERSION 1.3

var Window = Class.create();

Window.keepMultiModalWindow = false;
Window.hasEffectLib = (typeof Effect != 'undefined');
Window.resizeEffectDuration = 0.4;

Window.prototype = {
  // Constructor
  // Available parameters : className, blurClassName, title, minWidth, minHeight, maxWidth, maxHeight, width, height, top, left, bottom, right, resizable, zIndex, opacity, recenterAuto, wiredDrag
  //                        hideEffect, showEffect, showEffectOptions, hideEffectOptions, effectOptions, url, draggable, closable, minimizable, maximizable, parent, onload
  //                        add all callbacks (if you do not use an observer)
  //                        onDestroy onStartResize onStartMove onResize onMove onEndResize onEndMove onFocus onBlur onBeforeShow onShow onHide onMinimize onMaximize onClose
  
  initialize: function() {
    var id;
    var optionIndex = 0;
    // For backward compatibility like win= new Window("id", {...}) instead of win = new Window({id: "id", ...})
    if (arguments.length > 0) {
      if (typeof arguments[0] == "string" ) {
        id = arguments[0];
        optionIndex = 1;
      }
      else
        id = arguments[0] ? arguments[0].id : null;
    }
    
    // Generate unique ID if not specified
    if (!id)
      id = "window_" + new Date().getTime();
      
    if ($(id))
      alert("Window " + id + " is already registered in the DOM! Make sure you use setDestroyOnClose() or destroyOnClose: true in the constructor");

    this.options = Object.extend({
      className:         "dialog",
      blurClassName:     null,
      minWidth:          100, 
      minHeight:         20,
      resizable:         true,
      closable:          true,
      minimizable:       true,
      maximizable:       true,
      draggable:         true,
      userData:          null,
      showEffect:        (Window.hasEffectLib ? Effect.Appear : Element.show),
      hideEffect:        (Window.hasEffectLib ? Effect.Fade : Element.hide),
      showEffectOptions: {},
      hideEffectOptions: {},
      effectOptions:     null,
      parent:            document.body,
      title:             "&nbsp;",
      url:               null,
      onload:            Prototype.emptyFunction,
      width:             200,
      height:            300,
      opacity:           1,
      recenterAuto:      true,
      wiredDrag:         false,
      closeCallback:     null,
      destroyOnClose:    false,
      gridX:             1, 
      gridY:             1      
    }, arguments[optionIndex] || {});
    if (this.options.blurClassName)
      this.options.focusClassName = this.options.className;
      
    if (typeof this.options.top == "undefined" &&  typeof this.options.bottom ==  "undefined") 
      this.options.top = this._round(Math.random()*500, this.options.gridY);
    if (typeof this.options.left == "undefined" &&  typeof this.options.right ==  "undefined") 
      this.options.left = this._round(Math.random()*500, this.options.gridX);

    if (this.options.effectOptions) {
      Object.extend(this.options.hideEffectOptions, this.options.effectOptions);
      Object.extend(this.options.showEffectOptions, this.options.effectOptions);
      if (this.options.showEffect == Element.Appear)
        this.options.showEffectOptions.to = this.options.opacity;
    }
    if (Window.hasEffectLib) {
      if (this.options.showEffect == Effect.Appear)
        this.options.showEffectOptions.to = this.options.opacity;
    
      if (this.options.hideEffect == Effect.Fade)
        this.options.hideEffectOptions.from = this.options.opacity;
    }
    if (this.options.hideEffect == Element.hide)
      this.options.hideEffect = function(){ Element.hide(this.element); if (this.options.destroyOnClose) this.destroy(); }.bind(this)
    
    if (this.options.parent != document.body)  
      this.options.parent = $(this.options.parent);
      
    this.element = this._createWindow(id);       
    this.element.win = this;
    
    // Bind event listener
    this.eventMouseDown = this._initDrag.bindAsEventListener(this);
    this.eventMouseUp   = this._endDrag.bindAsEventListener(this);
    this.eventMouseMove = this._updateDrag.bindAsEventListener(this);
    this.eventOnLoad    = this._getWindowBorderSize.bindAsEventListener(this);
    this.eventMouseDownContent = this.toFront.bindAsEventListener(this);
    this.eventResize = this._recenter.bindAsEventListener(this);
 
    this.topbar = $(this.element.id + "_top");
    this.bottombar = $(this.element.id + "_bottom");
    this.content = $(this.element.id + "_content");
    
    Event.observe(this.topbar, "mousedown", this.eventMouseDown);
    Event.observe(this.bottombar, "mousedown", this.eventMouseDown);
    Event.observe(this.content, "mousedown", this.eventMouseDownContent);
    Event.observe(window, "load", this.eventOnLoad);
    Event.observe(window, "resize", this.eventResize);
    Event.observe(window, "scroll", this.eventResize);
    Event.observe(this.options.parent, "scroll", this.eventResize);
    
    if (this.options.draggable)  {
      var that = this;
      [this.topbar, this.topbar.up().previous(), this.topbar.up().next()].each(function(element) {
        element.observe("mousedown", that.eventMouseDown);
        element.addClassName("top_draggable");
      });
      [this.bottombar.up(), this.bottombar.up().previous(), this.bottombar.up().next()].each(function(element) {
        element.observe("mousedown", that.eventMouseDown);
        element.addClassName("bottom_draggable");
      });
      
    }    
    
    if (this.options.resizable) {
      this.sizer = $(this.element.id + "_sizer");
      Event.observe(this.sizer, "mousedown", this.eventMouseDown);
    }  
    
    this.useLeft = null;
    this.useTop = null;
    if (typeof this.options.left != "undefined") {
      this.element.setStyle({left: parseFloat(this.options.left) + 'px'});
      this.useLeft = true;
    }
    else {
      this.element.setStyle({right: parseFloat(this.options.right) + 'px'});
      this.useLeft = false;
    }
    
    if (typeof this.options.top != "undefined") {
      this.element.setStyle({top: parseFloat(this.options.top) + 'px'});
      this.useTop = true;
    }
    else {
      this.element.setStyle({bottom: parseFloat(this.options.bottom) + 'px'});      
      this.useTop = false;
    }
      
    this.storedLocation = null;
    
    this.setOpacity(this.options.opacity);
    if (this.options.zIndex)
      this.setZIndex(this.options.zIndex)

    if (this.options.destroyOnClose)
      this.setDestroyOnClose(true);

    this._getWindowBorderSize();
    this.width = this.options.width;
    this.height = this.options.height;
    this.visible = false;
    
    this.constraint = false;
    this.constraintPad = {top: 0, left:0, bottom:0, right:0};
    
    if (this.width && this.height)
      this.setSize(this.options.width, this.options.height);
    this.setTitle(this.options.title)
    Windows.register(this);      
  },
  
  // Destructor
  destroy: function() {
    this._notify("onDestroy");
    Event.stopObserving(this.topbar, "mousedown", this.eventMouseDown);
    Event.stopObserving(this.bottombar, "mousedown", this.eventMouseDown);
    Event.stopObserving(this.content, "mousedown", this.eventMouseDownContent);
    
    Event.stopObserving(window, "load", this.eventOnLoad);
    Event.stopObserving(window, "resize", this.eventResize);
    Event.stopObserving(window, "scroll", this.eventResize);
    
    Event.stopObserving(this.content, "load", this.options.onload);

    if (this._oldParent) {
      var content = this.getContent();
      var originalContent = null;
      for(var i = 0; i < content.childNodes.length; i++) {
        originalContent = content.childNodes[i];
        if (originalContent.nodeType == 1) 
          break;
        originalContent = null;
      }
      if (originalContent)
        this._oldParent.appendChild(originalContent);
      this._oldParent = null;
    }

    if (this.sizer)
        Event.stopObserving(this.sizer, "mousedown", this.eventMouseDown);

	/* comentado para resolver problema al hacer refresh en movilsat
    if (this.options.url) 
      this.content.src = null */

     if(this.iefix) 
      Element.remove(this.iefix);

    Element.remove(this.element);
    Windows.unregister(this);      
  },
    
  // Sets close callback, if it sets, it should return true to be able to close the window.
  setCloseCallback: function(callback) {
    this.options.closeCallback = callback;
  },
  
  // Gets window content
  getContent: function () {
    return this.content;
  },
  
  // Sets the content with an element id
  setContent: function(id, autoresize, autoposition) {
    var element = $(id);
    if (null == element) throw "Unable to find element '" + id + "' in DOM";
    this._oldParent = element.parentNode;

    var d = null;
    var p = null;

    if (autoresize) 
      d = Element.getDimensions(element);
    if (autoposition) 
      p = Position.cumulativeOffset(element);

    var content = this.getContent();
    // Clear HTML (and even iframe)
    this.setHTMLContent("");
    content = this.getContent();
    
    content.appendChild(element);
    element.show();
    if (autoresize) 
      this.setSize(d.width, d.height);
    if (autoposition) 
      this.setLocation(p[1] - this.heightN, p[0] - this.widthW);    
  },
  
  setHTMLContent: function(html) {
    // It was an url (iframe), recreate a div content instead of iframe content
    if (this.options.url) {
      this.content.src = null;
      this.options.url = null;
      
  	  var content ="<div id=\"" + this.getId() + "_content\" class=\"" + this.options.className + "_content\"> </div>";
      $(this.getId() +"_table_content").innerHTML = content;
      
      this.content = $(this.element.id + "_content");
    }
      
    this.getContent().innerHTML = html;
  },
  
  setAjaxContent: function(url, options, showCentered, showModal) {
    this.showFunction = showCentered ? "showCenter" : "show";
    this.showModal = showModal || false;
  
    options = options || {};

    // Clear HTML (and even iframe)
    this.setHTMLContent("");
 
    this.onComplete = options.onComplete;
    if (! this._onCompleteHandler)
      this._onCompleteHandler = this._setAjaxContent.bind(this);
    options.onComplete = this._onCompleteHandler;

    new Ajax.Request(url, options);    
    options.onComplete = this.onComplete;
  },
  
  _setAjaxContent: function(originalRequest) {
    Element.update(this.getContent(), originalRequest.responseText);
    if (this.onComplete)
      this.onComplete(originalRequest);
    this.onComplete = null;
    this[this.showFunction](this.showModal)
  },
  
  setURL: function(url) {
    // Not an url content, change div to iframe
    if (this.options.url) 
      this.content.src = null;
    this.options.url = url;
    var content= "<iframe frameborder='0' name='" + this.getId() + "_content'  id='" + this.getId() + "_content' src='" + url + "' width='" + this.width + "' height='" + this.height + "'> </iframe>";
    $(this.getId() +"_table_content").innerHTML = content;
    
    this.content = $(this.element.id + "_content");
  },

  getURL: function() {
  	return this.options.url ? this.options.url : null;
  },

  refresh: function() {
    if (this.options.url)
	    $(this.element.getAttribute('id') + '_content').src = this.options.url;
  },
  
  // Stores position/size in a cookie, by default named with window id
  setCookie: function(name, expires, path, domain, secure) {
    name = name || this.element.id;
    this.cookie = [name, expires, path, domain, secure];
    
    // Get cookie
    var value = WindowUtilities.getCookie(name)
    // If exists
    if (value) {
      var values = value.split(',');
      var x = values[0].split(':');
      var y = values[1].split(':');

      var w = parseFloat(values[2]), h = parseFloat(values[3]);
      var mini = values[4];
      var maxi = values[5];

      this.setSize(w, h);
      if (mini == "true")
        this.doMinimize = true; // Minimize will be done at onload window event
      else if (maxi == "true")
        this.doMaximize = true; // Maximize will be done at onload window event

      this.useLeft = x[0] == "l";
      this.useTop = y[0] == "t";

      this.element.setStyle(this.useLeft ? {left: x[1]} : {right: x[1]});
      this.element.setStyle(this.useTop ? {top: y[1]} : {bottom: y[1]});
    }
  },
  
  // Gets window ID
  getId: function() {
    return this.element.id;
  },
  
  // Detroys itself when closing 
  setDestroyOnClose: function() {
    this.options.destroyOnClose = true;
  },
  
  setConstraint: function(bool, padding) {
    this.constraint = bool;
    this.constraintPad = Object.extend(this.constraintPad, padding || {});
    // Reset location to apply constraint
    if (this.useTop && this.useLeft)
      this.setLocation(parseFloat(this.element.style.top), parseFloat(this.element.style.left));
  },
  
  // initDrag event

  _initDrag: function(event) {
    // No resize on minimized window
    if (Event.element(event) == this.sizer && this.isMinimized())
      return;

    // No move on maximzed window
    if (Event.element(event) != this.sizer && this.isMaximized())
      return;
      
    if (Prototype.Browser.IE && this.heightN == 0)
      this._getWindowBorderSize();
    
    // Get pointer X,Y
    this.pointer = [this._round(Event.pointerX(event), this.options.gridX), this._round(Event.pointerY(event), this.options.gridY)];
    if (this.options.wiredDrag) 
      this.currentDrag = this._createWiredElement();
    else
      this.currentDrag = this.element;
      
    // Resize
    if (Event.element(event) == this.sizer) {
      this.doResize = true;
      this.widthOrg = this.width;
      this.heightOrg = this.height;
      this.bottomOrg = parseFloat(this.element.getStyle('bottom'));
      this.rightOrg = parseFloat(this.element.getStyle('right'));
      this._notify("onStartResize");
    }
    else {
      this.doResize = false;

      // Check if click on close button, 
      var closeButton = $(this.getId() + '_close');
      if (closeButton && Position.within(closeButton, this.pointer[0], this.pointer[1])) {
        this.currentDrag = null;
        return;
      }

      this.toFront();

      if (! this.options.draggable) 
        return;
      this._notify("onStartMove");
    }    
    // Register global event to capture mouseUp and mouseMove
    Event.observe(document, "mouseup", this.eventMouseUp, false);
    Event.observe(document, "mousemove", this.eventMouseMove, false);
    
    // Add an invisible div to keep catching mouse event over iframes
    WindowUtilities.disableScreen('__invisible__', '__invisible__', this.overlayOpacity);

    // Stop selection while dragging
    document.body.ondrag = function () { return false; };
    document.body.onselectstart = function () { return false; };
    
    this.currentDrag.show();
    Event.stop(event);
  },
  
  _round: function(val, round) {
    return round == 1 ? val  : val = Math.floor(val / round) * round;
  },

  // updateDrag event
  _updateDrag: function(event) {
    var pointer =  [this._round(Event.pointerX(event), this.options.gridX), this._round(Event.pointerY(event), this.options.gridY)];  
    var dx = pointer[0] - this.pointer[0];
    var dy = pointer[1] - this.pointer[1];
    
    // Resize case, update width/height
    if (this.doResize) {
      var w = this.widthOrg + dx;
      var h = this.heightOrg + dy;
      
      dx = this.width - this.widthOrg
      dy = this.height - this.heightOrg
      
      // Check if it's a right position, update it to keep upper-left corner at the same position
      if (this.useLeft) 
        w = this._updateWidthConstraint(w)
      else 
        this.currentDrag.setStyle({right: (this.rightOrg -dx) + 'px'});
      // Check if it's a bottom position, update it to keep upper-left corner at the same position
      if (this.useTop) 
        h = this._updateHeightConstraint(h)
      else
        this.currentDrag.setStyle({bottom: (this.bottomOrg -dy) + 'px'});
        
      this.setSize(w , h);
      this._notify("onResize");
    }
    // Move case, update top/left
    else {
      this.pointer = pointer;
      
      if (this.useLeft) {
        var left =  parseFloat(this.currentDrag.getStyle('left')) + dx;
        var newLeft = this._updateLeftConstraint(left);
        // Keep mouse pointer correct
        this.pointer[0] += newLeft-left;
        this.currentDrag.setStyle({left: newLeft + 'px'});
      }
      else 
        this.currentDrag.setStyle({right: parseFloat(this.currentDrag.getStyle('right')) - dx + 'px'});
      
      if (this.useTop) {
        var top =  parseFloat(this.currentDrag.getStyle('top')) + dy;
        var newTop = this._updateTopConstraint(top);
        // Keep mouse pointer correct
        this.pointer[1] += newTop - top;
        this.currentDrag.setStyle({top: newTop + 'px'});
      }
      else 
        this.currentDrag.setStyle({bottom: parseFloat(this.currentDrag.getStyle('bottom')) - dy + 'px'});

      this._notify("onMove");
    }
    if (this.iefix) 
      this._fixIEOverlapping(); 
      
    this._removeStoreLocation();
    Event.stop(event);
  },

   // endDrag callback
   _endDrag: function(event) {
    // Remove temporary div over iframes
     WindowUtilities.enableScreen('__invisible__');
    
    if (this.doResize)
      this._notify("onEndResize");
    else
      this._notify("onEndMove");
    
    // Release event observing
    Event.stopObserving(document, "mouseup", this.eventMouseUp,false);
    Event.stopObserving(document, "mousemove", this.eventMouseMove, false);

    Event.stop(event);
    
    this._hideWiredElement();

    // Store new location/size if need be
    this._saveCookie()
      
    // Restore selection
    document.body.ondrag = null;
    document.body.onselectstart = null;
  },

  _updateLeftConstraint: function(left) {
    if (this.constraint && this.useLeft && this.useTop) {
      var width = this.options.parent == document.body ? WindowUtilities.getPageSize().windowWidth : this.options.parent.getDimensions().width;

      if (left < this.constraintPad.left)
        left = this.constraintPad.left;
      if (left + this.width + this.widthE + this.widthW > width - this.constraintPad.right) 
        left = width - this.constraintPad.right - this.width - this.widthE - this.widthW;
    }
    return left;
  },
  
  _updateTopConstraint: function(top) {
    if (this.constraint && this.useLeft && this.useTop) {        
      var height = this.options.parent == document.body ? WindowUtilities.getPageSize().windowHeight : this.options.parent.getDimensions().height;
      
      var h = this.height + this.heightN + this.heightS;

      if (top < this.constraintPad.top)
        top = this.constraintPad.top;
      if (top + h > height - this.constraintPad.bottom) 
        top = height - this.constraintPad.bottom - h;
    }
    return top;
  },
  
  _updateWidthConstraint: function(w) {
    if (this.constraint && this.useLeft && this.useTop) {
      var width = this.options.parent == document.body ? WindowUtilities.getPageSize().windowWidth : this.options.parent.getDimensions().width;
      var left =  parseFloat(this.element.getStyle("left"));

      if (left + w + this.widthE + this.widthW > width - this.constraintPad.right) 
        w = width - this.constraintPad.right - left - this.widthE - this.widthW;
    }
    return w;
  },
  
  _updateHeightConstraint: function(h) {
    if (this.constraint && this.useLeft && this.useTop) {
      var height = this.options.parent == document.body ? WindowUtilities.getPageSize().windowHeight : this.options.parent.getDimensions().height;
      var top =  parseFloat(this.element.getStyle("top"));

      if (top + h + this.heightN + this.heightS > height - this.constraintPad.bottom) 
        h = height - this.constraintPad.bottom - top - this.heightN - this.heightS;
    }
    return h;
  },
  
  
  // Creates HTML window code
  _createWindow: function(id) {
    var className = this.options.className;
    var win = document.createElement("div");
    win.setAttribute('id', id);
    win.className = "dialog";

    var content;
    if (this.options.url)
      content= "<iframe frameborder=\"0\" name=\"" + id + "_content\"  id=\"" + id + "_content\" src=\"" + this.options.url + "\"> </iframe>";
    else
      content ="<div id=\"" + id + "_content\" class=\"" +className + "_content\"> </div>";

    var closeDiv = this.options.closable ? "<div class='"+ className +"_close' id='"+ id +"_close' onclick='Windows.close(\""+ id +"\", event)'> </div>" : "";
    var minDiv = this.options.minimizable ? "<div class='"+ className + "_minimize' id='"+ id +"_minimize' onclick='Windows.minimize(\""+ id +"\", event)'> </div>" : "";
    var maxDiv = this.options.maximizable ? "<div class='"+ className + "_maximize' id='"+ id +"_maximize' onclick='Windows.maximize(\""+ id +"\", event)'> </div>" : "";
    var seAttributes = this.options.resizable ? "class='" + className + "_sizer' id='" + id + "_sizer'" : "class='"  + className + "_se'";
    var blank = "../themes/default/blank.gif";
    
    win.innerHTML = closeDiv + minDiv + maxDiv + "\
      <table id='"+ id +"_row1' class=\"top table_window\">\
        <tr>\
          <td class='"+ className +"_nw'></td>\
          <td class='"+ className +"_n'><div id='"+ id +"_top' class='"+ className +"_title title_window'>"+ this.options.title +"</div></td>\
          <td class='"+ className +"_ne'></td>\
        </tr>\
      </table>\
      <table id='"+ id +"_row2' class=\"mid table_window\">\
        <tr>\
          <td class='"+ className +"_w'></td>\
            <td id='"+ id +"_table_content' class='"+ className +"_content' valign='top'>" + content + "</td>\
          <td class='"+ className +"_e'></td>\
        </tr>\
      </table>\
        <table id='"+ id +"_row3' class=\"bot table_window\">\
        <tr>\
          <td class='"+ className +"_sw'></td>\
            <td class='"+ className +"_s'><div id='"+ id +"_bottom' class='status_bar'><span style='float:left; width:1px; height:1px'></span></div></td>\
            <td " + seAttributes + "></td>\
        </tr>\
      </table>\
    ";
    Element.hide(win);
    this.options.parent.insertBefore(win, this.options.parent.firstChild);
    Event.observe($(id + "_content"), "load", this.options.onload);
    return win;
  },
  
  
  changeClassName: function(newClassName) {    
    var className = this.options.className;
    var id = this.getId();
    $A(["_close", "_minimize", "_maximize", "_sizer", "_content"]).each(function(value) { this._toggleClassName($(id + value), className + value, newClassName + value) }.bind(this));
    this._toggleClassName($(id + "_top"), className + "_title", newClassName + "_title");
    $$("#" + id + " td").each(function(td) {td.className = td.className.sub(className,newClassName); });
    this.options.className = newClassName;
  },
  
  _toggleClassName: function(element, oldClassName, newClassName) { 
    if (element) {
      element.removeClassName(oldClassName);
      element.addClassName(newClassName);
    }
  },
  
  // Sets window location
  setLocation: function(top, left) {
    top = this._updateTopConstraint(top);
    left = this._updateLeftConstraint(left);

    var e = this.currentDrag || this.element;
    e.setStyle({top: top + 'px'});
    e.setStyle({left: left + 'px'});

    this.useLeft = true;
    this.useTop = true;
  },
    
  getLocation: function() {
    var location = {};
    if (this.useTop)
      location = Object.extend(location, {top: this.element.getStyle("top")});
    else
      location = Object.extend(location, {bottom: this.element.getStyle("bottom")});
    if (this.useLeft)
      location = Object.extend(location, {left: this.element.getStyle("left")});
    else
      location = Object.extend(location, {right: this.element.getStyle("right")});
    
    return location;
  },
  
  // Gets window size
  getSize: function() {
    return {width: this.width, height: this.height};
  },
    
  // Sets window size
  setSize: function(width, height, useEffect) {    
    width = parseFloat(width);
    height = parseFloat(height);
    
    // Check min and max size
    if (!this.minimized && width < this.options.minWidth)
      width = this.options.minWidth;

    if (!this.minimized && height < this.options.minHeight)
      height = this.options.minHeight;
      
    if (this.options. maxHeight && height > this.options. maxHeight)
      height = this.options. maxHeight;

    if (this.options. maxWidth && width > this.options. maxWidth)
      width = this.options. maxWidth;

    
    if (this.useTop && this.useLeft && Window.hasEffectLib && Effect.ResizeWindow && useEffect) {
      new Effect.ResizeWindow(this, null, null, width, height, {duration: Window.resizeEffectDuration});
    } else {
      this.width = width;
      this.height = height;
      var e = this.currentDrag ? this.currentDrag : this.element;

      e.setStyle({width: width + this.widthW + this.widthE + "px"})
      e.setStyle({height: height  + this.heightN + this.heightS + "px"})

      // Update content size
      if (!this.currentDrag || this.currentDrag == this.element) {
        var content = $(this.element.id + '_content');
        content.setStyle({height: height  + 'px'});
        content.setStyle({width: width  + 'px'});
      }
    }
  },
  
  updateHeight: function() {
    this.setSize(this.width, this.content.document.body.scrollHeight, true);

  },
  
  updateWidth: function() { 	
    this.setSize(this.content.contentWindow.document.body.scrollWidth, this.height, true);
  },
  
  // Brings window to front
  toFront: function() {
    if (this.element.style.zIndex < Windows.maxZIndex)  
      this.setZIndex(Windows.maxZIndex + 1);
    if (this.iefix) 
      this._fixIEOverlapping(); 
  },
   
  getBounds: function(insideOnly) {
    if (! this.width || !this.height || !this.visible)  
      this.computeBounds();
    var w = this.width;
    var h = this.height;

    if (!insideOnly) {
      w += this.widthW + this.widthE;
      h += this.heightN + this.heightS;
    }
    var bounds = Object.extend(this.getLocation(), {width: w + "px", height: h + "px"});
    return bounds;
  },
      
  computeBounds: function() {
     if (! this.width || !this.height) {
      var size = WindowUtilities._computeSize(this.content.innerHTML, this.content.id, this.width, this.height, 0, this.options.className)
      if (this.height)
        this.width = size + 5
      else
        this.height = size + 5
    }

    this.setSize(this.width, this.height);
    if (this.centered)
      this._center(this.centerTop, this.centerLeft);    
  },
  
  // Displays window modal state or not
  show: function(modal) {
    this.visible = true;
    if (modal) {
      // Hack for Safari !!
      if (typeof this.overlayOpacity == "undefined") {
        var that = this;
        setTimeout(function() {that.show(modal)}, 10);
        return;
      }
      Windows.addModalWindow(this);
      
      this.modal = true;      
      this.setZIndex(Windows.maxZIndex + 1);
      Windows.unsetOverflow(this);
    }
    else    
      if (!this.element.style.zIndex) 
        this.setZIndex(Windows.maxZIndex + 1);        
      
    // To restore overflow if need be
    if (this.oldStyle)
      this.getContent().setStyle({overflow: this.oldStyle});
      
    this.computeBounds();
    
    this._notify("onBeforeShow");   
    if (this.options.showEffect != Element.show && this.options.showEffectOptions)
      this.options.showEffect(this.element, this.options.showEffectOptions);  
    else
      this.options.showEffect(this.element);  
      
    this._checkIEOverlapping();
    WindowUtilities.focusedWindow = this
    this._notify("onShow");   
  },
  
  // Displays window modal state or not at the center of the page
  showCenter: function(modal, top, left) {
    this.centered = true;
    this.centerTop = top;
    this.centerLeft = left;

    this.show(modal);
  },
  
  isVisible: function() {
    return this.visible;
  },
  
  _center: function(top, left) {    
    var windowScroll = WindowUtilities.getWindowScroll(this.options.parent);    
    var pageSize = WindowUtilities.getPageSize(this.options.parent);    
    if (typeof top == "undefined")
      top = (pageSize.windowHeight - (this.height + this.heightN + this.heightS))/2;
    top += windowScroll.top
    
    if (typeof left == "undefined")
      left = (pageSize.windowWidth - (this.width + this.widthW + this.widthE))/2;
    left += windowScroll.left      
    this.setLocation(top, left);
    this.toFront();
  },
  
  _recenter: function(event) {     
    if (this.centered) {
      var pageSize = WindowUtilities.getPageSize(this.options.parent);
      var windowScroll = WindowUtilities.getWindowScroll(this.options.parent);    

      // Check for this stupid IE that sends dumb events
      if (this.pageSize && this.pageSize.windowWidth == pageSize.windowWidth && this.pageSize.windowHeight == pageSize.windowHeight && 
          this.windowScroll.left == windowScroll.left && this.windowScroll.top == windowScroll.top) 
        return;
      this.pageSize = pageSize;
      this.windowScroll = windowScroll;
      // set height of Overlay to take up whole page and show
      if ($('overlay_modal')) 
        $('overlay_modal').setStyle({height: (pageSize.pageHeight + 'px')});
      
      if (this.options.recenterAuto)
        this._center(this.centerTop, this.centerLeft);    
    }
  },
  
  // Hides window
  hide: function() {
    this.visible = false;
    if (this.modal) {
      Windows.removeModalWindow(this);
      Windows.resetOverflow();
    }
    // To avoid bug on scrolling bar
    this.oldStyle = this.getContent().getStyle('overflow') || "auto"
    this.getContent().setStyle({overflow: "hidden"});

    this.options.hideEffect(this.element, this.options.hideEffectOptions);  

     if(this.iefix) 
      this.iefix.hide();

    if (!this.doNotNotifyHide)
      this._notify("onHide");
  },

  close: function() {
    // Asks closeCallback if exists
    if (this.visible) {
      if (this.options.closeCallback && ! this.options.closeCallback(this)) 
        return;

      if (this.options.destroyOnClose) {
        var destroyFunc = this.destroy.bind(this);
        if (this.options.hideEffectOptions.afterFinish) {
          var func = this.options.hideEffectOptions.afterFinish;
          this.options.hideEffectOptions.afterFinish = function() {func();destroyFunc() }
        }
        else 
          this.options.hideEffectOptions.afterFinish = function() {destroyFunc() }
      }
      Windows.updateFocusedWindow();
      
      this.doNotNotifyHide = true;
      this.hide();
      this.doNotNotifyHide = false;
      this._notify("onClose");
    }
  },
  
  minimize: function() {
    if (this.resizing)
      return;
    
    var r2 = $(this.getId() + "_row2");
    
    if (!this.minimized) {
      this.minimized = true;

      var dh = r2.getDimensions().height;
      this.r2Height = dh;
      var h  = this.element.getHeight() - dh;

      if (this.useLeft && this.useTop && Window.hasEffectLib && Effect.ResizeWindow) {
        new Effect.ResizeWindow(this, null, null, null, this.height -dh, {duration: Window.resizeEffectDuration});
      } else  {
        this.height -= dh;
        this.element.setStyle({height: h + "px"});
        r2.hide();
      }

      if (! this.useTop) {
        var bottom = parseFloat(this.element.getStyle('bottom'));
        this.element.setStyle({bottom: (bottom + dh) + 'px'});
      }
    } 
    else {      
      this.minimized = false;
      
      var dh = this.r2Height;
      this.r2Height = null;
      if (this.useLeft && this.useTop && Window.hasEffectLib && Effect.ResizeWindow) {
        new Effect.ResizeWindow(this, null, null, null, this.height + dh, {duration: Window.resizeEffectDuration});
      }
      else {
        var h  = this.element.getHeight() + dh;
        this.height += dh;
        this.element.setStyle({height: h + "px"})
        r2.show();
      }
      if (! this.useTop) {
        var bottom = parseFloat(this.element.getStyle('bottom'));
        this.element.setStyle({bottom: (bottom - dh) + 'px'});
      }
      this.toFront();
    }
    this._notify("onMinimize");
    
    // Store new location/size if need be
    this._saveCookie()
  },
  
  maximize: function() {
    if (this.isMinimized() || this.resizing)
      return;
  
    if (Prototype.Browser.IE && this.heightN == 0)
      this._getWindowBorderSize();
      
    if (this.storedLocation != null) {
      this._restoreLocation();
      if(this.iefix) 
        this.iefix.hide();
    }
    else {
      this._storeLocation();
      Windows.unsetOverflow(this);
      
      var windowScroll = WindowUtilities.getWindowScroll(this.options.parent);
      var pageSize = WindowUtilities.getPageSize(this.options.parent);    
      var left = windowScroll.left;
      var top = windowScroll.top;
      
      if (this.options.parent != document.body) {
        windowScroll =  {top:0, left:0, bottom:0, right:0};
        var dim = this.options.parent.getDimensions();
        pageSize.windowWidth = dim.width;
        pageSize.windowHeight = dim.height;
        top = 0; 
        left = 0;
      }
      
      if (this.constraint) {
        pageSize.windowWidth -= Math.max(0, this.constraintPad.left) + Math.max(0, this.constraintPad.right);
        pageSize.windowHeight -= Math.max(0, this.constraintPad.top) + Math.max(0, this.constraintPad.bottom);
        left +=  Math.max(0, this.constraintPad.left);
        top +=  Math.max(0, this.constraintPad.top);
      }
      
      var width = pageSize.windowWidth - this.widthW - this.widthE;
      var height= pageSize.windowHeight - this.heightN - this.heightS;

      if (this.useLeft && this.useTop && Window.hasEffectLib && Effect.ResizeWindow) {
        new Effect.ResizeWindow(this, top, left, width, height, {duration: Window.resizeEffectDuration});
      }
      else {
        this.setSize(width, height);
        this.element.setStyle(this.useLeft ? {left: left} : {right: left});
        this.element.setStyle(this.useTop ? {top: top} : {bottom: top});
      }
        
      this.toFront();
      if (this.iefix) 
        this._fixIEOverlapping(); 
    }
    this._notify("onMaximize");

    // Store new location/size if need be
    this._saveCookie()
  },
  
  isMinimized: function() {
    return this.minimized;
  },
  
  isMaximized: function() {
    return (this.storedLocation != null);
  },
  
  setOpacity: function(opacity) {
    if (Element.setOpacity)
      Element.setOpacity(this.element, opacity);
  },
  
  setZIndex: function(zindex) {
    this.element.setStyle({zIndex: zindex});
    Windows.updateZindex(zindex, this);
  },

  setTitle: function(newTitle) {
    if (!newTitle || newTitle == "") 
      newTitle = "&nbsp;";
      
    Element.update(this.element.id + '_top', newTitle);
  },
   
  getTitle: function() {
    return $(this.element.id + '_top').innerHTML;
  },
  
  setStatusBar: function(element) {
    var statusBar = $(this.getId() + "_bottom");

    if (typeof(element) == "object") {
      if (this.bottombar.firstChild)
        this.bottombar.replaceChild(element, this.bottombar.firstChild);
      else
        this.bottombar.appendChild(element);
    }
    else
      this.bottombar.innerHTML = element;
  },

  _checkIEOverlapping: function() {
    if(!this.iefix && (navigator.appVersion.indexOf('MSIE')>0) && (navigator.userAgent.indexOf('Opera')<0) && (this.element.getStyle('position')=='absolute')) {
        new Insertion.After(this.element.id, '<iframe id="' + this.element.id + '_iefix" '+ 'style="display:none;position:absolute;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);" ' + 'src="javascript:false;" frameborder="0" scrolling="no"></iframe>');
        this.iefix = $(this.element.id+'_iefix');
    }
    if(this.iefix) 
      setTimeout(this._fixIEOverlapping.bind(this), 50);
  },

  _fixIEOverlapping: function() {
      Position.clone(this.element, this.iefix);
      this.iefix.style.zIndex = this.element.style.zIndex - 1;
      this.iefix.show();
  },
  
  _getWindowBorderSize: function(event) {
    // Hack to get real window border size!!
    var div = this._createHiddenDiv(this.options.className + "_n")
    this.heightN = Element.getDimensions(div).height;    
    div.parentNode.removeChild(div)

    var div = this._createHiddenDiv(this.options.className + "_s")
    this.heightS = Element.getDimensions(div).height;    
    div.parentNode.removeChild(div)

    var div = this._createHiddenDiv(this.options.className + "_e")
    this.widthE = Element.getDimensions(div).width;    
    div.parentNode.removeChild(div)

    var div = this._createHiddenDiv(this.options.className + "_w")
    this.widthW = Element.getDimensions(div).width;
    div.parentNode.removeChild(div);
    
    var div = document.createElement("div");
    div.className = "overlay_" + this.options.className ;
    document.body.appendChild(div);
    //alert("no timeout:\nopacity: " + div.getStyle("opacity") + "\nwidth: " + document.defaultView.getComputedStyle(div, null).width);
    var that = this;
    
    // Workaround for Safari!!
    setTimeout(function() {that.overlayOpacity = ($(div).getStyle("opacity")); div.parentNode.removeChild(div);}, 10);
    
    // Workaround for IE!!
    if (Prototype.Browser.IE) {
      this.heightS = $(this.getId() +"_row3").getDimensions().height;
      this.heightN = $(this.getId() +"_row1").getDimensions().height;
    }

    // Safari size fix
    if (Prototype.Browser.WebKit && Prototype.Browser.WebKitVersion < 420)
      this.setSize(this.width, this.height);
    if (this.doMaximize)
      this.maximize();
    if (this.doMinimize)
      this.minimize();
  },
 
  _createHiddenDiv: function(className) {
    var objBody = document.body;
    var win = document.createElement("div");
    win.setAttribute('id', this.element.id+ "_tmp");
    win.className = className;
    win.style.display = 'none';
    win.innerHTML = '';
    objBody.insertBefore(win, objBody.firstChild);
    return win;
  },
  
  _storeLocation: function() {
    if (this.storedLocation == null) {
      this.storedLocation = {useTop: this.useTop, useLeft: this.useLeft, 
                             top: this.element.getStyle('top'), bottom: this.element.getStyle('bottom'),
                             left: this.element.getStyle('left'), right: this.element.getStyle('right'),
                             width: this.width, height: this.height };
    }
  },
  
  _restoreLocation: function() {
    if (this.storedLocation != null) {
      this.useLeft = this.storedLocation.useLeft;
      this.useTop = this.storedLocation.useTop;
      
      if (this.useLeft && this.useTop && Window.hasEffectLib && Effect.ResizeWindow)
        new Effect.ResizeWindow(this, this.storedLocation.top, this.storedLocation.left, this.storedLocation.width, this.storedLocation.height, {duration: Window.resizeEffectDuration});
      else {
        this.element.setStyle(this.useLeft ? {left: this.storedLocation.left} : {right: this.storedLocation.right});
        this.element.setStyle(this.useTop ? {top: this.storedLocation.top} : {bottom: this.storedLocation.bottom});
        this.setSize(this.storedLocation.width, this.storedLocation.height);
      }
      
      Windows.resetOverflow();
      this._removeStoreLocation();
    }
  },
  
  _removeStoreLocation: function() {
    this.storedLocation = null;
  },
  
  _saveCookie: function() {
    if (this.cookie) {
      var value = "";
      if (this.useLeft)
        value += "l:" +  (this.storedLocation ? this.storedLocation.left : this.element.getStyle('left'))
      else
        value += "r:" + (this.storedLocation ? this.storedLocation.right : this.element.getStyle('right'))
      if (this.useTop)
        value += ",t:" + (this.storedLocation ? this.storedLocation.top : this.element.getStyle('top'))
      else
        value += ",b:" + (this.storedLocation ? this.storedLocation.bottom :this.element.getStyle('bottom'))
        
      value += "," + (this.storedLocation ? this.storedLocation.width : this.width);
      value += "," + (this.storedLocation ? this.storedLocation.height : this.height);
      value += "," + this.isMinimized();
      value += "," + this.isMaximized();
      WindowUtilities.setCookie(value, this.cookie)
    }
  },
  
  _createWiredElement: function() {
    if (! this.wiredElement) {
      if (Prototype.Browser.IE)
        this._getWindowBorderSize();
      var div = document.createElement("div");
      div.className = "wired_frame " + this.options.className + "_wired_frame";
      
      div.style.position = 'absolute';
      this.options.parent.insertBefore(div, this.options.parent.firstChild);
      this.wiredElement = $(div);
    }
    if (this.useLeft) 
      this.wiredElement.setStyle({left: this.element.getStyle('left')});
    else 
      this.wiredElement.setStyle({right: this.element.getStyle('right')});
      
    if (this.useTop) 
      this.wiredElement.setStyle({top: this.element.getStyle('top')});
    else 
      this.wiredElement.setStyle({bottom: this.element.getStyle('bottom')});

    var dim = this.element.getDimensions();
    this.wiredElement.setStyle({width: dim.width + "px", height: dim.height +"px"});

    this.wiredElement.setStyle({zIndex: Windows.maxZIndex+30});
    return this.wiredElement;
  },
  
  _hideWiredElement: function() {
    if (! this.wiredElement || ! this.currentDrag)
      return;
    if (this.currentDrag == this.element) 
      this.currentDrag = null;
    else {
      if (this.useLeft) 
        this.element.setStyle({left: this.currentDrag.getStyle('left')});
      else 
        this.element.setStyle({right: this.currentDrag.getStyle('right')});

      if (this.useTop) 
        this.element.setStyle({top: this.currentDrag.getStyle('top')});
      else 
        this.element.setStyle({bottom: this.currentDrag.getStyle('bottom')});

      this.currentDrag.hide();
      this.currentDrag = null;
      if (this.doResize)
        this.setSize(this.width, this.height);
    } 
  },
  
  _notify: function(eventName) {
    if (this.options[eventName])
      this.options[eventName](this);
    else
      Windows.notify(eventName, this);
  }
};

// Windows containers, register all page windows
var Windows = {
  windows: [],
  modalWindows: [],
  observers: [],
  focusedWindow: null,
  maxZIndex: 0,
  overlayShowEffectOptions: {duration: 0.5},
  overlayHideEffectOptions: {duration: 0.5},

  addObserver: function(observer) {
    this.removeObserver(observer);
    this.observers.push(observer);
  },
  
  removeObserver: function(observer) {  
    this.observers = this.observers.reject( function(o) { return o==observer });
  },
  
  // onDestroy onStartResize onStartMove onResize onMove onEndResize onEndMove onFocus onBlur onBeforeShow onShow onHide onMinimize onMaximize onClose
  notify: function(eventName, win) {  
    this.observers.each( function(o) {if(o[eventName]) o[eventName](eventName, win);});
  },

  // Gets window from its id
  getWindow: function(id) {
    return this.windows.detect(function(d) { return d.getId() ==id });
  },

  // Gets the last focused window
  getFocusedWindow: function() {
    return this.focusedWindow;
  },

  updateFocusedWindow: function() {
    this.focusedWindow = this.windows.length >=2 ? this.windows[this.windows.length-2] : null;    
  },
  
  // Registers a new window (called by Windows constructor)
  register: function(win) {
    this.windows.push(win);
  },
    
  // Add a modal window in the stack
  addModalWindow: function(win) {
    // Disable screen if first modal window
    if (this.modalWindows.length == 0) {
      WindowUtilities.disableScreen(win.options.className, 'overlay_modal', win.overlayOpacity, win.getId(), win.options.parent);
    }
    else {
      // Move overlay over all windows
      if (Window.keepMultiModalWindow) {
        $('overlay_modal').style.zIndex = Windows.maxZIndex + 1;
        Windows.maxZIndex += 1;
        WindowUtilities._hideSelect(this.modalWindows.last().getId());
      }
      // Hide current modal window
      else
        this.modalWindows.last().element.hide();
      // Fucking IE select issue
      WindowUtilities._showSelect(win.getId());
    }      
    this.modalWindows.push(win);    
  },
  
  removeModalWindow: function(win) {
    this.modalWindows.pop();
    
    // No more modal windows
    if (this.modalWindows.length == 0)
      WindowUtilities.enableScreen();     
    else {
      if (Window.keepMultiModalWindow) {
        this.modalWindows.last().toFront();
        WindowUtilities._showSelect(this.modalWindows.last().getId());        
      }
      else
        this.modalWindows.last().element.show();
    }
  },
  
  // Registers a new window (called by Windows constructor)
  register: function(win) {
    this.windows.push(win);
  },
  
  // Unregisters a window (called by Windows destructor)
  unregister: function(win) {
    this.windows = this.windows.reject(function(d) { return d==win });
  }, 
  
  // Closes all windows
  closeAll: function() {  
    this.windows.each( function(w) {Windows.close(w.getId())} );
  },
  
  closeAllModalWindows: function() {
    WindowUtilities.enableScreen();     
    this.modalWindows.each( function(win) {if (win) win.close()});    
  },

  // Minimizes a window with its id
  minimize: function(id, event) {
    var win = this.getWindow(id)
    if (win && win.visible)
      win.minimize();
    Event.stop(event);
  },
  
  // Maximizes a window with its id
  maximize: function(id, event) {
    var win = this.getWindow(id)
    if (win && win.visible)
      win.maximize();
    Event.stop(event);
  },

  // Closes a window with its id
  close: function(id, event) {
    var win = this.getWindow(id);
    if (win) 
      win.close();
    if (event)
      Event.stop(event);
  },
  
  blur: function(id) {
    var win = this.getWindow(id);  
    if (!win)
      return;
    if (win.options.blurClassName)
      win.changeClassName(win.options.blurClassName);
    if (this.focusedWindow == win)  
      this.focusedWindow = null;
    win._notify("onBlur");  
  },
  
  focus: function(id) {
    var win = this.getWindow(id);  
    if (!win)
      return;       
    if (this.focusedWindow)
      this.blur(this.focusedWindow.getId())

    if (win.options.focusClassName)
      win.changeClassName(win.options.focusClassName);  
    this.focusedWindow = win;
    win._notify("onFocus");
  },
  
  unsetOverflow: function(except) {    
    this.windows.each(function(d) { d.oldOverflow = d.getContent().getStyle("overflow") || "auto" ; d.getContent().setStyle({overflow: "hidden"}) });
    if (except && except.oldOverflow)
      except.getContent().setStyle({overflow: except.oldOverflow});
  },

  resetOverflow: function() {
    this.windows.each(function(d) { if (d.oldOverflow) d.getContent().setStyle({overflow: d.oldOverflow}) });
  },

  updateZindex: function(zindex, win) { 
    if (zindex > this.maxZIndex) {   
      this.maxZIndex = zindex;    
      if (this.focusedWindow) 
        this.blur(this.focusedWindow.getId())
    }
    this.focusedWindow = win;
    if (this.focusedWindow) 
      this.focus(this.focusedWindow.getId())
  }
};

var Dialog = {
  dialogId: null,
  onCompleteFunc: null,
  callFunc: null, 
  parameters: null, 
    
  confirm: function(content, parameters) {
    // Get Ajax return before
    if (content && typeof content != "string") {
      Dialog._runAjaxRequest(content, parameters, Dialog.confirm);
      return 
    }
    content = content || "";
    
    parameters = parameters || {};
    var okLabel = parameters.okLabel ? parameters.okLabel : "Ok";
    var cancelLabel = parameters.cancelLabel ? parameters.cancelLabel : "Cancel";

    // Backward compatibility
    parameters = Object.extend(parameters, parameters.windowParameters || {});
    parameters.windowParameters = parameters.windowParameters || {};

    parameters.className = parameters.className || "alert";

    var okButtonClass = "class ='" + (parameters.buttonClass ? parameters.buttonClass + " " : "") + " ok_button'" 
    var cancelButtonClass = "class ='" + (parameters.buttonClass ? parameters.buttonClass + " " : "") + " cancel_button'" 
    var content = "\
      <div class='" + parameters.className + "_message'>" + content  + "</div>\
        <div class='" + parameters.className + "_buttons'>\
          <input type='button' value='" + okLabel + "' onclick='Dialog.okCallback()' " + okButtonClass + "/>\
          <input type='button' value='" + cancelLabel + "' onclick='Dialog.cancelCallback()' " + cancelButtonClass + "/>\
        </div>\
    ";
    return this._openDialog(content, parameters)
  },
  
  alert: function(content, parameters) {
    // Get Ajax return before
    if (content && typeof content != "string") {
      Dialog._runAjaxRequest(content, parameters, Dialog.alert);
      return 
    }
    content = content || "";
    
    parameters = parameters || {};
    var okLabel = parameters.okLabel ? parameters.okLabel : "Ok";

    // Backward compatibility    
    parameters = Object.extend(parameters, parameters.windowParameters || {});
    parameters.windowParameters = parameters.windowParameters || {};
    
    parameters.className = parameters.className || "alert";
    
    var okButtonClass = "class ='" + (parameters.buttonClass ? parameters.buttonClass + " " : "") + " ok_button'" 
    var content = "\
      <div class='" + parameters.className + "_message'>" + content  + "</div>\
        <div class='" + parameters.className + "_buttons'>\
          <input type='button' value='" + okLabel + "' onclick='Dialog.okCallback()' " + okButtonClass + "/>\
        </div>";                  
    return this._openDialog(content, parameters)
  },
  
  info: function(content, parameters) {   
    // Get Ajax return before
    if (content && typeof content != "string") {
      Dialog._runAjaxRequest(content, parameters, Dialog.info);
      return 
    }
    content = content || "";
     
    // Backward compatibility
    parameters = parameters || {};
    parameters = Object.extend(parameters, parameters.windowParameters || {});
    parameters.windowParameters = parameters.windowParameters || {};
    
    parameters.className = parameters.className || "alert";
    
    var content = "<div id='modal_dialog_message' class='" + parameters.className + "_message'>" + content  + "</div>";
    if (parameters.showProgress)
      content += "<div id='modal_dialog_progress' class='" + parameters.className + "_progress'>  </div>";

    parameters.ok = null;
    parameters.cancel = null;
    
    return this._openDialog(content, parameters)
  },
  
  setInfoMessage: function(message) {
  	if($('modal_dialog_message') != null)
    	$('modal_dialog_message').update(message);
  },
  
  closeInfo: function() {
    Windows.close(this.dialogId);
  },
  
  _openDialog: function(content, parameters) {
    var className = parameters.className;
    
    if (! parameters.height && ! parameters.width) {
      parameters.width = WindowUtilities.getPageSize(parameters.options.parent || document.body).pageWidth / 2;
    }
    if (parameters.id)
      this.dialogId = parameters.id;
    else { 
      var t = new Date();
      this.dialogId = 'modal_dialog_' + t.getTime();
      parameters.id = this.dialogId;
    }

    // compute height or width if need be
    if (! parameters.height || ! parameters.width) {
      var size = WindowUtilities._computeSize(content, this.dialogId, parameters.width, parameters.height, 5, className)
      if (parameters.height)
        parameters.width = size + 5
      else
        parameters.height = size + 5
    }
    parameters.effectOptions = parameters.effectOptions ;
    parameters.resizable   = parameters.resizable || false;
    parameters.minimizable = parameters.minimizable || false;
    parameters.maximizable = parameters.maximizable ||  false;
    parameters.draggable   = parameters.draggable || false;
    parameters.closable    = parameters.closable || false;
    
    var win = new Window(parameters);
    win.getContent().innerHTML = content;
    
    win.showCenter(true, parameters.top, parameters.left);  
    win.setDestroyOnClose();
    
    win.cancelCallback = parameters.onCancel || parameters.cancel; 
    win.okCallback = parameters.onOk || parameters.ok;
    
    return win;    
  },
  
  _getAjaxContent: function(originalRequest)  {
      Dialog.callFunc(originalRequest.responseText, Dialog.parameters)
  },
  
  _runAjaxRequest: function(message, parameters, callFunc) {
    if (message.options == null)
      message.options = {}  
    Dialog.onCompleteFunc = message.options.onComplete;
    Dialog.parameters = parameters;
    Dialog.callFunc = callFunc;
    
    message.options.onComplete = Dialog._getAjaxContent;
    new Ajax.Request(message.url, message.options);
  },
  
  okCallback: function() {
    var win = Windows.focusedWindow;
    if (!win.okCallback || win.okCallback(win)) {
      // Remove onclick on button
      $$("#" + win.getId()+" input").each(function(element) {element.onclick=null;})
      win.close();
    }
  },

  cancelCallback: function() {
    var win = Windows.focusedWindow;
    // Remove onclick on button
    $$("#" + win.getId()+" input").each(function(element) {element.onclick=null})
    win.close();
    if (win.cancelCallback)
      win.cancelCallback(win);
  }
}
/*
  Based on Lightbox JS: Fullsize Image Overlays 
  by Lokesh Dhakar - http://www.huddletogether.com

  For more information on this script, visit:
  http://huddletogether.com/projects/lightbox/

  Licensed under the Creative Commons Attribution 2.5 License - http://creativecommons.org/licenses/by/2.5/
  (basically, do anything you want, just leave my name and link)
*/

if (Prototype.Browser.WebKit) {
  var array = navigator.userAgent.match(new RegExp(/AppleWebKit\/([\d\.\+]*)/));
  Prototype.Browser.WebKitVersion = parseFloat(array[1]);
}

var WindowUtilities = {  
  // From dragdrop.js
  getWindowScroll: function(parent) {
    var T, L, W, H;
    parent = parent || document.body;              
    if (parent != document.body) {
      T = parent.scrollTop;
      L = parent.scrollLeft;
      W = parent.scrollWidth;
      H = parent.scrollHeight;
    } 
    else {
      var w = window;
      with (w.document) {
        if (w.document.documentElement && documentElement.scrollTop) {
          T = documentElement.scrollTop;
          L = documentElement.scrollLeft;
        } else if (w.document.body) {
          T = body.scrollTop;
          L = body.scrollLeft;
        }
        if (w.innerWidth) {
          W = w.innerWidth;
          H = w.innerHeight;
        } else if (w.document.documentElement && documentElement.clientWidth) {
          W = documentElement.clientWidth;
          H = documentElement.clientHeight;
        } else {
          W = body.offsetWidth;
          H = body.offsetHeight
        }
      }
    }
    return { top: T, left: L, width: W, height: H };
  }, 
  //
  // getPageSize()
  // Returns array with page width, height and window width, height
  // Core code from - quirksmode.org
  // Edit for Firefox by pHaez
  //
  getPageSize: function(parent){
    parent = parent || document.body;              
    var windowWidth, windowHeight;
    var pageHeight, pageWidth;
    if (parent != document.body) {
      windowWidth = parent.getWidth();
      windowHeight = parent.getHeight();                                
      pageWidth = parent.scrollWidth;
      pageHeight = parent.scrollHeight;                                
    } 
    else {
      var xScroll, yScroll;

      if (window.innerHeight && window.scrollMaxY) {  
        xScroll = document.body.scrollWidth;
        yScroll = window.innerHeight + window.scrollMaxY;
      } else if (document.body.scrollHeight > document.body.offsetHeight){ // all but Explorer Mac
        xScroll = document.body.scrollWidth;
        yScroll = document.body.scrollHeight;
      } else { // Explorer Mac...would also work in Explorer 6 Strict, Mozilla and Safari
        xScroll = document.body.offsetWidth;
        yScroll = document.body.offsetHeight;
      }


      if (self.innerHeight) {  // all except Explorer
        windowWidth = self.innerWidth;
        windowHeight = self.innerHeight;
      } else if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode
        windowWidth = document.documentElement.clientWidth;
        windowHeight = document.documentElement.clientHeight;
      } else if (document.body) { // other Explorers
        windowWidth = document.body.clientWidth;
        windowHeight = document.body.clientHeight;
      }  

      // for small pages with total height less then height of the viewport
      if(yScroll < windowHeight){
        pageHeight = windowHeight;
      } else { 
        pageHeight = yScroll;
      }

      // for small pages with total width less then width of the viewport
      if(xScroll < windowWidth){  
        pageWidth = windowWidth;
      } else {
        pageWidth = xScroll;
      }
    }             
    return {pageWidth: pageWidth ,pageHeight: pageHeight , windowWidth: windowWidth, windowHeight: windowHeight};
  },

  disableScreen: function(className, overlayId, overlayOpacity, contentId, parent) {
    WindowUtilities.initLightbox(overlayId, className, function() {this._disableScreen(className, overlayId, overlayOpacity, contentId)}.bind(this), parent || document.body);
  },

  _disableScreen: function(className, overlayId, overlayOpacity, contentId) {
    // prep objects
    var objOverlay = $(overlayId);

    var pageSize = WindowUtilities.getPageSize(objOverlay.parentNode);

    // Hide select boxes as they will 'peek' through the image in IE, store old value
    if (contentId && Prototype.Browser.IE) {
      WindowUtilities._hideSelect();
      WindowUtilities._showSelect(contentId);
    }  
  
    // set height of Overlay to take up whole page and show
    objOverlay.style.height = (pageSize.pageHeight + 'px');
    objOverlay.style.display = 'none'; 
    if (overlayId == "overlay_modal" && Window.hasEffectLib && Windows.overlayShowEffectOptions) {
      objOverlay.overlayOpacity = overlayOpacity;
      new Effect.Appear(objOverlay, Object.extend({from: 0, to: overlayOpacity}, Windows.overlayShowEffectOptions));
    }
    else
      objOverlay.style.display = "block";
  },
  
  enableScreen: function(id) {
    id = id || 'overlay_modal';
    var objOverlay =  $(id);
    if (objOverlay) {
      // hide lightbox and overlay
      if (id == "overlay_modal" && Window.hasEffectLib && Windows.overlayHideEffectOptions)
        new Effect.Fade(objOverlay, Object.extend({from: objOverlay.overlayOpacity, to:0}, Windows.overlayHideEffectOptions));
      else {
        objOverlay.style.display = 'none';
        objOverlay.parentNode.removeChild(objOverlay);
      }
      
      // make select boxes visible using old value
      if (id != "__invisible__") 
        WindowUtilities._showSelect();
    }
  },

  _hideSelect: function(id) {
    if (Prototype.Browser.IE) {
      id = id ==  null ? "" : "#" + id + " ";
      $$(id + 'select').each(function(element) {
        if (! WindowUtilities.isDefined(element.oldVisibility)) {
          element.oldVisibility = element.style.visibility ? element.style.visibility : "visible";
          element.style.visibility = "hidden";
        }
      });
    }
  },
  
  _showSelect: function(id) {
    if (Prototype.Browser.IE) {
      id = id ==  null ? "" : "#" + id + " ";
      $$(id + 'select').each(function(element) {
        if (WindowUtilities.isDefined(element.oldVisibility)) {
          // Why?? Ask IE
          try {
            element.style.visibility = element.oldVisibility;
          } catch(e) {
            element.style.visibility = "visible";
          }
          element.oldVisibility = null;
        }
        else {
          if (element.style.visibility)
            element.style.visibility = "visible";
        }
      });
    }
  },

  isDefined: function(object) {
    return typeof(object) != "undefined" && object != null;
  },
  
  // initLightbox()
  // Function runs on window load, going through link tags looking for rel="lightbox".
  // These links receive onclick events that enable the lightbox display for their targets.
  // The function also inserts html markup at the top of the page which will be used as a
  // container for the overlay pattern and the inline image.
  initLightbox: function(id, className, doneHandler, parent) {
    // Already done, just update zIndex
    if ($(id)) {
      Element.setStyle(id, {zIndex: Windows.maxZIndex + 1});
      Windows.maxZIndex++;
      doneHandler();
    }
    // create overlay div and hardcode some functional styles (aesthetic styles are in CSS file)
    else {
      var objOverlay = document.createElement("div");
      objOverlay.setAttribute('id', id);
      objOverlay.className = "overlay_" + className
      objOverlay.style.display = 'none';
      objOverlay.style.position = 'absolute';
      objOverlay.style.top = '0';
      objOverlay.style.left = '0';
      objOverlay.style.zIndex = Windows.maxZIndex + 1;
      Windows.maxZIndex++;
      objOverlay.style.width = '100%';
      parent.insertBefore(objOverlay, parent.firstChild);
      if (Prototype.Browser.WebKit && id == "overlay_modal") {
        setTimeout(function() {doneHandler()}, 10);
      }
      else
        doneHandler();
    }    
  },
  
  setCookie: function(value, parameters) {
    document.cookie= parameters[0] + "=" + escape(value) +
      ((parameters[1]) ? "; expires=" + parameters[1].toGMTString() : "") +
      ((parameters[2]) ? "; path=" + parameters[2] : "") +
      ((parameters[3]) ? "; domain=" + parameters[3] : "") +
      ((parameters[4]) ? "; secure" : "");
  },

  getCookie: function(name) {
    var dc = document.cookie;
    var prefix = name + "=";
    var begin = dc.indexOf("; " + prefix);
    if (begin == -1) {
      begin = dc.indexOf(prefix);
      if (begin != 0) return null;
    } else {
      begin += 2;
    }
    var end = document.cookie.indexOf(";", begin);
    if (end == -1) {
      end = dc.length;
    }
    return unescape(dc.substring(begin + prefix.length, end));
  },
    
  _computeSize: function(content, id, width, height, margin, className) {
    var objBody = document.body;
    var tmpObj = document.createElement("div");
    tmpObj.setAttribute('id', id);
    tmpObj.className = className + "_content";

    if (height)
      tmpObj.style.height = height + "px"
    else
      tmpObj.style.width = width + "px"
  
    tmpObj.style.position = 'absolute';
    tmpObj.style.top = '0';
    tmpObj.style.left = '0';
    tmpObj.style.display = 'none';

    tmpObj.innerHTML = content;
    objBody.insertBefore(tmpObj, objBody.firstChild);

    var size;
    if (height)
      size = $(tmpObj).getDimensions().width + margin;
    else
      size = $(tmpObj).getDimensions().height + margin;
    objBody.removeChild(tmpObj);
    return size;
  }  
}

/************************************************************************************************************
	@fileoverview
	DHTML Suite for Applications.
	Copyright (C) 2006  Alf Magne Kalleland(post@dhtmlgoodies.com)<br>
	<br>
	This library is free software; you can redistribute it and/or<br>
	modify it under the terms of the GNU Lesser General Public<br>
	License as published by the Free Software Foundation; either<br>
	version 2.1 of the License, or (at your option) any later version.<br>
	<br>
	This library is distributed in the hope that it will be useful,<br>
	but WITHOUT ANY WARRANTY; without even the implied warranty of<br>
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU<br>
	Lesser General Public License for more details.<br>
	<br>
	You should have received a copy of the GNU Lesser General Public<br>
	License along with this library; if not, write to the Free Software<br>
	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA<br>
	<br>
	<br>
	www.dhtmlgoodies.com<br>
	Alf Magne Kalleland<br>

************************************************************************************************************/


/**
 *
 * @package DHTMLSuite for applications
 * @copyright Copyright &copy; 2006, www.dhtmlgoodies.com
 * @author Alf Magne Kalleland <post@dhtmlgoodies.com>
 */


/************************************************************************************************************
*
* Global variables
*
************************************************************************************************************/


// {{{ DHTMLSuite.createStandardObjects()
/**
 * Create objects used by all scripts
 *
 * @public
 */


var DHTMLSuite = new Object();

var standardObjectsCreated = false;	// The classes below will check this variable, if it is false, default help objects will be created
DHTMLSuite.eventElements = new Array();	// Array of elements that has been assigned to an event handler.

DHTMLSuite.createStandardObjects = function()
{
	DHTMLSuite.clientInfoObj = new DHTMLSuite.clientInfo();	// Create browser info object
	DHTMLSuite.clientInfoObj.init();
	if(!DHTMLSuite.configObj){	// If this object isn't allready created, create it.
		DHTMLSuite.configObj = new DHTMLSuite.config();	// Create configuration object.
		DHTMLSuite.configObj.init();
	}
	DHTMLSuite.commonObj = new DHTMLSuite.common();	// Create configuration object.
	DHTMLSuite.variableStorage = new DHTMLSuite.globalVariableStorage();;	// Create configuration object.
	DHTMLSuite.commonObj.init();
	window.onunload = function() { DHTMLSuite.commonObj.__clearGarbage(); }

	standardObjectsCreated = true;


}


DHTMLSuite.discardElement = function(element) {
	element = DHTMLSuite.commonObj.getEl(element);
	var gBin = document.getElementById('IELeakGBin');
	if (!gBin) {
		gBin = document.createElement('DIV');
		gBin.id = 'IELeakGBin';
		gBin.style.display = 'none';
		document.body.appendChild(gBin);
	}
	// move the element to the garbage bin
	gBin.appendChild(element);
	gBin.innerHTML = '';
}

/************************************************************************************************************
*	Configuration class used by most of the scripts
*
*	Created:			August, 19th, 2006
* 	Update log:
*
************************************************************************************************************/


/**
* @constructor
* @class Store global variables/configurations used by the classes below. Example: If you want to
*		 change the path to the images used by the scripts, change it here. An object of this
*		 class will always be available to the other classes. The name of this object is
*		"DHTMLSuite.configObj".	<br><br>
*
*		If you want to create an object of this class manually, remember to name it "DHTMLSuite.configObj"
*		This object should then be created before any other objects. This is nescessary if you want
*		the other objects to use the values you have put into the object. <br>
* @version				1.0
* @version 1.0
* @author	Alf Magne Kalleland(www.dhtmlgoodies.com)
**/
DHTMLSuite.config = function()
{
	var imagePath;	// Path to images used by the classes.
	var cssPath;	// Path to CSS files used by the DHTML suite.
}


DHTMLSuite.config.prototype = {
	// {{{ init()
	/**
	 *
	 * @public
	 */
	init : function()
	{
		this.imagePath = 'img/';	// Path to images		
		this.cssPath = 'css/';	// Path to images
	}
	// }}}
	,
	// {{{ setCssPath()
    /**
     * This method will save a new CSS path, i.e. where the css files of the dhtml suite are located.
     *
     * @param string newCssPath = New path to css files
     * @public
     */

	setCssPath : function(newCssPath)
	{
		this.cssPath = newCssPath;
	}
	// }}}
	,
	// {{{ setImagePath()
    /**
     * This method will save a new image file path, i.e. where the image files used by the dhtml suite ar located
     *
     * @param string newImagePath = New path to image files
     * @public
     */
	setImagePath : function(newImagePath)
	{
		this.imagePath = newImagePath;
	}
	// }}}
}



DHTMLSuite.globalVariableStorage = function()
{
	var menuBar_highlightedItems;	// Array of highlighted menu bar items
	this.menuBar_highlightedItems = new Array();

	var arrayDSObjects;	// Array of objects of class menuItem.
	this.arrayDSObjects = new Array();
}

DHTMLSuite.globalVariableStorage.prototype = {

}


/************************************************************************************************************
*	A class with general methods used by most of the scripts
*
*	Created:			August, 19th, 2006
*	Purpose of class:	A class containing common method used by one or more of the gui classes below,
* 						example: loadCSS.
*						An object("DHTMLSuite.commonObj") of this  class will always be available to the other classes.
* 	Update log:
*
************************************************************************************************************/


/**
* @constructor
* @class A class containing common method used by one or more of the gui classes below, example: loadCSS. An object("DHTMLSuite.commonObj") of this  class will always be available to the other classes.
* @version 1.0
* @author	Alf Magne Kalleland(www.dhtmlgoodies.com)
**/

DHTMLSuite.common = function()
{
	var loadedCSSFiles;	// Array of loaded CSS files. Prevent same CSS file from being loaded twice.
	var cssCacheStatus;	// Css cache status
	var eventElements;

	this.cssCacheStatus = true;	// Caching of css files = on(Default)
	this.eventElements = new Array();
}

DHTMLSuite.common.prototype = {

	// {{{ init()
    /**
     * This method initializes the DHTMLSuite_common object.
     *
     * @public
     */

	init : function()
	{
		this.loadedCSSFiles = new Array();
	}
	// }}}
	,
	// {{{ loadCSS()
    /**
     * This method loads a CSS file(Cascading Style Sheet) dynamically - i.e. an alternative to <link> tag in the document.
     *
     * @param string cssFileName = New path to image files
     * @public
     */

	loadCSS : function(cssFileName)
	{

		if(!this.loadedCSSFiles[cssFileName]){
			this.loadedCSSFiles[cssFileName] = true;
			var linkTag = document.createElement('LINK');
			if(!this.cssCacheStatus){
				if(cssFileName.indexOf('?')>=0)cssFileName = cssFileName + '&'; else cssFileName = cssFileName + '?';
				cssFileName = cssFileName + 'rand='+ Math.random();	// To prevent caching
			}
			linkTag.href = DHTMLSuite.configObj.cssPath + cssFileName;
			linkTag.rel = 'stylesheet';
			linkTag.media = 'screen';
			linkTag.type = 'text/css';
			document.getElementsByTagName('HEAD')[0].appendChild(linkTag);

		}
	}
	// }}}
	,
	// {{{ getTopPos()
    /**
     * This method will return the top coordinate(pixel) of an object
     *
     * @param Object inputObj = Reference to HTML element
     * @public
     */
	getTopPos : function(inputObj)
	{
	  var returnValue = inputObj.offsetTop;
	  while((inputObj = inputObj.offsetParent) != null){
	  	if(inputObj.tagName!='HTML'){
	  		returnValue += (inputObj.offsetTop - inputObj.scrollTop);
	  		if(document.all)returnValue+=inputObj.clientTop;
	  	}
	  }
	  return returnValue;
	}
	// }}}
	,
	// {{{ setCssCacheStatus()
    /**
     * Specify if css files should be cached or not.
     *
     *	@param Boolean cssCacheStatus = true = cache on, false = cache off
     *
     * @public
     */
	setCssCacheStatus : function(cssCacheStatus)
	{
	  this.cssCacheStatus = cssCacheStatus;
	}
	// }}}
	,
	// {{{ getLeftPos()
    /**
     * This method will return the left coordinate(pixel) of an object
     *
     * @param Object inputObj = Reference to HTML element
     * @public
     */
	getLeftPos : function(inputObj)
	{
	  var returnValue = inputObj.offsetLeft;
	  while((inputObj = inputObj.offsetParent) != null){
	  	if(inputObj.tagName!='HTML'){
	  		returnValue += inputObj.offsetLeft;
	  		if(document.all)returnValue+=inputObj.clientLeft;
	  	}
	  }
	  return returnValue;
	}
	// }}}
	,
	// {{{ cancelEvent()
    /**
     *
     *  This function only returns false. It is used to cancel selections and drag
     *
     *
     * @public
     */

	cancelEvent : function()
	{
		return false;
	}
	// }}}
	,
	// {{{ addEvent()
    /**
     *
     *  This function adds an event listener to an element on the page.
     *
     *	@param Object whichObject = Reference to HTML element(Which object to assigne the event)
     *	@param String eventType = Which type of event, example "mousemove" or "mouseup"
     *	@param functionName = Name of function to execute.
     *
     * @public
     */
	addEvent : function(whichObject,eventType,functionName)
	{
	  if(whichObject.attachEvent){
	    whichObject['e'+eventType+functionName] = functionName;
	    whichObject[eventType+functionName] = function(){whichObject['e'+eventType+functionName]( window.event );}
	    whichObject.attachEvent( 'on'+eventType, whichObject[eventType+functionName] );
	  } else
	    whichObject.addEventListener(eventType,functionName,false);
	  this.__addEventEl(whichObject);
	  delete(whichObject);
	  // whichObject = null;
	}
	// }}}
	,
	// {{{ removeEvent()
    /**
     *
     *  This function removes an event listener from an element on the page.
     *
     *	@param Object whichObject = Reference to HTML element(Which object to assigne the event)
     *	@param String eventType = Which type of event, example "mousemove" or "mouseup"
     *	@param functionName = Name of function to execute.
     *
     * @public
     */
	removeEvent : function(whichObject,eventType,functionName)
	{
	  if(whichObject.detachEvent){
	    whichObject.detachEvent('on'+eventType, whichObject[eventType+functionName]);
	    whichObject[eventType+functionName] = null;
	  } else
	    whichObject.removeEventListener(eventType,functionName,false);
	}
	,
	// {{{ __clearGarbage()
    /**
     *
     *  This function is used for Internet Explorer in order to clear memory when the page unloads.
     *
     *
     * @private
     */
    __clearGarbage : function()
    {
   		/* Example of event which causes memory leakage in IE

   		DHTMLSuite.commonObj.addEvent(expandRef,"click",function(){ window.refToMyMenuBar[index].__changeMenuBarState(this); })

   		We got a circular reference.

   		*/

    	if(!DHTMLSuite.clientInfoObj.isMSIE)return;

    	for(var no in DHTMLSuite.variableStorage.arrayDSObjects){
    		DHTMLSuite.variableStorage.arrayDSObjects[no] = false;
    	}

    	for(var no=0;no<DHTMLSuite.eventElements.length;no++){
    		DHTMLSuite.eventElements[no].onclick = null;
    		DHTMLSuite.eventElements[no].onmousedown = null;
    		DHTMLSuite.eventElements[no].onmousemove = null;
    		DHTMLSuite.eventElements[no].onmouseout = null;
    		DHTMLSuite.eventElements[no].onmouseover = null;
    		DHTMLSuite.eventElements[no].onmouseup = null;
    		DHTMLSuite.eventElements[no].onfocus = null;
    		DHTMLSuite.eventElements[no].onblur = null;
    		DHTMLSuite.eventElements[no].onkeydown = null;
    		DHTMLSuite.eventElements[no].onkeypress = null;
    		DHTMLSuite.eventElements[no].onkeyup = null;
    		DHTMLSuite.eventElements[no].onselectstart = null;
    		DHTMLSuite.eventElements[no].ondragstart = null;
    		DHTMLSuite.eventElements[no].oncontextmenu = null;
    		DHTMLSuite.eventElements[no].onscroll = null;

    	}
    	window.onunload = null;
    	DHTMLSuite = null;

    }

    ,
	// {{{ __addEventEl()
    /**
     *
     *  Add element to garbage collection array. The script will loop through this array and remove event handlers onload in ie.
     *
     *
     * @private
     */
    __addEventEl : function(el)
    {
    	DHTMLSuite.eventElements[DHTMLSuite.eventElements.length] = el;
    }
	,
	// {{{ getEl()
	/**
	 * Return a reference to an object
	 *
	 * @param Object elRef = Id, name or direct reference to element
	 * @return Object HTMLElement - direct reference to element
	 * @public
	 */
	getEl : function(elRef){
		if(typeof elRef=='string'){
			if(document.getElementById(elRef))return document.getElementById(elRef);
			if(document.forms[elRef])return document.forms[elRef];
			if(document[elRef])return document[elRef];
			if(window[elRef])return window[elRef];
		}
		return elRef;	// Return original ref.

	}
    ,

	// {{{ getSrcElement()
    /**
     *
     *  Returns a reference to the element which triggered an event.
     *	@param Event e = Event object
     *
     *
     * @private
     */
    getSrcElement : function(e)
    {
    	var el;
		// Dropped on which element
		if (e.target) el = e.target;
			else if (e.srcElement) el = e.srcElement;
			if (el.nodeType == 3) // defeat Safari bug
				el = el.parentNode;
		return el;
    }

}


/************************************************************************************************************
*	Client info class
*
*	Created:			August, 18th, 2006
* 	Update log:
*
************************************************************************************************************/

/**
* @constructor
* @class Purpose of class: Provide browser information to the classes below. Instead of checking for
*		 browser versions and browser types in the classes below, they should check this
*		 easily by referncing properties in the class below. An object("DHTMLSuite.clientInfoObj") of this
*		 class will always be accessible to the other classes. * @version 1.0
* @author	Alf Magne Kalleland(www.dhtmlgoodies.com)
**/


DHTMLSuite.clientInfo = function()
{
	var browser;			// Complete user agent information

	var isOpera;			// Is the browser "Opera"
	var isMSIE;				// Is the browser "Internet Explorer"
	var isFirefox;			// Is the browser "Firefox"
	var navigatorVersion;	// Browser version
}

DHTMLSuite.clientInfo.prototype = {

	/**
	* 	Constructor
	*	Params: 		none:
	*  	return value: 	none;
	**/
	// {{{ init()
    /**
     *
	 *
     *  This method initializes the script
     *
     *
     * @public
     */

	init : function()
	{
		this.browser = navigator.userAgent;
		this.isOpera = (this.browser.toLowerCase().indexOf('opera')>=0)?true:false;
		this.isFirefox = (this.browser.toLowerCase().indexOf('firefox')>=0)?true:false;
		this.isMSIE = (this.browser.toLowerCase().indexOf('msie')>=0)?true:false;
		this.isSafari = (this.browser.toLowerCase().indexOf('safari')>=0)?true:false;
		this.navigatorVersion = navigator.appVersion.replace(/.*?MSIE (\d\.\d).*/g,'$1')/1;
	}
	// }}}
}

/************************************************************************************************************
*	DHTML menu model item class
*
*	Created:						October, 30th, 2006
*	@class Purpose of class:		Save data about a menu item.
*
*
*
* 	Update log:
*
************************************************************************************************************/

DHTMLSuite.menuModelItem = function()
{
	var id;					// id of this menu item.
	var itemText;			// Text for this menu item
	var itemIcon;			// Icon for this menu item.
	var url;				// url when click on this menu item
	var parentId;			// id of parent element
	var separator;			// is this menu item a separator
	var jsFunction;			// Js function to call onclick
	var depth;				// Depth of this menu item.
	var hasSubs;			// Does this menu item have sub items.
	var type;				// Menu item type - possible values: "top" or "sub".
	var helpText;			// Help text for this item - appear when you move your mouse over the item.
	var state;
	var submenuWidth;		// Width of sub menu items.
	var visible;			// Visibility of menu item.

	this.state = 'regular';
}

DHTMLSuite.menuModelItem.prototype = {

	setMenuVars : function(id,itemText,itemIcon,url,parentId,helpText,jsFunction,type,submenuWidth)
	{
		this.id = id;
		this.itemText = itemText;
		this.itemIcon = itemIcon;
		this.url = url;
		this.parentId = parentId;
		this.jsFunction = jsFunction;
		this.separator = false;
		this.depth = false;
		this.hasSubs = false;
		this.helpText = helpText;
		this.submenuWidth = submenuWidth;
		this.visible = true;
		if(!type){
			if(this.parentId)this.type = 'top'; else this.type='sub';
		}else this.type = type;


	}
	// }}}
	,
	// {{{ setState()
    /**
     *	Update the state attribute of a menu item.
     *
     *  @param String newState New state of this item
     * @public
     */
	setAsSeparator : function(id,parentId)
	{
		this.id = id;
		this.parentId = parentId;
		this.separator = true;
		this.visible = true;
		if(this.parentId)this.type = 'top'; else this.type='sub';
	}
	// }}}
	,
	// {{{ setState()
    /**
     *	Update the visible attribute of a menu item.
     *
     *  @param Boolean visible true = visible, false = hidden.
     * @public
     */
	setVisibility : function(visible)
	{
		this.visible = visible;
	}
	// }}}
	,
	// {{{ getState()
    /**
     *	Return the state attribute of a menu item.
     *
     * @public
     */
	getState : function()
	{
		return this.state;
	}
	// }}}
	,
	// {{{ setState()
    /**
     *	Update the state attribute of a menu item.
     *
     *  @param String newState New state of this item
     * @public
     */
	setState : function(newState)
	{
		this.state = newState;
	}
	// }}}
	,
	// {{{ setSubMenuWidth()
    /**
     *	Specify width of direct subs of this item.
     *
     *  @param int newWidth Width of sub menu group(direct sub of this item)
     * @public
     */
	setSubMenuWidth : function(newWidth)
	{
		this.submenuWidth = newWidth;
	}
	// }}}
	,
	// {{{ setIcon()
    /**
     *	Specify new menu icon
     *
     *  @param String iconPath Path to new menu icon
     * @public
     */
	setIcon : function(iconPath)
	{
		this.itemIcon = iconPath;
	}
	// }}}
	,
	// {{{ setText()
    /**
     *	Specify new text for the menu item.
     *
     *  @param String newText New text for the menu item.
     * @public
     */
	setText : function(newText)
	{
		this.itemText = newText;
	}
}

/************************************************************************************************************
*	DHTML menu model class
*
*	Created:						October, 30th, 2006
*	@class Purpose of class:		Saves menu item data
*
*
*	Demos of this class:			demo-menu-strip.html
*
* 	Update log:
*
************************************************************************************************************/


/**
* @constructor
* @class Purpose of class:	Organize menu items for different menu widgets. demos of menus: (<a href="../../demos/demo-menu-strip.html" target="_blank">Demo</a>)
* @version 1.0
* @author	Alf Magne Kalleland(www.dhtmlgoodies.com)
*/


DHTMLSuite.menuModel = function()
{
	var menuItems;					// Array of menuModelItem objects
	var menuItemsOrder;			// This array is needed in order to preserve the correct order of the array above. the array above is associative
									// And some browsers will loop through that array in different orders than Firefox and IE.
	var submenuType;				// Direction of menu items(one item for each depth)
	var mainMenuGroupWidth;			// Width of menu group - useful if the first group of items are listed below each other
	this.menuItems = new Array();
	this.menuItemsOrder = new Array();
	this.submenuType = new Array();
	this.submenuType[1] = 'top';
	for(var no=2;no<20;no++){
		this.submenuType[no] = 'sub';
	}
	if(!standardObjectsCreated)DHTMLSuite.createStandardObjects();
}

DHTMLSuite.menuModel.prototype = {
	// {{{ addItem()
    /**
     *	Add separator (special type of menu item)
     *
 	 *
     *
     *  @param int id of menu item
     *  @param string itemText = text of menu item
     *  @param string itemIcon = file name of menu icon(in front of menu text. Path will be imagePath for the DHTMLSuite + file name)
     *  @param string url = Url of menu item
     *  @param int parent id of menu item
     *  @param String jsFunction Name of javascript function to execute. It will replace the url param. The function with this name will be called and the element triggering the action will be
     *					sent as argument. Name of the element which triggered the menu action may also be sent as a second argument. That depends on the widget. The context menu is an example where
     *					the element triggering the context menu is sent as second argument to this function.
     *
     * @public
     */
	addItem : function(id,itemText,itemIcon,url,parentId,helpText,jsFunction,type,submenuWidth)
	{
		if(!id)id = this.__getUniqueId();	// id not present - create it dynamically.
		this.menuItems[id] = new DHTMLSuite.menuModelItem();
		this.menuItems[id].setMenuVars(id,itemText,itemIcon,url,parentId,helpText,jsFunction,type,submenuWidth);
		this.menuItemsOrder[this.menuItemsOrder.length] = id;
		return this.menuItems[id];
	}
	,
	// {{{ addItemsFromMarkup()
    /**
     *	This method creates all the menuModelItem objects by reading it from existing markup on your page.
     *	Example of HTML markup:
     *<br>
		&nbsp;&nbsp;&nbsp;&nbsp;&lt;ul id="menuModel">
		<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;li id="50000" itemIcon="../img/disk.gif">&lt;a href="#" title="Open the file menu">File&lt;/a>
		<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;ul width="150">
		<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;li id="500001" jsFunction="saveWork()" itemIcon="../img/disk.gif">&lt;a href="#" title="Save your work">Save&lt;/a>&lt;/li>
		<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;li id="500002">&lt;a href="#">Save As&lt;/a>&lt;/li>
		<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;li id="500004" itemType="separator">&lt;/li>
		<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;li id="500003">&lt;a href="#">Open&lt;/a>&lt;/li>
		<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/ul>
		<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/li>
		<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;li id="50001">&lt;a href="#">View&lt;/a>
		<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;ul width="130">
		<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;li id="500011">&lt;a href="#">Source&lt;/a>&lt;/li>
		<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;li id="500012">&lt;a href="#">Debug info&lt;/a>&lt;/li>
		<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;li id="500013">&lt;a href="#">Layout&lt;/a>
		<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;ul width="150">
		<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;li id="5000131">&lt;a href="#">CSS&lt;/a>&nbsp;&nbsp;
		<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;li id="5000132">&lt;a href="#">HTML&lt;/a>&nbsp;&nbsp;
		<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;li id="5000133">&lt;a href="#">Javascript&lt;/a>&nbsp;&nbsp;
		<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/ul>
		<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/li>
		<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
		<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/ul>
		<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/li>
		<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;li id="50003" itemType="separator">&lt;/li>
		<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;li id="50002">&lt;a href="#">Tools&lt;/a>&lt;/li>
		<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;/ul>&nbsp;&nbsp;
     *
     *  @param String ulId = ID of <UL> tag on your page.
     *
     * @public
     */
	addItemsFromMarkup : function(ulId)
	{
		if(!document.getElementById(ulId)){
			alert('<UL> tag with id ' + ulId + ' does not exist');
			return;
		}
		var ulObj = document.getElementById(ulId);
		var liTags = ulObj.getElementsByTagName('LI');
		for(var no=0;no<liTags.length;no++){	// Walking through all <li> tags in the <ul> tree

			var id = liTags[no].id.replace(/[^0-9]/gi,'');	// Get id of item.
			if(!id)id = this.__getUniqueId();
			this.menuItems[id] = new DHTMLSuite.menuModelItem();	// Creating new menuModelItem object
			this.menuItemsOrder[this.menuItemsOrder.length] = id;
			// Get the attributes for this new menu item.

			var parentId = 0;	// Default parent id
			if(liTags[no].parentNode!=ulObj)parentId = liTags[no].parentNode.parentNode.id;	// parent node exists, set parentId equal to id of parent <li>.

			/* Checking type */
			var type = liTags[no].getAttribute('itemType');
			if(!type)type = liTags[no].itemType;
			if(type=='separator'){	// Menu item of type "separator"
				this.menuItems[id].setAsSeparator(id,parentId);
				continue;
			}
			if(parentId)type='sub'; else type = 'top';

			var aTag = liTags[no].getElementsByTagName('A')[0];	// Get a reference to sub <a> tag
			if(!aTag){
				continue;
			}
			if(aTag)var itemText = aTag.innerHTML;	// Item text is set to the innerHTML of the <a> tag.
			var itemIcon = liTags[no].getAttribute('itemIcon');	// Item icon is set from the itemIcon attribute of the <li> tag.
			var url = aTag.href;	// url is set to the href attribute of the <a> tag
			if(url=='#' || url.substr(url.length-1,1)=='#')url='';	// # = empty url.

			var jsFunction = liTags[no].getAttribute('jsFunction');	// jsFunction is set from the jsFunction attribute of the <li> tag.

			var submenuWidth = false;	// Not set from the <li> tag.
			var helpText = aTag.getAttribute('title');
			if(!helpText)helpText = aTag.title;

			this.menuItems[id].setMenuVars(id,itemText,itemIcon,url,parentId,helpText,jsFunction,type,submenuWidth);
		}
		var subUls = ulObj.getElementsByTagName('UL');
		for(var no=0;no<subUls.length;no++){
			var width = subUls[no].getAttribute('width');
			if(!width)width = subUls[no].width;
			if(width){
				var id = subUls[no].parentNode.id.replace(/[^0-9]/gi,'');
				this.setSubMenuWidth(id,width);
			}
		}
		ulObj.style.display='none';

	}
	// }}}
	,
	// {{{ setSubMenuWidth()
    /**
     *	This method specifies the width of a sub menu group. This is a useful method in order to get a correct width in IE6 and prior.
     *
     *  @param int id = ID of parent menu item
     *  @param String newWidth = Width of sub menu items.
     * @public
     */
	setSubMenuWidth : function(id,newWidth)
	{
		this.menuItems[id].setSubMenuWidth(newWidth);
	}
	,
	// {{{ setMainMenuGroupWidth()
    /**
     *	Add separator (special type of menu item)
     *
     *  @param String newWidth = Size of a menu group
     *  @param int parent id of menu item
     * @public
     */
	setMainMenuGroupWidth : function(newWidth)
	{
		this.mainMenuGroupWidth = newWidth;
	}
	,
	// {{{ addSeparator()
    /**
     *	Add separator (special type of menu item)
     *
     *  @param int parent id of menu item
     * @public
     */
	addSeparator : function(parentId)
	{
		id = this.__getUniqueId();	// Get unique id
		if(!parentId)parentId = 0;
		this.menuItems[id] = new DHTMLSuite.menuModelItem();
		this.menuItems[id].setAsSeparator(id,parentId);
		this.menuItemsOrder[this.menuItemsOrder.length] = id;
		return this.menuItems[id];
	}
	,
	// {{{ init()
    /**
     *	Initilizes the menu model. This method should be called when all items has been added to the model.
     *
     *
     * @public
     */
	init : function()
	{
		this.__getDepths();
		this.__setHasSubs();

	}
	// }}}
	,
	// {{{ setMenuItemVisibility()
    /**
     *	Save visibility of a menu item.
     *
     *	@param int id = Id of menu item..
     *	@param Boolean visible = Visibility of menu item.
     *
     * @public
     */
	setMenuItemVisibility : function(id,visible)
	{
		this.menuItems[id].setVisibility(visible);
	}
	// }}}
	,
	// {{{ setSubMenuType()
    /**
     *	Set menu type for a specific menu depth.
     *
     *	@param int depth = 1 = Top menu, 2 = Sub level 1...
     *	@param String newType = New menu type(possible values: "top" or "sub")
     *
     * @private
     */
	setSubMenuType : function(depth,newType)
	{
		this.submenuType[depth] = newType;

	}
	// }}}
	,
	// {{{ __getDepths()
    /**
     *	Create variable for the depth of each menu item.
     *
     *
     * @private
     */
	getItems : function(parentId,returnArray)
	{
		if(!parentId)return this.menuItems;
		if(!returnArray)returnArray = new Array();
		for(var no=0;no<this.menuItemsOrder.length;no++){
			var id = this.menuItemsOrder[no];
			if(!id)continue;
			if(this.menuItems[id].parentId==parentId){
				returnArray[returnArray.length] = this.menuItems[id];
				if(this.menuItems[id].hasSubs)return this.getItems(this.menuItems[id].id,returnArray);
			}
		}
		return returnArray;

	}
	// }}}
	,
	// {{{ __getUniqueId()
    /**
     *	Returns a unique id for a menu item. This method is used by the addSeparator function in case an id isn't sent to the method.
     *
     *
     * @private
     */
	__getUniqueId : function()
	{
		var num = Math.random() + '';
		num = num.replace('.','');
		num = '99' + num;
		num = num /1;
		while(this.menuItems[num]){
			num = Math.random() + '';
			num = num.replace('.','');
			num = num /1;
		}
		return num;
	}
	// }}}
	,
	// {{{ __getDepths()
    /**
     *	Create variable for the depth of each menu item.
     *
     *
     * @private
     */
   __getDepths: function(){
		for (var no = 0; no < this.menuItemsOrder.length; no++) {
			var id = this.menuItemsOrder[no];
			if (!id)
				continue;
			
			var userA = navigator.userAgent;
			
			if (navigator.codeName == "Mozilla" && userA.match("Firefox/3.5") !== null){
				while (!this.menuItems[id]) { //add this
				}
			}
			this.menuItems[id].depth = 1;
			if (this.menuItems[id].parentId) {
				this.menuItems[id].depth = this.menuItems[this.menuItems[id].parentId].depth + 1;

			}
			this.menuItems[id].type = this.submenuType[this.menuItems[id].depth];
		// Save menu direction for this menu item.
		}
	}

    // }}}
    ,
    // {{{ __setHasSubs()
    /**
     *	Create variable for the depth of each menu item.
     *
     *
     * @private
     */
    __setHasSubs: function(){
		for (var no = 0; no < this.menuItemsOrder.length; no++) {
			var id = this.menuItemsOrder[no];
			if (!id)
				continue;
			
			var userA = navigator.userAgent;
			
			if (navigator.codeName == "Mozilla" && userA.match("Firefox/3.5") !== null){
				while (!this.menuItems[id]) { //add this
				}
			}
			if (this.menuItems[id].parentId) {
				this.menuItems[this.menuItems[id].parentId].hasSubs = 1;

			}
		}
	}
    // }}}
    ,
	// {{{ __hasSubs()
    /**
     *	Does a menu item have sub elements ?
     *
     *
     * @private
     */
	// }}}
	__hasSubs : function(id)
	{
		for(var no=0;no<this.menuItemsOrder.length;no++){
			var id = this.menuItemsOrder[no];
			if(!id)continue;
			if(this.menuItems[id].parentId==id)return true;
		}
		return false;
	}
	// }}}
	,
	// {{{ __deleteChildNodes()
    /**
     *	Deleting child nodes of a specific parent id
     *
     *	@param int parentId
     *
     * @private
     */
	// }}}
	__deleteChildNodes : function(parentId,recursive)
	{
		var itemsToDeleteFromOrderArray = new Array();
		for(var prop=0;prop<this.menuItemsOrder.length;prop++){
    		var id = this.menuItemsOrder[prop];
    		if(!id)continue;
			
			if(this.menuItems[id] && this.menuItems[id].parentId==parentId && parentId){
				this.menuItems[id] = false;
				itemsToDeleteFromOrderArray[itemsToDeleteFromOrderArray.length] = id;
				this.__deleteChildNodes(id,true);	// Recursive call.
			}
		}

		if(!recursive){
			for(var prop=0;prop<itemsToDeleteFromOrderArray;prop++){
				if(!itemsToDeleteFromOrderArray[prop])continue;
				this.__deleteItemFromItemOrderArray(itemsToDeleteFromOrderArray[prop]);
			}
		}
		this.__setHasSubs();
	}
	// }}}
	,
	// {{{ __deleteANode()
    /**
     *	Deleting a specific node from the menu model
     *
     *	@param int id = Id of node to delete.
     *
     * @private
     */
	// }}}
	__deleteANode : function(id)
	{
		this.menuItems[id] = false;
		this.__deleteItemFromItemOrderArray(id);
	}
	,
	// {{{ __deleteItemFromItemOrderArray()
    /**
     *	Deleting a specific node from the menuItemsOrder array(The array controlling the order of the menu items).
     *
     *	@param int id = Id of node to delete.
     *
     * @private
     */
	// }}}
	__deleteItemFromItemOrderArray : function(id)
	{
		for(var no=0;no<this.menuItemsOrder.length;no++){
			var tmpId = this.menuItemsOrder[no];
			if(!tmpId)continue;
			if(this.menuItemsOrder[no]==id){
				this.menuItemsOrder.splice(no,1);
				return;
			}
		}

	}
	// }}}
	,
	// {{{ __appendMenuModel()
    /**
     *	Replace the sub items of a menu item with items from a new menuModel.
     *
     *	@param menuModel newModel = An object of class menuModel - the items of this menu model will be appended to the existing menu items.
     *	@param Int parentId = Id of parent element of the appended items.
     *
     * @private
     */
	// }}}
	__appendMenuModel : function(newModel,parentId)
	{
		if(!newModel)return;
		var items = newModel.getItems();
		for(var no=0;no<newModel.menuItemsOrder.length;no++){
			var id = newModel.menuItemsOrder[no];
			if(!id)continue;
			if(!items[id].parentId)items[id].parentId = parentId;
			this.menuItems[id] = items[id];
			for(var no2=0;no2<this.menuItemsOrder.length;no2++){	// Check to see if this item allready exists in the menuItemsOrder array, if it does, remove it.
				if(!this.menuItemsOrder[no2])continue;
				if(this.menuItemsOrder[no2]==items[id].id){
					this.menuItemsOrder.splice(no2,1);
				}
			}
			this.menuItemsOrder[this.menuItemsOrder.length] = items[id].id;
		}
		this.__getDepths();
		this.__setHasSubs();
	}
	// }}}
}

/* Class for menu items - a view */

/************************************************************************************************************
*	DHTML menu item class
*
*	Created:						October, 21st, 2006
*	@class Purpose of class:		Creates the HTML for a single menu item.
*
*	Css files used by this script:	menu-item.css
*
*	Demos of this class:			demo-menu-strip.html
*
* 	Update log:
*
************************************************************************************************************/

/**
* @constructor
* @class Purpose of class:	Creates the div(s) for a menu item. This class is used by the menuBar class. You can
*	also create a menu item and add it where you want on your page. the createItem() method will return the div
*	for the item. You can use the appendChild() method to add it to your page.
*
* @version 1.0
* @author	Alf Magne Kalleland(www.dhtmlgoodies.com)
*/


DHTMLSuite.menuItem = function()
{
	var layoutCSS;
	var divElement;							// the <div> element created for this menu item
	var expandElement;						// Reference to the arrow div (expand sub items)
	var cssPrefix;							// Css prefix for the menu items.
	var modelItemRef;						// Reference to menuModelItem

	this.layoutCSS = 'menu-item.css';
	this.cssPrefix = 'DHTMLSuite_';

	if(!standardObjectsCreated)DHTMLSuite.createStandardObjects();


	var objectIndex;
	this.objectIndex = DHTMLSuite.variableStorage.arrayDSObjects.length;


}
DHTMLSuite.menuItem.prototype =
{

	/*
	*	Create a menu item.
	*
	*	@param menuModelItem menuModelItemObj = An object of class menuModelItem
	*/
	createItem : function(menuModelItemObj){
		DHTMLSuite.commonObj.loadCSS(this.layoutCSS);	// Load css

		DHTMLSuite.variableStorage.arrayDSObjects[this.objectIndex] = this;

		this.modelItemRef = menuModelItemObj;

		this.divElement = 'DHTMLSuite_menuItem' + menuModelItemObj.id;

		var div = document.createElement('DIV');	// Create main div
		document.body.appendChild(div);
		div.id = this.divElement;	// Giving this menu item it's unque id
		div.className = this.cssPrefix + 'menuItem_' + menuModelItemObj.type + '_regular';
		div.onselectstart = function() { return false; };
		if(menuModelItemObj.helpText){	// Add "title" attribute to the div tag if helpText is defined
			div.title = menuModelItemObj.helpText;
		}

		// Menu item of type "top"
		if(menuModelItemObj.type=='top'){
			this.__createMenuElementsOfTypeTop(div);
		}

		if(menuModelItemObj.type=='sub'){
			this.__createMenuElementsOfTypeSub(div);
		}

		if(menuModelItemObj.separator){
			div.className = this.cssPrefix + 'menuItem_separator_' + menuModelItemObj.type;
			div.innerHTML = '<span></span>';
		}else{
			/* Add events */
			var tmpVar = this.objectIndex/1;
			div.onclick = function(e) { DHTMLSuite.variableStorage.arrayDSObjects[tmpVar].__navigate(e); }
			div.onmousedown = this.__clickMenuItem;			// on mouse down effect
			div.onmouseup = this.__rolloverMenuItem;		// on mouse up effect
			div.onmouseover = this.__rolloverMenuItem;		// mouse over effect
			div.onmouseout = this.__rolloutMenuItem;		// mouse out effect.

		}
		DHTMLSuite.commonObj.__addEventEl(div);
		return div;
	}
	// }}}
	,
	// {{{ setLayoutCss()
	/**
	 *	Creates the different parts of a menu item of type "top".
	 *
	 *  @param String newLayoutCss = Name of css file used for the menu items.
	 *
	 * @public
	 */
	setLayoutCss : function(newLayoutCss){
		this.layoutCSS = newLayoutCss;

	}
	// }}}
	,
	// {{{ __createMenuElementsOfTypeTop()
	/**
	 *	Creates the different parts of a menu item of type "top".
	 *
	 *  @param menuModelItem menuModelItemObj = Object of type menuModelItemObj
	 *  @param Object parentEl = Reference to parent element
	 *
	 * @private
	 */
	__createMenuElementsOfTypeTop : function(parentEl){
		if(this.modelItemRef.itemIcon){
			var iconDiv = document.createElement('DIV');
			iconDiv.innerHTML = '<img src="' + this.modelItemRef.itemIcon + '">';
			iconDiv.id = 'menuItemIcon' + this.modelItemRef.id
			parentEl.appendChild(iconDiv);
		}
		if(this.modelItemRef.itemText){
			var div = document.createElement('DIV');
			div.innerHTML = this.modelItemRef.itemText;
			div.className = this.cssPrefix + 'menuItem_textContent';
			div.id = 'menuItemText' + this.modelItemRef.id;
			parentEl.appendChild(div);
		}
		if(this.modelItemRef.hasSubs){
			/* Create div for the arrow -> Show sub items */
			var div = document.createElement('DIV');
			div.className = this.cssPrefix + 'menuItem_top_arrowShowSub';
			div.id = 'DHTMLSuite_menuBar_arrow' + this.modelItemRef.id;
			parentEl.appendChild(div);
			this.expandElement = div.id;
		}

	}
	// }}}
	,

	// {{{ __createMenuElementsOfTypeSub()
	/**
	 *	Creates the different parts of a menu item of type "sub".
	 *
	 *  @param menuModelItem menuModelItemObj = Object of type menuModelItemObj
	 *  @param Object parentEl = Reference to parent element
	 *
	 * @private
	 */
	__createMenuElementsOfTypeSub : function(parentEl){
		if(this.modelItemRef.itemIcon){
			parentEl.style.backgroundImage = 'url(\'' + this.modelItemRef.itemIcon + '\')';
			parentEl.style.backgroundRepeat = 'no-repeat';
			parentEl.style.backgroundPosition = 'left center';
		}
		if(this.modelItemRef.itemText){
			var div = document.createElement('DIV');
			div.className = 'DHTMLSuite_textContent';
			div.innerHTML = this.modelItemRef.itemText;
			div.className = this.cssPrefix + 'menuItem_textContent';
			div.id = 'menuItemText' + this.modelItemRef.id;
			parentEl.appendChild(div);
		}

		if(this.modelItemRef.hasSubs){
			/* Create div for the arrow -> Show sub items */
			var div = document.createElement('DIV');
			div.className = this.cssPrefix + 'menuItem_sub_arrowShowSub';
			parentEl.appendChild(div);
			div.id = 'DHTMLSuite_menuBar_arrow' + this.modelItemRef.id;
			this.expandElement = div.id;
			div.previousSibling.style.paddingRight = '15px';
		}
	}
	// }}}
	,
	// {{{ setCssPrefix()
	/**
	 *	Set css prefix for the menu item. default is 'DHTMLSuite_'. This is useful in case you want to have different menus on a page with different layout.
	 *
	 *  @param String cssPrefix = New css prefix.
	 *
	 * @public
	 */
	setCssPrefix : function(cssPrefix){
		this.cssPrefix = cssPrefix;
	}
	// }}}
	,
	// {{{ setMenuIcon()
	/**
	 *	Replace menu icon.
	 *
	 *	@param String newPath - Path to new icon (false if no icon);
	 *
	 * @public
	 */
	setIcon : function(newPath){
		this.modelItemRef.setIcon(newPath);
		if(this.modelItemRef.type=='top'){	// Menu item is of type "top"
			var div = document.getElementById('menuItemIcon' + this.modelItemRef.id);	// Get a reference to the div where the icon is located.
			var img = div.getElementsByTagName('IMG')[0];	// Find the image
			if(!img){	// Image doesn't exists ?
				img = document.createElement('IMG');	// Create new image
				div.appendChild(img);
			}
			img.src = newPath;	// Set image path
			if(!newPath)DHTMLSuite.discardElement(img);	// No newPath defined, remove the image.
		}
		if(this.modelItemRef.type=='sub'){	// Menu item is of type "sub"
			document.getElementById(this.divElement).style.backgroundImage = 'url(\'' + newPath + '\')';		// Set backgroundImage for the main div(i.e. menu item div)
		}
	}
	// }}}
	,
	// {{{ setText()
	/**
	 *	Replace the text of a menu item
	 *
	 *	@param String newText - New text for the menu item.
	 *
	 * @public
	 */
	setText : function(newText){
		this.modelItemRef.setText(newText);
		document.getElementById('menuItemText' + this.modelItemRef.id).innerHTML = newText;

	}

	// }}}
	,
	// {{{ __clickMenuItem()
	/**
	 *	Effect - click on menu item
	 *
	 *
	 * @private
	 */
	__clickMenuItem : function(){
		this.className = this.className.replace('_regular','_click');
		this.className = this.className.replace('_over','_click');
	}
	// }}}
	,
	// {{{ __rolloverMenuItem()
	/**
	 *	Roll over effect
	 *
	 *
	 * @private
	 */
	__rolloverMenuItem : function(){
		this.className = this.className.replace('_regular','_over');
		this.className = this.className.replace('_click','_over');
	}
	// }}}
	,
	// {{{ __rolloutMenuItem()
	/**
	 *	Roll out effect
	 *
	 *
	 * @private
	 */
	__rolloutMenuItem : function(){
		this.className = this.className.replace('_over','_regular');

	}
	// }}}
	,
	// {{{ setState()
	/**
	 *	Set state of a menu item.
	 *
	 *	@param String newState = New state for the menu item
	 *
	 * @public
	 */
	setState : function(newState){
		document.getElementById(this.divElement).className = this.cssPrefix + 'menuItem_' + this.modelItemRef.type + '_' + newState;
		this.modelItemRef.setState(newState);
	}
	// }}}
	,
	// {{{ getState()
	/**
	 *	Return state of a menu item.
	 *
	 *
	 * @public
	 */
	getState : function(){
		var state = this.modelItemRef.getState();
		if(!state){
			if(document.getElementById(this.divElement).className.indexOf('_over')>=0)state = 'over';
			if(document.getElementById(this.divElement).className.indexOf('_click')>=0)state = 'click';
			this.modelItemRef.setState(state);
		}
		return state;
	}
	// }}}
	,
	// {{{ __setHasSub()
	/**
	 *	Update the item, i.e. show/hide the arrow if the element has subs or not.
	 *
	 *
	 * @private
	 */
	__setHasSub : function(hasSubs){
		this.modelItemRef.hasSubs = hasSubs;
		if(!hasSubs){
			document.getElementById(this.cssPrefix +'menuBar_arrow' + this.modelItemRef.id).style.display='none';
		}else{
			document.getElementById(this.cssPrefix +'menuBar_arrow' + this.modelItemRef.id).style.display='block';
		}
	}
	// }}}
	,
	// {{{ hide()
	/**
	 *	Hide the menu item.
	 *
	 *
	 * @public
	 */
	hide : function(){
		this.modelItemRef.setVisibility(false);
		document.getElementById(this.divElement).style.display='none';
	}
	,
 	// {{{ show()
	/**
	 *	Show the menu item.
	 *
	 *
	 * @public
	 */
	show : function(){
		this.modelItemRef.setVisibility(true);
		document.getElementById(this.divElement).style.display='block';
	}
	// }}}
	,
	// {{{ __hideGroup()
	/**
	 *	Hide the group the menu item is a part of. Example: if we're dealing with menu item 2.1, hide the group for all sub items of 2
	 *
	 *
	 * @private
	 */
	__hideGroup : function(){
		if(this.modelItemRef.parentId){
			document.getElementById(this.divElement).parentNode.style.visibility='hidden';
			if(DHTMLSuite.clientInfoObj.isMSIE){
				try{
					var tmpId = document.getElementById(this.divElement).parentNode.id.replace(/[^0-9]/gi,'');
					document.getElementById('DHTMLSuite_menuBarIframe_' + tmpId).style.visibility = 'hidden';
				}catch(e){
					// IFRAME hasn't been created.
				}
			}
		}

	}
	// }}}
	,
	// {{{ __navigate()
	/**
	 *	Navigate after click on a menu item.
	 *
	 *
	 * @private
	 */
	__navigate : function(e){
		/* Check to see if the expand sub arrow is clicked. if it is, we shouldn't navigate from this click */
		if(document.all)e = event;
		if(e){
			var srcEl = DHTMLSuite.commonObj.getSrcElement(e);
			if(srcEl.id.indexOf('arrow')>=0)return;
		}
		if(this.modelItemRef.state=='disabled')return;
		if(this.modelItemRef.url){
			location.href = this.modelItemRef.url;
		}
		if(this.modelItemRef.jsFunction){
			//try{
				eval(this.modelItemRef.jsFunction);
			//}catch(e){
				//alert('Defined Javascript code for the menu item( ' + this.modelItemRef.jsFunction + ' ) cannot be executed');
			//}
		}
	}
	,
	// }}}
	// {{{ setJsFunction()
	/**
	 *	Set JsFunction of a menu item.
	 *
	 *	@param String newJsFunction = New function for the menu item
	 *
	 * @public
	 */
	setJsFunction : function(newJsFunction){
		this.modelItemRef.jsFunction=newJsFunction;
	}
	// }}}
}

/*[FILE_START:dhtmlSuite-menuBar.js] */
/************************************************************************************************************
*	DHTML menu bar class
*
*	Created:						October, 21st, 2006
*	@class Purpose of class:		Creates a top bar menu
*
*	Css files used by this script:	menu-bar.css
*
*	Demos of this class:			demo-menu-bar.html
*
* 	Update log:
*
************************************************************************************************************/
/**
* @constructor
* @class Purpose of class:	Creates a top bar menu strip. Demos: <br>
*	<ul>
*	<li>(<a href="../../demos/demo-menu-bar-2.html" target="_blank">A menu with a detailed description on how it is created</a>)</li>
*	<li>(<a href="../../demos/demo-pane-splitter.html" target="_blank">Menu bar in a pane splitter pane</a>)</li>
*	</ul>
*
*	<a href="../img/menu-bar-1.gif" target="_blank">Image describing the classes</a> <br><br>
*
* @version 1.0
* @author	Alf Magne Kalleland(www.dhtmlgoodies.com)
*/

DHTMLSuite.menuBar = function(){
	var menuItemObj;
	var layoutCSS;					// Name of css file
	var menuBarBackgroundImage;		// Name of background image
	var menuItem_objects;			// Array of menu items - html elements.
	var menuBarObj;					// Reference to the main dib
	var menuBarHeight;
	var menuItems;					// Reference to objects of class menuModelItem
	var highlightedItems;			// Array of currently highlighted menu items.
	var menuBarState;				// Menu bar state - true or false - 1 = expand items on mouse over
	var activeSubItemsOnMouseOver;	// Activate sub items on mouse over	(instead of onclick)

	var submenuGroups;				// Array of div elements for the sub menus
	var submenuIframes;				// Array of sub menu iframes used to cover select boxes in old IE browsers.
	var createIframesForOldIeBrowsers;	// true if we want the script to create iframes in order to cover select boxes in older ie browsers.
	var targetId;					// Id of element where the menu will be inserted.
	var menuItemCssPrefix;			// Css prefix of menu items.
	var cssPrefix;					// Css prefix for the menu bar
	var menuItemLayoutCss;			// Css path for the menu items of this menu bar
	var objectIndex;			// Global index of this object - used to refer to the object of this class outside
	this.cssPrefix = 'DHTMLSuite_';
	this.menuItemLayoutCss = false;	// false = use default for the menuItem class.
	this.layoutCSS = 'menu-bar.css';
	this.menuBarBackgroundImage = 'menu_strip_bg.jpg';
	this.menuItem_objects = new Object();
	DHTMLSuite.variableStorage.menuBar_highlightedItems = new Array();

	this.menuBarState = false;

	this.menuBarObj = false;
	this.menuBarHeight = 26;
	this.submenuGroups = new Array();
	this.submenuIframes = new Array();
	this.targetId = false;
	this.activeSubItemsOnMouseOver = false;
	this.menuItemCssPrefix = false;
	this.createIframesForOldIeBrowsers = true;
	try{
		if(!standardObjectsCreated)DHTMLSuite.createStandardObjects();
	}catch(e){
		alert('You need to include the dhtmlSuite-common.js file');
	}

	this.objectIndex = DHTMLSuite.variableStorage.arrayDSObjects.length;;
	DHTMLSuite.variableStorage.arrayDSObjects[this.objectIndex] = this;
}

DHTMLSuite.menuBar.prototype = {
	// {{{ init()
	/**
	 *	Initilizes the script - This method should be called after your set methods.
	 *
	 *
	 * @public
	 */
	init : function(){

		DHTMLSuite.commonObj.loadCSS(this.layoutCSS);
		this.__createMainMenuDiv();	// Create general divs
		this.__createMenuItems();	// Create menu items
		this.__setBasicEvents();	// Set basic events.
		window.refToThismenuBar = this;
	}
	// }}}
	,
	// {{{ setTarget()
	/**
	 *	Specify where this menu bar will be inserted. the element with this id will be parent of the menu bar.
	 *
	 *  @param String idOfHTMLElement = Id of element where the menu will be inserted.
	 *
	 * @public
	 */
	setTarget : function(idOfHTMLElement){
		this.targetId = idOfHTMLElement;

	}
	// }}}
	,
	// {{{ setLayoutCss()
	/**
	 *	Specify the css file for this menu bar
	 *
	 *  @param String nameOfNewCssFile = Name of new css file.
	 *
	 * @public
	 */
	setLayoutCss : function(nameOfNewCssFile){
		this.layoutCSS = nameOfNewCssFile;

	}
	// }}}
	,
	// {{{ setMenuItemLayoutCss()
	/**
	 *	Specify the css file for the menu items
	 *
	 *  @param String nameOfNewCssFile = Name of new css file.
	 *
	 * @public
	 */
	setMenuItemLayoutCss : function(nameOfNewCssFile){
		this.menuItemLayoutCss = nameOfNewCssFile;

	}
	// }}}
	,
	// {{{ setCreateIframesForOldIeBrowsers()
	/**
	 *	This method specifies if you want to the script to create iframes behind sub menu groups in order to cover eventual select boxes. This
	 *	is needed if you have users with older IE browsers(prior to version 7) and when there's a chance that a sub menu could appear on top
	 *	of a select box.
	 *
	 *  @param Boolean createIframesForOldIeBrowsers = true if you want the script to create iframes to cover select boxes in older ie browsers.
	 *
	 * @public
	 */
	setCreateIframesForOldIeBrowsers : function(createIframesForOldIeBrowsers){
		this.createIframesForOldIeBrowsers = createIframesForOldIeBrowsers;

	}
	// }}}
	,
	// {{{ addMenuItems()
	/**
	 *	Add menu items
	 *
	 *  @param DHTMLSuite.menuModel menuModel Object of class DHTMLSuite.menuModel which holds menu data
	 *
	 * @public
	 */
	addMenuItems : function(menuItemObj){
		this.menuItemObj = menuItemObj;
		this.menuItems = menuItemObj.getItems();
	}
	// }}}
	,
	// {{{ setActiveSubItemsOnMouseOver()
	/**
	 *	 Specify if sub menus should be activated on mouse over(i.e. no matter what the menuState property is).
	 *
	 *	@param Boolean activateSubOnMouseOver - Specify if sub menus should be activated on mouse over(i.e. no matter what the menuState property is).
	 *
	 * @public
	 */
	setActiveSubItemsOnMouseOver : function(activateSubOnMouseOver){
		this.activeSubItemsOnMouseOver = activateSubOnMouseOver;
	}
	// }}}
	,
	// {{{ setMenuItemState()
	/**
	 *	This method changes the state of the menu bar(expanded or collapsed). This method is called when someone clicks on the arrow at the right of menu items.
	 *
	 *	@param Number menuItemId - ID of the menu item we want to switch state for
	 * 	@param String state - New state(example: "disabled")
	 *
	 * @public
	 */
	setMenuItemState : function(menuItemId,state){
		//try{
			this.menuItem_objects[menuItemId].setState(state);
		/*}catch(e){
			//alert('menu item with id ' + menuItemId + ' does not exists or you have called the setMenuItemState method before the menu has been initialized');
			if (parent.userLoggedIn) parent.refreshMenu(true);
			else parent.refreshMenu();
		}*/

	}
	// }}}
	,
	// {{{ setMenuItemCssPrefix()
	/**
	 *	Specify prefix of css classes used for the menu items. Default css prefix is "DHTMLSuite_". If you wish have some custom styling for some of your menus,
	 *	create a separate css file and replace DHTMLSuite_ for the class names with your new prefix.  This is useful if you want to have two menus on the same page
	 *	with different stylings.
	 *
	 *	@param String newCssPrefix - New css prefix for menu items.
	 *
	 * @public
	 */
	setMenuItemCssPrefix : function(newCssPrefix){
		this.menuItemCssPrefix = newCssPrefix;
	}
	// }}}
	,
	// {{{ setCssPrefix()
	/**
	 *	Specify prefix of css classes used for the menu bar. Default css prefix is "DHTMLSuite_" and that's the prefix of all css classes inside menu-bar.css(the default css file).
	 *	If you want some custom menu bars, create and include your own css files, replace DHTMLSuite_ in the class names with your own prefix and set the new prefix by calling
	 *	this method. This is useful if you want to have two menus on the same page with different stylings.
	 *
	 *	@param String newCssPrefix - New css prefix for the menu bar classes.
	 *
	 * @public
	 */
	setCssPrefix : function(newCssPrefix){
		this.cssPrefix = newCssPrefix;
	}
	// }}}
	,
	// {{{ deleteAllMenuItems()
	/**
	 *	Delete all menu items. This is useful if you want to replace the entire menu model. Remember to call init() after new model has been added.
	 *
	 * @private
	 */
	deleteAllMenuItems : function(){
		this.hideSubMenus(); // Hide all sub menus
		this.__deleteMenuItems(0,false);
		this.__clearAllMenuItems();
	}
	// }}}
	,
	// {{{ replaceSubMenus()
	/**
	 *	This method replaces existing sub menu items with a new subset (To replace all menu items, pass 0 as idOfParentMenuItem)
	 *
	 *
	 *	@param Number idOfParentMenuItem - ID of parent element ( 0 if top node) - if set, all sub elements will be deleted and replaced with the new menu model.
	 *	@param menuModel newMenuModel - Reference to object of class menuModel
	 *
	 * @private
	 */
	replaceMenuItems : function(idOfParentMenuItem,newMenuModel){
		this.hideSubMenus();	// Hide all sub menus
		this.__deleteMenuItems(idOfParentMenuItem);	// Delete old menu items.
		this.menuItemObj.__appendMenuModel(newMenuModel,idOfParentMenuItem);	// Appending new menu items to the menu model.
		this.__clearAllMenuItems();
		this.__createMenuItems();
	}
	// }}}
	,
	// {{{ deleteMenuItems()
	/**
	 *	This method deletes menu items from the menu dynamically
	 *
	 *	@param Number idOfParentMenuItem - Parent id - parent id of the elements to delete.
	 *	@param Boolean deleteParentElement - Should parent element also be deleted, or only sub elements?
	 *
	 * @public
	 */
	deleteMenuItems : function(idOfParentMenuItem,deleteParentElement){
		//this.hideSubMenus();	// Hide all sub menus
		this.__deleteMenuItems(idOfParentMenuItem,deleteParentElement);
		this.__clearAllMenuItems();
		this.__createMenuItems();
	}
	// }}}
	,
	// {{{ appendMenuItems()
	/**
	 *	This method appends menu items to the menu dynamically
	 *
	 *	@param Integer idOfParentMenuItem - Parent id - where to append the new items.
	 *	@param menuModel newMenuModel - Object of type menuModel. This menuModel will be appended as sub elements of defined idOfParentMenuItem
	 *
	 * @public
	 */
	appendMenuItems : function(idOfParentMenuItem,newMenuModel){
		this.hideSubMenus();	// Hide all sub menus
		this.menuItemObj.__appendMenuModel(newMenuModel,idOfParentMenuItem);	// Appending new menu items to the menu model.
		this.__clearAllMenuItems();
		this.__createMenuItems();
	}
	// }}}
	,
	// {{{ hideMenuItem()
	/**
	 *	This method doesn't delete menu items. it hides them only.
	 *
	 *	@param Number menuItemId - Id of the item you want to hide.
	 *
	 * @public
	 */
	hideMenuItem : function(menuItemId){
		this.menuItem_objects[menuItemId].hide();

	}
	// }}}
	,
	// {{{ showMenuItem()
	/**
	 *	This method shows a menu item. If the item isn't hidden, nothing is done.
	 *
	 *	@param Number menuItemId - Id of the item you want to show
	 *
	 * @public
	 */
	showMenuItem : function(menuItemId){
		this.menuItem_objects[menuItemId].show();
	}
	// }}}
	,
	// {{{ setText()
	/**
	 *	Replace the text for a menu item
	 *
	 *	@param Integer menuItemId - Id of menu item.
	 *	@param String newText - New text for the menu item.
	 *
	 * @public
	 */
	setText : function(menuItemId,newText){
		this.menuItem_objects[menuItemId].setText(newText);
	}
	// }}}
	,
	// {{{ setIcon()
	/**
	 *	Replace menu icon for a menu item.
	 *
	 *	@param Integer menuItemId - Id of menu item.
	 *	@param String newPath - Path to new menu icon. Pass blank or false if you want to clear the menu item.
	 *
	 * @public
	 */
	setIcon : function(menuItemId,newPath){
		this.menuItem_objects[menuItemId].setIcon(newPath);
	}
	// }}}
	,
	// {{{ __clearAllMenuItems()
	/**
	 *	Delete HTML elements for all menu items.
	 *
	 * @private
	 */
	__clearAllMenuItems : function(){
		for(var prop=0;prop<this.menuItemObj.menuItemsOrder.length;prop++){
			var id = this.menuItemObj.menuItemsOrder[prop];
			if(!id)continue;
			if(this.submenuGroups[id]){
				var div = document.getElementById(this.submenuGroups[id]);
				DHTMLSuite.discardElement(div);
				this.submenuGroups[id] = null;
			}
			if(this.submenuIframes[id]){
				var ref = document.getElementById(this.submenuIframes[id]);
				DHTMLSuite.discardElement(ref);
				this.submenuIframes[id] = null;
			}
		}
		this.submenuGroups = new Array();
		this.submenuIframes = new Array();
		this.menuBarObj.innerHTML = '';
	}
	// }}}
	,
	// {{{ __deleteMenuItems()
	/**
	 *	This method deletes menu items from the menu, i.e. menu model and the div elements for these items.
	 *
	 *	@param Integer idOfParentMenuItem - Parent id - where to start the delete process.
	 *	@param Boolean includeParent - Delete parent menu item in addition to the sub menu items.
	 *
	 * @private
	 */
	__deleteMenuItems : function(idOfParentMenuItem,includeParent){
		if(includeParent)this.menuItemObj.__deleteANode(idOfParentMenuItem);
		if(!this.submenuGroups[idOfParentMenuItem])return;	// No sub items exists.
		this.menuItem_objects[idOfParentMenuItem].__setHasSub(false);	// Delete existing sub menu divs.
		this.menuItemObj.__deleteChildNodes(idOfParentMenuItem);	// Delete existing child nodes from menu model
		var groupBox = document.getElementById(this.submenuGroups[idOfParentMenuItem]);
		DHTMLSuite.discardElement(groupBox);// Delete sub menu group box.
		if(this.submenuIframes[idOfParentMenuItem]){
			DHTMLSuite.discardElement(this.submenuIframes[idOfParentMenuItem]);
		}
		this.submenuGroups.splice(idOfParentMenuItem,1);
		this.submenuIframes.splice(idOfParentMenuItem,1);
	}
	// }}}
	,
	// {{{ __changeMenuBarState()
	/**
	 *	This method changes the state of the menu bar(expanded or collapsed). This method is called when someone clicks on the arrow at the right of menu items.
	 *
	 *
	 * @private
	 */
	__changeMenuBarState : function(){
		var objectIndex = this.getAttribute('objectRef');
		var obj = DHTMLSuite.variableStorage.arrayDSObjects[objectIndex];
		var parentId = this.id.replace(/[^0-9]/gi,'');

		var state = obj.menuItem_objects[parentId].getState();

		if(state=='disabled')return;
		obj.menuBarState = !obj.menuBarState;
		if(!obj.menuBarState)obj.hideSubMenus();else{
			obj.hideSubMenus();
			setTimeout('DHTMLSuite.variableStorage.arrayDSObjects[' + objectIndex + '].__expandGroup(' + parentId+ ')',10);
		}
	}
	// }}}
	,
	// {{{ __createDivs()
	/**
	 *	Create the main HTML elements for this menu dynamically
	 *
	 *
	 * @private
	 */
	__createMainMenuDiv : function(){
		window.refTomenuBar = this;	// Reference to menu strip object

		this.menuBarObj = document.createElement('DIV');
		this.menuBarObj.className = this.cssPrefix + 'menuBar_' + this.menuItemObj.submenuType[1];

		if(!document.getElementById(this.targetId)){
			alert('No target defined for the menu object');
			return;
		}
		// Appending menu bar object as a sub of defined target element.
		var target = document.getElementById(this.targetId);
		target.appendChild(this.menuBarObj);
	}
	// }}}
	,
	// {{{ hideSubMenus()
	/**
	 *	Deactivate all sub menus ( collapse and set state back to regular )
	 *	In case you have a menu inside a scrollable container, call this method in an onscroll event for that element
	 *	example document.getElementById('textContent').onscroll = menuBar.__hideSubMenus;
	 *
	 *	@param Event e - this variable is present if this method is called from an event. You will never use this parameter
	 *
	 * @public
	 */
	hideSubMenus : function(e){
		if(this && this.tagName){	/* Method called from event */
			if(document.all)e = event;
			var srcEl = DHTMLSuite.commonObj.getSrcElement(e);
			if(srcEl.tagName.toLowerCase()=='img')srcEl = srcEl.parentNode;
			if(srcEl.className && srcEl.className.indexOf('arrow')>=0){
				return;
			}

		}
		for(var no=0;no<DHTMLSuite.variableStorage.menuBar_highlightedItems.length;no++){
			// se agrego la condicion && DHTMLSuite.variableStorage.menuBar_highlightedItems[no].getState()!='active' para que no se cambie el estilo de la opcion activa
			if(DHTMLSuite.variableStorage.menuBar_highlightedItems[no].getState()!='disabled' && DHTMLSuite.variableStorage.menuBar_highlightedItems[no].getState()!='active')DHTMLSuite.variableStorage.menuBar_highlightedItems[no].setState('regular');	// Set state back to regular
			DHTMLSuite.variableStorage.menuBar_highlightedItems[no].__hideGroup();	// Hide eventual sub menus
		}
		DHTMLSuite.variableStorage.menuBar_highlightedItems = new Array();
	}
	,
	// {{{ __hideSubMenusAfterSmallDelay()
	/**
	 *	Hide sub menu items after a small delay - mouse down event for the HTML elemnet
	 *
	 *
	 * @private
	 */
	__hideSubMenusAfterSmallDelay : function(){
		var ind = this.objectIndex;
		setTimeout('DHTMLSuite.variableStorage.arrayDSObjects[' + ind + '].hideSubMenus()',15);
	}
	// }}}
	,
	// {{{ __expandGroup()
	/**
	 *	Expand a group of sub items.
	 *
	 * 	@param integer idOfParentMenuItem - Id of parent element
	 *
	 * @private
	 */
	__expandGroup : function(idOfParentMenuItem){
		var groupRef = document.getElementById(this.submenuGroups[idOfParentMenuItem]);
		var subDiv = groupRef.getElementsByTagName('DIV')[0];

		var numericId = subDiv.id.replace(/[^0-9]/g,'');

		groupRef.style.visibility='visible';	// Show menu group.
		if(this.submenuIframes[idOfParentMenuItem])document.getElementById(this.submenuIframes[idOfParentMenuItem]).style.visibility = 'visible';	// Show iframe if it exists.
		DHTMLSuite.variableStorage.menuBar_highlightedItems[DHTMLSuite.variableStorage.menuBar_highlightedItems.length] = this.menuItem_objects[numericId];
		this.__positionSubMenu(idOfParentMenuItem);

		if(DHTMLSuite.clientInfoObj.isOpera){	/* Opera fix in order to get correct height of sub menu group */
			var subDiv = groupRef.getElementsByTagName('DIV')[0];	/* Find first menu item */
			subDiv.className = subDiv.className.replace('_over','_over');	/* By "touching" the class of the menu item, we are able to fix a layout problem in Opera */
		}
	}

	,
	// {{{ __activateMenuElements()
	/**
	 *	Traverse up the menu items and highlight them.
	 *
	 *	@param HTMLElement parentMenuItemObject - Reference to the DIV tag(menu element) triggering the event. This would be the parent menu item of the sub menu to expand
	 *	@param Object menuBarObjectRef - Reference to this menuBar object
	 *	@param Boolean firstIteration - First iteration of this method, i.e. not recursive ?
	 *
	 * @private
	 */
	__activateMenuElements : function(e,firstIteration,parentMenuItemObject){
		if(!parentMenuItemObject){
			if(document.all)e = event;
			parentMenuItemObject = DHTMLSuite.commonObj.getSrcElement(e);
			if(!parentMenuItemObject.getAttribute('DHTMLSuite_menuItem'))parentMenuItemObject = parentMenuItemObject.parentNode;
			if(!parentMenuItemObject.getAttribute('DHTMLSuite_menuItem'))parentMenuItemObject = parentMenuItemObject.parentNode;
		}
		var numericId = parentMenuItemObject.id.replace(/[^0-9]/g,'');	// Get a numeric reference to current menu item.
		var state = this.menuItem_objects[numericId].getState();	// Get state of this menu item.
		if(state=='disabled')return;	// This menu item is disabled - return from function without doing anything.
		this.menuItem_objects[numericId].setState('over');	// Switch state of menu item.

		if(!this.menuBarState && !this.activeSubItemsOnMouseOver)return;	// Menu is not activated and it shouldn't be activated on mouse over.

		if(firstIteration && DHTMLSuite.variableStorage.menuBar_highlightedItems.length>0){
			this.hideSubMenus();	// First iteration of this function=> Hide other sub menus.
		}

		// What should be the state of this menu item -> If it's the one the mouse is over, state should be "over". If it's a parent element, state should be "active".
		var newState = 'over';
		//Comentado para eliminar issue generado al hacer mouse out en el menu
		//if(!firstIteration)newState = 'active';	// State should be set to 'over' for the menu item the mouse is currently over.

		this.menuItem_objects[numericId].setState(newState);	// Switch state of menu item.
		if(this.submenuGroups[numericId]){	// Sub menu group exists. call the __expandGroup method.
			this.__expandGroup(numericId);	// Expand sub menu group
		}
		DHTMLSuite.variableStorage.menuBar_highlightedItems[DHTMLSuite.variableStorage.menuBar_highlightedItems.length] = this.menuItem_objects[numericId];	// Save this menu item in the array of highlighted elements.
		if(this.menuItems[numericId].parentId){	// A parent element exists. Call this method over again with parent element as input argument.
			this.__activateMenuElements(false,false,document.getElementById(this.menuItem_objects[this.menuItems[numericId].parentId].divElement));
		}
	}
	// }}}
	,
	// {{{ __createMenuItems()
	/**
	 *	Creates the HTML elements for the menu items.
	 *
	 *
	 * @private
	 */
	__createMenuItems : function(){

		var index = this.objectIndex;
		// Find first child of the body element. trying to insert the element before first child instead of appending it to the <body> tag, ref: problems in ie
		var firstChild = false;
		var firstChilds = document.getElementsByTagName('DIV');
		if(firstChilds.length>0)firstChild = firstChilds[0]

		for(var no=0;no<this.menuItemObj.menuItemsOrder.length;no++){	// Looping through menu items
			var indexThis = this.menuItemObj.menuItemsOrder[no];
			if(!this.menuItems[indexThis].id)continue;
			try{
				this.menuItem_objects[this.menuItems[indexThis].id] = new DHTMLSuite.menuItem();
			}catch(e){
				alert('Error: You need to include dhtmlSuite-menuItem.js in your html file');
			}
			if(this.menuItemCssPrefix)this.menuItem_objects[this.menuItems[indexThis].id].setCssPrefix(this.menuItemCssPrefix);	// Custom css prefix set
			if(this.menuItemLayoutCss)this.menuItem_objects[this.menuItems[indexThis].id].setLayoutCss(this.menuItemLayoutCss);	// Custom css file name

			var ref = this.menuItem_objects[this.menuItems[indexThis].id].createItem(this.menuItems[indexThis]); // Create div for this menu item.
			ref.setAttribute('DHTMLSuite_menuItem',1);
			// Actiave sub elements when someone moves the mouse over the menu item - exception: not on separators.
			if(!this.menuItems[indexThis].separator){
				ref.onmouseover = function(e){ DHTMLSuite.variableStorage.arrayDSObjects[index].__activateMenuElements(e,true); }
			}

			if(!this.menuItems[indexThis].jsFunction && !this.menuItems[indexThis].url){
				ref.setAttribute('objectRef',index);	/* saving the index of this object in the DHTMLSuite.variableStorage array as a property of the tag - We need to do this in order to avoid circular references and thus memory leakage in IE */
				ref.onclick = this.__changeMenuBarState;
			}
			DHTMLSuite.commonObj.__addEventEl(ref);
			if(this.menuItem_objects[this.menuItems[indexThis].id].expandElement && 1==2){	/* Small arrow at the right of the menu item exists - expand subs */
				try{
					var expandRef = document.getElementById(this.menuItem_objects[this.menuItems[indexThis].id].expandElement);	/* Creating reference to expand div/arrow div */
					var parentId = DHTMLSuite.variableStorage.arrayDSObjects[index].menuItems[indexThis].parentId + '';	// Get parent id.
					var tmpId = expandRef.id.replace(/[^0-9]/gi,'');
					expandRef.setAttribute('objectRef',index/1);	/* saving the index of this object in the DHTMLSuite.variableStorage array as a property of the tag - We need to do this in order to avoid circular references and thus memory leakage in IE */
					expandRef.objectRef = index/1;
				}catch(e){

				}
			}
			var target = this.menuBarObj;	// Temporary variable - target of newly created menu item. target can be the main menu object or a sub menu group(see below where target is updated).

			if(this.menuItems[indexThis].depth==1 && this.menuItemObj.submenuType[this.menuItems[indexThis].depth]!='top' && this.menuItemObj.mainMenuGroupWidth){	/* Main menu item group width set */
				var tmpWidth = this.menuItemObj.mainMenuGroupWidth + '';
				if(tmpWidth.indexOf('%')==-1)tmpWidth = tmpWidth + 'px';
				target.style.width = tmpWidth;
			}

			if(this.menuItems[indexThis].depth=='1'){	/* Top level item */
				if(this.menuItemObj.submenuType[this.menuItems[indexThis].depth]=='top'){	/* Type = "top" - menu items side by side */
					ref.style.styleFloat = 'left';
					ref.style.cssText = 'float:left';
				}
			}else{
				if(!this.menuItems[indexThis].depth){
					alert('Error in menu model(depth not defined for a menu item). Remember to call the init() method for the menuModel object.');
					return;
				}
				if(!this.submenuGroups[this.menuItems[indexThis].parentId]){	// Sub menu div doesn't exist - > Create it.

					this.submenuGroups[this.menuItems[indexThis].parentId] = 'DHTMLSuite_menuBarSubGroup' + this.menuItems[indexThis].parentId;
					var div = document.createElement('DIV');
					div.style.zIndex = 30000;
					div.style.position = 'absolute';
					div.id = this.submenuGroups[this.menuItems[indexThis].parentId];
					div.style.visibility = 'hidden';	// Initially hidden.
					div.className = this.cssPrefix + 'menuBar_' + this.menuItemObj.submenuType[this.menuItems[indexThis].depth];

					if(firstChild){
						firstChild.parentNode.insertBefore(div,firstChild);
					}else{
						document.body.appendChild(div);
					}

					if(DHTMLSuite.clientInfoObj.isMSIE && this.createIframesForOldIeBrowsers){	// Create iframe object in order to conver select boxes in older IE browsers(windows).
						this.submenuIframes[this.menuItems[indexThis].parentId] = 'DHTMLSuite_menuBarIframe_' + this.menuItems[indexThis].parentId;
						var iframe = document.createElement('<IFRAME src="about:blank" frameborder=0>');
						iframe.id = this.submenuIframes[this.menuItems[indexThis].parentId];
						iframe.style.position = 'absolute';
						iframe.style.zIndex = 9000;
						iframe.style.visibility = 'hidden';
						if(firstChild){
							firstChild.parentNode.insertBefore(iframe,firstChild);
						}else{
							document.body.appendChild(iframe);
						}
					}
				}
				target = document.getElementById(this.submenuGroups[this.menuItems[indexThis].parentId]);	// Change target of newly created menu item. It should be appended to the sub menu div("A group box").
			}
			target.appendChild(ref); // Append menu item to the document.

			if(this.menuItems[indexThis].visible == false)this.hideMenuItem(this.menuItems[indexThis].id);	// Menu item hidden, call the hideMenuItem method.
			// Linea Comentada Para eliminar el issue que resaltaba varias opciones del menu al agregar un nuevo item
			//if(this.menuItems[indexThis].state != 'regular')this.menuItem_objects[this.menuItems[indexThis].id].setState(this.menuItems[indexThis].state);	// Menu item hidden, call the hideMenuItem method.

		}

		this.__setSizeOfAllSubMenus();	// Set size of all sub menu groups
		this.__positionAllSubMenus();	// Position all sub menu groups.
		if(DHTMLSuite.clientInfoObj.isOpera)this.__fixMenuLayoutForOperaBrowser();	// Call a function which fixes some layout issues in Opera.
	}
	// }}}
	,
	// {{{ __fixMenuLayoutForOperaBrowser()
	/**
	 *	A method used to fix the menu layout in Opera.
	 *
	 *
	 * @private
	 */
	__fixMenuLayoutForOperaBrowser : function(){
		for(var no=0;no<this.menuItemObj.menuItemsOrder.length;no++){
			var id = this.menuItemObj.menuItemsOrder[no];
			if(!id)continue;
			document.getElementById(this.menuItem_objects[id].divElement).className = document.getElementById(this.menuItem_objects[id].divElement).className.replace('_regular','_regular');	// Nothing is done but by "touching" the class of the menu items in Opera, we make them appear correctly
		}
	}

	// }}}
	,
	// {{{ __setSizeOfAllSubMenus()
	/**
	 *	*	Walk through all sub menu groups and call the positioning method for each one of them.
	 *
	 *
	 * @private
	 */
	__setSizeOfAllSubMenus : function(){
		for(var no=0;no<this.menuItemObj.menuItemsOrder.length;no++){
			var prop = this.menuItemObj.menuItemsOrder[no];
			if(!prop)continue;
			this.__setSizeOfSubMenus(prop);
		}
	}
	// }}}
	,
	// {{{ __positionAllSubMenus()
	/**
	 *	Walk through all sub menu groups and call the positioning method for each one of them.
	 *
	 *
	 * @private
	 */
	__positionAllSubMenus : function(){
		for(var no=0;no<this.menuItemObj.menuItemsOrder.length;no++){
			var prop = this.menuItemObj.menuItemsOrder[no];
			if(!prop)continue;
			if(this.submenuGroups[prop])this.__positionSubMenu(prop);
		}
	}
	// }}}
	,
	// {{{ __positionSubMenu(parentId)
	/**
	 *	Position a sub menu group
	 *
	 *	@param parentId
	 *
	 * @private
	 */
	__positionSubMenu : function(parentId){
		try{
			var shortRef = document.getElementById(this.submenuGroups[parentId]);

			var depth = this.menuItems[parentId].depth;
			var dir = this.menuItemObj.submenuType[depth];

			var ref = document.getElementById(this.menuItem_objects[parentId].divElement);
			if(dir=='top'){
				shortRef.style.left = DHTMLSuite.commonObj.getLeftPos(ref) + 'px';
				shortRef.style.top = (DHTMLSuite.commonObj.getTopPos(ref) + ref.offsetHeight) + 'px';
			}else{
				shortRef.style.left = (DHTMLSuite.commonObj.getLeftPos(ref) + ref.offsetWidth) + 'px';
				shortRef.style.top = (DHTMLSuite.commonObj.getTopPos(ref)) + 'px';
			}

			if(DHTMLSuite.clientInfoObj.isMSIE){
				var iframeRef = document.getElementById(this.submenuIframes[parentId]);
				iframeRef.style.left = shortRef.style.left;
				iframeRef.style.top = shortRef.style.top;
				iframeRef.style.width = shortRef.clientWidth + 'px';
				iframeRef.style.height = shortRef.clientHeight + 'px';
			}
		}catch(e){

		}
	}
	// }}}
	,
	// {{{ __setSizeOfSubMenus(parentId)
	/**
	 *	Set size of a sub menu group
	 *
	 *	@param parentId
	 *
	 * @private
	 */
	__setSizeOfSubMenus : function(parentId){
		try{
			var shortRef = document.getElementById(this.submenuGroups[parentId]);
			
			// Verificacion agregada para evitar el problema con firefox: la aplicación no carga si esta variable del menu no existe
			if (shortRef !== null){
				var subWidth = Math.max(shortRef.offsetWidth,document.getElementById(this.menuItem_objects[parentId].divElement).offsetWidth);
			}
			if(this.menuItems[parentId].submenuWidth)subWidth = this.menuItems[parentId].submenuWidth;
			if(subWidth>400)subWidth = 150;	// Hack for IE 6 -> force a small width when width is too large.
			subWidth = subWidth + '';
			if(subWidth.indexOf('%')==-1)subWidth = subWidth + 'px';
			
			// Verificacion agregada para evitar el problema con firefox: la aplicación no carga si esta variable del menu no existe
			if (shortRef !== null){
				shortRef.style.width = subWidth;
				if(DHTMLSuite.clientInfoObj.isMSIE){
					var ref = document.getElementById(this.submenuIframes[parentId]);
					ref.style.width = shortRef.style.width;
					ref.style.height = shortRef.style.height;
				}
			}
		}catch(e){

		}

	}
	// }}}
	,
	// {{{ __repositionMenu()
	/**
	 *	Position menu items.
	 *
	 *
	 * @private
	 */
	__repositionMenu : function(inputObj){
		inputObj.menuBarObj.style.top = document.documentElement.scrollTop + 'px';

	}
	// }}}
	,
	// {{{ __menuItemRollOver()
	/**
	 *	Position menu items.
	 *
	 *
	 * @private
	 */
	__menuItemRollOver : function(menuItemHTMLElementRef){
		var numericId = menuItemHTMLElementRef.id.replace(/[^0-9]/g,'');
		menuItemHTMLElementRef.className = 'DHTMLSuite_menuBar_menuItem_over_' + this.menuItems[numericId]['depth'];
	}
	// }}}
	,
	// {{{ __menuItemRollOut()
	/**
	 *	Position menu items.
	 *
	 *
	 * @private
	 */
	__menuItemRollOut : function(menuItemHTMLElementRef){
		var numericId = menuItemHTMLElementRef.id.replace(/[^0-9]/g,'');
		menuItemHTMLElementRef.className = 'DHTMLSuite_menuBar_menuItem_' + this.menuItems[numericId]['depth'];
	}
	// }}}
	,
	// {{{ __menuNavigate()
	/**
	 *	Navigate by click on a menu item
	 *
	 *
	 * @private
	 */
	__menuNavigate : function(menuItemHTMLElementRef){
		var numericIndex = menuItemHTMLElementRef.id.replace(/[^0-9]/g,'');
		var url = this.menuItems[numericIndex]['url'];
		if(!url)return;
	}
	// }}}
	,
	// {{{ __setBasicEvents()
	/**
	 *	Set basic events for the menu widget.
	 *
	 *
	 * @private
	 */
	__setBasicEvents : function(){
		var ind = this.objectIndex;

		DHTMLSuite.commonObj.addEvent(document.documentElement,"click",this.hideSubMenus);
		DHTMLSuite.commonObj.addEvent(document.documentElement,"mouseup",this.hideSubMenus);

	}
	,
	// {{{ setJsFunction()
	/**
	 *	Replace the JsFunction for a menu item
	 * 
	 *	@param Integer menuItemId - Id of menu item.
	 *	@param String newJsFunction - New function for the menu item.
	 *
	 * @public
	 */
	setJsFunction : function(menuItemId,newJsFunction){
		//try{
			if (this.menuItem_objects[menuItemId]) this.menuItem_objects[menuItemId].setJsFunction(newJsFunction);
			else {
				//history.go(0);
				if (parent.userLoggedIn) parent.refreshMenu(true);
				else parent.refreshMenu();
			}
			
		/*}catch(e){
			alert('menu item with id ' + menuItemId + ' does not exists or you have called the setJsFunction method before the menu has been initialized');
		}*/
	}
}