//<?
//==============================================================================
//	jRamki 2.0
//==============================================================================

// librerias
if(typeof(jRamkiLib)=="undefined") {
	var jRamkiLib = "jramki.lib/";
}

// oculta el contenido del documento
if(typeof(jRamkiLoading)=="undefined") { var jRamkiLoading = "loading..."; }
var jRamkiWhiteScreen = null;

var $eDetectBody = window.setInterval(function() {
	if(document.body) {
		if(jRamkiLoading) {
			jRamkiWhiteScreen 						= document.createElement("DIV");
			jRamkiWhiteScreen.id 					= "jRamkiWhiteScreen";
			jRamkiWhiteScreen.style.position		= "absolute";
			jRamkiWhiteScreen.style.top				= "0";
			jRamkiWhiteScreen.style.left			= "0";
			jRamkiWhiteScreen.style.width			= "100%";
			jRamkiWhiteScreen.style.height			= "100%";
			jRamkiWhiteScreen.style.backgroundColor	= "#FFFFFF";
			jRamkiWhiteScreen.style.textAlign 		= "center";
			document.body.appendChild(jRamkiWhiteScreen);
			
			var $sMessage							= jRamkiLoading;
			jRamkiLoading							= document.createElement("DIV");
			jRamkiLoading.id 						= "jRamkiLoading";
			jRamkiLoading.style.display 			= "block";
			jRamkiLoading.style.width 				= "150px";
			jRamkiLoading.style.height 				= "18px";
			jRamkiLoading.style.padding				= "5px 10px";
			jRamkiLoading.style.margin 				= "10px auto";
			
			jRamkiLoading.style.borderStyle			= "solid";
			jRamkiLoading.style.borderWidth			= "1px";
			jRamkiLoading.style.borderColor			= "#888889";
			jRamkiLoading.style.backgroundColor		= "#F0F0F0";
			
			jRamkiLoading.style.color 				= "#666667";
			jRamkiLoading.style.fontFamily 			= "verdana, arial";
			jRamkiLoading.style.fontSize 			= "12px";
			jRamkiLoading.style.fontStyle 			= "normal";
			jRamkiLoading.style.textAlign 			= "center";
			jRamkiLoading.style.lineHeight 			= "18px";
		
			var jRamkiLoadingIcon					= document.createElement("IMG");
			jRamkiLoadingIcon.src					= jRamkiLib+"/loader.gif";
			//jRamkiLoadingIcon.align					= "abscenter";
			jRamkiLoadingIcon.style.marginRight		= "8px";

			jRamkiLoading.appendChild(jRamkiLoadingIcon);
			jRamkiLoading.appendChild(document.createTextNode($sMessage));
			jRamkiWhiteScreen.appendChild(jRamkiLoading);
		} else {
			jRamkiWhiteScreen = true;
		}
		clearInterval($eDetectBody);
	}
}, 5);


// Inicio del FrameWork
if(typeof(window.onload)=="function") {
	$fWindowOnLoad = window.onload;
	window.onload = function () {
		jRamki.ini();
		$fWindowOnLoad();
	}
} else {	
	window.onload = function () {
		jRamki.ini();
	}
}

