<!--// 2007 Intelygenz  - www.intelygenz.com <%//-->
i_core_nVersion=0.826;
/*
	[VER] 	 P:\IG_IntelyGenZ\IG11_Desarrollo_Librerias\IG11_01_Js\docs\i_core.txt
	[DOC]	 http://intranet.intelygenz.com/ig05_intranet/desarrollo/areas/dev/docs/i_core.html
	[UPDATE] P:\IG_IntelyGenZ\IG11_Desarrollo_Librerias\IG11_01_Js\src\i_core.js

	open -> i_igz.js,  i_marray.js, i_xbd.js, i_lang_XX.js
*/


//
// ************************* INICIO DE PROTOTYPEs y Funciones Globales
//


// [nFuns]	: numero de funciones
// [bUltima]: pinta tambien la ultima funcion
// [bInverso]: orden de las funciones
function FunCaller(nFuns,bUltima,bInverso) {
	var sFun, sText = "";
	if (!ICore.m_bIsServer && !oIGZ.m_bIE) return (sText)
	var a = arguments;
	if (!bUltima) a = a.caller;
	if (!nFuns) nFuns=-1;
	for (a = a.caller; a !=null; a = a.caller) {
		sFun = a.callee.toString().match(/function (.*\))/);
		if ((sFun != null) && (sFun.length!=0)) {
			if (bInverso) sText += "\n < "+sFun[1];
			else sText = "\n > "+sFun[1]+sText;
		}
		if (a.caller == a || !nFuns) break;
		else --nFuns
	}
	return (sText + "\n");
}
function funcname(f) {
 var s = f.toString().match(/function (\w*)/)[1];
 if ((s == null) || (s.length==0)) return "anonymous";
 return s;
}
function stacktrace() {
 var s = "";
 for (var a = arguments.caller; a !=null; a = a.caller) {
	s += "->"+funcname(a.callee) + "\n";
	if (a.caller == a) {s+="*"; break;}
 }
 return s;
}


OBJECT = new function (){
	this.f_indexOf = function (oObj, sItemName){
		var nIndex = -1;
		var f=-1;
		for ( obj_param in oObj ) {
			f++;
			if ( obj_param == sItemName ){
				nIndex = f;
				break;
			}
		}
		return nIndex;
	}
}

// [3] Number
// sFormatOut = cIcDDdd	('I','.I,DD','I,dd','I,Ddd')
Number.prototype.f_formatNumber = function (sFormatOut){
	var sNumDec = "", nNumInt;
	var cCharInt = "", cCharDec = ""
	if (IsNull(sFormatOut)) sFormatOut = ICore.m_sNumberFormat
	var nPos = sFormatOut.toLowerCase().lastIndexOf("i")
	if (nPos!=-1 && (nPos+2)<sFormatOut.length)  cCharDec = sFormatOut.charAt(nPos+1)
	if (cCharDec=="") {
		nNumInt = Math.floor(Math.round(this))
	}
	else {
		nNumInt = Math.floor(Math.abs(this))
		var sDec = this.toString()
		var nDecsMin =  sFormatOut.f_countMatches ("D")
		var nDecs = 0
		var nPosD = sDec.indexOf (".")
		if (nPosD!=-1) {
			nDecs = sDec.length - (nPosD+1)
		}
		if (nDecsMin || nDecs) {
			var nDecsMax =	sFormatOut.f_countMatches ("d",1)
			if (nDecs>nDecsMax)	{	//Redondeo
				var n = this*Math.pow(10, nDecsMax)
				n = (Math.round (n)).toString()
				nNumInt = n.substring (0,nPosD)
				sDec = n.substring (nPosD)
			}
			else {
				sDec = sDec.substring (sDec.length-nDecs)
				if (nDecs<nDecsMin) {	//Añado 0
					sDec = sDec + "0000000000".substring(0,nDecsMin-nDecs)
				}
			}
//status += this+"/"+nPosD+"/"+nDecs+"["+nNumInt+"."+sDec+"]"
			sNumDec = cCharDec + sDec
		}
	}

	var sNumInt = nNumInt.toString()
	if (sFormatOut.f_indexOf ("i",0,1)==1)  cCharInt = sFormatOut.charAt(0)
	if (cCharInt!="") {
		var sNumFmt = ""
		while (sNumInt.length>3){
			sNumFmt = cCharInt + sNumInt.substring(sNumInt.length-3,sNumInt.length) + sNumFmt ;
			sNumInt = sNumInt.substring(0,sNumInt.length-3) ;
		}
		sNumInt = sNumInt + sNumFmt;
		if (this<0) sNumInt = "-"+sNumInt
	}
	return (sNumInt+ sNumDec)
}

Number.prototype.f_toNumber = function (){
	return (this)
}


/*
Pasa números a formatos de texto standar
Formatos: "IMPORTE" (1.300,25), "EUR" (100.485,124), "USA" (100,485.124)
*/
Number.prototype.m_a_vNumberFormats=["IMPORTE", ".I,DD"
 								    ,"EUR" 	  , ".I,ddd"
 								    ,"USA"    , ",I.ddd"
 								    ];
Number.prototype.f_parse2Format = function (sOut){
	var vVal 	 = Number(this);
	var nTypeOut = this.m_a_vNumberFormats.f_indexOf(sOut);
	var sFormat  = nTypeOut!=-1 ? this.m_a_vNumberFormats[nTypeOut+1] : "";
	vVal = this.f_formatNumber( sFormat );
	return ( vVal );
}

// [vNumber] oNumber/sNumber
Number.prototype.f_range= function (vMin,vMax) {
	var bOk =1
	if (vMin) {
		if (typeof(vMin)=="string") vMin=vMin.f_toNumber()
		if (this<vMin) bOk=0
	}
	if (bOk && vMax) {
		if (typeof(vMax)=="string") vMax=vMax.f_toNumber()
		if (this>vMax) bOk=0
	}
	return (bOk)
}

//
// [4] String
//
// sFormatOut, [sFormatIn], [sIsNaN]
String.prototype.f_formatNumber = function (sFormatOut,sFormatIn,sIsNaN){
	var nNum = this.f_toNumber (sFormatIn, "-")
	if (isNaN(nNum) && !IsUndefined(sIsNaN)) {
		sNum = sIsNaN
	}
	else {
		if (isNaN(nNum)) nNum = 0
		sNum = nNum.f_formatNumber(sFormatOut)
	}
	return (sNum)
}

// [sFormatIn] por defecto intenta detectarlo
String.prototype.f_toNumber = function (sFormatIn, sIsNaN){
	var nNum = this;
	if (this.length==0) nNum = sIsNaN ? sIsNaN : "0";
	var cCharInt = "", cCharDec = ""
	if (IsNull(sFormatIn) || !sFormatIn) {
		sFormatIn = this.f_findFormat()
	}
	if (sFormatIn.f_indexOf ("i",0,1)==1)  cCharInt = sFormatIn.charAt(0)
	var nPos = sFormatIn.toLowerCase().lastIndexOf("i")
	if (nPos!=-1 && (nPos+1)!=sFormatIn.length)  cCharDec = sFormatIn.charAt(nPos+1)

	if (cCharInt!="") nNum = nNum.f_replace (cCharInt,"")
	if (cCharDec==",") nNum = nNum.f_replace (cCharDec,".")

	return (parseFloat(nNum))
}

String.prototype.f_findFormat = function () {
	var re = new RegExp(".*\\..*,.*","gi");
	if (re.exec(this)) return (".I,")
	re = new RegExp(".*,.*\\..*","gi");
	if (re.exec(this)) return (",I.")

	re = new RegExp(",","gi");				//BUG: si 1,000 ¿1000 o 1?
	var a_sMatches = this.match(re);
	if (a_sMatches) {
		if (a_sMatches.length>1) return (",I.");
		else return ("I,")
	}

	re = new RegExp("\\.","gi");			//BUG: si 1.000 ¿1000 o 1?
	a_sMatches = this.match(re);
	if (a_sMatches && a_sMatches.length>1) return (".I,");

	return ("I.")
}


// Devuelve el numero máximo de caracteres nMaxLength y le suma sFin si ha tenido que recortarlo
//nMaxLength, [sFin], [bPalabra], [bRemoveHtml]
String.prototype.f_getMaxString = function (nMaxLength, sFin, bPalabra, bRemoveHtml){
	return ( this.f_maxLength(nMaxLength, sFin, bPalabra, bRemoveHtml) );
}
String.prototype.f_maxLength = function (nMaxLength, sFin, bPalabra, bRemoveHtml){
	var sStr = this;
	if (bRemoveHtml) {
		sStr = sStr.replace (/<(?:.*?\s*)?>/g,"")
	}
	if ( sStr.length >= nMaxLength ) {
		sStr = sStr.substring(0, nMaxLength);
		if (bPalabra) {
			var re = new RegExp(".*[^a-z0-9_áéíóúñ]","gi");	//(".*\\W","gi") falla con acentos
			var oMatch = re.exec(sStr)
			if (oMatch) sStr = sStr.substr(0,oMatch.lastIndex-1)
		}
		if (!IsNull(sFin)) sStr += sFin;	// && sFin
	}
	return (sStr);
}




//Usa RegExp y algunos caracteres especiales dan problemas !!!
//Cuenta numero de coincidencias de una cadena en otra
String.prototype.f_countMatches = function (sBuscado, bCaseInd, nStartPos){
	var sTexto = this;
	var nCount = 0;
	var sModo = "g"
	if (bCaseInd) sModo += "i"
	if (nStartPos) sTexto = sTexto.substr(nStartPos)
	if (sBuscado.indexOf(".")!=-1) sBuscado = sBuscado.replace(".","\\.")
	var re = new RegExp(sBuscado,sModo);
	var a_sMatches = sTexto.match(re);
	if (a_sMatches) nCount = a_sMatches.length;
	return (nCount)
}

// [nVeces] = el numero de ocurrencia que nos interesa del texto buscado (la segunda, la tercera...)
String.prototype.f_indexOf = function (sBuscado,nStartPos,bCaseInd,nVeces,bAcentoInd){
	var oMatch;
	var nPos=-1;
	var sTexto = this;
	var sModo = "g"
	if (bCaseInd) sModo += "i"
	if (nStartPos) sTexto = sTexto.substr(nStartPos)
	else nStartPos = 0
	if (!nVeces) nVeces=1
	if (bAcentoInd) sTexto = sTexto.f_removeAcentos()
	var re = new RegExp(sBuscado,sModo);
	while ((oMatch = re.exec(sTexto))!=null && --nVeces){	}
	if (oMatch) nPos = oMatch.index + nStartPos
	return (nPos)
}

// El orden de los cambios es fundamental (no cambiar caracteres que acabamos de añadir)
// String.fromCharCode(92,34) = //'
// Para JS: /',/",/r,/n,//.... son un solo caracter
/*
String.prototype.m_a_vTextFormats=["TEXT"	,[String.fromCharCode(92)		,"\r" 	,"\n"    	,"'"	,'"']
 								  ,"HTML"	,["&#92;"				 		,""   	,"<BR />"	,"'"	,'"']
 								  ,"JS"  	,[String.fromCharCode(92,92)	,"\\r"	,"\\n"   	,"\'" 	,String.fromCharCode(92,34)]
 								  ,"JSHTML" ,[String.fromCharCode(92,92)	,""		,"<BR />"	,"\\'"	,String.fromCharCode(92,34)]
 								  ,"SQL" 	,[String.fromCharCode(92)	 	,""   	,""			,"''"	,""]
 								  ];
*/
String.prototype.m_a_vTextFormats=["TEXT"	,[String.fromCharCode(92)	 	,"\r" 	,"\n"		,"'"	,'"'	,'/'	]
 								  ,"HTML"	,["&#92;"				  	 	,""   	,"<BR />"	,"'"	,'"'	,'/'	]
 								  ,"JS"  	,[String.fromCharCode(92,92)	,"\\r"	,"\\n"		,"\\'"	,'\\"'	,'\\/'	]
 								  ,"JSHTML" ,[String.fromCharCode(92,92)	,""		,"<BR />"	,"\\'"	,'\\"'	,'\\/'	]
 								  ,"SQL" 	,[String.fromCharCode(92)		,"\r"   ,"\n"		,"''"	,'"'	,'/'	]
 								  ]