// jRamki - Objeto Principal
jRamki = new function() {

	/** FUNCTION
	ini: Inicializa el FrameWork y carga todas las clases externas.
	**/
	this.ini = function() {
		var $eRunFrameWork = window.setInterval(function() {
			if(jRamkiWhiteScreen) {
				// Variables Globales
				jRamki.state 								= false;
				jRamki.name	 								= "jRamki";
				jRamki.version 								= "2.0";		//1.0		// 0.8
				jRamki.created 								= "20090220";	//20081202	//20080530
				jRamki.author 								= "HyTCom";
				jRamki.signature 							= jRamki.name+" v"+jRamki.version+" "+jRamki.created;

				jRamki.lib 									= jRamkiLib;

				jRamki.GLOBALS								= new Object();
				jRamki.GLOBALS["id"]						= jRamki.Hash();
				jRamki.GLOBALS["browser"]					= jRamki.DetectBrowser();
				jRamki.GLOBALS["elements"]					= new Array();
				jRamki.GLOBALS["zindex"]					= jRamki.Zindex();

				jRamki.GLOBALS["emouse"]					= null;
				jRamki.GLOBALS["onmousemove"]				= null;
				jRamki.GLOBALS["mousebutton"]				= null;

				jRamki.GLOBALS["cookies"]				   	= null;
				jRamki.GLOBALS["trace"]						= null;

				// Clases Genéricas
				jRamki.GLOBALS["classDefault"]				= ["ajax", "css", "fn", "form", "fx"];
				jRamki.GLOBALS["classLoading"]				= 0;
				jRamki.GLOBALS["classLoaded"]				= new Object();
				
				jRamki.GLOBALS["onLoadSentences"]			= new Array();
				
				jRamki.DOM 									= new Array();
				jRamki.$aEventsKeys 						= new Array();

				// Inclusión de Clases
				for(var $nClass in jRamki.GLOBALS["classDefault"]) {
					var $sClassName = jRamki.GLOBALS["classDefault"][$nClass];
					jRamki.IncludeJson($sClassName, jRamki.lib+"jrk_"+($sClassName.toLowerCase())+".json");
					jRamki.GLOBALS["classLoading"]++;
				}

				jRamki.state = window.setInterval("jRamki.OnLoadJRamki()", 50);
				
				clearInterval($eRunFrameWork);
			}
		}, 10);
	}
	/** FUNCTION END **/


	/** FUNCTION
	DetectBrowser: Detecta el navegador con el cual se está viendo el sitio.
	**/
	this.DetectBrowser = function () {
		if(navigator.appName=="Netscape") {
			return 0;
		} else if(navigator.appName=="Microsoft Internet Explorer") {
			return 1;
		} else {
			return 2;
		}
	}
	/** FUNCTION END **/


	/** FUNCTION
	Hash: Retorna, de manera aleatoria, un numero hexadecimal de 16 caracteres
		que siempre comienza con una letra (A-F).
	**/
	this.Hash = function() {
		var $eNow = new Date();
		var $nHash = Math.round(Math.random() * $eNow.getTime());
		$sHash = $nHash.toString(16)+($eNow.getTime()-$nHash).toString(16);
		$sHash = $sHash.toUpperCase();
		return ($sHash.substring(0, 1)==parseInt($sHash.substring(0, 1))) ? "A"+$sHash.substring(0, 15) : $sHash.substring(0, 16);
	}
	/** FUNCTION END **/

	this.inDOM = function($eElement) {
		return (typeof($eElement.jramki)!="undefined") ? true : false;
	}

	/** FUNCTION
	Interval: Permite configurar la ejecución de una funcion, por medio del 
		método setInterval().
	Input:
		arguments[0] = funcion a ejecutarse;
		arguments[1] = intervalo de tiempo entre ejecuciones;
		arguments[n] = argumentos que serán pasados a arguments[0];
	Output:
		Retorna el id generado por el método setInterval();
	**/
	this.Interval = function() {
		var $nInterval = false;

		if(arguments[0] && typeof(arguments[1])=="number") {
			var $fHandler = arguments[0];
			var $nDelay = arguments[1];
			var $aArguments = [];

			for(var $x=2; $x<arguments.length; $x++) {
				$aArguments.push(arguments[$x]);
			}
		
			$nInterval = window.setInterval(
				function(){
					$fHandler($aArguments);
				}
			, $nDelay);
		}
		
		return $nInterval;
	}
	/** FUNCTION END **/


	/** FUNCTION
	Timeout: Permite configurar la ejecución de una funcion, por medio del 
		método setTimeout().
	Input:
		arguments[0] = funcion a ejecutarse;
		arguments[1] = intervalo de tiempo antes de la ejecucion;
		arguments[n] = argumentos que serán pasados a arguments[0] como array;
	Output:
		Retorna el id generado por el método setTimeout();
	**/
	this.Timeout = function() {
		var $nInterval = false;

		if(arguments[0] && typeof(arguments[1])=="number") {
			var $fHandler = arguments[0];
			var $nDelay = arguments[1];
			var $aArguments = [];

			for(var $x=2; $x<arguments.length; $x++) {
				$aArguments.push(arguments[$x]);
			}

			$nTimeout = window.setTimeout(
				function(){
					$fHandler($aArguments);
				}
			, $nDelay);
		}
		
		return $nTimeout;
	}
	/** FUNCTION END **/


	/** FUNCTION
	IncludeJson: Incluye un archivo javascript en el documento.
	Input:
		$sJSFile = url del archivo a incluir;
	**/
	this.IncludeJson = function($sClassName, $sJsonFile) {
		if($sJsonFile.substring(0, 10).indexOf("://")!=-1) {
			var $sProtocol	= $sJsonFile.substring(0, $sJsonFile.indexOf("//")+2);
			var $sURL		= $sJsonFile.substring($sProtocol.length);
			var $sDomain	= $sURL.substring(0, $sURL.indexOf("/"));
			var $sPath		= $sURL.substring($sURL.indexOf("/"));

			if($sDomain!=document.domain) {
				$sJsonFile = $sProtocol+document.domain+$sPath;
			}
		}

		var $eScript 	= document.createElement("script");
		$eScript.type 	= "text/javascript";
		$eScript.src 	= $sJsonFile;
		var $eScripts 	= document.getElementsByTagName("script")[0];
		$eScripts.parentNode.insertBefore($eScript, $eScripts);
		
		jRamki.GLOBALS["classLoaded"][$sClassName] = false;
		
		if($eScript.readyState) {  //IE
			$eScript.onreadystatechange = function(){
				if($eScript.readyState == "loaded" || $eScript.readyState == "complete") {
					$eScript.onreadystatechange = null;
					jRamki.GLOBALS["classLoaded"][$sClassName] = true;
					jRamki.GLOBALS["onLoadSentences"][jRamki.GLOBALS["onLoadSentences"].length] = "$()."+$sClassName+" = jRamki."+$sClassName+"; $()."+$sClassName+".construct();";
					jRamki.GLOBALS["classLoading"]--;
				}
			};
		} else {  //Others
			$eScript.onload = function(){
				jRamki.GLOBALS["classLoaded"][$sClassName] = true;
				jRamki.GLOBALS["onLoadSentences"][jRamki.GLOBALS["onLoadSentences"].length] = "$()."+$sClassName+" = jRamki."+$sClassName+"; $()."+$sClassName+".construct();";
				jRamki.GLOBALS["classLoading"]--;
			};
		}
	}
	/** FUNCTION END **/

	/** FUNCTION
	AddEvent: Añade un evento al elemento referenciado.
	Input:
		$eElement = elemento al cual se añadirá el evento;
		$sEvent = nombre el evento;
		$sFunction = función que se ejecutará cuando ocurra el evento;
	**/
	this.AddEvent = function($eElement, $sEvent, $sFunction) {
		if($eElement.addEventListener) {
			$eElement.addEventListener($sEvent, $sFunction, false);
			return true;
		} else if($eElement.attachEvent) {
			var $uReturn = $eElement.attachEvent("on"+$sEvent, $sFunction);
			return $uReturn;
		} else {
			alert("Handler could not be attached");
		}
	}
	/** FUNCTION END **/


	this.RemoveEvent = function($eElement, $sEvent, $sFunction){
		if($eElement.removeEventListener) {
			$eElement.removeEventListener($sEvent, $sFunction, false);
			return true;
		} else if($eElement.detachEvent) {
			var $uReturn = $eElement.detachEvent("on"+$sEvent, $sFunction);
			return $uReturn;
		} else {
			alert("Handler could not be removed");
		}
	} 


	this.Zindex = function($eElement) {
		if(!this.GLOBALS["zindex"] || $eElement) {
			var $nHighest = 0;  
			var $nCurrent = 0;  

			var $aElements = [];
			if($eElement) {
				$aElements = $eElement.getElementsByTagName("*");
			} else {
				$aElements = document.getElementsByTagName("*");
			}

			for(var $x=0; $x < $aElements.length; $x++){
				if($aElements[$x].currentStyle) {
					if($aElements[$x].currentStyle["zIndex"]) {
						$nCurrent = parseFloat($aElements[$x].currentStyle["zIndex"]);
					} else {
						$nCurrent = $nHighest;
					}
				} else if(window.getComputedStyle) {
					if(window.getComputedStyle($aElements[$x], null)) {
						$nCurrent = parseFloat(window.getComputedStyle($aElements[$x], null).getPropertyValue("z-index"));
					} else {
						$nCurrent = $nHighest;
					}
				}

				if(!isNaN($nCurrent) && $nCurrent > $nHighest && $nCurrent < 1000000) {
					$nHighest = $nCurrent;
				}
			}
			
			var $nNextZindex = $nHighest+1;
		} else {
			var $nNextZindex = this.GLOBALS["zindex"]++;
		}
		
		return $nNextZindex;
	}

	this.AddEventKey = function($nKeyCode, $fAction, $bDisable) {
		var $bDisable = (typeof($bDisable)=="undefined") ? false : $bDisable;
		this.$aEventsKeys[$nKeyCode] = {action:$fAction, disable:$bDisable};
		document.onkeydown = this.OnPressKey;
	}

	this.OnPressKey = function($hEvent) {
		var $nKeyCode = $().getKeyCode($hEvent);
	
		var $aEventsKeys = jRamki.$aEventsKeys;
		if(typeof($aEventsKeys[$nKeyCode])!="undefined") {
			$aEventsKeys[$nKeyCode].action();
			return ($aEventsKeys[$nKeyCode].disable) ? false : true;
		}

		return true;
	}

	this.RemoveEventKey = function($nKeyCode) {
		delete this.$aEventsKeys[$nKeyCode];
		var $y = 0;
		for(var $x in this.$aEventsKeys) {
			if(typeof(this.$aEventsKeys[$x])!="undefined") {
				$y++;
			}
		}
		if($y==0) { document.onkeydown = null; }
	}
	
	this.getKeyCode = function($hEvent) {
		var $hEvent = $hEvent || window.event;

		if(typeof($hEvent.which)=="number") { //NS 4, NS 6+, Mozilla 0.9+, Opera
			var $nKeyCode = $hEvent.which;
		} else if(typeof($hEvent.keyCode)=="number") { //IE, NS 6+, Mozilla 0.9+
			var $nKeyCode  = $hEvent.keyCode;
		} else if(typeof($hEvent.charCode)=="number") { //also NS 6+, Mozilla 0.9+
			var $nKeyCode  = $hEvent.charCode;
		} else {
			var $nKeyCode = false;
		}
		
		return $nKeyCode;
	}


	this.Use = function($eElement, $sClassName) {
		if(this.GLOBALS["classLoaded"][$sClassName] && !$eElement[$sClassName]) {
			jRamki.extend($eElement, $sClassName);
		}

		return $eElement[$sClassName];
	}
}


//==============================================================================
//	Definición de Funciones
//==============================================================================
jRamki.onloads = new Array();

// jRamki - Cargador de Entenciones
jRamki.extend = function($eElement, $uSourceCode) {
	if(typeof($uSourceCode)=="string") {
		var $aSourceCode = jRamki[$uSourceCode];

		var $eParent = $eElement;
		$eElement[$uSourceCode] = new Object();
		$eElement = $eElement[$uSourceCode];
		$eElement.parent = $eParent;
	} else {
		var $aSourceCode = $uSourceCode;
	}

	for(var $x in $aSourceCode) {
		$eElement[$x] = $aSourceCode[$x];
	}

	if($eElement.parent && $eElement.parent.$this) { $eElement.elem = $eElement.parent.$this; }
	if($eElement.construct) { $eElement.construct(); }

	return $eElement;
}


// jRamki - Cargador del FrameWork
jRamki.extend(jRamki, {
	RemovejRamkiWhiteScreen : function() {
		var $eClose = jRamki.Interval(function() {
			if(jRamkiWhiteScreen && jRamkiWhiteScreen!==true && jRamkiWhiteScreen.parentNode) {
				jRamkiWhiteScreen.parentNode.removeChild(jRamkiWhiteScreen);
			}
			clearInterval($eClose);
		}, 10);
	},


	/** FUNCTION
	OnLoadJRamki: Instrucciones que se ejecutan una vez cargadas las clases
		externas del FrameWork.
	**/
	OnLoadJRamki : function() {
		var $nLoaded = 0;
		for(var $x in jRamki.GLOBALS["classLoaded"]) { $nLoaded++; }

		if($nLoaded >= jRamki.GLOBALS["classDefault"].length) {
			clearInterval(jRamki.state);
			this.$nLoader = window.setInterval("jRamki.RunFrameWork()", 10);
		}
	},
	/** FUNCTION END **/


	/** FUNCTION
	RunFrameWork: Instrucciones que se ejecutan una vez cargado el FrameWork.
	**/
	RunFrameWork : function () {
		clearInterval(this.$nLoader);
		this.state = true;

		// Funciones del usuario 'OnLoad Window'
		if(typeof(jRamki.onloads)=="object") {
			this.load();
		} else {
			this.LoadSentences();		
		}
	},

	onload : function() {
		jRamki.onloads[jRamki.onloads.length] = arguments;
	},


	load : function($uClasses) {
		var $aToLoad;
		var $bRunOnload = false;

		if(typeof($uClasses)=="object") {
			$aToLoad = [$uClasses];
		} else if(typeof($uClasses)=="string") {
			$aToLoad = [[$uClasses]];
		} else {
			$aToLoad = jRamki.onloads;
			$bRunOnload = true;
		}

		var $nOnload = $aToLoad.length;
		for(var $y=0; $y<$nOnload; $y++) {
			var $aArguments = $aToLoad[$y];
			var $nClasses = $aArguments.length;
			for(var $x=0; $x<$nClasses; $x++) {
				if(typeof($aArguments[$x])!="function") {
					var $sClassName = $aArguments[$x].toLowerCase();
					if(typeof(jRamki.GLOBALS["classLoaded"][$sClassName])=="undefined") {
						jRamki.GLOBALS["classLoaded"][$sClassName] = false;
						this.IncludeJson($sClassName, jRamki.lib + "jrk_"+$sClassName+".json");
						jRamki.GLOBALS["classLoading"]++;
					}
				}
			}
		}

		var $hLoader = {};
		$hLoader.$nLoaderTimer = jRamki.Interval(
			function($aArguments) {
				if(jRamki.GLOBALS["classLoading"]==0 && $aArguments[1]) {
				
					window.clearInterval($aArguments[0].$nLoaderTimer);
					jRamki.LoadSentences();
				}
			}, 10, $hLoader, $bRunOnload
		);

	},
	
	LoadSentences : function() {
		if(jRamki.GLOBALS["onLoadSentences"].length) {
			for(var $x in jRamki.GLOBALS["onLoadSentences"]) {
				var $sToEval = jRamki.GLOBALS["onLoadSentences"][$x];
				eval($sToEval);
			}
		}
	
		var $nOnload = jRamki.onloads.length;
		for(var $y=0; $y<$nOnload; $y++) {
			var $aArguments = jRamki.onloads[$y];
			if(typeof($aArguments[$aArguments.length - 1])=="function") {
				var $fSuccess = $aArguments[$aArguments.length - 1];
				$fSuccess();
			}
		}

		// eliminación del loading
		this.RemovejRamkiWhiteScreen();
	}
});