String.prototype.f_parse2Format= function (sFrom,sTo){
	var sStr=String( this );
	var nFrom=this.m_a_vTextFormats.f_indexOf(sFrom);
	var nTo=this.m_a_vTextFormats.f_indexOf(sTo);
	var a_sFrom=this.m_a_vTextFormats[nFrom+1];
	var a_sTo=this.m_a_vTextFormats[nTo+1];

	for(var n=0;n<a_sFrom.length;n++){
		sStr=sStr.f_replace(a_sFrom[n],a_sTo[n]);
	}
	return ( sStr );
}

String.prototype.f_removeAcentos = function () {
	var sTexto = this;
	var a_sOldChar = ["/[á]/g","/[é]/g","/[í]/g","/[ó]/g","/[úü]/g","/[Á]/g","/[É]/g","/[Í]/g","/[Ó]/g","/[ÚÜ]/g"]
	var a_sNewChar = ["a","e","i","o","u","A","E","I","O","U"]

	for (var f=0;f<a_sOldChar.length;f++){
		sTexto = sTexto.replace (eval(a_sOldChar[f]), a_sNewChar[f]);
	}
	return (sTexto)
}

//"abcx".f_replace("x","d");
//nAccion : (0 por defecto)  0=replace+delete / 1=insert delante / 2=insert detras
//	[DEPRECATED] 3=replace+delete+NoCaseSensitive	(Usar nAccion=0 y bCaseInd=1)
//bOnlyOne : (0 por defecto)  0=realiza n cambios 1=realiza solo 1 cambio
String.prototype.f_replace=function(sBuscado,sNuevo,nAccion,bOnlyOne,nStartPos,bCaseInd){	// 9.2 Search & insert/replace/delete un texto
	if (nAccion==3) {
		nAccion = 0
		bCaseInd = 1
	}

	if (!sBuscado) bOnlyOne=1;
	if (!bOnlyOne) bOnlyOne=0;
	if (!nAccion)  nAccion =0;
	var nPos1, nPos2, sTexto=this;
	if (sNuevo==null) sNuevo="";
	var sNuevoTmp = "";
	var nBuscado= sBuscado.length;
	var nNuevo	= sNuevo.length;

	if (bCaseInd) {
		sBuscado = sBuscado.toUpperCase()
		nPos1 = sTexto.toUpperCase().indexOf(sBuscado, nStartPos);
	}
	else nPos1 = this.indexOf(sBuscado,nStartPos);

	var nC = 0;
	while (nPos1!=-1 && ++nC<1000){
		nPos2=nPos1;
		if (nAccion==0) nPos2 += nBuscado;
		if (nAccion==2) {
			nPos1 += nBuscado;
			nPos2 += nBuscado;
		}
		if (bCaseInd) {
			sNuevoTmp = sNuevo.f_replace("<SEARCH />", sTexto.substring(nPos1, nPos1+nBuscado) );
			nNuevo	  = sNuevoTmp.length;
			sTexto = sTexto.substr(0,nPos1) + sNuevoTmp + sTexto.substr(nPos2);
		}
		else {
			sTexto = sTexto.substr(0,nPos1) + sNuevo + sTexto.substr(nPos2);
		}
		//sTexto = sTexto.substr(0,nPos1) + sNuevo.f_replace("<"+"SEARCH /"+">", sTexto.substring(nPos1, nPos2) ) + sTexto.substr(nPos2);
		if (!bOnlyOne) {
			nPos1 += nNuevo;
			if (nAccion==1) nPos1 += nBuscado;
			if (bCaseInd){
				nPos1 = sTexto.toUpperCase().indexOf(sBuscado, nPos1);
			}
			else nPos1 = sTexto.indexOf(sBuscado,nPos1);
		}
		else nPos1=-1;
	}
	return (sTexto);
}

// [bNoLeft],[bNoRight]
String.prototype.f_trim = function(bNoTrimL,bNoTrimR) {
	var sTrimL, sTrimR;
	if (!bNoTrimL) sTrimL = "\\s"
	if (!bNoTrimR) sTrimR = "\\s"
	return (this.f_trimString (sTrimL, sTrimR, null, "g"))
}

// [sTrimL],[sTrimL],[sTrim],[sFlags]
String.prototype.f_trimString = function(sTrimL,sTrimR,sTrimAll,sFlags) {
	var sStr = this
	if (IsNull(sFlags)) sFlags = "g";	//Espacios
	if (sTrimL) {
		var re = new RegExp("^"+sTrimL+"*",sFlags);
		sStr = sStr.replace(re,"")
	}
	if (sTrimR) {
		var re = new RegExp(sTrimR+"*$",sFlags);
		sStr = sStr.replace(re,"")
	}
	if (sTrimAll) {
		var re = new RegExp(sTrimAll+"*",sFlags);
		sStr = sStr.replace(re,"")
	}
	return (sStr)
}


//
// Devuelve un número hexadecimal único para cada cadena (Se usa en los menus)
String.prototype.f_getHexCode = function () {
	var sStr = this;
	var vReturn = "", vCharCode;
	for (var f=0, F=sStr.length; f<F; f++) {
		vCharCode = sStr.charCodeAt(f);			// Caracter en ASCII
		vCharCode = vCharCode.toString(16);		// Entero a Hexadecimal
		vReturn  += vCharCode;
	}
	return (vReturn);
}


//
// [5] Array
//

Array.prototype.m_a_sCOLs = [];
Array.prototype.m_a_aROWs = [];

// v0.823 [new] Array.prototype.f_replace - Jonas
Array.prototype.f_replace=function(sBuscado,sNuevo,nAccion,bOnlyOne,nStartPos,bCaseInd){
	var a_new = [];
	for ( var f=0, F=this.length; f<F; f++ ){
		a_new.push( String(this[f]).f_replace(sBuscado,sNuevo,nAccion,bOnlyOne,nStartPos,bCaseInd) );
	}
	return a_new;
}

// Igual que f_insert, pero modifica directamente el array que le pasamos
Array.prototype.f_add=function (a_vValores,nPos){
	var f
	var nLen = this.length;
	if (!IsArray(a_vValores)) a_vValores = [a_vValores]
	var nLenSub = a_vValores.length;
	if (nPos>=0) {
		for (f=nLen;f>nPos;f--) {
			this [f+nLenSub] = this [f]
		}
	}
	else {
		nPos = nLen
	}
	for (f=0; f<nLenSub; f++){
		this [nPos+f] = a_vValores[f]
	}
}

Array.prototype.f_move=function (nPosI, nPosF){
	var vVal  = this[nPosI];
	var a_new = this.f_delete(nPosI, 1);
//	if ( nPosI < nPosF ) nPosF++;
	a_new = a_new.f_insert(vVal, nPosF);
	return (a_new);
}

Array.prototype.f_addArguments=function (){
	for(var n=0;n<arguments.length;n++){
		this[this.length]=arguments[n];
	}
}

Array.prototype.f_avg = function (){
	var nSuma = 0, nTotal = 0
	for (var f=0;f<this.length;f++){
		nSuma += Number (this[f])
		if(this[f]!=''){nTotal++}
	}
	if(nTotal!=0) nTotal = nSuma / nTotal
	return (nTotal)
}

Array.prototype.f_copy = function (){
	return (this.concat())
}

// Cuenta el numero de coincidencias de un valor en el Array
Array.prototype.f_countMatches=function (vValue,sProp,bCaseInd,bParte,nStartPos){
	var vValueC,f;
	var nLen = this.length;
	if (bCaseInd) vValue = vValue.toLowerCase();
	var nCount=0;
	if (!nStartPos) nStartPos=0
	for (f=nStartPos;f<nLen;f++){
		if(sProp) eval("vValueC=this[f]."+sProp) ;
		else vValueC = this[f];
		if (bCaseInd) vValueC = vValueC.toLowerCase();
		if (bParte) {
			if (vValueC.indexOf(vValue)!=-1) nCount++;
		}
		else{
			if (vValueC==vValue) nCount++;
		}
	}
	return (nCount);
}

//Borra el numero de elementos (nElements) desde la posicion (nPos)
Array.prototype.f_delete=function (nPos,nElements){
	if(!nElements) nElements=this.length-nPos;
	var a_vItem1=this.slice(0, nPos);
	var a_vItem2=this.slice(nPos+nElements);
	return ( a_vItem1.concat(a_vItem2) );
}

Array.prototype.f_getMax = function (){
	var aTemp = [].concat(this)
	return (aTemp.sort(OrdenNumerico).reverse())[0]
}

Array.prototype.f_getMin = function (){
	var aTemp = [].concat(this)
	return (aTemp.sort(OrdenNumerico))[0]
}

Array.prototype.f_getVal = function (nIndex){
	var sVal = ''
	if (!isNaN(nIndex) && nIndex<this.length){
		 sVal = this [nIndex]
	}
	return (sVal)
}

Array.prototype.f_getVals = function (vIndex){
	if(!IsArray(vIndex)) vIndex=[vIndex];
	var nIndex
	var a_vDatos = []
	for (var f=0;f<vIndex.length;f++)	{
		nIndex = vIndex [f]
		if (!isNaN(nIndex) && nIndex<this.length){
			 a_vDatos.push (this[nIndex])
		}
	}
	return (a_vDatos)
}

//Devuelve la posicion de vValue en el array, si no existe -1
//[sProp] para objetos
Array.prototype.f_indexOf=function (sBuscado,sProp,bCaseInd,bParte,nStartIndex,nStartPos,bAcentoInd){
	var vValueC;
	var nPos=-1;
	// String(sBuscado)=="undefined"
	if (IsNull(sBuscado)) return (nPos)
	sBuscado = sBuscado.toString()
	if (!nStartIndex) nStartIndex=0
	var f=nStartIndex;
	var nLen=this.length;
	if (bCaseInd) sBuscado = sBuscado.toLowerCase();
	if (bAcentoInd)	sBuscado = sBuscado.f_removeAcentos()
	while(f<nLen && nPos<0){
		if(sProp){
			eval("vValueC=this[f]."+sProp)
		}
		else {
			if (String(this[f]) == "undefined") break
			vValueC = this[f];
		}
		vValueC = vValueC.toString()
		if (bParte) {
			if (vValueC.f_indexOf(sBuscado,nStartPos,bCaseInd,0,bAcentoInd)!=-1) nPos=f;
		}
		else{

			if (bCaseInd) vValueC = vValueC.toLowerCase();
			if (nStartPos) vValueC = vValueC.substr(nStartPos)
			if (bAcentoInd)	 vValueC = vValueC.f_removeAcentos()

			if (vValueC==sBuscado) nPos=f;
		}
		f++
	}
	return (nPos);
}

// Devuelve el value que esta en la posicion relativa al valor buscado
Array.prototype.f_indexOfVal=function (sBuscado,nPosVal,vReturn){
	var sVal=(vReturn==0 || vReturn)? vReturn : "";
	var nPos = this.f_indexOf (sBuscado)
	if (nPos!=-1) sVal = this[nPos+nPosVal]
	return (sVal)
}

Array.prototype.f_insert = function(a_vArrayMed,nPos){
var a_vArrayIni, a_vArrayFin = []
	if (nPos==null){

		a_vArrayIni = this
	}
	else{
		a_vArrayIni = this.slice(0, nPos)
		a_vArrayFin = this.slice(nPos)
	}
	return (a_vArrayIni.concat(a_vArrayMed,a_vArrayFin))
}

//nAccion: 0=replace / 1=insert delante / 2=insert detras
Array.prototype.f_setVals=function (sValor,nAccion){
	var sValorT = sValor
	for (var f=0;f<this.length;f++){
		if (nAccion==1) sValorT = sValor + this[f];
		if (nAccion==2) sValorT = this[f]+ sValor;
		this[f] = sValorT
	}
}