//==============================================================================
//	MOU | Funciones del Mouse
//==============================================================================
jRamki.extend(jRamki, {

	mousemove : function($uFunction) {
		jRamki.GLOBALS["emouse"] = {top:0, right:1, bottom:1, left:0, x:0, y:0};
		
		jRamki.OnMouseMoveEvents = function($hEvent) {
			jRamki.GLOBALS["emouse"] = jRamki.eMouse($hEvent);
			return false;
		}

		if($uFunction!=null) {
			var $fFunction = (typeof($uFunction)=="object") ? $uFunction[0] : $uFunction;
			if(typeof($fFunction)=="function") {
				var $aArguments = (typeof($uFunction[1])!="undefined") ? $uFunction[1] : [];
				jRamki.OnMouseMoveEvents = function($hEvent) {
					jRamki.GLOBALS["emouse"] = jRamki.eMouse($hEvent);
					$fFunction($hEvent, $aArguments);
					return false;
				}
			}
		}

		this.AddEvent(document, "mousemove", jRamki.OnMouseMoveEvents);
	},


	mousexy : function($hEvent) {
		var $aMouseCoords = {};
		if($hEvent.pageX || $hEvent.pageY) {
			$aMouseCoords = {x : $hEvent.pageX, y : $hEvent.pageY};
		} else {
			$aMouseCoords = {
				x : ($hEvent.clientX + document.body.scrollLeft - document.body.clientLeft),
				y : ($hEvent.clientY + document.body.scrollTop  - document.body.clientTop)
			};
		}

		return $aMouseCoords;
	},


	eMouse : function($hEvent) {
		var $aMouseCoords = this.mousexy($hEvent);
		return {
			top		: $aMouseCoords.y,
			right	: $aMouseCoords.x+1,
			bottom	: $aMouseCoords.y+1,
			left	: $aMouseCoords.x,
			y		: $aMouseCoords.y,
			x		: $aMouseCoords.x
		};
	},


	mousedown : function() {
		this.AddEvent(document, "mousedown", this.onMouseDown);
	},


	onMouseDown : function($hEvent) {
		var $eButton = null;
		if(jRamki.GLOBALS.browser==0) { // Mozilla
			if($hEvent.which == 1) {
				$eButton = "left";
			} else if($hEvent.which == 3) {
				$eButton = "right";
			}
		} else if(jRamki.GLOBALS.browser==1) { // IE
			if($hEvent.button == 1) {
				$eButton = "left";
			} else if($hEvent.button == 2) {
				$eButton = "right";
			}
		}

		jRamki.GLOBALS.mousebutton = $eButton;
		return $eButton;
	}
});