// [bIndices]			Devuelve array con valores/indices				0/1
// [bOrdenacion]		Ordenado creciente/decreciente					0/1
// [nOrden]				""=auto 0=numerica 1=alfabetica 2=fecha
// [bCaseDependiente]	0=AaBb		1=ABab
Array.prototype.f_sort=function (bIndices,bOrdenacion,nOrden,bCaseDependiente){
var f=0,vValor,vValorT,sCifrasF,nCifrasF
	var bValoresNulos=0
	var nLength = this.length				//elementos
	if (nLength==0) return (this)

	var a_vArrayWork = []
	a_vArrayWork = a_vArrayWork.concat(this)

	var nCifras = nLength.toString().length		// cifras
	var sBase = "000000"

	if (nOrden==null || nOrden==""){			// determinamos el tipo de datos
		nOrden=0						//Numeros
		while (nOrden==0 && f<nLength){				//buscamos algun texto
			vValor = a_vArrayWork[f++]
/*
			if (IsUndefined(vValor)) vValor=""
			vValor = vValor.toString().replace(/[,]/g,".")				// cambio comas por puntos
			if (vValor!=parseFloat(vValor)) nOrden=1		//Texto
*/
			if (!IsNull(vValor) && isNaN(vValor) && vValor!=""){
				vValor = vValor.toString().replace(/[,]/g,".")				// cambio comas por puntos
				if (vValor!=parseFloat(vValor)) nOrden=1		//Texto
			}
			else {
				bValoresNulos=1
			}
		}

		if (!IsNull(vValor) && isNaN(vValor)) {
			var sDateFormat = "D/M/Y h:m"
			var sDateFormatOut = "nYYYYnMMnDDnHH24nMMN"
			if (vValor.length<=10) {
				sDateFormat = "D/M/Y"
				sDateFormatOut = "nYYYYnMMnDD"
				if (vValor.indexOf("/")==4) sDateFormat = "Y/M/D"
			}
			else {
				if (vValor.f_countMatches(":")==2) sDateFormat = "D/M/Y h:m:s"
			}
			vValorT = vValor.f_toDate (sDateFormat)

			if (GetType(vValorT)==Date) {
				for (f=0;f<nLength;f++){
					a_vArrayWork[f] =  a_vArrayWork[f].toString().f_toDateDraw (sDateFormat,sDateFormatOut)
				}
				nOrden=2
			}
		}
	}

	if (isNaN(nOrden) || (nOrden==0 && bValoresNulos)) {		//v0.743
		f=0
		while (f<nLength){
			vValor = a_vArrayWork[f++]
			if (vValor=="" || IsNull(vValor)) a_vArrayWork[f-1] = -999999999
		}
	}

	for (f=0;f<nLength;f++){
		sCifrasF = f.toString()
		nCifrasF = sCifrasF.length
		a_vArrayWork[f] = a_vArrayWork[f] + "" + sBase.substring(0,nCifras-nCifrasF) + sCifrasF
	}

	switch (nOrden){
	case 1:					//Str
		for (f=0;f<nLength;f++){
			if (!bCaseDependiente) a_vArrayWork[f] = a_vArrayWork[f].toLowerCase()
			a_vArrayWork[f] = a_vArrayWork[f].f_removeAcentos()
		}
		a_vArrayWork.sort()
		break
	case 2:					//Date
		a_vArrayWork.sort()
		break
	default:				//Num
		a_vArrayWork.sort(OrdenNumerico)
	}

	var a_vArrayDest = []
	if (bIndices){								//Indices
		for (f=0;f<nLength;f++){
			vValor = a_vArrayWork[f]
			a_vArrayDest[f] = parseInt (vValor.substr(vValor.length-(nCifras)),10)
		}
	}
	else{										//Vals
		for (f=0;f<nLength;f++){
			vValor = a_vArrayWork[f]
			a_vArrayDest[f] = this [parseInt (vValor.substr(vValor.length-(nCifras)),10)]
		}
	}
	if (bOrdenacion) a_vArrayDest.reverse()		//Desc

	return (a_vArrayDest)
}

function OrdenNumerico(nValor1,nValor2){	//pasa del caso de igualdad
	if (parseFloat(nValor1)==parseFloat(nValor2)) return (0);
	if (parseFloat(nValor1)<parseFloat(nValor2)) return (-1);
	return (1);
}

// Devuelve array ordenado con los elementos diferentes del primer array o repetidos en los 2 arrays
// [bRepetidos] devuelve array de elementos repetidos
// [bPos] : 0=array de Datos 1=array de Indices
Array.prototype.f_subCompare=function (a_vArray,bRepetidos,bPos,bCaseInd,bDistintosAll){
	var g = 0;
	var a_vUnicos = []
	var a_vUnicosPos = []
	for (var f=0;f<this.length;f++){
		if (a_vArray.f_indexOf(this[f],0,bCaseInd)==-1) {
			if (!bRepetidos) {
				a_vUnicos[g] = this[f]
				a_vUnicosPos[g++] = f;
			}
		}
		else {
			if (bRepetidos) {
				a_vUnicos[g] = this[f]
				a_vUnicosPos[g++] = f;
			}
		}
	}
	if (!bRepetidos && bDistintosAll) {
		for (var f=0;f<a_vArray.length;f++){
			if (this.f_indexOf(a_vArray[f],0,bCaseInd)==-1) {
				a_vUnicos[g] = a_vArray[f]
				a_vUnicosPos[g++] = f;
			}
		}
	}

	if (a_vUnicos.length>1) a_vUnicos = a_vUnicos.f_sort();
	if (bPos) a_vUnicos = a_vUnicosPos;
	return (a_vUnicos)
}

// Devuelve el array sin los elementos con el mismo valor que le pasamos
Array.prototype.f_subDelete= function (sTexto) {
	return (this.f_subIndexOf (sTexto,0,0,0,0,0,0,1))
}

// Devuelve array ordenado con los elementos unicos de 1 array (distinct)
// [bPos] : 0=array de Datos 1=array de Pos
// [bRepetidos] : devuelve los repetidos
Array.prototype.f_subDistinct=function (bPos,bCaseInd,bRepetidos,bNoOrdenado){
	var g = 0, h=0;
	var a_vUnicos = []
	var a_vUnicosPos = []
	var a_vRepetidos = []
	var a_vRepetidosPos = []
	for (var f=0;f<this.length;f++){
		if (a_vUnicos.f_indexOf(this[f],0,bCaseInd)==-1) {
			a_vUnicos[g] = this[f]
			a_vUnicosPos[g++] = f;
		}
		else {
			a_vRepetidos[h] = this[f]
			a_vRepetidosPos[h++] = f;
		}
	}
	if (!bRepetidos) {
		if (bPos) a_vUnicos = a_vUnicosPos;
	}
	else {
		a_vUnicos = a_vRepetidos	//.f_sort();
		if (bPos) a_vUnicos = a_vRepetidosPos;
	}
	if (!bNoOrdenado && !bPos) a_vUnicos = a_vUnicos.f_sort()
	return (a_vUnicos)
}

Array.prototype.f_subIndexOf = function(sTexto,bIndices,bCaseDependiente,bParte,bAcentoDependiente,nStartIndex,nStartPos,bDistinto){
	var f,vValue,vValueC,nIndex
	var a_vFinal= []
	var nFinal=0

	sTexto = String(sTexto);
	if (!nStartIndex) nStartIndex = 0
	for (f=nStartIndex;f<this.length;f++){
		vValue = String(this[f]);
		if (bParte) {
			nIndex = vValue.f_indexOf(sTexto,nStartPos,!bCaseDependiente)
		}
		else {
			vValueC = vValue
			if (!bCaseDependiente){
				sTexto = sTexto.toUpperCase()
				vValueC = vValueC.toUpperCase()
			}
			if (!bAcentoDependiente){
				 sTexto = sTexto.f_removeAcentos()
				 vValueC = vValueC.f_removeAcentos()
			}
			nIndex= -1
			if (vValueC==sTexto) nIndex=1
		}
		if (nIndex!=-1 ^ bDistinto ){
			if (bIndices) vValue = f
			a_vFinal[nFinal++]= vValue
		}
	}
	return (a_vFinal);
}

Array.prototype.f_suma = function (){
	var nNum, nSuma = 0
	for (var f=0;f<this.length;f++){
		nNum   = Number (this[f])
//alert(nNum+"\n"+this[f])
		if(!isNaN(nNum)) nSuma += nNum;
	}
	return (nSuma)
}

// *** DEP **
Array.prototype.f_addElements=function (){
	var oArgs=( IsArray(arguments[0]) )? arguments[0] : arguments;
	for(var n=0;n<oArgs.length;n++){
		this[this.length]=oArgs[n];
	}
}
Array.prototype.f_cmpElements=function (a_vArray,bRepetidos,bPos,bCaseInd){
	return (this.f_subCompare (a_vArray,bRepetidos,bPos,bCaseInd))
}
Array.prototype.f_delOfArray=function (nPos,nElements){
	return (this.f_delete (nPos,nElements))
}
Array.prototype.f_getColIf = function (vValue,bCaseInd,bParte,nStartIndex,nStartPos){
	return (this.f_subIndexOf(vValue,1,!bCaseInd,bParte,0,nStartIndex,nStartPos) )
}
Array.prototype.f_getDistinct=function (bPos,bCaseInd){
	return (this.f_subDistinct (bPos,bCaseInd))
}
Array.prototype.f_getValFromIndex = function (a_nIndex) {
	return (this.f_getVals (a_nIndex))
}
Array.prototype.f_subVal = function (a_nIndex) {
	return (this.f_getVals (a_nIndex))
/*
	var a_vValues = []
	for (var f=0; f<a_nIndex.length; f++){
		a_vValues [f] = this [a_nIndex[f]]
	}
	return (a_vValues)
*/
}
// ***

// [6] MArray
// Reg = numero Registro
// Row = Datos de 1 Fila (Registro)
// Col = Datos de 1 Columna (Campo)
// Val = Valor del Campo de un Registro


Array.prototype.f_addColEXML=function (sCampo,sEXML){
	oIEXML.f_addColEXML (this,sCampo,sEXML)
}

Array.prototype.f_modColEXML=function (sCampo,sEXML){
	oIEXML.f_modColEXML (this,sCampo,sEXML)
}


//Añade un columna nueva a un MArray
//sNewCol  : Nombre de la nueva columna
//nValor : Valor para la nueva columna
Array.prototype.f_maAddCol=function (sNewCol,vValor){
	var a_vNextValues = []
	var nCols = this[0].length
	var nPosOld = this[1].length - 1
	var nRegs= this.f_maGetRegs();
	this[0].f_addElements(sNewCol);
	var nPosNew = nPosOld + nRegs
	for(var n=nRegs;n>0;n--){
		this[1][nPosNew--]=vValor;
		if (n>1) {
			for (var f=0; f<nCols; f++){
				this[1][nPosNew--] = this[1][nPosOld--]
			}
		}
	}
}

//Copia columnas de un array a otro cuando tienen un campo que los relaciona
// vCampoRelacionado = s/a = sCampo/['sCampoS','sCampoD']
// vCampoS = s/a = sCampo/[sCampo1,sCampo2...]
// [vCampoD] = s/a = sCampo/[sCampo1,sCampo2...]
Array.prototype.f_maCopyCols=function (a_ArrayS,vCampoRel,vCampoS,vCampoD){
	var sCampoD,nID,nReg,vValue
	var sCampoRelS = vCampoRel
	var sCampoRelD = vCampoRel
	if (IsArray(vCampoRel)){
		sCampoRelS = vCampoRel[0]
		sCampoRelD = vCampoRel[1]
	}
	if (!IsArray(vCampoS)) vCampoS = [vCampoS]
	if (!IsArray(vCampoD)) vCampoD = [vCampoD]
	for (var f=0;f<vCampoS.length;f++){
		sCampoD = vCampoD[f]
		if (!sCampoD) {
			sCampoD = vCampoS[f]
			vCampoD[f] = vCampoS[f]
		}
		if (this[0].f_indexOf(sCampoD)==-1) {
			this.f_maAddCol(sCampoD,"");
		}
	}
	for(var n=0;n<this.f_maGetRegs();n++){
		nID =this.f_maGetVal(sCampoRelD,n);
		nReg  =a_ArrayS.f_maGetReg(sCampoRelS,nID);
		for (var f=0;f<vCampoS.length;f++){
			vValue=a_ArrayS.f_maGetVal(vCampoS[f],nReg);
			this.f_maSetVal(vCampoD[f],vValue,n);
		}
	}
}
String.prototype.f_maCopyCols=function (a_ArrayS,vCampoRel,vCampoS,vCampoD){
	(this.f_maBArray2MArray()).f_maCopyCols (a_ArrayS,vCampoRel,vCampoS,vCampoD)
}