//==============================================================================
//	 Manejo de Coockies
//==============================================================================
jRamki.extend(jRamki, {

	Cookies : function() {
		jRamki.GLOBALS["cookies"] = new Object();
		var $aAllCookies = document.cookie.split('; ');
		for (var $x=0; $x<$aAllCookies.length; $x++) {
			var $aCookiePair = $aAllCookies[$x].split('=');
			jRamki.GLOBALS["cookies"][$aCookiePair[0]] = $aCookiePair[1];
		}
	},

	delcookie : function($sName) {
		if(!jRamki.GLOBALS["cookies"]) { jRamki.Cookies(); }
		jRamki.setcookie($sName, '', -1);
		jRamki.GLOBALS["cookies"][$sName] = undefined;
	},
	
	getcookie : function($uName) {
		if(!jRamki.GLOBALS["cookies"]) { jRamki.Cookies(); }
		if(typeof($uName)=="undefined") {
			return jRamki.GLOBALS["cookies"];
		} else {
			return jRamki.GLOBALS["cookies"][$uName];
		}
	},

	setcookie : function($sName, $uValue, $nSeconds) {
		if(!jRamki.GLOBALS["cookies"]) { jRamki.Cookies(); }
		if($nSeconds) {
			var $nMiliSeconds = parseInt($nSeconds)*1000;
			var $eDate = new Date();
			$eDate.setTime($eDate.getTime()+$nMiliSeconds);
			var $sExpire = "; expires="+$eDate.toGMTString();
		} else {
			var $sExpire = "";
		}

		alert($sName+"="+$uValue+$sExpire+"; path=/");
		document.cookie = $sName+"="+$uValue+$sExpire+"; path=/";
		jRamki.GLOBALS["cookies"][$sName] = $uValue;
	}
});

jRamki.extend(jRamki, {

	base64Encode : function($sText) {
		var $sBase64KeyString = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
		var $sOutput = "";
		var $nChr1, $nChr2, $nChr3;
		var $nEnc1, $nEnc2, $nEnc3, $nEnc4;
		var $x = 0;

		do {
			$nChr1 = $sText.charCodeAt($x++);
			$nChr2 = $sText.charCodeAt($x++);
			$nChr3 = $sText.charCodeAt($x++);

			$nEnc1 = $nChr1 >> 2;
			$nEnc2 = (($nChr1 & 3) << 4) | ($nChr2 >> 4);
			$nEnc3 = (($nChr2 & 15) << 2) | ($nChr3 >> 6);
			$nEnc4 = $nChr3 & 63;

			if (isNaN($nChr2)) {
				$nEnc3 = $nEnc4 = 64;
			} else if (isNaN($nChr3)) {
				$nEnc4 = 64;
			}

			$sOutput += $sBase64KeyString.charAt($nEnc1) + $sBase64KeyString.charAt($nEnc2) + $sBase64KeyString.charAt($nEnc3) + $sBase64KeyString.charAt($nEnc4);
		} while ($x < $sText.length);

		return $sOutput;
	},

	// codifica una cadena en Base64
	base64Decode : function($sText) {
		var $sBase64KeyString = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
		var $sOutput = "";
		var $nChr1, $nChr2, $nChr3;
		var $nEnc1, $nEnc2, $nEnc3, $nEnc4;
		var $x = 0;

		// remove all characters that are not A-Z, a-z, 0-9, +, /, or =
		$sText = $sText.replace(/[^A-Za-z0-9\+\/\=]/g, "");

		do {
			$nEnc1 = $sBase64KeyString.indexOf($sText.charAt($x++));
			$nEnc2 = $sBase64KeyString.indexOf($sText.charAt($x++));
			$nEnc3 = $sBase64KeyString.indexOf($sText.charAt($x++));
			$nEnc4 = $sBase64KeyString.indexOf($sText.charAt($x++));

			$nChr1 = ($nEnc1 << 2) | ($nEnc2 >> 4);
			$nChr2 = (($nEnc2 & 15) << 4) | ($nEnc3 >> 2);
			$nChr3 = (($nEnc3 & 3) << 6) | $nEnc4;

			$sOutput += String.fromCharCode($nChr1);

			if($nEnc3 != 64) {
				$sOutput += String.fromCharCode($nChr2);
			}
			if ($nEnc4 != 64) {
				$sOutput += String.fromCharCode($nChr3);
			}
		} while ($x < $sText.length);

		return $sOutput;
	}
});


//==============================================================================
//	Handlers
//==============================================================================
/** FUNCTION
$: Captura elementos en base a su id o al propio elemento y los convierte en
	objetos del jRamki DOM.
Input:
	arguments = elementos a ser capturados;
**/
function $() {
	if(arguments.length==0) { return jRamki; }

	var $aElements = [];
	var $eElement = null;

	for(var $x=0; $x<arguments.length; $x++) {
		var $uElement = arguments[$x];
		var $bBuilt = false;

		if(typeof($uElement)=="string" || typeof($uElement)=="number") {
			$uElement = $uElement.toString();
			if($uElement.substring(0,1)=="#") {
				$bBuilt = true;
				$uElement = $uElement.substring(1, $uElement.length);
				
				var $aElement	= $uElement.split(".");
				var $uElement	= $aElement[0];
				var $uExtend	= ($aElement[1]) ? $aElement[1] : null;
			}

			$eElement = document.getElementById($uElement);
		} else if(typeof($uElement) == "object") {
			if($uElement.nodeType && $uElement.nodeType!=1) {
				$eElement = $uElement;
			} else {
				$eElement = (typeof($uElement.jramki)!="undefined") ? jRamki.DOM[$uElement.jramki] : $uElement;
			}
		} else {
			$eElement = null;
		}

		if($eElement && $eElement.nodeType) {
			// extencion del objeto
			if(typeof($eElement.jramki)=="undefined" && $bBuilt) {
				// seteo del id en caso de no tenerlo
				if(!$eElement.id) { $eElement.id = jRamki.Hash(); }
			
				// cantidad de elementos en el jRamki.DOM
				var $nDOM = jRamki.DOM.length;
				$eElement.jramki = $nDOM;
				
				// nuevo objecto jRamki
				jRamki.DOM[$nDOM] = {};
				
				// seteo del parent
				jRamki.DOM[$nDOM].$this = $($eElement.id);
			
				// funciones genericas
				jRamki.extend(jRamki.DOM[$nDOM], jRamki.fn);
				jRamki.Use(jRamki.DOM[$nDOM], "css");
			} else {
				var $nDOM = $eElement.jramki;
			}

			// extenciones
			if($uExtend) {
				jRamki.Use(jRamki.DOM[$nDOM], $uExtend);
			}

			if(arguments.length==1) {
				if($bBuilt) {
					return (!$uExtend) ? jRamki.DOM[$eElement.jramki] : jRamki.DOM[$eElement.jramki][$uExtend];
				} else {
					return $eElement;
				}
			} else {
				$aElements.push($eElement);
			}
		}
	}

	return ($aElements.length) ? $aElements : $eElement;
}
/** FUNCTION END **/


/** FUNCTION
$().delete: Elimina un objeto del jRamki DOM.
Input:
	$uElement = elemento, o id del mismo, que será eliminado;
**/
$().unset = function($uElement) {
	var $eElement = ($uElement.jramki) ? $uElement : $($uElement);
	delete jRamki.DOM[$eElement.jramki]
	delete $eElement.jramki;
}
/** FUNCTION END **/