// numero de coincidencias de los valores de un columna
Array.prototype.f_maCountMatches=function (sFieldName,vValue,sProp,bCaseInd,bParte,nStartPos){
	var a_vCountMatches=[];
	for(var n=0;n<this.f_maGetRegs();n++){
		a_vCountMatches.f_addElements(this.f_maGetVal(sFieldName,n));
	}
	return ( a_vCountMatches.f_countMatches(vValue,sProp,bCaseInd,bParte,nStartPos) );
}
String.prototype.f_maCountMatches = function(sFieldName,vValue,sProp,bCaseInd,bParte,nStartPos){
	return ((this.f_maBArray2MArray()).f_maCountMatches(sFieldName,vValue,sProp,bCaseInd,bParte,nStartPos))
}

Array.prototype.f_maDeleteCol=function (a_sCampos){
	if(!IsArray(a_sCampos)) a_sCampos=[a_sCampos];
	var a_nPosiciones = this[0].f_subCompare ( a_sCampos,1,1,0)
	a_nPosiciones.reverse()		//para borrar 1º los ultimos

	var a_vArray=this[1];
	var nCampos = this[0].length
	var nRegs = this.f_maGetRegs()
	var nLastRegPos = nCampos * (nRegs-1)

	for(var f=0; f<nRegs;f++){
		for (var g=0; g<a_nPosiciones.length; g++){
			if (f==0) this[0].splice(a_nPosiciones[g], 1)
			this[1].splice(nLastRegPos+a_nPosiciones[g], 1)
		}
		nLastRegPos -= nCampos
	}
}

//Borra Filas
//[nRegPos] : 0-(n-1) Registro donde borramos. Por defecto es el ultimo.
//[nRegs] : Filas que borra. Por defecto 1
Array.prototype.f_maDeleteRow=function (nRegPos,nRegs){
	var a_vArray=this[1];
	if (nRegPos!=0 && !nRegPos) nRegPos =this.f_maGetRegs()-1;
	if (!nRegs) nRegs=1
	var nCampos = this[0].length
	var nDelPosIni = (nRegPos) * nCampos
	var nDelPosFin = (nRegPos+nRegs) * nCampos
	this[1]=a_vArray.slice(0, nDelPosIni);
	this[1]=this[1].concat(a_vArray.slice(nDelPosFin));
}

Array.prototype.f_maDeleteRows=function (a_nRegs){
	a_nRegs = a_nRegs.f_sort (0,1,0)
	for (var f=0;f<a_nRegs.length;f++) {
		this.f_maDeleteRow (a_nRegs[f],1)
	}
}

// Devuelve un Array con la columna pedida
Array.prototype.f_maGetCol=function (sCampo){
	var a_vCampo = [];
	if(this.f_maGetRegs() && sCampo && this[0].length!=0){
		var nCampoPos=this[0].f_indexOf(sCampo,"",1);
		if (nCampoPos != -1){
			var nCampos = this[0].length;
			for (var f=0;f<this.f_maGetRegs();f++){
				a_vCampo[f] = this[1] [(f*nCampos)+nCampoPos]
			}
		}
		else {
			ErrorJS ("f_maGetCol: no esta definido el campo ["+sCampo+"]\n"+this[0]+FunCaller(),"",1)		// de ["+sArrayBase+"]
		}
	}
	return (a_vCampo)
}
String.prototype.f_maGetCol=function (sCampo){
	return ((this.f_maBArray2MArray()).f_maGetCol(sCampo))
}

Array.prototype.f_maGetColName=function (nPos){
	return (this[0][nPos])
}

Array.prototype.f_maGetColPos=function (sCampo){
	return (this[0].f_indexOf(sCampo));
}
String.prototype.f_maGetColPos = function(sCampo){
	return ((this.f_maBArray2MArray()).f_maGetColPos(sCampo))
}

Array.prototype.f_maGetCols = function(){
	return (this[0].length)
}


// Devuelve el numero de registro en el que se encuentra un valor de un campo
// sValue :Valor buscado
// sFieldName:Nombre del campo
Array.prototype.f_maGetReg=function (sFieldName,sValue){
	var a_sTags=this[0], a_vValues=this[1], nPosValue=-1, nRegNum=-1, nPosInc=0;

	if(a_sTags.length!=0 && this.f_maGetRegs()){
		if(sFieldName) nPosInc=a_sTags.f_indexOf(sFieldName);
		var nPosC=nPosInc;
		sValue = String (sValue)
		while(nPosC<a_vValues.length && nPosValue==-1){
			if(a_vValues[nPosC]==sValue) nPosValue=nPosC;
			nPosC+=a_sTags.length;
		}
		if(nPosValue!=-1) nRegNum=Math.floor(nPosValue/a_sTags.length);
	}
	return (nRegNum)
}
String.prototype.f_maGetReg=function (sFieldName,sValue){
	return ((this.f_maBArray2MArray()).f_maGetReg(sFieldName,sValue))
}

Array.prototype.f_maGetRegIf = function(sCampoIn, sValueIn){
	var a_vCol=this.f_maGetCol(sCampoIn);
	var nReg  =a_vCol.f_indexOf(sValueIn);
	return ( nReg );
}

Array.prototype.f_maGetRegs=function (){
	var nRegs=0;
/*
	if(!IsArray(this[0]) || this[0].length==0 || !IsArray(this[1]) || this[1].length==0) {
		nRegs=0
	}
*/
//ErrorJS (this.length +"\n"+IsArray(this[0]) +"\n"+ IsArray(this[1]))
	if (this.length==2 && IsArray(this[0]) && IsArray(this[1])) {
		nRegs = this[1].length/this[0].length
	}

	if (nRegs>0 && (nRegs != Math.ceil(nRegs))){
		ErrorJS("[i_core.js "+ICore.m_nVersion +"] El numero de campos del MArray ["+ this[0].length+"] no es proporcional al numero de elementos ["+ this[1].length+ "]\n\n"+this.f_maDebug(),"",1) ;
	}
	return (nRegs);
}
String.prototype.f_maGetRegs = function(){
	return ((this.f_maBArray2MArray()).f_maGetRegs())
}

// Devuelva un array con los registros que cumplen TODAS las condiciones
Array.prototype.f_maGetRegsIf=function (a_sCampo,a_vValor){
	var nReg=-1, f=0, a_nRegs, a_nIndices
	a_nRegs=this.f_maSubIndexOf (a_sCampo[f],a_vValor[f],1);
	while (a_nRegs.length && ++f<a_sCampo.length) {
		a_nIndices = this.f_maSubIndexOf (a_sCampo[f],a_vValor[f],1)
		if (a_nIndices.length) {
			a_nRegs = a_nRegs.f_subCompare (a_nIndices,1,0)
		}
		else {
			a_nRegs = []
			break
		}
	}
	return (a_nRegs)
}

/*
[a_nReg/nReg]	Numero de Registro que queremos recoger (0 por defecto)
[sReturn]	Cadena que devuelve si no existe el campo/registro
*/
Array.prototype.f_maGetVal=function (sCampo,a_nReg,sReturn){
	var	vValor=""
	var bError=1
	if (!IsUndefined(sReturn)) {
		vValor = sReturn
		bError=0
	}
	var nCol = this[0].f_indexOf (sCampo,"",1)
	if (nCol != -1){
		if(!IsArray(a_nReg)) {
			if (IsUndefined(a_nReg)) a_nReg=0
			if (a_nReg>=this.f_maGetRegs()){
				if (bError) ErrorJS ("f_maGetVal: campo '"+sCampo+"' del registro "+a_nReg+" y este MArray solo tiene "+this.f_maGetRegs() +" registros."+FunCaller(),this,1)		// de ["+sArrayBase+"]
			}
			else {
				vValor=this[1][nCol+(this[0].length*a_nReg)];
			}
		}
		else{
			vValor = []
//No avisa si el registro se sale del rango
			for (var f=0;f<a_nReg.length;f++){
				vValor[f]=this[1][nCol+(this[0].length*a_nReg[f])];
			}
		}
	}
	else {
		if (bError) ErrorJS ("f_maGetVal: no esta definido el campo ["+sCampo+"]\n"+this[0]+FunCaller(),"",1)		// de ["+sArrayBase+"]
	}
	return (vValor);
}
String.prototype.f_maGetVal = function(sCampo,nReg,sReturn){
	return ((this.f_maBArray2MArray()).f_maGetVal(sCampo,nReg,sReturn))
}

//[sVal] Valor por defecto en el caso de que no haya ninguno
Array.prototype.f_maGetValIf=function (sField, sColName, vColVal, sVal){
	if (IsUndefined(sVal)) sVal = ""
	var nReg=this.f_maGetReg(sColName, vColVal);
//if (sColName=="sTAGName") alert (nReg+"\n"+vColVal)
	if (nReg!=-1) sVal = this.f_maGetVal(sField ,nReg)
	return (sVal);
}

//Une 2 marrays
Array.prototype.f_maJoin=function (a_maData){
//Debug(a_maData[0] + "_"+a_maData[0].length)
	for (var g=0;g<a_maData[0].length;g++) {	//Campos
//Debug(g+". "+a_maData[0][g])
//Debug(a_maData.f_maGetCol (a_maData[0][g]))
		this.f_maAddCol(a_maData[0][g],  a_maData.f_maGetCol (a_maData[0][g]))
	}
}



/*
a_vValues	: Valores del nuevo registro. Admite "" para insertar registro vacio
[nRegPos]	: Registro donde añadimos los nuevos valores. Por defecto es el ultimo.
[bDelRegs]	: Borra los registros cuya posicion haya sido sustituida
*/
Array.prototype.f_maNewRow=function (a_vValues,nRegPos,bDelRegs){
	var a_sArray=this[0], a_vArray=this[1];
	if (typeof(a_vValues)=="string") {
		a_vValues = []
		for (var f=0; f<a_sArray.length; f++){
			a_vValues[f] = ""
		}
	}

	if((a_vValues.length%a_sArray.length)!=0) {
		ErrorJS("f_maNewRow(): a_vValues tiene tamaño "+a_vValues.length+" y deberia ser "+a_sArray.length+"\nValores: "+a_vValues+"\n"+this.f_maDebug(),"",1) ;
	}
	else{
		nRegPos=(!nRegPos && nRegPos!=0)? a_vArray.length : nRegPos*a_sArray.length;
		this[1]=a_vArray.slice(0, nRegPos);
		if (!IsArray(a_vValues)) {
			if (a_vValues.length){
				var a_vValuesNew = []
				for (var f=0; f<a_vValues.length; f++){
					a_vValuesNew[f] = a_vValues[f]
				}
				a_vValues = a_vValuesNew
			}
//			else {
//				a_vValues = a_vValues.toString().split(",")
//			}
		}
		else {
			a_vValues = ArrayObject2Array (a_vValues);
		}

		this[1]=this[1].concat(a_vValues);
		if(bDelRegs) this[1]=this[1].concat(a_vArray.slice(nRegPos+a_vValues.length));
		else this[1]=this[1].concat(a_vArray.slice(nRegPos));
	}
}



Array.prototype.f_maGetRows = function (a_nRegs){
	if(!IsArray(a_nRegs)) a_nRegs=[a_nRegs];
	var nPos, a_vRows=[];
	for(var f=0; f<a_nRegs.length; f++){
		nPos=Number(a_nRegs[f]*this[0].length);
		a_vRows=a_vRows.concat(this[1].slice(nPos, nPos+this[0].length));
	}
	return (a_vRows);
}

Array.prototype.f_maSetVal=function (sCampo,vValue,nReg){
	this[1][(nReg*this[0].length)+this[0].f_indexOf(sCampo,"",1)]=vValue;
}
String.prototype.f_maSetVal = function(sCampo,Value,nRegistro){
	return ((this.f_maBArray2MArray()).f_maSetVal(sCampo,Value,nRegistro))
}

Array.prototype.f_maSetValIf=function (sCampoIf,sValueIf,sCampo,vValue, bAddIfNot){
	var nReg = this.f_maGetReg (sCampoIf,sValueIf)
	if (nReg!=-1) {
		this.f_maSetVal (sCampo, vValue, nReg);
	}
	else {
		if(bAddIfNot){
			this.f_maNewRow (new Array(this[0].length));
			nReg = this.f_maGetRegs()-1;
			this.f_maSetVal (sCampoIf, sValueIf, nReg);
		}
	}
}

Array.prototype.f_maSort = function(sCampo,bIndices,bOrdenacion,nOrden,bCaseDependiente){
	var a_vOrdenado = []
	var a_vCol = this.f_maGetCol (sCampo)
	if (a_vCol.length) a_vOrdenado = a_vCol.f_sort (bIndices,bOrdenacion,nOrden,bCaseDependiente)
	return (a_vOrdenado)
}
String.prototype.f_maSort = function(sCampo,bIndices,bOrdenacion,nOrden,bCaseDependiente){
	return ((this.f_maBArray2MArray()).f_maSort(sCampo,bIndices,bOrdenacion,nOrden,bCaseDependiente))
}

Array.prototype.f_maSubDistinct = function(sCampo,bIndices,bCaseDependiente,bRepetidos,bOrdenados){
	var a_vDistinct = []
	var a_vCol = this.f_maGetCol (sCampo)
	if (a_vCol.length) a_vDistinct = a_vCol.f_subDistinct (bIndices,!bCaseDependiente,bRepetidos,!bOrdenados)
	return (a_vDistinct)
}
String.prototype.f_maSubDistinct = function(sCampo,bIndices,bCaseDependiente,bRepetidos,bOrdenados){
	return ((this.f_maBArray2MArray()).f_maSubDistinct(sCampo,bIndices,bCaseDependiente,bRepetidos,bOrdenados))
}

// vLogic: OR / AND / NOT / XOR
// 	OR : 		 	sCampo	/a_sValor
// 	OR/AND/NOT/XOR: a_sCampo/a_sValor
// [bIndices],[bCaseDep],[bParte],[bAcentoDep],[bRepetidos],[bDistinto],[vLogic]
Array.prototype.f_maSubIndexOf = function(vCampo,vValor,bIndices,bCaseDep,bParte,bAcentoDep,bRepetidos,bDistinto,vLogic){
	var f,g,a_vCol, a_vSubVal, sLogic
	var a_vSub = []
	if (!bDistinto) bDistinto=0

	if (!IsArray(vCampo)) {
		vCampo = [vCampo];
		vValor = [vValor];
		if (!vLogic) vLogic = ["OR"]
	}
	else {
		if (!vLogic) vLogic = ["AND"]
	}
	if (!IsArray (vLogic)) vLogic = [vLogic]

	if (vCampo.length!=vValor.length) {
		ErrorJS("[f_maSubIndexOf] Los parámetros vCampo y vValor tienen distinta dimensión:\n["+vCampo.length+"] "+ vCampo +"\n["+vValor.length+"] "+ vValor+"\n","",1) ;
	}

/*
		a_vCol = this.f_maGetCol (vCampo)
		if (a_vCol.length) {
			if(!IsArray(vValor)) vValor = [vValor];
			for (f=0;f<vValor.length;f++){
				a_vSub = a_vSub.concat(a_vCol.f_subIndexOf (vValor[f],bIndices,bCaseDep,bParte,bAcentoDep,0,0,bDistinto))
			}
			if (vValor.length>1 && !bRepetidos) a_vSub = a_vSub.f_subDistinct (0,!bCaseDep,bRepetidos,1)
		}
	}
*/

	sLogic = "OR"	//La primera es siempre OR
	for (f=0;f<vCampo.length;f++){
		a_vCol = this.f_maGetCol (vCampo[f])
		a_vVal = vValor[f]

//Array.prototype.f_maGetVal=function (sCampo,a_nReg,sReturn)
//Optimizar: solo coja los valores que no tenemos ya
		if(!IsArray(a_vVal)) a_vVal = [a_vVal];
		a_vSubVal = []
		for (g=0;g<a_vVal.length;g++) {
			a_vSubVal = a_vSubVal.concat(a_vCol.f_subIndexOf (a_vVal[g],bIndices,bCaseDep,bParte,bAcentoDep,0,0,bDistinto))
//alert(f+"_"+g+" "+vCampo[f]+"="+vValor[g]+"\n"+a_vSubVal)
		}

		switch (sLogic) {
			case "OR":
				a_vSub = a_vSub.concat (a_vSubVal)
				break
			case "AND":
				a_vSub = a_vSub.f_subCompare (a_vSubVal,1)
				break
			case "NOT":
//alert(a_vSub+"\n_"+a_vSubVal+"\n_"+(a_vSub.f_subCompare (a_vSubVal,1)).f_subCompare (a_vSubVal,0,0,0,1))
				a_vSub = (a_vSub.f_subCompare (a_vSubVal,1)).f_subCompare (a_vSub,0,0,0,1)
				break
			case "XOR":
				a_vSub = a_vSub.f_subCompare (a_vSubVal,0,0,0,1)
				break
		}
		if (f<vLogic.length) {
			sLogic = vLogic[f]
		}
	}
	if (!bRepetidos) a_vSub = a_vSub.f_subDistinct (0,!bCaseDep,bRepetidos,1)
//Devolver ordenados los indices?
	return (a_vSub)
}

String.prototype.f_maSubIndexOf = function(sCampo,sTexto,bIndices,bCaseDep,bParte,bAcentoDep){
	return ((this.f_maBArray2MArray()).f_maSubIndexOf(sCampo,sTexto,bIndices,bCaseDep,bParte,bAcentoDep))
}

Array.prototype.f_maSubSort = function(a_nIndices,sCampo,bIndices,bOrdenacion,nOrden,bCaseDependiente){
	var a_vOrdenado = []
	var a_vCol = this.f_maGetVal (sCampo,a_nIndices)
	if (a_vCol.length) a_vOrdenado = a_vCol.f_sort (bIndices,bOrdenacion,nOrden,bCaseDependiente)
	if (bIndices) a_vOrdenado = a_nIndices.f_getVals (a_vOrdenado)
	return (a_vOrdenado)
}

String.prototype.f_maSubSort = function(a_nIndices,sCampo,bIndices,bOrdenacion,nOrden,bCaseDependiente){
	return ((this.f_maBArray2MArray()).f_maSubSort(a_nIndices,sCampo,bIndices,bOrdenacion,nOrden,bCaseDependiente))
}



//Da un subarray con los camposOut cuando el campoIn es igual al valor pasado
//Para los indices usar f_maSubIndexOf
// vValue = sText/a_sTextos
// [a_sCampoOut] : Por defecto devuelve todos los campos
// [bDistinto] : cuando el campoIn NO es igual
Array.prototype.f_maSubValIf = function (sCampoIn,vValue,a_sCampoOut,bCaseDep,bParte,bDistinto,bAcentoDep,bRepetidos){
	var a_vCampoOut = new Array();
	if (!this.f_maGetRegs()) return (a_vCampoOut)
	if(a_sCampoOut && !IsArray(a_sCampoOut)) a_sCampoOut = [a_sCampoOut];			//Compatibilidad: si viene una cadena lo convertimos en un array con un solo valor
	if(!a_sCampoOut || a_sCampoOut.length==0) a_sCampoOut = this[0];

	var a_nSubIndex = this.f_maSubIndexOf (sCampoIn,vValue,1,bCaseDep,bParte,bAcentoDep,bRepetidos,bDistinto)
	for (var f=0;f<a_nSubIndex.length;f++){
	 	for(var g=0; g<a_sCampoOut.length; g++){
	 		a_vCampoOut[a_vCampoOut.length] = this.f_maGetVal(a_sCampoOut[g],a_nSubIndex[f]);
	 	}
	}
	return (a_vCampoOut)
}

//Da un subarray con los camposOut de los registros a_nRegs
// [a_sCampoOut] : Por defecto devuelve todos los campos
Array.prototype.f_maSubValByRegs =function (a_sCampoOut, a_nRegs){
	var a_vVals=new Array();
	if(a_sCampoOut && !IsArray(a_sCampoOut)) a_sCampoOut = [a_sCampoOut];
	if(!a_sCampoOut || a_sCampoOut.length==0) a_sCampoOut = this[0];
	for(var f=0; f<a_nRegs.length; f++){
		for(var g=0; g<a_sCampoOut.length; g++){
			a_vVals[a_vVals.length]=this.f_maGetVal(a_sCampoOut[g], a_nRegs[f]);
		}
	}
	return (a_vVals);
}

Array.prototype.f_maSuma = function (sCampo,a_nRegs){
	var a_sValores = []
	if (a_nRegs) {
		a_sValores = this.f_maGetVal (sCampo,a_nRegs)
	}
	else {
		a_sValores = this.f_maGetCol (sCampo)
	}
	return (a_sValores.f_suma())
}

Array.prototype.f_maSumaCampos = function (a_sCampos,a_nRegs){
	if(!IsArray(a_nRegs)) a_nRegs = [a_nRegs];
	var maValores = this.f_maSubValByRegs (a_sCampos, a_nRegs)
	var a_sValores = new Array()
	for (var f=0;f<a_nRegs.length;f++) {
		a_sValores = a_sValores.concat(maValores[f])
	}
	return (a_sValores.f_suma())
}


// sCampo,[sCampoIf],[sValueIf]
Array.prototype.f_maSumaColIf = function (sCampo,sCampoIf,sValueIf,bDistinto){
	var a_sValores = []
	if (sCampoIf) {
		a_sValores = this.f_maSubValIf (sCampoIf,sValueIf,sCampo,0,0,bDistinto)
	}
	else {
		a_sValores = this.f_maGetCol (sCampo)
	}
	return (a_sValores.f_suma())
}
String.prototype.f_maSumaColIf = function(sCampo,sCampoIf,sValueIf,bDistinto){
	return ((this.f_maBArray2MArray()).f_maSumaColIf(sCampo,sCampoIf,sValueIf,bDistinto))
}

// Pasa dos arrays a MArray
String.prototype.f_maBArray2MArray = function(){
	return ([eval ("a_s"+this),eval ("a_v"+this)])
}

// *** DEP **
Array.prototype.f_addCol=function (sNewCol,vValor){
	this.f_maAddCol (sNewCol,vValor)
}
Array.prototype.f_addRegVal=function (a_vValues,nRegPos,bDelRegs){
	this.f_maNewRow (a_vValues,nRegPos,bDelRegs)
}
Array.prototype.f_copyCol=function (a_Array,sRel,sNew){
	this.f_maCopyCols (a_Array,sRel,sNew)
}
Array.prototype.f_maDelRow=function (nRegPos,nRegs){	// DEP usar f_maDeleteRow que va de 0-(n-1)
	if (nRegPos) nRegPos --
	this.f_maDeleteRow (nRegPos,nRegs)
}
Array.prototype.f_getRegNumOfVal=function (sFieldName,sValue){
	return (this.f_maGetReg (sFieldName,sValue))
}
Array.prototype.f_getRegsNum=function (){
	return (this.f_maGetRegs())
}
	String.prototype.f_getRegsNum = function(){
		return ((this.f_maBArray2MArray()).f_maGetRegs())
	}
Array.prototype.f_getRegVal=function (sCampo,nReg){
	return (this.f_maGetVal(sCampo,nReg))
}
	String.prototype.f_getRegVal = function(sCampo,nReg){
		return ((this.f_maBArray2MArray()).f_maGetVal(sCampo,nReg))
	}
Array.prototype.f_maBuscaValor=function (sFieldName,sValue){
	return (this.f_maGetReg(sFieldName,sValue))
}
	String.prototype.f_maBuscaValor=function (sFieldName,sValue){
		return ((this.f_maBArray2MArray()).f_maGetReg(sFieldName,sValue))
	}
Array.prototype.f_maDelReg=function (nRegPos,nRegs){
	this.f_maDelRow (nRegPos,nRegs)
}
Array.prototype.f_maGetColIf = function (sCampoIn,vValue,sCampoOut,bCaseInd,bParte){
	return (this.f_maSubValIf (sCampoIn,vValue,sCampoOut,bCaseInd,bParte))
}
Array.prototype.f_maGetDistinct = function(sCampo,bIndices,bCaseDependiente){
	return (this.f_maSubDistinct(sCampo,bIndices,bCaseDependiente))
}
	String.prototype.f_maGetDistinct = function(sCampo,bIndices,bCaseDependiente){
		return ((this.f_maBArray2MArray()).f_maSubDistinct(sCampo,bIndices,bCaseDependiente))
	}