/** FUNCTION
$$: Retorna una, varias o todas las propiedades asignadas a un elemento. Entre
	ellas se encuentran todos los estilos computados por el navegador.
Input:
	$uElement = elemento, o id del mismo, sobre el cual se evaluará el método;
	$uProperties = nombre de la propiedad o Array con los nombres de las mismas;
Output:
	Array o String con los valores solicitados.
**/
function $$($uElement, $uProperties) {
	var $eElement = (typeof($uElement)=="string") ? $($uElement) : $uElement;
	if(!$eElement || typeof($eElement)!="object") { return false; }

	// atributos
	var $aAttributes = [];
	if($eElement.attributes) {
		for(var $x in $eElement.attributes) {
			if($eElement.attributes[$x] && $eElement.attributes[$x].nodeType==2) {
				$aAttributes[$eElement.attributes[$x].nodeName.toLowerCase()] = $eElement.attributes[$x].nodeValue;
			}
		}
	}

	// estilos computados por el navegador
	if($eElement.style) {
		$aAttributes["style"] = {};
		var $aStyles = $eElement.style;
		for(var $sStyle in $aStyles) {

			// lee los estilos como $().css.getStyle
			var $sMozProperty = $sStyle.replace(/([A-Z])/g, function($sString, $sMatch) { return "-"+$sMatch.toLowerCase(); });
			var $sIEProperty = $sStyle.replace(/\-(\w)/g, function($sString, $sMatch) { return $sMatch.toUpperCase(); });
			var $sValue = "";
			if(document.defaultView && document.defaultView.getComputedStyle){
				$sValue = document.defaultView.getComputedStyle($eElement, "").getPropertyValue($sMozProperty);
			} else if($eElement.currentStyle){
				try {
					$sValue = $eElement.currentStyle[$sIEProperty] || "";
				}
				catch(e){}
			}
	
			$aAttributes["style"][$sStyle] = $sValue;
			$aAttributes["style."+$sMozProperty] = $sValue;
			$aAttributes["style."+$sIEProperty] = $sValue;
		}
	}

	// recorrido y asignacion de propiedades
	var $sPropType = typeof($uProperties);
	if($sPropType!="undefined") {
		if($sPropType=="string" || $sPropType=="number") {
			var $uReturn = $eElement[$uProperties] || $aAttributes[$uProperties];
		} else if($sPropType=="object") {
			var $uReturn = [];
			for(var $nProperty in $uProperties) {
				var $sProperty = $uProperties[$nProperty];
				$uReturn[$sProperty] = $eElement[$sProperty] || $aAttributes[$sProperty];
			}
		}
	} else {
		// retorna TODAS las propiedades del elemento
		for(var $sProperty in $eElement) {
			$aAttributes[$sProperty] = $eElement[$sProperty];
		}
		
		var $uReturn = $aAttributes;
	}

	return $uReturn;
}
/** FUNCTION END **/


/** FUNCTION
$B: Codifica y decodifica cadenas en base64.
**/
function $B($sString, $bDecode) {
	if($bDecode) {
		return $().base64Decode($sString);		
	} else {
		return $().base64Encode($sString);
	}
}
/** FUNCTION END **/


/** FUNCTION
$C: Retorna o setea el valor de una Coockie, o el retorna el array de cookies.
**/
function $C($sName, $uValue) {
	if($uValue) {
		$().setcookie($sName, $uValue);
	} else {
		return $().getcookie($sName);		
	}
}
/** FUNCTION END **/


function $E($uElement) {
	var $eElement = null;

	if(typeof($uElement)=="string") {
		$eElement = $($uElement);
	} else if(typeof($uElement)=="object") {
		$eElement = ($uElement.elem) ? $uElement.elem : $uElement;
	}
	
	return $eElement;
}


/** FUNCTION
$G: Retorna la variable jRamki GLOBALS, o un indice de la misma.
Si $uValue esta definido, entonces setea ese valor
**/
function $G($uIndex, $uValue) {
	if(typeof($uIndex)=="undefined") {
		return jRamki.GLOBALS;
	} else {
		if(typeof($uValue)!="undefined") {
			jRamki.GLOBALS[$uIndex] = $uValue;
		}
		return jRamki.GLOBALS[$uIndex];
	}
}
/** FUNCTION END **/


/** FUNCTION
$ID: Retorna el id de un elemento. En caso de no tenerlo lo crea y asigna.
**/
function $ID($eElement) {
	if(!$eElement.id) { $eElement.id = $H(); }
	return $eElement.id;
}
/** FUNCTION END **/


/** FUNCTION
$H: Alias de jRamki.Hash();
**/
function $H() {
	return $().Hash();
}
/** FUNCTION END **/


/** FUNCTION
$M: Retorna el valor de la variable GLOBALS emouse.
**/
function $M($sCoord) {
	if(!$G("emouse")) { jRamki.mousemove(); }
	var $eMouse = $G("emouse");
	if($sCoord) {
		$eMouse = $eMouse[$sCoord];
	}
	return $eMouse;
}
/** FUNCTION END **/


/** FUNCTION
$P: Retorna nodo HTML padre.
**/
function $P($eElement) {
	var $eParentNode = $eElement;
	while($eParentNode = $eParentNode.parentNode) {
		if($eParentNode.nodeType=="1") { return $eParentNode; }
	}
	
	return $eElement;
}
/** FUNCTION END **/