Array.prototype.f_maGetValFromCol=function (sField, sColName, vColVal){
	return ( this.f_maGetValIf(sField, sColName, vColVal) );
}
Array.prototype.f_setRegVal=function (sCampo,vValue,nReg){
	return (this.f_maSetVal(sCampo,vValue,nReg))
}
	String.prototype.f_setRegVal = function(sCampo,vValue,nReg){
		return ((this.f_maBArray2MArray()).f_maSetVal(sCampo,vValue,nReg))
	}
// ***

// [7] Objetos
//Borra los elementos que le pasemos
//[ vValue, [sProp ]solo si es un objeto ]
Array.prototype.f_delElements=function (){
	var nPos, vValue, sProp;
	var a_vArray=this;
	for(var n=0;n<arguments.length;n+=2){
		vValue=arguments[n];
		sProp =arguments[n+1];
		nPos  =this.f_indexOf(vValue,sProp);
		if(nPos!=-1) a_vArray=this.f_delOfArray(nPos,1);		//esta funcion esta deprecated !!!
	}
	return (a_vArray);
}

//Cualquier 'Object' hereda todos los miembros de oObj
/*	Deprecated v0.826
Object.prototype.f_extend = function (oObj) {
	for (var sProp in oObj) {
		this[sProp] = oObj[sProp];
	}
}
*/


//Ordena un array de objetos según la propiedad sProperty
//[bDesc] 0-ASC o 1-DESC
protected_sArrayProperty="";
Array.prototype.f_sortBy=function (sProperty,bDesc){
	this.sort( function (p_vValue1,p_vValue2){ return (eval("p_vValue1."+protected_sArrayProperty) - eval("p_vValue2."+protected_sArrayProperty)); } );
}

//Objetos genéricos
oITraceFlags=new function(){
	this.m_sObj="oITraceFlags";
	this.m_a_Flags=[["sName","nTime"],[]];
	this.f_newFlag=function (sName){
		var nReg=this.m_a_Flags.f_getRegNumOfVal("sName",sName);
		if(nReg==-1) nReg=this.m_a_Flags.f_getRegsNum();
		this.m_a_Flags.f_addRegVal([sName,new Date().getTime()/1000],nReg);
	}

	this.f_getFlag=function (sName){
		var nTime1 = this.m_a_Flags.f_getRegVal("nTime",this.m_a_Flags.f_getRegNumOfVal("sName",sName));
		var nTime2 = new Date().getTime()/1000;
		return (nTime2-nTime1);
	}
}

// [8] Fecha

function ICrono(){
	this.m_sObj="ICrono";

	this.f_reset=function (){
		this.m_Start=new Date();
		this.m_Last =this.m_Start;
	}
	this.f_reset();

	this.f_get=function (bTexto){
		var oTime = new Date() - this.m_Last;
		this.m_Last = new Date();
		if (bTexto) oTime = " ["+oTime+"/"+(this.m_Last-this.m_Start)+"]"
		return oTime
	}
}

IDate = new function () {
	this.m_a_sDateNames =[["Lunes","Martes","Miércoles","Jueves","Viernes","Sábado","Domingo"]
							,["Enero","Febrero","Marzo","Abril","Mayo","Junio","Julio","Agosto","Septiembre","Octubre","Noviembre","Diciembre"]
							,["L","M","X","J","V","S","D"]
						];
}
Date.prototype.m_a_sDateNames=IDate.m_a_sDateNames;
Date.prototype.m_a_sDateChars=["nHH24","nH24","nHH12","nH12","sH12","nMMN","nMN","nSS","nS","nMIL","sDD","sD","nDD","nD","sMM","sM","nMM","nM","nYYYY","nYY"];
Date.prototype.f_drawFormat=function (sFormat,a_sSemana,a_sMeses){
	if (this=="undefined" || this=="NaN" || typeof(this)!="object") return ("")
	var cChar, nWeekDay=(this.getDay()>0)? this.getDay()-1 : 6;
//	var a_sSemana=(!a_sSemana)? this.m_a_sDateNames[0] : a_sSemana;
//	var a_sMeses =(!a_sMeses)? this.m_a_sDateNames[1] : a_sMeses;
	if (IsNull(a_sSemana)) a_sSemana=this.m_a_sDateNames[0]
	if (IsNull(a_sMeses)) a_sMeses=this.m_a_sDateNames[1]

	var sDD	 =a_sSemana[nWeekDay];
	var sD	 =sDD.substring(0, 3)+".";
	var nD	 =this.getDate();
	var nDD  =(nD<10)? "0"+nD : nD;
	var nM =this.getMonth()+1;
	var sMM  =a_sMeses[nM-1];
	var sM =sMM.substring(0, 3)+".";
	var nMM  =(nM<10)? "0"+nM : nM;
	var nYYYY=this.getYear();
	if (nYYYY < ICore.m_nY2K)  nYYYY += 2000
	if (nYYYY < 500) nYYYY += 1900
	var nYY  =String(nYYYY).substring(2,String(nYYYY).length);
	var nH24 =this.getHours();
	var nHH24=(nH24<10)? "0"+nH24 : nH24;
	var nH12 =((this.getHours()%12)==0)? 12 : this.getHours()%12;
	var nHH12=(nH12<10)? "0"+nH12 : nH12;
	var sH12 =(nH24>12)? "pm" : "am";
	var nMN  =this.getMinutes();
	var nMMN =(nMN<10)? "0"+nMN : nMN;
	var nS =this.getSeconds();
	var nSS  =(nS<10)? "0"+nS : nS;
	var nMIL =this.getMilliseconds();

	if (IsNull(sFormat)) sFormat = "nDD/nMM/nYYYY"
	var sDate=sFormat;
	for(var i=0; i<this.m_a_sDateChars.length; i++){
		cChar=this.m_a_sDateChars[i];
		vChar=eval(cChar);
		if(sFormat.indexOf(cChar)!=-1) sDate=sDate.f_replace(cChar,eval(cChar));
	}
	return ( sDate );
}

Date.prototype.f_printFormat=function (sFormat){ document.write( this.f_drawFormat(sFormat) ) }

String.prototype.f_swapDateFormat=function (sInputFormat, sOutputFormat){
	ErrorJS ("f_swapDateFormat deprecated: usa f_toDate","",5)
}

// [vDate]: oDate, sDate
Date.prototype.f_range= function (vDateMin,vDateMax) {
	var bOk =1
	if (vDateMin) {
		if (typeof(vDateMin)=="string") vDateMin=vDateMin.f_toDate()
		if (this<vDateMin) bOk=0
	}
	if (bOk && vDateMax) {
		if (typeof(vDateMax)=="string") vDateMax=vDateMax.f_toDate()
		if (this>vDateMax) bOk=0
	}
//alert (this+"\n"+vDateMin+"\n"+vDateMax+"\n"+bOk)
	return (bOk)
}

Date.prototype.f_timer=function (bReset){
	var dTime = new Date() - this
	var dHoy = new Date()
	if (bReset) this.setDate (dHoy.getDate())
	return (dTime)
}

// Solo importa el caracter que va despues del de formato
// "D/M/Y h:m_s.i"	"YMD"
// [nForceFormat] el dato tiene que tener el formato exacto que le pasamos 	[0/1/2] [No/Todos/solo el Y (YYYY/YY)]		//v0.783
String.prototype.f_toDate=function (sInputFormat,nForceFormat){
	var nLen,nLenInput,nChar,nDateType,nChar2,nDateType2,f
	var a_sDateTypes = ["Y","M","D","h","m","s","i"];
	var a_sDate = [0,1,1,0,0,0,0];
	var a_sLen =  [0,0,0,0,0,0,0];
	var oDate = null;		//v0.783
	var reF
	if (IsNull(sInputFormat)) sInputFormat = "D/M/Y"
	var sIF = sInputFormat
	var nDateDiffs = 0		//errores de formato con nForceFormat

	reF = RegExp("nYYYY|nYY|YYYY|YY|Y","gi");
	sIF = sIF.replace(reF,"Y");

	reF = RegExp("nMIL","g");		// Importante que se parseen antes que el mes (...nMM|nM|MM...)
	sIF = sIF.replace(reF,"i");
	reF = RegExp("nMMN|nMN","g");
	sIF = sIF.replace(reF,"m");

	reF = RegExp("sMM|sM|nMM|nM|MM","g");
	sIF = sIF.replace(reF,"M");
	reF = RegExp("sDD|sD|nDD|nD|DD","g");
	sIF = sIF.replace(reF,"D");
	reF = RegExp("nHH24|nH24|nHH12|nH12|sH12","g");
	sIF = sIF.replace(reF,"h");
	reF = RegExp("nSS|nS","g");
	sIF = sIF.replace(reF,"s");

	if (nForceFormat) { 			//v0.783
		for (f=0; f<sIF.length; f++) {
			if (a_sDateTypes.f_indexOf (sIF.charAt(f),"",0,0)!=-1) nDateDiffs++
		}
	}

	var sDate = this.f_trim()
	while (sIF.length) {
		nLen = 1
		nLenInput = 1

		nChar = sIF.charAt(0)
		nDateType = a_sDateTypes.f_indexOf (nChar,"",0,0)
		if (nDateType!=-1){		//Es un tipo de dato
			nDateDiffs--
			nChar2 = sIF.charAt(1)
			nDateType2 = a_sDateTypes.f_indexOf (nChar2,"",0,0)
			if (nDateType2!=-1) {		//Hemos encontrado donde termina
				nLen=2
				if (nChar=="Y") {
					nLen=4
				}
			}
			else{
				nLen =  sDate.indexOf(nChar2)
				if (nChar2!="" && nLen!=-1) {							//0.775 hay caracter de fin
					nLenInput = sIF.indexOf(nChar2)
				}
				else{
					nLen = sDate.length
					nLenInput = sIF.length
				}
			}
//if (nDateType==0) alert(nLen+"_"+parseInt(sDate)+"\nsIF:"+sIF+"\nnDateType2:"+nDateType2+"\nnChar2:"+nChar2)
//alert (sDate.substr (0,nLen) +"_"+Number (sDate.substr (0,nLen))+"_"+parseInt (sDate.substr (0,nLen)))
			a_sDate [nDateType] = Number (sDate.substr (0,nLen))	//0.778
			a_sLen  [nDateType] = nLen
		}
		sIF = sIF.substr (nLenInput)
		sDate = sDate.substr (nLen)
	}

	if (nForceFormat==2 || (nForceFormat==1 && !nDateDiffs)) {		//Y	0.786
		var nY = sInputFormat.f_countMatches("Y")
		if (nY>1 && nY!=a_sLen[0]) {
			nDateDiffs = 1
		}
		else {
			nDateDiffs = 0
		}
	}

	if (!nForceFormat || !nDateDiffs) {		//0.783
		if (a_sDate[0]<ICore.m_nY2K) a_sDate[0] = 2000 + Number (a_sDate[0])
		if (a_sDate[0] && a_sDate[1] && a_sDate[2]) oDate = new Date(a_sDate[0], a_sDate[1]-1, a_sDate[2], a_sDate[3], a_sDate[4], a_sDate[5],a_sDate[6])

		if (!IsNull(oDate)){				//0.803
			if ( (a_sDate[1]!=1+oDate.getMonth()) || (a_sDate[2]!=oDate.getDate()) ) oDate = null
		}
	}

	return (oDate);
}

// sInputFormat,sFormat,[a_sSemana],[a_sMeses]
String.prototype.f_toDateDraw = function (sInputFormat,sFormat,a_sSemana,a_sMeses,nForceFormat){
	var sDate = ""
	if (this!=''){
		var dDate = this.f_toDate (sInputFormat,nForceFormat)
//		if (typeof(dDate)!='undefined' ) sDate = dDate.f_drawFormat (sFormat,a_sSemana,a_sMeses)
		if (!IsNull(dDate)) sDate = dDate.f_drawFormat (sFormat,a_sSemana,a_sMeses)
	}
	return (sDate)
}


/*	DEP
	USAR:
		Date.prototype.f_drawFormat
		String.prototype.f_toDate
*/
String.prototype.m_a_sDateNames=[new Date().m_a_sDateNames[1]
								,new Date().m_a_sDateNames[0]
					];
String.prototype.f_parse2Date=function (nShowType){
	ErrorJS ("f_parse2Date deprecated: usa f_drawFormat","",5)
	var sDate="";
	var oDate=this.f_toDate("D/M/Y");
	switch(nShowType){
		case 1:
			sDate=oDate.f_drawFormat("nDD/nMM/nYY");
			break;
		case 2:
			sDate=oDate.f_drawFormat("nD de sMM de nYYYY");
			break;
		case 3:
			sDate=oDate.f_drawFormat("sDD, nD de sMM de nYYYY");
			break;
		case 4:
			sDate=oDate.f_drawFormat("sD, nDD/nMM/nYY");
			break;
		case 5:
			sDate=oDate.f_drawFormat("nYYYY/nMM/nDD");
			break;
		default:
			sDate=oDate.f_drawFormat("nDD/nMM/nYYYY");
	}
	return ( sDate );
}

// [9] Auxiliares
function ArrayObject2Array (a_vArray){
	if (typeof(a_vArray.join) != "function") { 		// 0.809 falso Array de IE (es un object y no un function)
//		a_vArray = a_vArray.toString().split(",")	// Falla si el contenido tiene ,
		var a_vNew = new Array();
//alert (typeof(a_vArray.join)+"\n"+a_vArray.length+"\n"+a_vArray[0])
		for(var f=0;f<a_vArray.length;f++) {
			a_vNew[f] = a_vArray[f]
		}
//alert (f+"\n"+a_vNew+"\n"+a_vArray.join)
		a_vArray = a_vNew
	}
	return a_vArray;
}

function CompareValues (v1,v2,bAnyType) {
	var b=0;
	if (bAnyType || (typeof(v1)==typeof(v2))) {
		if (IsArray (v1) && v1.length == v2.length) {
			b=1;
		    for (var i = 0; i < v1.length; i++) {
				b=1;
		        if (IsArray (v1[i])) { // nested array
		            if (!CompareValues(v1[i],v2[i]) ) {
		            	b=0
		            	break;
		            }
		        }
		    	else {
		        	if (v1[i]!=v2[i]) {
		        		b=0;
		        		break;
		        	}
				}
		    }
		}
		else {
			if (v1==v2) b=1
		}
	}
	else {
		ErrorJS ("[i_core.CompareValues] Estas comparando tipos distintos: " +v1+ "("+typeof(v1)+")/" +v2+ "("+typeof(v2)+")")
	}
    return b;
}

function GetType(vObj, bExists){
	var vType=0;
	if(bExists){
		if(typeof(vObj)=="string"){
			vType =eval("typeof("+vObj+")")

			if (vType=="undefined" || vType=="unknown") {
				vType=0
			}
			else if(vType=="object"){
				vType=eval(vObj+".constructor");
				if(typeof(vType)=="undefined") vType=eval(vObj);
			}
		}
		else ErrorJS("GetType: Debes pasar 'vObj' entre comillas si quieres saber si la variable ha sido definida.");
	}
	else {
		if(vObj!=null){			//a veces da un error raro por multisesion en aspirina
			vType= vObj.constructor
			if(typeof(vType)=="undefined") vType=vObj;
		}
	}
	if(typeof(vType)=="undefined" || vType=="undefined") vType=0;

	return (vType);
}

function IsArray(vVar){
	var bReturn = 0;
	if (vVar) {
		var a = vVar.push;
//ErrorJS (vVar+"\n"+typeof(a)+"\n"+!IsUndefined(a)+"\n"+String(GetType(vVar)).substring(0,20).toUpperCase())
		var sType = String(GetType(vVar)).substring(0,20).toUpperCase()		//para SAFARI y Arrays falsos
//		if ( !IsUndefined(a) && (sType.indexOf("INTERNAL FUNCTION")!=-1 || sType.indexOf("FUNCTION ARRAY()")!=-1) ) {
		if ( !IsUndefined(a) && sType.indexOf("FUNCTION")!=-1 ) {
			bReturn = 1;
		}
	}
	//if (vVar && typeof(vVar)=="object" && vVar.constructor==Array)
	return( bReturn );
}


function IsDate(sStr){
	var bDate=0;
//	if ( isNaN(sStr) ) {
		var oDate=new Date(sStr);
		if (!isNaN(oDate)) bDate=1;
//	}
	return (bDate);
}

// [bOnlyNull] no admite undefined como null
function IsNull(vVar,bOnlyNull){
	return ((vVar==null && !(bOnlyNull && IsUndefined(vVar)) )? 1 : 0 );
}

function IsUndefined(vVar){
	return( ( typeof(vVar)=="undefined")? 1 : 0 );
}

function IsMArrays(vVar){
	return (IsMArray(vVar) || IsMArrayOld(vVar));
}

function IsMArray(vVar){
	return ( (vVar && vVar.m_sObj && vVar.m_sObj.indexOf("[NotAnObject] MArray_instance_")!=-1) ? 1 : 0 );
}

function IsMArrayOld(vVar){
	var bReturn = false;
	if (IsArray(vVar) && vVar.length == 2 && IsArray(vVar[0]) && IsArray(vVar[1])) {
		bReturn = true;
	}
	return (bReturn);
}

//Devuelve numero entre 1 y nMax
function Random(nMax) { return (Math.ceil (Math.random()*nMax) ) }

// [10] Debug & Error
function DebugObj(oObj, nGroups, sFilter, bNotValue, bReturn){
	var i,v,s,nPos,sObj

	if (IsNull(oObj)) return ("null")
	if(!sFilter) sFilter="";
	if(!nGroups) nGroups=50;
	if(ICore.m_bIsServer) Response.write("<B>- - - - - - DebugObj - "+ICore.f_getVersion()+"</B><BR />");
	var a = [];

	if (IsArray(oObj)){
		for (i=0;i<oObj.length;i++){
			a.push (i +".["+oObj[i]+"] ("+typeof(oObj[i])+")")
		}
	}
	else {
		for(i in oObj){
			if(!bNotValue && i) {
				v = oObj[i]
				s=v + " ("+typeof(v)+")"
				if (typeof(v)=="function") {
					sObj = v.toString()
					nPos= sObj.indexOf("{")
					if (nPos!=-1) s= sObj.substring(0,nPos)
				}
			}
			if(i.indexOf(sFilter)!=-1) a.push (i +" = "+s)
			s=""
		}
		a.sort();
	}

	s="";
	if(oObj.m_sKeyName) s+=oObj.m_sKeyName;
	else if (oObj.m_sObj) s+=oObj.m_sObj;
	if(oObj.m_nVersion) s+=" [v"+oObj.m_nVersion + "]";
	s+= " ("+a.length+" propiedades)\n"
	var nGroupsC=0;
	for(i=0; i<a.length; i++){
		nGroupsC++;
		if(nGroupsC>=nGroups){
			nGroupsC=0;
			if(ICore.m_bIsServer) Response.write(s+"<BR />")
			else if (!bReturn) {
				alert(s);
				s="";
			}
			else {
				s +="\n"
			}
		}
		s+=a[i]+""
		if(ICore.m_bIsServer) s+="<BR />";
		else s+="\t";
	}
	if(ICore.m_bIsServer) Response.write("<HR><BR /><BR />");
	return (s)
}

//	[nReg],[nModo],[a_sCampos],[bOrdenado]
//	nModo	: 0(por campos)=Campo,Valor... / 1(por registros)=Campos,Valores
Array.prototype.f_maShowDebug=function (nReg,nModo,a_sCampos,bOrdenado) {
	var sTexto,nDir
	if (nReg!=null) {
		sTexto = DebugMArrayReg (this,a_sCampos,nReg,nModo,bOrdenado)
		sTexto += "\n\n Pulsa [Cancelar] para ver el siguiente registro"
		if (nReg++>=this.f_maGetRegs()-1 ) nReg=0
		nDir = confirm (sTexto)
		if (!nDir) {
			this.f_maShowDebug (nReg,nModo,a_sCampos,bOrdenado)
		}
	}
	else {
		sTexto = this.f_maDebug (a_sCampos,nModo)
		alert (sTexto)
	}
}

// [a_sCampos]	: campos a mostrar
Array.prototype.f_maDebug=function (a_sCampos,nModo) {
	var f,g, nPos,nRegLen, nRegistrosIni=3, nRegistrosFin=2
	var nRegistrosMax=nRegistrosIni + nRegistrosFin
	var sHTML= ""

	var nRegistros = Math.ceil(this[1].length/this[0].length)
	if (nRegistros<=nRegistrosMax) {
		nRegistrosMax = nRegistros
		nRegistrosIni = nRegistros
	}
	sHTML += "\tETIQUETAS ("+this[0].length+" etiquetas)\n[" + this[0] + "]\n"
	sHTML += "\tVALORES ("+this[1].length + " valores / " + this[1].length/this[0].length + " registros)\n"
	if (nModo) {
		for (f=0;f<nRegistrosIni;f++){
			sHTML += DebugMArrayReg (this,a_sCampos,f,nModo)
		}
		if (nRegistrosMax<nRegistros){
			sHTML += "\t...\n\t...\n\t...\n"
			for (f=nRegistros-nRegistrosFin;f<nRegistros;f++){
				sHTML += DebugMArrayReg (this,a_sCampos,f,nModo)
			}
		}
	}
	else {
		if (!a_sCampos) a_sCampos = this[0]
		for (f=0;f<a_sCampos.length;f++){
			sHTML += a_sCampos[f] +":\t"

			nPos = this[0].f_indexOf(a_sCampos[f],0,1)
			if (nPos==-1) {
				sHTML += "este campo no existe"
			}
			else {
				nRegLen = this[0].length
				for (g=0;g<nRegistrosIni;g++){
					sHTML += this[1][(g*nRegLen)+nPos] + "\t,"
				}
				if (nRegistrosMax<nRegistros){
					sHTML += "\t.....\t,"
					for (g=nRegistros-nRegistrosFin;g<nRegistros;g++){
						sHTML += this[1][(g*nRegLen)+nPos] + "\t,"
					}
				}
				sHTML = sHTML.substring (0,sHTML.length-2)
			}
			sHTML += "\n"
		}
	}
	return sHTML
}
String.prototype.f_maDebug=function (a_sCampos){
	return ((this.f_maBArray2MArray()).f_maDebug(a_sCampos))
}

function DebugMArrayReg (vMArrayBase,a_sCampos,nReg,bSimple,bOrdenado) {
	var sValor,nPos
	var sHTML = ""
	if (!a_sCampos) a_sCampos = vMArrayBase[0]
	var nDatos = a_sCampos.length
	if (bOrdenado) a_sCampos.sort()
	for (var g=0;g<nDatos;g++){
		sValor = "No existe!!!"
		nPos = vMArrayBase[0].f_indexOf(a_sCampos[g],0,1)
		if (nPos!=-1) sValor = vMArrayBase[1][(vMArrayBase[0].length*nReg)+nPos]
		if (!bSimple) sHTML += "\n" + a_sCampos[g] + ":\t "
		else if (g) sHTML += ","
		sHTML += sValor
	}
	if (bSimple) {
		sHTML = "["+ sHTML+"]\t(Reg." + (nReg) + ")\n"
	}
	else {
		sHTML = "[Registro " + (nReg) + " / "+ vMArrayBase.f_maGetRegs() +" ]\n"+sHTML
	}
	return (sHTML)
}

function Porcentaje (vNum,vTotal,sFmt) {
	var nRes = 0
	var nNum = vNum.f_toNumber ()
	var nTotal = vTotal.f_toNumber ()
//	if (!isNaN(nNum) && !isNaN())
	nRes = nNum*100/nTotal
	if (!isNaN(nRes)) nRes = nRes.f_formatNumber(sFmt)
//	if (nDecs)
	return (nRes)
}

function ErrorEx (e) {
	var sError = e+" "+e.name + ": "+e.description + " [" + (e.number>>16&0x1FFF) + " " + (e.number&0xFFFF) + "/"+ e.number +"]";
	return sError
}

function ErrorJSLibs(){
	ErrorJS(null,null,null,null, 1);
}