// Parent properties
function $$P($eElement, $sProperty, $uValue) {
	var $eJramki = (typeof($eElement.jramki)!="undefined") ? jRamki.DOM[$eElement.jramki] : {};
	if($uValue) {
		if($eElement[$sProperty]==$uValue || $eJramki[$sProperty]==$uValue) { return $eElement; }
	} else {
		if($eElement[$sProperty] || $eJramki[$sProperty]) { return $eElement; }
	}

	while($eElement = $eElement.parentNode) {
		$eJramki = (typeof($eElement.jramki)!="undefined") ? jRamki.DOM[$eElement.jramki] : {};	
		if($uValue) {
			if($eElement[$sProperty]==$uValue || $eJramki[$sProperty]==$uValue) {
				var $eParent = $eElement;
				break;
			}
		} else {
			if($eElement[$sProperty] || $eJramki[$sProperty]) {
				var $eParent = $eElement;
				break;
			}	
		}
	}

	return ($eParent) ? $eParent : false;
}


function $S($eElement) {
	if(typeof($eElement)=="object") {
		var $nLength = 0;
		for(var $x=0 in $eElement) {
			$nLength++;
		}
		return $nLength;
	} else {
		if($eElement.length) { return $eElement.length; }
	}
	
	return null;
}

/** FUNCTION
$T: Herramienta similar al Trace de ActionScript, inserta un DIV en el domuento
	actual en el cual se imprimirá todo lo que se requiera. Util para hacer
	seguimientos y depuraciones.
Input:
	$sMesage = mensaje a imprimir;
	$bClear = limpia la ventana antes de imprimir;
**/
function $T($sMesage, $bClear) {
	var $sPriority = (jRamki.GLOBALS['browser']!==1) ? " !important" : "";
	
	if(!jRamki.GLOBALS['trace']) {
		jRamki.GLOBALS['trace'] 						= document.createElement("div");
		jRamki.GLOBALS['trace'].style.position			= "fixed"+$sPriority;
		jRamki.GLOBALS['trace'].style.bottom 			= "0%"+$sPriority;
		jRamki.GLOBALS['trace'].style.width				= "100%"+$sPriority;
		jRamki.GLOBALS['trace'].style.backgroundColor	= "#FFFFFF"+$sPriority;
		jRamki.GLOBALS['trace'].style.color				= "#000000"+$sPriority;
		jRamki.GLOBALS['trace'].style.fontFamily		= "monospace"+$sPriority;
		jRamki.GLOBALS['trace'].style.fontSize			= "8pt"+$sPriority;
		jRamki.GLOBALS['trace'].style.padding			= "0px"+$sPriority;
		jRamki.GLOBALS['trace'].style.margin			= "0px"+$sPriority;
		jRamki.GLOBALS['trace'].style.borderStyle		= "none"+$sPriority;
		jRamki.GLOBALS['trace'].style.zIndex			= "1000000";
		
		var $eTitleBar							= document.createElement("div");
		$eTitleBar.onclick						= function() {
													var $eMesageZone = $("_RMKTRACER_");
													$eMesageZone.style.display = ($eMesageZone.style.display != 'none') ? "none" : "block";
												}
		$eTitleBar.style.height					= "16px"+$sPriority;
		$eTitleBar.style.width					= "100%"+$sPriority;
		$eTitleBar.style.backgroundColor		= "#C6D0D0"+$sPriority;
		$eTitleBar.style.color					= "#000000"+$sPriority;
		$eTitleBar.style.fontFamily				= "monospace"+$sPriority;
		$eTitleBar.style.fontSize				= "10pt"+$sPriority;
		$eTitleBar.style.fontWeight				= "bold"+$sPriority;
		$eTitleBar.style.borderStyle			= "solid"+$sPriority;
		$eTitleBar.style.borderWidth			= "2px 0px 3px 0px"+$sPriority;
		$eTitleBar.style.borderColor			= "#BFCACA"+$sPriority;
		$eTitleBar.style.borderTopColor			= "#E8F2F2"+$sPriority;
		$eTitleBar.style.padding				= "4px 4px 4px 10px"+$sPriority;
		$eTitleBar.style.cursor					= "pointer"+$sPriority;
		$eTitleBar.appendChild(document.createTextNode("jRamki - Trace"));
		
		var $eMesageZone 						= document.createElement("div");
		$eMesageZone.id							= "_RMKTRACER_";
		$eMesageZone.style.display				= "block"+$sPriority;
		$eMesageZone.style.height				= "200px"+$sPriority;
		$eMesageZone.style.overflow				= "auto"+$sPriority;
		$eMesageZone.style.padding				= "10px"+$sPriority;
		$eMesageZone.style.borderStyle			= "none"+$sPriority;

		jRamki.GLOBALS['trace'].appendChild($eTitleBar);
		jRamki.GLOBALS['trace'].appendChild($eMesageZone);
		document.body.appendChild(jRamki.GLOBALS['trace']);
	}
	
	//var $eTracer = $("_RMKTRACER_");
	var $eTracer = document.getElementById("_RMKTRACER_");
	if($bClear) {
		$eTracer.innerHTML = $sMesage;
	} else {
		$eTracer.innerHTML = $sMesage + "<hr size='1' color='#DDDDDD' noshade />" + $eTracer.innerHTML;
	}
}
/** FUNCTION END **/


/** FUNCTION
$U: Retorna el nombre pasado como variable añadiendole el id de session.
Input:
	$sName = nombre;
**/
function $U($sName) {
	return $sName+jRamki.GLOBALS["id"];
}
/** FUNCTION END **/