function ErrorJS(vVar,oObj,nModo,bManual, bShowLibs){
	if (IsUndefined(vVar)) {
		vVar="";
		if ( bShowLibs ) vVar += this.m_sErroresLibs
		vVar += ICore.m_sErrores
		if (IsUndefined(nModo)) nModo = 4
		if (!ICore.m_nShowErrores) ICore.m_nShowErrores=1
	}
	else {
		if (nModo!=2 && !ICore.m_bIsServer && !bManual) {
			var sSign = "*"
			if (nModo==5) sSign="-"
			window.top.document.title += sSign
		}
		ICore.m_sErrores += "[Error: "+ ++ICore.m_nErrores + "["+new Date().f_drawFormat("nH24:nMMN")+"]" + vVar + "\n\n"
	}
	var sError = vVar,sErrorObj=""
	if (nModo==5) nModo=2;

	if (!bManual) {
		if (!ICore.m_nShowErrores) return;
		if (!nModo || ICore.m_nHTMLErrores--<ICore.m_nShowErrores) --ICore.m_nShowErrores
	}

	var sPagePath = (ICore.m_bIsServer)? "http://"+Request.ServerVariables("HTTP_HOST")+Request.ServerVariables("URL") : document.location.href;
/*
	if (oObj) {
		if (!IsNull(oObj) && typeof(oObj)=="object"){
			sErrorObj += DebugObj(oObj,8,null,null,1)
		}
	}

	if (IsMArray(vVar)) sError = vVar.f_debug()
	else if (GetType(vVar)==Array && IsMArrayOld(vVar)) sError = vVar.f_maDebug()
*/
//	if (IsMArray(vVar) || (GetType(vVar)==Array && IsMArrayOld(vVar))) sError = vVar.f_maDebug()
	if (oObj && !IsNull(oObj) && typeof(oObj)=="object") vVar = oObj
	if (IsMArrays(vVar)) sErrorObj = vVar.f_maDebug()
	else if (typeof(vVar)=="object") {
		sErrorObj = DebugObj(vVar,10,null,null,1)
//Response.write(typeof(vVar))
	}

	var sHTML=""
	sHTML+="<TABLE cellpadding='1' cellspacing='0' border='1' width='100%'>";
	sHTML+="<TR bgcolor='#666666'>";
	sHTML+="<TD><FONT face='Arial' size='1' color='#FF0000'><NOBR><B>ErrorJS "+ (ICore.m_bIsServer ? "Servidor" : "Cliente")+":</B></NOBR></FONT></TD>";
	sHTML+="<TD><FONT face='Arial' size='1' color='#c0c0ff'>"+sPagePath+"</FONT></TD>";
	sHTML+="<TD align='right'><A href='javascript:document.location.reload()'><FONT face='Arial' size='1' color='#00FF00'><B>[ RELOAD PAGE ]</B></FONT></A></TD>";
	sHTML+="</TR>";
	sHTML+="<TR bgcolor='#000000'>";
	sHTML+="<TD colspan='3'>"
	sHTML+=		"<FONT face='Arial' size='2' color='#e0e0e0'>"+sError.toString().f_replace("\n","<BR>")+"</FONT>"
	if (sErrorObj) {
//		sHTML+=		"<BR />"
//	sHTML+=		"<FONT face='Arial' size='2' color='#b0b0b0'>"+sErrorObj.toString().f_replace("\n","<BR>")+"</FONT>"
		sHTML+=		"<FONT color='#b0b0b0' size=3><PRE>"+sErrorObj+"</PRE></FONT>"
	}
	sHTML+=		"</TD>";
	sHTML+="</TR>";
	sHTML+="</TABLE>";

	var sErrorAlert = sPagePath + "\n\n***Error JS ["+new Date().f_drawFormat("nH24:nMMN")+"] ***\n" + sError + "\n" + sErrorObj

//alert(nModo+": "+sErrorAlert +"\n"+ICore.m_sServer)
	switch (nModo) {
		case 1 :
			if (ICore.m_bIsServer) {
				Response.write (sHTML);
			}
			else {
				if (ICore.m_sServer=="DEV") {
					if (oIGZ.m_bInitialized) {
						var sBody =document["body"].innerHTML;
						document["body"].innerHTML=sHTML+sBody;
					}
					else {
						if (!ICore.m_sErrorJS) oIGZ.m_a_sPostStartUps[oIGZ.m_a_sPostStartUps.length] = 'document["body"].innerHTML=ICore.m_sErrorJS+document["body"].innerHTML';
						ICore.m_sErrorJS += sHTML
					}
				}
				else {
					window.status = sError
				}
			}
			break;
		case 2 :
			if (ICore.m_bIsServer) {
				Response.write ("/*"+sHTML+"*/\n");
			}
			else if (ICore.m_sServer=="DEV") {
				window.status = sError
			}
			break;
		case 3 :
			sHTML = sError
			break;
		case 4 :
			sHTML = ""
			ICore.f_showError (sErrorAlert)
			break;
		default:
			if (ICore.m_sServer=="DEV") {
				if(ICore.m_bIsServer) {
					Response.write (sHTML);
					Response.end ()
				}
				else {
					ICore.f_showError (sErrorAlert)
				}
			}
			else {
				if(!ICore.m_bIsServer) window.status = sError
				else {
					Debug( sError );
					if (protected_bDebugMode) Response.end ()
				}
			}
	}
	if (sHTML) return (sHTML)
}


//
// ************************* FIN DE PROTOTYPEs y Funciones Globales
//


//
// El objeto ICore tiene que ir siempre al final
//


ICore = new function () {
	this.m_sObj = "ICore";
	this.m_bIsServer = ( typeof(Server)!="undefined" )? 1 : 0;
	this.m_sIGZsign  = "© " +new Date().getYear()+ " Intelygenz - www.intelygenz.com";
	this.m_sAuthor 	 = "";
	this.m_nVersion	 = i_core_nVersion;
	this.m_sKeyName	 = "iCore";
	this.f_getVersion = function () {
		return (this.m_sKeyName+ " v" +this.m_nVersion+ "\n"+this.m_sIGZsign);
	}

	this.m_nShowErrores = 3;	// alert N errores / 0=todos
	this.m_nHTMLErrores = 5;    // pinta N errores / 0=todos
	this.m_nY2K		 	= 20;   // años menores de XX se ponen a 20XX

	this.m_oOnErrorEvent=(!this.m_bIsServer)? window.onerror : null;

	if(this.m_bIsServer) this.m_sUrl=("http://"+Request.ServerVariables("SERVER_NAME")+Request.ServerVariables("URL")).toLowerCase()
	else this.m_sUrl=String(document.location.href)

	this.m_a_sDevHosts = [
						 ".intelygenz.com"

						 // dev servers
						 ,"://almax", "://192.168.0.9"
						 ,"://debi", "://192.168.0.15"

						 // old dev servers
						 ,"://cafetera", "://192.168.0.7"

						 // local dev
						 ,"://localhost", "://127.0.0.1"
						 ]

	this.f_checkDevHosts = function () {
		var sEntorno = "PRO"
		if (this.m_sUrl.indexOf("www.intelygenz.com")==-1) {
			var f=-1, F=this.m_a_sDevHosts.length;
			while ( ++f<F && this.m_sUrl.indexOf(this.m_a_sDevHosts[f])==-1 ) { }
			if (  f<F ) sEntorno = "DEV";
		}
		this.m_sServer = sEntorno
	}
	this.f_checkDevHosts();

	this.m_oErrorJS = ""
	this.m_sErrorJS = ""
	this.m_nErrores = 0
	this.m_sErrores = ""
	this.m_sLibsPath = "/libs/js";

	this.m_sNumberFormat = ".I,DD"

	// Controla todas las cargas de librerias
	this.m_sDebugLoad = ""
	this.m_sErroresLibs = "";
	this.f_debugLoad = function (sText,nMode) {		//ponerlo al principio o antes de la funcion
		this.m_sErroresLibs += g_oICrono.f_get(1) +"\n"+ sText;
		this.m_sErroresLibs += "\t\t\t\t".substring (0,4-((sText.length)/9))
		if (!this.m_bIsServer && !IsNull(document.location.search) && document.location.search.indexOf("igzdebug")!=-1) {
			if (!this.m_sDebugLoad) this.m_sDebugLoad = "["+document.location.pathname+"]\n"

			this.m_sDebugLoad += sText + "\n";
			if (nMode==1) {
				oIGZ.m_a_sStartUps.push("ICore.f_debugLoad (oIGZ.f_checkLoadedLibs ())");
			}
			alert(this.m_sDebugLoad)
		}
	}

	// Mensaje de error controlado
	this.f_showError = function (sError) {
		var bNotCopy = confirm(sError + "\n\nPulsa 'Cancelar' o ESC para copiar el error al portapapeles");

		if (oIGZ.m_bIE) {	//no funciona en FF	?que pasa con IE7¿
			if (!bNotCopy && document["body"]) {
				var oForm = document.createElement("<FORM name='FCopy' style='display:none'>")
	//			var oForm = document.createElement("FORM")
	//			oForm.name = "FCopy"
	//			oForm.style = "display:none"

				var oInput = document.createElement("<TEXTAREA NAME='zzCopy'>")
	//			var oInput = document.createElement("TEXTAREA")
	//			oInput.name = "zzCopy"
				oInput.value=sError
				document["body"].appendChild(oForm)
				oForm.appendChild(oInput)
				var oRange=oInput.createTextRange()
				oRange.execCommand("Copy")
				document["body"].removeChild(oForm)
			}
		}
	}

	// Devuelve el texto sDefault que le pasemos si el valor de vVal es null
	this.f_getValue = function (vVal, sDefault, bOnlyNull) {
		return IsNull( vVal, bOnlyNull ) ? sDefault : vVal;
	}

	// JS CLIENTE
	//
	this.m_sLang   = "es";
	this.m_sParams = "";		//"?" 0.814
	if (!this.m_bIsServer) {
		var sPath="", sParam = "";

		var oUserAgent = navigator.userAgent.toLowerCase();
		var bDOM  = document.getElementById ? 1 : 0;
		var sLang = this.m_sLang;

		if (bDOM) {
			var sLangT;
			var a_scripts = document.getElementsByTagName("SCRIPT");
			var f=0, F=a_scripts.length;

			while( f<F && a_scripts[f]
			 		&& (
			 			!a_scripts[f].getAttribute("src")
			 			|| (a_scripts[f].getAttribute("src") && a_scripts[f].getAttribute("src").indexOf("i_core.js")==-1)
			 		)
			 	){
					f++
				}

			if ( f<F ) {
				sPath  = a_scripts[f].getAttribute("src");
				sLangT = a_scripts[f].getAttribute("lang");
			}

			if ( sLangT ) sLang=sLangT;
		}
		else {
			sPath = document.all["Ncore"].src;
		}

		this.m_sLang = sLang

		if (sPath) {
			if (sPath.indexOf("?")!=-1) this.m_sParams = sPath.substring(sPath.indexOf("?")-1);				//0.814
			sPath  = sPath.substring(0,sPath.lastIndexOf("/")+1)
		}
		this.m_sLibsPath = sPath;

		// Retrocompatibilidad y comprobación de carga de i_xbd.js
		oXBD = new function () {
			this.f_load = function () { ErrorJS("Falta el objeto oXBD.\nComprueba que la librería '"+sPath+"i_xbd.js' existe."); }
		}
		oXJS = oXBD;
	}
}

g_oICrono = new ICrono ();
ICore.f_debugLoad ("i_core")


//Retro-Compatibilidad
//
oCore = ICore;
var g_nShowErrores = ICore.m_nShowErrores;
var g_nHTMLErrores = ICore.m_nHTMLErrores;
var g_nY2K 		   = ICore.m_nY2K;
var g_sLang		   = ICore.m_sLang;


ICore.f_debugLoad ("i_core END");
if (!ICore.m_bIsServer){
	document.write ("<SCRIPT type='text/javascript' charset='iso-8859-1' src='" +ICore.m_sLibsPath+ "i_igz.js"+ICore.m_sParams+"'></SCRIPT>\n");
	document.write ("<SCRIPT type='text/javascript' charset='iso-8859-1' src='" +ICore.m_sLibsPath+ "i_marray.js"+ICore.m_sParams+"'></SCRIPT>\n");
	document.write ("<SCRIPT type='text/javascript' charset='iso-8859-1' src='" +ICore.m_sLibsPath+ "i_lang_"+ICore.m_sLang+".js"+ICore.m_sParams+"'></SCRIPT>\n");
	document.write ("<SCRIPT type='text/javascript' charset='iso-8859-1' src='" +ICore.m_sLibsPath+ "i_xbd.js"+ICore.m_sParams+"'></SCRIPT>\n");
}


//<!--%>//-->