// #########################################################################
// >>> JSDom (JavaScript DOM library) <<<
// Autore: Giuseppe Masella
// Web: http://www.gm3d.it
// Version: 0.1.6
// Last Update: 5 Gennaio 2007
// #########################################################################
var JSDVER='0.1.6';

// ### Tipi di dato ###
// [+] ---------------------------------------------------------------------------------------------------------------------------------------------------
	// FUNZIONE che verifica se un valore è settato o meno (quindi diverso da 'undefined', null, o da lunghezza 0)
	function isSet(Var){return(typeof(Var)=='undefined'||Var==null||Var.length==0)?false:true}
	
	// FUNZIONE che verifica se il tipo di dato è "stringa"
	function isString(obj){return typeof(obj)=='string'}
	
	// FUNZIONE che verifica se il tipo di dato è "numerico"
	function isNumber(obj){return typeof(obj)=='number'}
	
	// FUNZIONE che verifica se il tipo di dato è "float"
	function isFloat(num){return isNumber(num)&&num-Math.floor(num)!=0}
	
	// FUNZIONE che verifica se il tipo di dato è "array"
	function isArray(obj){return obj&&!isString(obj)&&isSet(obj.length)}
	
	// FUNZIONE che verifica se il tipo di dato è "oggetto"
	function isObject(obj){return typeof(obj)=='object'}
	
	// FUNZIONE che verifica se il tipo di dato è "funzione"
	function isFunction(obj){return obj instanceof Function}
	
	// FUNZIONE che verifica se il tipo di dato è "nodo di testo"
	function isTextNode(obj){return obj.nodeType==3&&inArray(!/\S/,obj.nodeValue)}
	
	// FUNZIONE che verifica se il tipo è elemento 
	function isElement(obj){return obj.nodeType==1}
// [-] ---------------------------------------------------------------------------------------------------------------------------------------------------


// ### Numeri ###
// [+] ---------------------------------------------------------------------------------------------------------------------------------------------------
	// FUNZIONE che converte una stringa o un numero reale restituendo un numero intero 
	// ES 1: toInt(2.6) -> 2 (int)
	// ES 2: toInt("as54a") -> 54 (int)
	function toInt(v){return parseInt(v)}

	// Funzione che filtra una stringa restituendo una stringa contenente solo i numeri in essa presenti
	// ES: numFilter("puo_42a") -> "42" (str)
	function numFilter(str){return str.replace(/[^0-9]/gi,'')}

	// Funzione che filtra una stringa restituendo solo le lettere dell'alfabeto (quindi non le accentate) in essa contenuta
	// ES: alphabFilter("a4ùefG26") -> "aefG" (str)
	function alphabFilter(str){return str.replace(/[^a-zA-Z]/gi,'')}
	
	// FUNZIONE che converte a Float una stringa contenente un numero con la virgola
	// ES 1: toFloat("2.5") -> 2.5 (flo)
	// ES 2: [ "2.5" + "2.9" = "2.92" ???? (ERRATO) ] mentre : [ toFloat("2.5") + toFloat("2.9") = 5.4 (CORRETTO) ]
	function toFloat(str){return parseFloat(str)}

	// FUNZIONE che genera un numero random compreso nell'intervallo [min-max]
	function $random(min,max){return Math.floor(Math.random()*(max-min+1)+min)}
	
	// FUNZIONE che verifica se un determinato numero o stringa "val" ricade all'interno di un determinato intervallo [a-z]
	// INPUT: 1) (var) val --> valore da verificare se ricade nell'intervallo
	// 		2) (var) a --> limite minimo dell'intervallo
	//		3) (var) z --> limite massimo dell'intervallo
	//
	// OUTPUT: (bool) la funzione restituisce true se il valore rientra nell'intervallo, mentre restituisce false se non rientra nell'intervallo
	// ES 1: isIn("d","a","z") -> true 
	// ES 2: isIn(4,10,21) -> false 
	function isIn(val,a,z){return val>=a&&val<=z}

	// FUNZIONE che verifica se un numero è pari o meno
	function isPeer(v){return v%2==0}
// [-] ---------------------------------------------------------------------------------------------------------------------------------------------------


// ### DOM ###
// [+] ---------------------------------------------------------------------------------------------------------------------------------------------------
	// FUNZIONE alias di getElementById()
	function ID(el,obj){return isString(el)?(obj||document).getElementById(el):el}
	
	// FUNZIONE alias di getElementsByName()
	function NAME(nm,obj){return(obj||document).getElementsByName(nm)}
	
	// FUNZIONE alias di getElementsByTagName()
	function TAG(tag,obj){return((isString(obj)?ID(obj):obj)||document).getElementsByTagName(tag)}

	// FUNZIONE alias della funzione "non proprietaria" getElementsByClassName() che rileva un gruppo di elementi DOM in base alla classe comune ad essi asociata
	// INPUT:	1) (str) cls --> nome della classe da intercettare
	// 		2) (str) tag (default *) --> eventuale tag degli elementi all'interno dei quali cercare la classe
	//		3) (var) obj (default document) --> oggetto all'interno del quale cercare gli elementi aventi la classe specificata
	//
	// OUTPUT: (arr) array contenente gli elementi aventi la classe specificata
	//
	// Versione precedente della Funzione:
	// function CLASS(obj,tag,cls){var dA=document.all,E=(tag=="*"&&dA)?dA:TAG(tag,obj),A=[],R,O,i;cls=cls.replace(/\-/g, "\\-");R=new RegExp("(^|\\s)"+cls+"(\\s|$)");O;for(i=0;i<E.length;i++){O=E[i];if(R.test(O.className))A.push(O)}return(A)}
	function CLASS(cls,tag,obj){var T=TAG(tag||'*',obj),i,A=[];for(i=0;i<T.length;i++)if(hasClassName(T[i],cls))A.push(T[i]);return A}

	// FUNZIONE alias della funzione "non proprietaria" getElementsByTagsName() che rileva i diversi tag specificati in list
	// INPUT: 1) (arr) list --> array contenente la lista dei tag da rilevare
	//		2) (var) obj (default document) --> oggetto all'interno del quale cercare gli elementi aventi il tag specificato
	//
	// OUTPUT: (arr) array contenente gli elementi relativi ai tag specificati
	function TAGS(list,obj){var A=[],i,t,j;for(i in list){t=TAG(list[i],obj);for(j=0;j<t.length;j++)A.push(t[j])}return A}
	
	// FUNZIONE che rileva un gruppo di elementi DOM in base alla coppia attributo-valore
	// INPUT: 1) (str) attr --> attributo da cercare
	//		2) (var) var --> valore che l'attributo deve avere
	//		3) (var) tag (default '*') --> eventuale tag dell'elemento all'interno del quale cercare l'attributo
	//		4) (var) obj (default document) --> eventuale elemento all'interno del quale cercare il tag con l'attributo specificato
	//		5) (str) reg ['in'|'start'|'end'|'full'] (default 'full') --> eventuale regola in base alla quale cercare (*)
	//		   (*) reg è utile per fare ricerche in base al contenuto parziale dell'attributo (es: l'attributo il cui valore inizia per ... o finisce per ... o contiene ...)
	//
	// OUTPUT: (arr) array contenente gli elementi aventi la coppia attributo-valore specificata
	function ATTRIBUTE(attr,val,tag,obj,reg){
		var T=TAG(tag||'*',obj),i,A=[];
		for(i=0;i<T.length;i++)if(strSrc(getProperty(T[i],attr),val,reg))A.push(T[i]);
		return A
	}
	
	// FUNZIONE che restituisce il riferimento al tag <body> del documento
	function tagBody(){return TAG('body')[0]}
	
	// FUNZIONE che restituisce il riferimento al tag <head> del documento
	function tagHead(){return TAG('head')[0]}
	
	// FUNZIONE che restituisce il nome in minuscolo del tag dell'oggetto selezionato
	function getTag(obj){return lower(ID(obj).tagName)}
	
	// FUNZIONE alias di innerHTML che consente di inserire testo ed oggetti all'interno di un elemento
	function html(el,val){el=ID(el);el.innerHTML=val;return el}
	// la seguente versione dicono che sia ottimizzata per i browser non IE, nel senso che velocizza di molto i tempi di inserimento DOM (*** da testare ***)
	// function html(el,val){var a=ID(el),b;if(isIe()){a.innerHTML=val}else{b=clone(a);b.innerHTML=val;replaceDom(a,b)}return a}
	
	// FUNZIONE che restituisce il contenuto di un elemento
	function getContent(el){return ID(el).innerHTML}

	// FUNZIONE che consente di settare una determinata proprietà per l'elemento selezionato
	// INPUT: 1) (var) el --> riferimento all'elemento
	//		2) (str) prop --> nome della proprietà da settare
	//		3) (str) value --> valore da attribuire alla proprietà
	//
	// OUTPUT: (var) riferimento all'elemento selezionato
	// FN Precedente: 
	// function setProperty(el,prop,value){el=ID(el);switch(prop){case'class':el.className=value;break;case'style':setStyles(el,value);break;case'text':el.innerHTML=value;break;default:el.setAttribute(prop,value)}return el}
	function setProperty(el,prop,val){
		var p=prop,e=ID(el);
		switch(p){
			case'class':e.className=val;break;
			case'style':setStyles(e,val);break;
			case'text':html(e,val);break;
			case'for':e.setAttribute(isIe()?'htmlFor':p,val);break;
			default:e.setAttribute(p,val)
		}
		return e
	}
	
	// FUNZIONE che consente di settare un'insieme di proprietà per l'elemento selezionato
	// INPUT: 1) (var) el --> riferimento all'elemento
	//		2) (arr) arr --> array associativo delle proprietà con rispettivi valori da settare: {"id":"id_nm","src":"img.png","alt":"Immagine PNG"}
	//
	// OUTPUT: (var) riferimento all'elemento selezionato
	function setProperties(el,arr){for(var P in arr)el=setProperty(el,P,arr[P]);return el}
	
	// FUNZIONE alias di getAttribute() che restituisce il valore della proprietà specificata dell'elemento selezionato
	// INPUT: 1) (var) el --> riferimento all'elemento
	//		2) (str) p --> proprietà della quale si vuole il valore
	//
	// OUTPUT: (var) valore della proprietà specificata
	function getProperty(el,p){
		el=ID(el);
		if(isIe())
			switch(p){
				case'class':p='className';break;
				case'for':p='htmlFor';break;
				case'style':return el.style.cssText
			}
		return el.getAttribute(p)
	}

	// FUNZIONE che crea un elemento DOM con eventuali attributi
	// INPUT: 1) (str) tag --> tag da creare
	//		2) (arr) attr --> array associativo contenente i settaggi degli attributi dell'elemento es:
	//			{"id":"id_el", "class":"cls_nm", "style":"color:#FFF;border:1px solid #CCC;font-size:10px", "text":"<b>Testo dell'elemento</b>"}
	//			N.B: oltre ai tipici attributi impostabili per i tag xhtml, è stato aggiunto il seguente: "text" per inserire "al volo" i contenuti all'interno del tag
	//
	// OUTPUT: (var) la funzione restituisce il riferimento all'oggetto appena creato ...
	// .. N.B: per inserire nel documento l'oggetto così creato, utilizzare le funzioni: html() , insertInto() ,insertBefore(), insertAfter(), replaceDom()
	function createDom(tag,attr){return setProperties(document.createElement(tag),attr)}
	
	// FUNZIONE che rimuove un'elemento dom con tutto il suo eventuale contenuto
	function domRemove(el){el=ID(el);if(el)el.parentNode.removeChild(el)}
	
	// FUNZIONE che rimuove il contenuto di un determinato elemento
	function cleanNode(n){html(n,'')}
	
	// FUNZIONE alias di cloneNode() per la clonazione di un nodo
	// INPUT: 1) (var) riferimento all'elemento da clonare
	//
	// OUTPUT: (var) riferimento al clone
	function clone(el){return ID(el).cloneNode(true)}
	
	// FUNZIONE che consente di sostituire via DOM un elemento "nw" con "el"
	// INPUT: 1) (var) el --> riferimento all'elemento preesistente da sostituire
	//		2) (var) nw --> riferimento all'elemento sostituto (nuovo elemento)
	// 
	// OUTPUT: (var) riferimento al nuovo elemento
	function replaceDom(el,nw){var d=ID(el),s=ID(nw),p=d.parentNode;s?p.replaceChild(s,d):p.removeChild(d);return s}
	
	// FUNZIONE che inserisce un elemento "el" subito dopo all'elemento "rEL"
	// INPUT: 1) (var) el --> elemento da inserire
	//		2) (var) rEl --> riferimento all'elemento dopo il quale inserire "el"
	//
	// OUTPUT: (var) riferimento all'elemento appena inserito
	function insertAfter(el,rEl){rEl=ID(rEl);rEl.parentNode.insertBefore(el,rEl.nextSibling);return el}
	
	// FUNZIONE che inserisce un elemento "el" subito prima all'elemento "rEL"
	// INPUT: 1) (var) el --> elemento da inserire
	//		2) (var) rEl --> riferimento all'elemento prima del quale inserire "el"
	//
	// OUTPUT: (var) riferimento all'elemento appena inserito
	function insertBefore(el,rEl){rEl=ID(rEl);rEl.parentNode.insertBefore(el,rEl);return el}
	
	// FUNZIONE che inserisce all'interno di un elemento un sinngolo o più elementi
	// INPUT: 1) (var) el --> elemento all'interno del quale inserire
	//		2) (var) ins --> elemento da inserie o array di elementi da inserire es: [el1,el2,eln] (l'inserimento avviene rispettando l'ordine di indice dell'array)
	//
	// OUTPUT: (var) riferimento all'elemento all'interno del quale si è appena fatto l'inserimento
	function insertInto(el,ins){el=ID(el);var A=toArr(ins),i;for(i in A)el.appendChild(isString(A[i])?document.createTextNode(A[i]):A[i]);return el}
	
	// FUNZIONE che restituisce il nodo padre (parent) di quello selezionato
	// INPUT: 1) (var) el --> riferimento all'elemento in questione
	//		2) (int) n (default 1) --> numero di parent da attraversare, se non specificato la funzione restituisce il riferimento al parent subito precedente
	//
	// OUTPUT: (var) riferimento al nodo parent
	function getParent(el,n){var i,e=ID(el),n=n?n:1;for(i=0;i<n;i++)e=e.parentNode;return e}
	
	// FUNZIONE che restituisce il primo elemento (child (figlio)) presente all'interno dell'elemento selezionato
	function getFirst(el){var x=ID(el).firstChild;while(!isElement(x))x=x.nextSibling;return x}
	
	// FUNZIONE che restituisce l'ultimo elemento (child (figlio)) presente all'interno dell'elemento selezionato
	function getLast(el){var x=ID(el).lastChild;while(!isElement(x))x=x.previousSibling;return x}
	
	// FUNZIONE che dato un elemento, ne restituisce l'elemento successivo di pari livello (fratello)
	function getNext(el){var x=ID(el).nextSibling;while(!isElement(x))x=x.nextSibling;return x}

	// FUNZIONE che dato un elemento, ne restituisce l'elemento precedente di pari livello (fratello)
	function getPrevious(el){var x=ID(el).previousSibling;while(!isElement(x))x=x.previousSibling;return x}
// [-] ---------------------------------------------------------------------------------------------------------------------------------------------------


// ### Style ###
// [+] ---------------------------------------------------------------------------------------------------------------------------------------------------
	// FUNZIONE che restituisce il valore di una determinata proprietà di un foglio di stile associato ad un determinato elemento
	// INPUT: 1) (var) el --> riferimento all'elemento
	//		2) (str) prop --> proprietà CSS relativa all'elemento, della quale si vuol sapere il valore
	//
	// OUTPUT: (str) valore della proprietà richiesta
	function getStyle(el,prop){el=ID(el);var P=camelCase(prop),dV=document.defaultView,st=el.style[P]||false;if(!st){if(dV)st=dV.getComputedStyle(el,null).getPropertyValue(prop);else if(el.currentStyle)st=el.currentStyle[P]}return st}

	// FUNZIONE che setta valore e proprietà di uno stile css relativo ad un determinato elemento
	// INPUT: 1) (var) el --> riferimento all'elemento
	//		2) (str) prop --> proprietà CSS relativa all'elemento, della quale si vuol settare il valore
	// 		3) (var) value --> valore da assegnare alla proprietà CSS
	//
	// OUTPUT: nessuno
	function setStyle(el,prop,value){prop=='opacity'?setOpacity(el,value):prop=='position'?setCssRelPos(el,value):ID(el).style[camelCase(prop)]=value}
	
	// FUNZIONE che trasforma una stringa css in un array associativo contenente come chiavi le proprietà css e come elementi i valori delle proprietà css
	// INPUT: 1) (str) style --> stringa dello stile da trasformare in array associativo
	//
	// OUTPUT: (arr) array associativo avente per chiavi le proprietà css e per rispettivi valori i valori css
	function style2arr(style){return str2assocArr(rmvBlank(style),':',';')}
	
	// FUNZIONE che applica ad un elemento una stringa di stile css
	// INPUT: 1) (var) el --> riferimento all'elemento al quale applicare lo stile
	//		2) (str) styles --> stringa css da applicare all'elemento es: "color:#FFF;border:1px solid #CCC;..."
	// 
	// OUTPUT: nessuno
	function setStyles(el,styles){
		var i,s=style2arr(styles);
		// [+] HACK per IE<7 relativo al "position:fixed"
		if(s['position']=='fixed'&&isOldIe()&&isWin()){
			//setScroll(0,0);
			var SC=getPageScroll();
			setCssRelPos(el,'fixed');
			var P=['left','top'],i;
			for(i in P)
				if(s[P[i]]){
					s[P[i]]=(SC[i]+toInt(s[P[i]]))+'px';
					setStyle(el,P[i],s[P[i]])
				}
			//Il codice eseguito dal ciclo for equivale a:
			//if(s['left']){
			//	s['left']=(SC[0]+toInt(s['left']))+'px';
			//	setStyle(el,'left',s['left'])
			//}
			//if(s['top']){
			//	s['top']=(SC[1]+toInt(s['top']))+'px';
			//	setStyle(el,'top',s['top'])
			//}
		}
		// [-]
		for(i in s)if(s[i]+'')setStyle(el,i,s[i])
	}
	
	// FUNZIONE che estrae l'unità di misura da una stringa riportante il valore di una dimensione css
	// INPUT: 1) (str) v --> stringa riportante il valore di una dimensione css
	//
	// OUTPUT: (str) unità di misura estratta dalla dimensione css
	function getCssUnit(v){
		var U=["px","%","em"],i;
		for(i in U)if(strSrc(lower(v),U[i]),'end')return U[i];
		return null
	}
	
	// FUNZIONE che restituisce un array associativo contenente le dimensioni di "margin" o "border" o "padding" di un elemento di tipo "box" per ogni lato di quest'ultimo
	// INPUT: 1) (var ) el --> riferimento all'elemento di tipo box
	//		2) (str ) what ["margin"|"border"|"padding"] --> elemento del box model del quale si vuol sapere la dimensione
	//		3) (bool) int [false|true] (default false) --> se true, indica di produrre le dimensioni senza l'unità di misura, altrimenti (false) con l'unità di misura.
	//
	// OUTPUT: (arr) array associativo contenente le dimensioni relative ai quattro lati dell'elemendo box selezionato:
	/* array(
		["top"] => dimensione al lato superiore del box,
		["right"] => dimensione al lato destro del box,
		["bottom"] => dimensione al lato inferiore del box,
		["left"] => dimensione al lato sinistro del box
	   )
	
	  Esempi:
	  var padding=getBoxSpace('box','padding',true); // restituisce il padding dell'elemento 'box'
	  var margin=getBoxSpace('box','margin',true); // restituisce il margin dell'elemento 'box'
	  var border=getBoxSpace('box','border',true); // restituisce il border dell'elemento 'box'
	*/
	function getBoxSpace(el,what,int){
		var D=["top","right","bottom","left"],i,S={},s;
		for(i in D){s=getStyle(el,what+"-"+D[i]);S[D[i]]=int?toInt(s):s}
		return S
	}
	
	// FUNZIONE che restituisce il valore di opacità (trasparenza) di un elemento
	// INPUT: 1) (var) el --> riferimento all'elemento
	//
	//
	// OUTPUT: (real) valore dell'opacità (trasparenza) dell'elemento compreso fra 1.00 e 0.00
	function getOpacity(el){return toFloat(getStyle(el,'opacity'))||1}
	
	// FUNZIONE che imposta un valore di opacità (trasparenza) per un elemento
	// INPUT: 1) (var ) el --> riferimento all'elemento
	//		2) (real) val --> valore dell'opacità compreso fra 1.00 e 0.00
	//
	// OUTPUT: nessuno
	function setOpacity(el,val){var S=ID(el).style;S.filter=val==1?"":"alpha(opacity="+val*100+")";S.KHTMLOpacity=S.MozOpacity=S.opacity=val}
	
	// FUNZIONE che imposta la trasparenza di una detrminata proprietà di elemento
	// INPUT: 1) (var) el --> riferimento all'elemento
	//		2) (str) what ['color'|'background-color'|'border-color'] --> indica cosa impostare a 'transparent'
	//
	// OUTPUT: nessuno
	function setTransparent(el,what){setStyle(el,what,'transparent')}
	
	// FUNZIONE che imposta l'immagine di background di un elemento
	function setBgImg(el,img){ID(el).style.backgroundImage=img?'url('+img+')':'none'}
	
	// FUNZIONE che restituisce il percorso dell'immagine di background associata ad un elemento
	function getBgImg(el){var I=replace$(getStyle(el,'background-image'),['url(',')','"'],'');return I=='none'?false:I}
	
	// FUNZIONE che consente di settare il background-repeat di un elemento
	// INPUT: 1) (var) el --> riferimento all'elemento per il quale impostare il bgRepeat
	//		2) (str) rep --> tipo di repeat da applicare:
	// 			> no-repeat, 
	//			> repeat, 
	//			> repeat-x, 
	//			> repeat-y
	//
	// OUTPUT: nessuno
	function setBgRepeat(el,rep){ID(el).style.backgroundRepeat=rep}
	
	// FUNZIONE che consente di settare la posizione dell'immagine di background di un elemento
	function setBgPos(el,x,y){ID(el).style.backgroundPosition=x+' '+y}
	
	// FUNZIONE che restituisce un array [x,y] contenente le coordinate dell'immagine di bg di un elemento
	function getBgPos(el){var R,B=getStyle(el,'background-position'),i;if(!isSet(B))return[0,0];for(i in B=trin(B).split(' '))B[i]=!isNaN(R=Math.round(toFloat(B[i])))?R:B[i];return B}
	
	// FUNZIONE per il posizionamento di un elemento all'interno del documento
	// INPUT: 1) (var) el --> riferimento all'elemento
	//		2) (str) pos [absolute|fixed|relative|static] --> tipo di posizionamento da applicare all'elemento (*)
	//
	// OUTPUT: nessuno
	// (*) 	Il posizionamento "fixed" non è nativamente supportato dalle versioni di IE inferiori alla 7. 
	// 		Per ovviare a tale mancanza, questa FN (quando chiamata) applica una serie di patch che fanno in modo che "fixed" possa essere emulato dalle versioni di IE inferiori alla 7 
	// Versione precedente della FN:
	// function setCssRelPos(el,pos){(isOldIe()&&isWin()&&pos=='fixed')?oldIePosFixed(el):ID(el).style.position=pos}
	function setCssRelPos(el,pos){resetIePosFixed(el);if(isOldIe()&&isWin()&&pos=='fixed'){iePO$=pos;oldIePosFixed(el)}else{la$t[el+'']=iePO$=ID(el).style.position=pos}}
	
	// [+] FUNZIONI patch per la risoluzione del "position:fixed" sulle versioni di IE inferiori alla 7
	// --- --------------------------------------------------------------------------------------------
	var iePO$="",la$t={},$fIeW={};
	function oldIePosFixed(el){
		var p=getPos(el);
		la$t[el+'']="fixed";
		function S(){var s=getPageScroll(),L=s[0]+p[0],T=s[1]+p[1],e=ID(el).style;e.top=T+'px';e.left=L+'px';e.position='absolute'}
		S();wFix(el,S)
	}
	function resetIePosFixed(el){if(isOldIe()&&isWin()&&iePO$=='fixed')wFix(el,"")}
	function wFix(el,FN){window.onscroll=function(){$fIeW[el+'']=FN;for(var i in $fIeW)$exec($fIeW[i])}}
	// --- --------------------------------------------------------------------------------------------
	// [-]
	
	// FUNZIONE che verifica se due elementi sono tra di loro sovrapposti
	// INPUT: 1) (var) el1 --> riferimento all'elemento 1
	//		2) (var) el2 --> riferimento all'elemento 2
	//
	// OUTPUT: (bool) true se sono sovrapposti, false se non lo sono
	function isOverlap(el1,el2){
		var p1=getPos(el1),p2=getPos(el2);
		function S(v){return v>0?"+":v<0?"-":0}return((S(p1[1]-p2[3])!=S(p1[3]-p2[1]))&&(S(p1[0]-p2[2])!=S(p1[2]-p2[0])))?true:false
	}
	
	// FUNZIONE che consente di settare il font-size in px di un elemento
	function setFontSize(el,size){ID(el).style.fontSize=size+"px"}
	
	// FUNZIONE che restituisce un array riportante i valori di ridimensionamento in scala (proporzionale) di un elemento box
	// INPUT: 1) (arr) A --> array riportante le dimensioni di partenza [w,h]
	//		2) (int) w --> larghezza massima alla quale riportare la nuova larghezza (*)
	//		3) (int) h --> altezza massima alla quale riportare la nuova altezza (*)
	// (*) ..	se vengono valorizzati h e w la funzione non effettua il calcolo in scala è restituisce integralmente un array con le dimensioni date in input
	// 		se viene valorizzato solo w la funzione ridimensiona h in proporzione a tale valore
	//		se viene valorizzato solo h, la funzione ridimensiona w in proporzione a tale valore
	//
	// OUTPUT: (arr) array riportante le nuove dimensioni in scala
	function scaleBox(A,w,h){var R=Math.round;if(w&&!h){h=R(w*(A[1]/A[0]))}else if(!w&&h){w=R(h*(A[0]/A[1]))}return[w,h]}
	
	// FUNZIONE che restituisce un array contenente le coordinate del centro di un box
	function getCenterBox(s){R=Math.round;return[R(s[0]/2),R(s[1]/2)]}
	
	// FUNZIONE che consente di impostare le dimensioni in px di un elemento box
	function setBoxSize(el,w,h){var S=ID(el).style,R=Math.round;S.width=R(w)+"px";S.height=R(h)+"px"}
	
	// FUNZIONE che restituisce un array contenente le dimensioni [w,h] di un elemento
	function getSize(el){el=ID(el);return[el.offsetWidth||el.width,el.offsetHeight||el.height]}

	// FUNZIONE che restituisce la posizione effettiva (DOM) di un elemento all'interno del documento
	// N.B: 	nella maggioranza dei casi serve sapere soltanto la posizione X del lato sinistro del box e la posizione Y del laro superiore del box,
	// 		questa funzione oltre a queste due posizioni restituisce anche quelle relative agli altri due lati del box che è utile conoscere per esempio, 
	//		nel caso si voglia sapere se due elementi sono tra di loro sovrapposti.
	// INPUT: 1) (var) riferimento all'elemento
	//
	// OUTPUT: (arr) array riportante 4 valori: 
	/* array(
		[0] => posizione X del lato sinistro del box,
		[1] => posizione Y del lato superiore del box, 
		[2] => posizione X del lato destro del box, 
		[3] => posizione Y del lato inferiore del box
	   )
	*/
	function getPos(el){
		var e=ID(el),L="offsetLeft",T="offsetTop",p=[e[L],e[T]],S,D=getSize(el);
		if(getParent(e))while(e=e.offsetParent){p[0]+=e[L];p[1]+=e[T]}
		// [+] HACK per IE<7 nel caso di "position:fixed"
		if(isOldIe()&&isWin()&&iePO$=='fixed'&&la$t[el+'']=="fixed"){
			S=getPageScroll();
			p[0]-=S[0];
			p[1]-=S[1]
		}
		// [-]
		p[2]=p[0]+D[0]-1;
		p[3]=p[1]+D[1]-1;
		//if(isSafari()){alert('safari');
		//	p[0]-=document.body.offsetLeft;
		//	p[1]-=document.body.offsetTop;
		//}
		return p
	}
	
	// FUNZIONE che restituisce la posizione CSS di un elemento
	// INPUT: 1) (var) riferimento all'elemento
	//
	// OUTPUT: (arr) array riportante 4 valori non nesessariamente valorizati: [posizione X L1, posizione Y L1, posizione X L2, posizione Y L2] 
	function getCSSPos(el){el=ID(el).style;return[el.left,el.top,el.right,el.bottom]}
	
	// FUNZIONE che setta la posizione (CSS) di un elemento in modalità fissa o assoluta
	// INPUT: 1) (var ) el --> identificativo dell'elemento da posizionare
	//		2) (int ) x --> posizione rispetto all'asse delle x
	//		3) (int ) y --> posizione rispetto all'asse delle y
	//		4) (bool) fiXed (default false) [true|false|''] --> se true indica che il posizionamento è fisso eltrimenti assoluto
	//		5) (int ) zIndex (default null) se specificato setta l'elevazione dell'elemento rispetto agli altri elementi del documento
	//
	// OUTPUT: nessuno
	//
	// Funzione precedente:
	//	function setPos(el,x,y,fiXed,zIndex){
	//		var P="position:"+(fiXed?"fixed":"absolute")+";top:"+y+"px;left:"+x+"px";
	//		if(isOldIe())setStyles(el,P);
	//		setStyles(el,P+(zIndex?";z-index:"+zIndex:""))
	//	}
	function setPos(el,x,y,fiXed,zIndex){
		setStyles(el,"position:"+(fiXed?"fixed":"absolute")+";top:"+y+"px;left:"+x+"px"+(zIndex?";z-index:"+zIndex:""))
	}
	
	// FUNZIONE semplificata che determina le dimensioni del body
	function getBodySize(){var dB=document.body;return[dB.clientWidth,dB.clientHeight]}
	
	// FUNZIONE avanzata che calcola le dimensioni del documento (body)
	// INPUT: 1) (bool) sBar [true|false/""] (default "") --> se true indica di considerare anche lo spazio occupato dalle scrollbar
	//
	// OUTPUT: (arr) array riportante:
	/* array(
		[0] => larghezza totale del body, 
		[1] => altezza dell'area visibile del body, 
		[2] => altezza totale del body
	   )
	*/
	function bodySize(sBar){var sW=sBar?16:0,w=window,d=document,ie=d.all&&!w.opera,std=d.compatMode=="CSS1Compat"?d.documentElement:d.body,oH=std.offsetHeight,sH=std.scrollHeight;return[(ie)?std.clientWidth:w.innerWidth-sW,(ie)?std.clientHeight:w.innerHeight,oH>sH?oH:sH]}

	// FUNZIONE che in base a larghezza ed altezza fornite, calcola e restituisce le coordinate per il posizionamento di un elemento di tali dimensioni al centro del body
	// INPUT: 1) (int ) w --> larghezza
	//		2) (int ) h --> altezza
	//		3) (bool) scrollPos [true|false/''] (default "") --> indica se considerare o meno la posizione di scrolling attuale
	//
	// OUTPUT: (arr) array contenente le coordinate di posizionamento accentrato rispetto all'area visibile del body [x,y]
	function relCenterOfBody(w,h,scrollPos){var b=bodySize(true),R=Math.round,S=scrollPos?getPageScroll():[0,0];return[R(b[0]/2-w/2),R(b[1]>h?S[1]+b[1]/2-h/2:S[1]+10)]}
	
	// FUNZIONE che posiziona un elemento al centro dell'area visibile del body
	// INPUT: 1) (var ) el --> identificativo dell'elemento da posizionare
	//		2) (bool) PosFiXed [true|false/""] (default "") --> indica il tipo di posizionamento:
	//			A) true --> posizionamento fisso 
	//			B) false o "" --> posizionamento assoluto
	//
	// OUTPUT: nessuno
	function setCenterOfBody(el,PosFiXed){var s=getSize(el),c=relCenterOfBody(s[0],s[1],!PosFiXed);setPos(el,c[0],c[1],PosFiXed)}
	
	// FUNZIONE che restituisce il valore dello z-index dell'elemento selezionato
	function getZindex(el){var i=toInt(getStyle(el,'z-index'));return i?i:0}
	
	// FUNZIONE che restituisce il valore di z-index maggiore (tra un'intervallo definito di elementi o fra tutti quelli del documento) e il relativo elemento
	// INPUT: 1) (var) el ['*'|array[EL1,EL2,...,ELn]] --> lista definita (array) degli elementi da confrontare, o '*' carattere jolly che considera tutti gli elementi della pagina
	// 
	// OUTPUT: (arr) array contenente due valori: 
	//			> (int) z-index maggiore
	//			> (var) riferimento all'elemento con z-index maggiore
	function getMaxZindex(el){var M=0,Z,i,E=null,e=isArray(el)?el:TAG('*');for(i=0;i<e.length;i++){Z=getZindex(e[i]);if(Z>M){M=Z;E=e[i]}}return[M,E]}
	
	// FUNZIONE che imposta lo z-index di un elemento
	function setZindex(el,i){return setStyle(el,'z-index',i)}
	
	// ## [+] la visibilità css ("visibility") è quella proprietà CSS che nasconde alla vista del client l'oggetto ma ne preserva il relativo spazio occupato ##
	// --
	// FUNZIONE che imposta la visibilità CSS ("visibility") di un elemento
	function setVisibility(el,hide){ID(el).style.visibility=hide?"hidden":"visible"}
	
	// FUNZIONE che verifica se un elemento è visibile (proprietà "visibility") o meno
	function isVisible(el){return getStyle(el,'visibility')=='hidden'?false:true}
	
	// FUNZIONE che imposta o meno la visibilità di tutti i tag <select> presenti su un documento all'interno di un determinato elemento
	// INPUT: 1) (bool) hide --> se true nasconde le select, false le mostra
	//		2) (var ) parent --> riferimento all'elemento all'interno del quale impostare la visibilità delle select
	//
	// OUTPUT: nessuno
	function hideShowSelect(hide,parent){var s=TAG("select",parent),i;for(i=0;i<s.length;i++)setVisibility(s[i],hide)}
	// --
	// ## [-]
	
	// ## [+] "display" è quella proprietà CSS che nasconde o mostra alla vista del client l'oggetto compreso il relativo spazio occupato ##
	// --
	// FUNZIONE che imposta la visualizzazione o meno di un elemento 
	function setDisplay(el,hide){ID(el).style.display=hide?"none":""}
	
	// FUNZIONE che verifica se un elemento è visualizzato o meno
	function isDisplayed(el){return getStyle(el,'display')=='none'?false:true}
	
	// FUNZIONE SEMPLICE che a seconda dello stato di visualizzazione attuale, fa lo switch tra gli stati "visualizzato/non visualizzato"
	// INPUT: 1) (var) el --> riferimento all'oggetto in questione
	//
	// OUTPUT: (bool) true se l'elemento è visualizzato, false se l'elemento non è visualizzato
	function toggle(el){var D=isDisplayed(el);setDisplay(el,D);return !D}
	
	// FUNZIONE AVANZATA che a seconda dello stato di visualizzazione attuale, fa lo switch tra gli stati "visualizzato/non visualizzato"
	// INPUT: 1) (var) el --> riferimento all'oggetto in questione
	//		2) (var) btn --> riferimento all'oggetto che funge da pulsante di switch
	//		3) (str) txtOn --> testo da mostrare sul pulsante di switch quando l'elemento è visualizzato a video
	//		4) (str) txtOff --> testo da mostrare sul pulsante di switch quando l'elemento non è visualizzato a video
	//		5) (str) clsOn --> classe da associare al pulsante quando l'elemento è visualizzato a video
	//		6) (str) clsOn --> classe da associare al pulsante quando l'elemento non è visualizzato a video
	//
	// OUTPUT: nessuno
	function advToggle(el,btn,txtOn,txtOff,clsOn,clsOff){var A=clsOn,B=clsOff,T=txtOff,b=ID(btn);if(!toggle(el)){T=txtOn;A=clsOff;B=clsOn}replaceClassName(b,A,B);html(b,T)}
	// --
	// ## [-]
// [-] ---------------------------------------------------------------------------------------------------------------------------------------------------


// ### Array ###
// [+] ---------------------------------------------------------------------------------------------------------------------------------------------------
	//	// ---
	//	// Supporto per il metodo push (Array) per IE 5
	//	if(!isFunction(Array.prototype.push)){Array.prototype.push=function _Push(v){this[this.length]=v}}
	//	// ---
	//
	//	// Alias di Array.length
	//	Array.prototype.len=function(){return this.length}

	// FUNZIONE alias del metodo length che restituisce la lunghezza di un array o di una stringa
	function len(v){return v.length}

	// FUNZIONE che forza una variabile ad array (se questa non lo è già)
	function toArr(arg){return isArray(arg)?arg:[arg]}
	
	// FUNZIONE che verifica se un determinato valore "fnd" è presente all'interno di un array
	function inArray(arr,fnd){return getIndex(arr,fnd)!=-1}
	
	// FUNZIONE che restituisce il valore dell'ultimo elemento dell'array o l'ultimo carattere di una stringa
	function Last(a){return a[a.length-1]}

	// FUNZIONE che cerca un valore all'interno degli elementi di un determinato array restituendone il/i relativo/i indice/i
	// INPUT: 1) (arr ) arr --> array sorgente
	//		2) (var ) fnd --> valore da cercare all'interno dell'array
	//		3) (str) reg ['in'|'start'|'end'|'full'] (default 'full') --> eventuale regola in base alla quale cercare (*)
	//		   (*) reg è utile per fare ricerche in base al contenuto parziale degli elementi dell'array (es: l'elemento il cui valore inizia per ... o finisce per ... o contiene ... o è uguale a ...)
	//		4) (bool) r [false|true] (default false) --> se impostato a true indica che la ricerca all'interno dell'array deve essere ricorsiva (cioè si vogliono determinare gli indici del vettore con gli elementi pari a "fnd")
	//
	// OUTPUT: (var) se r è impostato a:
	//			true -> la funzione restituisce gli indici dell'array all'occorrenza di "fnd" altrimenti restituisce false se non trovato
	//			false-> la funzione restituisce il primo indice dell'array all'occorrenza di "fnd" altrimenti restituisce -1 se non trovato
	//
	// Versione precedente della Funzione:
	// function getIndex(arr,fnd){for(var i in arr){if(arr[i]==fnd)return i}return-1}
	function getIndex(a,fnd,reg,r){var i,R=[];if(r){for(i in a)if(strSrc(a[i],fnd,reg))R.push(i);return R.length>0?R:false}else{for(i in a)if(strSrc(a[i],fnd,reg))return i;return -1}}
	
	// FUNZIONE che rimuove tutti gli eventuali elementi di un array con valore pari aquello specificato in "fnd"
	function arrRemove(arr,fnd){var i=0;L=arr.length;while(i<L){if(arr[i]===fnd){arr.splice(i,1);L--}else{i++}}return arr}

	// FUNZIONE che filtra un array in base all'elenco dei relativi indici (o chiavi)
	// INPUT: 1) (arr) arr --> array da filtrare
	//		2) (arr) i --> array contenente gli indici di "arr" da selezionare
	//
	// OUTPUT: (arr) array filtrato
	function arrKfilter(arr,i){var j,A=[];for(j in i)A.push(arr[i[j]]);return A}
	
	// FUNZIONE che effettua la fusione di due array (con ridondanza dei valori)
	function arrExtend(arr,nwArr){for(var i in nwArr)arr.push(nwArr[i]);return arr}
	
	// FUNZIONE che esegue il codice fn per ogni elemento dell'array
	function foreach(arr,fn){for(var i in arr)fn.call('',arr[i],i)}
	
	// FUNZIONE che applica la fn ad ogni elemento dell'array
	function map(arr,fn){var i,t=[];for(i in arr){t.push(fn(arr[i]))}return t} // ??
	
	// FUNZIONE che restituisce le occorrenze di un valore all'interno di un array
	function arrRecurrence(arr,val){var i,c=0;for(i in arr){if(arr[i]===val)c++}return c}
	
	// FUNZIONE che ordina un array numerico in maniera crescente o decrescente
	// INPUT: 1) (arr) arr --> array da ordinare
	//		2) (str) dir --> direttiva di ordinamento dell'array:
	//			> "asc" (default) ordinamento crescente
	//			> "desc" ordinamento decrescente
	//
	// OUTPUT: (arr) array ordinato
	function numSort(arr,dir){return arr.sort(function(a,b){return dir=='desc'?b-a:a-b})}
	
	// FUNZIONE che mischia casualmente l'ordine degli elementi di un array
	function arrShuffle(arr){for(var j,x,i=arr.length;i;j=parseInt(Math.random()*i),x=arr[--i],arr[i]=arr[j],arr[j]=x);return arr}
	
	// FUNZIONE che a partire da due array produce un unico array associativo dove i valori del primo array diventano chiavi e i valori del secondo diventano valori dell'array associativo
	function arr2Assoc(aK,aV){var R={},L=Math.min(aK.length,aV.length),i;for(i=0;i<L;i++)R[aK[i]]=aV[i];return R}
	
	// FUNZIONE che a partire da una stringa con separatori di gruppo e di elementi, produce un array associativo
	// INPUT: 1) (str) str --> stringa con separatori di gruppo e di elementi ES: "a-1 a-2 a-3"
	//		2) (str) grp --> stringa che funge da separatore di gruppo (nell'esempio "-")
	//		3) (str) lst --> stringa che funge da separatore li lista (nell'esempio " ")
	//
	// OUTPUT: (arr) array (oggetto JS) costruito a partire dalla stringa
	function str2assocArr(str,grp,lst){var s=str.split(lst),i,a={},p;for(i=0;i<s.length;i++){p=s[i].split(grp);a[p[0]]=p[1]}return a}
	
	// FUNZIONE che converte un array associativo in stringa
	// INPUT: 1) (arr) arr --> array (oggetto JS) da convertire in stringa
	//		2) (str) grp --> stringa che fungerà da separatore di gruppo all'interno della stringa finale
	//		3) (str) lst --> stringa che fungerà da separatore li lista all'interno della stringa finale
	//
	// OUTPUT: (str) stringa risultante dalla conversione
	function assocArr2Str(arr,grp,lst){var s='',i;for(i in arr)s+=i+grp+arr[i]+lst;return s.substring(0,s.length-1)}
	
	// FUNZIONE che serializza un array in modo che possa essere deserializzato con la funzione "unserialize()" di PHP
	function serialize(a){var S=T='',c=0,K;switch(typeof(a)){case'object':for(K in a){T+=serialize(K);T+=serialize(a[K]);c++}S='a:'+c+':{'+T+'}';break;case'number':S+=(a-Math.floor(a)!=0)?'d:'+a+';':'i:'+a+';';break;case'string':S+='s:'+a.length+':"'+a+'";';break;case'boolean':S+=a?'b:1;':'b:0;';break}return S}
	
	// FUNZIONE alias di alert() che in più rispetto a questa visualizza il contenuto di un array associativo (imploso)
	// N.B: Funzione utile in fase di debug soprattutto nei casi in cui si voglia visualizzare in una finestra di alert il contenuto di un array (associativo o non)
	function alert_r(a){return alert(isArray(a)?a:isObject(a)?assocArr2Str(a,':',','):a)}
// [-] ---------------------------------------------------------------------------------------------------------------------------------------------------


// ### Classi CSS ### 
// [+] ---------------------------------------------------------------------------------------------------------------------------------------------------
	// FUNZIONE che genera un array contenente l'elenco distinto delle classi associate ad un determinato elemento
	function cla$$(el){return trin(trim(ID(el).className)).split(' ')}
	
	// FUNZIONE che verifica se ad un determinato elemento è associata o meno una determinata classe
	function hasClassName(el,clsNm){return inArray(cla$$(el),clsNm)}
	
	// FUNZIONE che restituisce un array con il/i nome/i della/e classe/i che soddisfa/no la regola "reg" impostata
	// INPUT: 1) (var ) el --> riferimento all'elemento all'interno delle cui classi cercare
	//		2) (str ) str --> nome della classe o porzione da cercare
	//		3) (str ) reg ['in'|'start'|'end'|'full'] (default 'full') --> eventuale regola in base alla quale cercare (*)
	//		   (*) reg è utile per fare ricerche in base al contenuto parziale degli elementi dell'array (es: l'elemento il cui valore inizia per ... o finisce per ... o contiene ... o è uguale a ...)
	//		4) (bool) r [false|true] (default false) --> se impostato a true indica che la ricerca all'interno delle classi deve essere ricorsiva (cioè si vogliono determinare tutte le classi dell'elemento pari a "str" con la regola "reg")
	//
	// OUTPUT: (var) se r è impostato a:
	//			true -> la funzione restituisce le classi all'occorrenza di "str" altrimenti restituisce false se non trovate
	//			false-> la funzione restituisce la prima classe all'occorrenza di "str" altrimenti restituisce false se non trovata
	function getClassWith(el,str,reg,r){var C=cla$$(el),i=getIndex(C,str,reg,r);return i==-1||!i?false:arrKfilter(C,toArr(i))}
	
	// FUNZIONE che accoda una nuova classe all'elenco delle classi di un determinato elemento
	function addClassName(el,clsNm){el=ID(el);if(!inArray(cla$$(el),clsNm))el.className+=el.className?' '+clsNm:clsNm}
	
	// FUNZIONE che rimuove una determinata classe da un determinato elemento
	// INPUT: 1) (var) el --> riferimento all'elemento dal quale rimuovere la classe
	//		2) (str) clsNm --> nome della classe da rimuovere
	//
	// OUTPUT: (bool) esito della rimozione:
	//		true  -> la classe era associata all'elemento ed è stata rimossa
	//		false -> la classe non è associata all'elemento (nessuna rimozione effettuata)
	function removeClassName(el,clsNm){var R=true;hasClassName(el,clsNm)?ID(el).className=arrRemove(cla$$(el),clsNm).join(' '):R=false;return R}
	
	// FUNZIONE che sostituisce una classe "a" con una classe "b" dell'elenco delle classi associate ad un determinato elemento
	// INPUT: 1) (var ) el --> riferimento all'elemento dal quale sostituire la classe "a" con la classe "b"
	//		2) (str ) a --> nome della classe da sostituire
	//		3) (str ) b --> nome della classe sostituta
	//		4) (bool) ifExist [false|true] (default false) --> il settaggio di questo parametro comporta due funzionamenti diversi della funzione:
	//				ifExist=false -> indica di associare la classe "b" anche se la classe "a" non esiste
	//				ifExist=true  -> indica di non associare la classe "b" se la classe "a" non esiste
	function replaceClassName(el,a,b,ifExist){if(!removeClassName(el,a)&&ifExist)return false;addClassName(el,b)}
// [-] ---------------------------------------------------------------------------------------------------------------------------------------------------


// ### Query String ###
// [+] ---------------------------------------------------------------------------------------------------------------------------------------------------
	// FUNZIONE che restituisce l'intera Query String
	function getQuery(){return window.location.search.substring(1)}
	
	// FUNZIONE che restituisce il valore di una determinata variabile ricevuta via Query String
	function getQueryVar(vName){var v=getQuery().split("&"),i,p;for(i in v){p=v[i].split("=");if(p[0]==vName)return p[1]}return false}
// [-] ---------------------------------------------------------------------------------------------------------------------------------------------------


// ### Cookies ###
// [+] ---------------------------------------------------------------------------------------------------------------------------------------------------
	// N.B: IE6 ha problemi nella gestione dei cookies per cui per tale versione del brovser le seguenti funzioni non funzionano.
	
	// FUNZIONE per la creazione dei cookie
	function setCookie(key,val,days,path,domain,secure){
		var d=new Date(),ex='';
		if(days){
			d.setDate(d.getDate()+days);
			ex=';expires='+d.toGMTString()
		}
		document.cookie=key+'='+escape(val)+ex+(path?';path='+path:"")+(domain?";domain="+domain:"")+(secure?";secure":"")
	}

	// FUNZIONE per la determinazione del valore di un determinato cookie
	//function getCookie(key){var kEQ=key+'=',ca=document.cookie.split(';'),c,x;for(x=0;x<ca.length;x++){c=ca[x];while(c.charAt(0)==' ')c=c.substring(1,c.length);if(c.indexOf(kEQ)==0)return c.substring(kEQ.length,c.length)}return}

	// FUNZIONE per la determinazione del valore di un determinato cookie
	function getCookie(name){var C,S,L,E,N=name;C=document.cookie;S=C.indexOf(N+"=");L=S+N.length+1;if(!S&&N!=C.substring(0,N.length))return null;if(S==-1)return null;E=C.indexOf(';',L);if(E==-1)E=C.length;return unescape(C.substring(L,E))}

	// FUNZIONE per l'eliminazione di un determinato cookie
	function delCookie(key,path,domain){setCookie(key,'',-360,path,domain)}

	// FUNZIONE che verifica se il client accetta o meno i cookies
	function chkCookies(){setCookie('chkCk',1,1);if(getCookie('chkCk')){delCookie('chkCk');return true}return false}
// [-] ---------------------------------------------------------------------------------------------------------------------------------------------------


// ### Stringhe ###
// [+] ---------------------------------------------------------------------------------------------------------------------------------------------------
	// FUNZIONE che consente di verificare se una stringa è presente all'interno di un'altra
	// INPUT: 1) (str) str --> stringa di origine (pagliaio)
	//		2) (src) src --> stringa da cercare (ago)
	//
	// OUTPUT: (bool) la funzione restituisce TRUE se la stringa è presente altrimenti restituisce FALSE
	// N.B: il controllo è CASE SENSITIVE
	function inString(str,src){return strPos(str,src)!=-1}
	
	// FUNZIONE che restituisce la posizione di una stringa all'interno di un'altra
	// INPUT: 1) (str) str --> stringa di origine (pagliaio)
	//		2) (src) src --> stringa da cercare (ago)
	//
	// OUTPUT: (int) la funzione restituisce valori da 0 a n nel caso di stringa trovata, altrimenti -1 in caso di insuccesso
	// N.B: il controllo è CASE SENSITIVE
	function strPos(str,src){return str.indexOf(src)}

	// FUNZIONE alias di toUpperCase()
	function upper(s){return s.toUpperCase()}
	
	// FUNZIONE alias di toLowerCase()
	function lower(s){return s.toLowerCase()}
	
	// FUNZIONE che pone in maiuscolo tutte i primi caratteri delle parole di una determinata stringa
	function capitalize(str){return lower(str).replace(/\b[a-z]/g,function(M){return upper(M)})}
	
	// FUNZIONE che trasforma una stringa con separatori di parola "-" in formato camelcase: "prova-camel-case" -> "provaCamelCase"
	function camelCase(str){return str.replace(/-\D/gi,function(M){return upper(M.charAt(M.length-1))})}
	
	// FUNZIONE che effettua il replace ricorsivo all'interno di una stringa
	// INPUT: 1) (str) str --> stringa di origine
	//		2) (var) src --> array di stringhe da cercare o singola stringa da cercare
	//		3) (var) rmv --> array di stringhe di sostituzione o singola stringa di sostituzione
	// 
	// OUTPUT: (bool) stringa filtrata risultante
	//
	//function replace$(str,src,rmv){var s=toArr(src),i;for(i in s){str=str.replace(eval("/\\"+s[i]+"/g"),isArray(rmv)?rmv[i]:rmv)}return str}
	function replace$(str,src,rmv){var s=toArr(src),i,r;for(i in s){r=isArray(rmv)?rmv[i]:rmv;while(inString(str,s[i])){P=strPos(str,s[i]);str=str.substring(0,P)+r+str.substring(P+s[i].length,str.length)}}return str}
	
	// FUNZIONE che elimina gli spazi bianchi esterni alla stringa
	function trim(s){return ""+s.replace(/^\s*|\s*$/g,'')}
	
	// FUNZIONE che elimina i doppi spazi bianchi all'interno della stringa sostituendoli con i songoli spazi, inoltre esegue anche il trim()
	function trin(s){return trim(s.replace(/\s\s/g,' '))}
	
	// FUNZIONE che elimina tutti gli spazi bianchi da una stringa
	function rmvBlank(s){return s.replace(/\s/g,'')}
	
	// FUNZIONE che restituisce il numero di parole contenute in una stringa
	function words(s){return trin(s).split(" ").length}
	
	// FUNZIONE che sostituisce l'accapo html (<br />) con quello di sistema (\n)
	function br2nl(s){return s.replace(/<br\s?\/?>/gi,"\n")}
	
	// FUNZIONE che sostituisce l'accapo di sistema (/n) con quello di html (<br />)
	function nl2br(s){return s.replace(/\n/g, "<br />")}
	
	// FUNZIONE che esegue l'escape degli apici singoli (') e doppi (")
	function addSlashes(s){return s.replace(/\"/g,"\\\"").replace(/\'/g,"\\\'")}
	
	// FUNZIONE che elimina l'escape degli apici singoli (') e doppi (")
	function stripSlashes(s){return s.replace(/\\['"]{1,}/g,function(match){return(match.charAt(1))})}
	
	// FUNZIONE che rimuove tutti i tags html da una stringa
	function stripTags(s){return s.replace(/<([^>]+)>/g,'')}
	
	// FUNZIONE che da una stringa rimuove il tag <script> preservando il contenuto di quest'ultimo
	function stripScripts(s){return s.replace(/<script[^>]{0,}>|<\/script>/gi,'')}
	
	// FUNZIONE che restituisce i primi "len" caratteri di una stringa
	function firstChars(s,len){return s.substring(0,len)}
	
	// FUNZIONE che restituisce gli ultimi "len" caratteri di una stringa
	function lastChars(s,len){return s.substring(s.length-len,s.length)}
	
	// FUNZIONE che verifica se in base alla regola specificata, una stringa è presente all'interno di un'altra
	// INPUT: 1) (str) str --> stringa (pagliaio) all'interno della quale cercare
	//		2) (str) src --> stringa (ago) da cercare
	//		3) (str) reg ['in'|'start'|'end'|'full'] (default 'full') --> regola in base alla quale cercare (se non specificata viene cercata l'intera stringa)
	//
	// OUTPUT: (bool) true se la ricerca ha avuto esito positivo, altrimenti false
	function strSrc(str,src,reg){
		var R=false;
		switch(reg){
			case'in':R=inString(str,src);break;
			case'start':R=firstChars(str,src.length)===src;break;
			case'end':R=lastChars(str,src.length)===src;break;
			default:R=str===src
		}
		return R
	}

	// FUNZIONE che taglia una stringa al numero di caratteri specificato
	// INPUT: 1) (str) str --> stringa di origine
	//		2) (int) maxLen --> lunghezza massima della stringa
	//
	// OUTPUT: (str) stringa risultante
	// ES: truncate('Oggi è una bella giornata',6) --> 'Oggi è...'
	function truncate(str,maxLen){return str.length>maxLen?str.slice(0, maxLen-3)+"...":str}

	// FUNZIONE che effettua la codifica o decodifica di una stringa in base64
	// INPUT: 1) (str ) s --> stringa di origine
	//		2) (bool) decode [true|false] (default false) --> se true indica di decodificare altrimenti (false) di codificare
	//
	// OUTPUT: (str) stringa risultante (dipende da decode)
	function base64(s,decode){var o="",c1,c2,c3,e1,e2,e3,e4,i=0,sfc=String.fromCharCode;if(decode){function kS(){return keyStr.indexOf(s.charAt(i++))}s=s.replace(/[^A-Za-z0-9\+\/\=]/g,"");do{e1=kS();e2=kS();e3=kS();e4=kS();c1=(e1<<2)|(e2>>4);c2=((e2&15)<<4)|(e3>>2);c3=((e3&3)<<6)|e4;o+=sfc(c1);if(e3!=64)o+=sfc(c2);if(e4!=64)o+=sfc(c3)}while(i<s.length)}else{do{function cC(){return s.charCodeAt(i++)}function kC(e){return keyStr.charAt(e)}c1=cC();c2=cC();c3=cC();e1=c1>>2;e2=((c1&3)<<4)|(c2>>4);e3=((c2&15)<<2)|(c3>>6);e4=c3&63;if(isNaN(c2)){e3=e4=64}else if(isNaN(c3)){e4=64}o=o+kC(e1)+kC(e2)+kC(e3)+kC(e4)}while(i<s.length)}return o}
	
	// FUNZIONE che converte i caratteri speciali contenuti in una stringa in entità html
	// INPUT: 1) (str) s --> stringa di origine
	//		2) (str) op [encode|decode] (default decode) --> indica se effettuare la codifica o la decodifica delle entità
	//
	// OUTPUT: (str) stringa risultante (dipende da op)
	function entities(s,op){var E,g='grave',a='acute',A=str2assocArr('&:amp,\':apos,":quot,<:lt,>:gt,à:a'+g+',è:e'+g+',ì:i'+g+',ò:o'+g+',ù:u'+g+',á:a'+a+',é:e'+a+',í:i'+a+',ó:o'+a+',ú:u'+a+',À:A'+g+',È:E'+g+',Ì:I'+g+',Ò:O'+g+',Ù:U'+g+',Á:A'+a+',É:E'+a+',Í:I'+a+',Ó:O'+a+',Ú:U'+a,':',',');if(op=='encode'){for(E in A)s=s.replace(eval("/"+E+"/g"),'&'+A[E]+';')}else{for(E in A)s=s.replace(eval("/&"+A[E]+";/g"),E)}return s}
	
	// FUNZIONE che scambia i valori "a" e "b" nella variabile "v"
	function swap(v,a,b){return v==b?a:b}
	
	// FUNZIONE che riempie una stringa con "pad" fino al raggiungimento complessivo della lunghezza massima "len"
	// INPUT:	1) (str) str --> stringa di origine
	//		2) (int) len --> lunghezza massima della stringa finale risultante
	//		3) (str) pad --> stringa o carattere di riempimento 
	//		4) (str) dir [left|right] (default "left") --> direzione di riempimento con pad
	//
	// OUTPUT: (str) stringa risultante
	function strPad(str,len,pad,dir){str+='';var L=str.length,t="";if(len>L){while(t.length<len)t+=pad;t=t.substring(0,len-L);}return dir=="right"?str+t:t+str}
// [-] ---------------------------------------------------------------------------------------------------------------------------------------------------


// ### Colori ###
// [+] ---------------------------------------------------------------------------------------------------------------------------------------------------
	// FUNZIONE che effettua la conversione del colore dal formato esadecimale al formato RGB
	// INPUT: 1) (str) hex --> codice esadecimale del colore
	//
	// OUTPUT: (arr) array contenente i valori [R,G,B] del colore
	function hex2Rgb(hex){function t(i){return hex.charAt(i)}hex=hex.substring(1);if(hex.length==3)hex=t(0)+t(0)+t(1)+t(1)+t(2)+t(2);return[parseInt(t(0)+t(1),16),parseInt(t(2)+t(3),16),parseInt(t(4)+t(5),16)]}
	
	// FUNZIONE che effettua la conversione del colore dal formato RGB a quello esadecimale
	// INPUT: 1) (arr) arr --> array contenente i valori [R,G,B] del colore
	//
	// OUTPUT: (str) codice esadecimale del colore
	function rgb2Hex(arr){function t(i){var t=arr[i].toString(16);return t.length==1?"0"+t:t}return "#"+t(0)+t(1)+t(2)}
	
	// FUNZIONE che monocromizza un colore (in scala di grigi) 
	// INPUT: 1) v [array(r,g,b)|hex] --> array [R,G,B] o codice hex del colore da convertire nell'equivalente della scala dei grigi
	//
	// OUTPUT: (str) codice esadecimale del colore
	function monochromize(v){var r=isArray(v)?v:hex2Rgb(v),z=Math.round(r[0]*.299+r[1]*.587+r[2]*.114);return rgb2Hex([z,z,z])}
	
	// FUNZIONE che altera la tonalità di un colore secondo la percentuale di opacità impostata
	// INPUT: 1) (arr ) --> array contenente i valori RGB del colore da alterare
	//		2) (real) --> valore percentuale di opacità compreso nell'intervallo 1.00 - 0.00 (*)
	// 		   (*) valori vicini a 1.00 producono un colore con la predominante di "color", mentre valori vicini a 0.00 producono un colore con la predominante di "base"
	//		3) (arr ) --> array contenente i valori RGB del colore base (verso il quale tendere al diminuire dell'opacità)
	//
	// OUTPUT: (arr) array contenente i valori RGB del colore risultante
	function setColorHue(color,opacity,base){
		var R=Math.round,RGB=[],w;
		for(w=0;w<3;w++)RGB[w]=R(color[w]*opacity)+base?R(base[w]*(1.0-opacity)):0;
		return RGB
	}

	// FUNZIONE che restituisce un array multidimensionale contenente le tonalità di colore comprese fra due colori
	// INPUT: 1) (str) c1 --> colore di partenza (in RGB)
	// 		2) (str) c2 --> colore di arrivo (in RGB)
	//
	// OUTPUT: (arr) array multidimensionale contenente le tonalità di colore (in RGB) comprese fra due colori
	function colorPath(c1,c2){
		var C=[],p=1.0;
		do{
			C[C.length]=setColorHue(c1,p,c2);
			p-=.01;
		}while(p>0);
		return C
	}
// [-] ---------------------------------------------------------------------------------------------------------------------------------------------------


// ### Validazione ###
// [+] ---------------------------------------------------------------------------------------------------------------------------------------------------
	// FUNZIONE che verifica se un determinato indirizzo eMail è scritto correttamente
	function isEmail(str){return new RegExp(/\b[A-Z0-9._%-]+@[A-Z0-9.-]+\.[A-Z]{2,4}\b/i).test(str)}

	// FUNZIONE che verifica se un determinato indirizzo (url) è scritto correttamente
	function isUrl(s){return (/(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/).test(s)}
// [-] ---------------------------------------------------------------------------------------------------------------------------------------------------


// ### File ###
// [+] ---------------------------------------------------------------------------------------------------------------------------------------------------
// FUNZIONE dato un percorso di un file, restituisce un array contenente nome, estensione ed eventuale path del file
// INPUT: 1) (str) path --> path contenente il file
//
// OUTPUT: (arr) array contenente agli indici:
//	[0] -> il nome del file
//	[1] -> l'estensione del file
//	[2] -> il percorso del file
function getInfoFile(path){
	var f=Last(path.split("/")),nm=f.split("."),ext=Last(nm);
	return[arrRemove(nm,ext).join('.'),ext,path.replace(f,'')||false]
}
// [-] ---------------------------------------------------------------------------------------------------------------------------------------------------


// ### Eventi ###
// [+] ---------------------------------------------------------------------------------------------------------------------------------------------------
	//function addEvent(O,type,FN){O=ID(O);if(!FN.$$guid)FN.$$guid=addEvent.guid++;if(!O.events)O.events={};var FNs=O.events[type];if(!FNs){FNs=O.events[type]={};if(O["on"+type])FNs[0]=O["on"+type]}FNs[FN.$$guid]=FN;O["on"+type]=handleEvent}addEvent.guid=1;
	//function removeEvent(O,type,FN){O=ID(O);if(O.events&&O.events[type])delete O.events[type][FN.$$guid]}
	//function handleEvent(e){var R=true;e=e||fixEvent(window.event);var FNs=this.events[e.type];for(var i in FNs){this.$$handleEvent=FNs[i];if(this.$$handleEvent(e)===false)R=false}return R}
	//function fixEvent(e){e.preventDefault=fixEvent.preventDefault;e.stopPropagation=fixEvent.stopPropagation;return e}fixEvent.preventDefault=function(){this.R=false};fixEvent.stopPropagation=function(){this.cancelBubble=true}
	
	// http://dean.edwards.name/weblog/2005/10/add-event/
	//function addEvent(el,type,FN){el=ID(el);if(el.addEventListener){el.addEventListener(type,FN,false)}else{if(!FN.$$guid)FN.$$guid=addEvent.guid++;if(!el.events)el.events={};var FNs=el.events[type];if(!FNs){FNs=el.events[type]={};if(el["on"+type])FNs[0]=el["on"+type]}FNs[FN.$$guid]=FN;el["on"+type]=handleEvent}}
	//addEvent.guid=1;
	//function removeEvent(el,type,FN){el=ID(el);el.removeEventListener?el.removeEventListener(type,FN,false):(el.events&&el.events[type])?delete el.events[type][FN.$$guid]:''}
	//function handleEvent(e){var R=true,e=e||fixEvent(((this.ownerDocument||this.document||this).parentWindow||window).event),FNs=this.events[e.type],i;for(i in FNs){this.$$handleEvent=FNs[i];if(this.$$handleEvent(e)===false)R=false}return R}
	//function fixEvent(e){e.preventDefault=fixEvent.preventDefault;e.stopPropagation=fixEvent.stopPropagation;return e}
	//fixEvent.preventDefault=function(){this.returnValue=false};
	//fixEvent.stopPropagation=function(){this.cancelBubble=true};
	function addEvent(obj,type,FN){obj=ID(obj);if(obj.attachEvent){obj['e'+type+FN]=FN;obj[type+FN]=function(){obj['e'+type+FN](window.event)};obj.attachEvent('on'+type,obj[type+FN])}else{obj.addEventListener(type,FN,false)}}
	function removeEvent(obj,type,FN){obj=ID(obj);if(obj.detachEvent){obj.detachEvent('on'+type,obj[type+FN]);obj[type+FN]=null;}else{obj.removeEventListener(type,FN,false)}} 
	
	// [+] FUNZIONE onDomLoad()
	// ------------------------------------------------------------------------------------------------------------------------------------------------------------
	// Questa funzione risolve il problema di internet explorer nell'ascoltare l'evento "DOMContentLoaded" ed è da utilizzarsi per l'esecuzione delle funzioni JS
	// ... dopo il caricamento dell'albero DOM del documento corrente
	function onDomLoad(FN){var _OnL=$STK;$STK=function(){_OnL();FN();return}}
	function $STK(){}
	var _rOnL=false;
	if(document.addEventListener){
		document.addEventListener("DOMContentLoaded",function(){if(!_rOnL){_rOnL=true;$STK()}},false)
	}else if(isIe()){
		document.write("<scr"+"ipt id='DOMReady' defer=true "+"src=//:><\/scr"+"ipt>");
		ID("DOMReady").onreadystatechange=function(){if(this.readyState=="complete"&&!_rOnL){_rOnL=true;$STK()}}
	}
	var _OnL=window.onload;
	window.onload=function(){if(isFunction(_OnL)){_OnL()}if(!_rOnL){_rOnL=true;$STK()}};
	// ------------------------------------------------------------------------------------------------------------------------------------------------------------
	// [-]

	//function LOAD(FN){var w=window,o=w.onload;w.onload=!isFunction(o)?FN:function(){o();FN()}}
	function LOAD(FN){addEvent(window,'load',FN)}
// [-] ---------------------------------------------------------------------------------------------------------------------------------------------------


// ### Mouse ###
// [+] ---------------------------------------------------------------------------------------------------------------------------------------------------
	// FUNZIONE che restituisce la posizione del mouse all'interno del documento corrente
	function getMousePos(e){if(!e)e=window.event;var S=getPageScroll(),pX=e.pageX,pY=e.pageY,cX=e.clientX,cY=e.clientY,L="scrollLeft",T="scrollTop";return(pX||pY)?[pX,pY]:(cX||cY)?[cX+S[0],cY+S[1]]:[0,0]}
	
	// FUNZIONE che consente di eseguire una funzione su un elemento all'evento della rotellina del mouse
	// ES: 
	//	onDomLoad(
	//		function(){
	//			onMouseWheel(
	//				"test",
	//				function(delta){
	//					var fs=toInt(getStyle(this,'fontSize'));
	//					if(isNaN(fs))fs=10;
	//					setStyle(this,'fontSize',fs+delta+"px")
	//				}
	//			)
	//		}
	//	)
	function onMouseWheel(el,FN){el=ID(el);function onWheel(e){var D=0,W=e.wheelDelta,d=e.detail;if(W){D=W/120;if(window.opera)D=-D}else if(d)D=-d/3;if(D)FN.call(el,D);if(e.preventDefault)e.preventDefault();e.returnValue=false;return false}(el.addEventListener&&!window.opera)?el.addEventListener("DOMMouseScroll",onWheel,false):el.onmousewheel=(function(b){return function(E){if(!E)E=window.event;if(b)b.call(el,E);return onWheel(E)}})(el.onmousewheel)}
// [-] ---------------------------------------------------------------------------------------------------------------------------------------------------


// ### Varie ###
// [+] ---------------------------------------------------------------------------------------------------------------------------------------------------
	// FUNZIONE che effettua una chiamata di una funzione da codice
	function $exec(fn){if(isFunction(fn))fn.call()}
	
	// FUNZIONE che effettua il countdown visivo o non eseguendo al termine di questo la funzione specificata
	// INPUT: 1) (int) numero di secondi di countdown
	//		2) (fn ) funzione di servizio "function(){...}" contenente il codice o funzione da eseguire al termine del countdown
	//		3) (rif) riferimento all'elemento (tramite id) dove visualizzare dinamicamente il countdown
	function countdownExec(sec,fn,el){sec--;sec==0?$exec(fn):timer(function(){countdownExec(sec,fn,el)},1000);if(el)html(ID(el),sec)}
	
	// FUNZIONE che mette in pausa l'engine javascript per un numero di millisecondi specificato
	function pause(ms){var nw=new Date(),ext=nw.getTime()+ms;while(true){nw=new Date();if(nw.getTime()>ext)return}}
	
	// FUNZIONE alias di confirm()
	function conferma(q,FNy,FNn){$exec(confirm(q)?FNy:FNn)}
	
	// FUNZIONE che effettua il redirect ad una pagina da javascript
	function redirect(url){window.location.href=url}
	
	// FUNZIONE che ricarica la pagina corrente (refresh)
	function reLoad(){window.location.reload()}
	
	// FUNZIONE che consente di modificare al volo un link
	function modLink(id,txt,url){html(id,txt).href=url}
// [-] ---------------------------------------------------------------------------------------------------------------------------------------------------


// ### Ajax ###
// [+] ---------------------------------------------------------------------------------------------------------------------------------------------------
	// FUNZIONE che istanzia l'oggetto XMLHTTP per le richieste AJAX
	function XMLHttp(){return window.XMLHttpRequest?new XMLHttpRequest():new ActiveXObject("Microsoft.XMLHTTP")||new ActiveXObject("Msxml2.XMLHTTP")}
	
	// array js globale che tiene traccia delle risposte ajax al'interno di un documento
	var AjxR$=[]; 
	
	// FUNZIONE che imposta l'identificativo (indice) della corrente richiesta AJAX
	function setAjaxIndex(){return AjxR$.length}
	
	// FUNZIONE che rileva la risposta AJAX in base al relativo indice impostato con "setAjaxIndex()"
	// N.B: 	onde evitare che nella risposta appaiano dei caratteri incomprensibili, prima di "stampare" la risposta AJAX sul documento ...
	//		... accertarsi di effettuare (nello script che elabora la risposta) l'encode dei caratteri speciali "ES PHP --> htmlentities($testo_risposta)"
	function getAjaxResponse(ajxIndx){return AjxR$[ajxIndx]}
	
	// FUNZIONE che effettua la richiesta AJAX
	// INPUT: 1) (str ) url --> percorso dello script al quale inviare la richiesta ajax
	//		2) (str ) mtd [GET|POST] --> metodo della richiesta ajax
	//		3) (str ) trg [alert()|eval()|id|''] --> eventuale id dell'elemento del documento corrente dove vusializzare la corrente risposta ajax:
	//				A) "alert" -> se specificato, indica alla funzione di visualizzare in una finestra di dialogo alert() la risposta ajax
	//				B) "eval()" -> se specificato, indica alla funzione di eseguire (valutare) il codice JS restituito dalla risposta ajax
	//				C) id_elemento -> se specificato, indica alla funzione di visualizzare la risposta all'interno dell'elemento dell'elemento avente l'ID specificato
	//				D) '' -> se non viene specificato nulla, la funzione non visualizza il risultato dell'elaborazione ma lo esegue in background
	//		4) (fn  ) onLoading --> eventuale funzione da eseguire durante l'elaborazione della richiesta ajax
	//		5) (fn  ) onComplete --> eventuale funzione da eseguire al termine dell'elaborazione della richiesta ajax
	//		6) (int ) indx --> eventuale indice della richiesta corrente. Se non specificato, la risposta non viene indicizzata nell'array globale delle risposte e quindi non si potrà farvi riferimento al di fuori della funzione
	//		7) (bool) xml --> se impostato a true indica che la risposta alla richiesta sarà codificata in XML 
	//
	// OUTPUT: (bool) TRUE se la richiesta ajax ha avuto esito positivo, FALSE se si sono verificati problemi
	//
	// N.B: 	onde evitare che nella risposta appaiano dei caratteri incomprensibili, prima di "stampare" la risposta AJAX sul documento ...
	//		... accertarsi di effettuare (nello script che elabora la risposta) l'encode dei caratteri speciali "ES PHP --> htmlentities($testo_risposta)"
	function ajaxRequest(url,par,mtd,trg,onLoading,onComplete,indx,xml){
		var r,ERR,R=XMLHttp(),i,p='',L,X="[Ajax Error]: ",x=isSet(indx),M=X+'Il tuo browser non supporta XMLHTTP';
		mtd=upper(mtd);
		$exec(onLoading);
		if(R){
			for(i in par)p+=i+"="+encodeURIComponent(par[i])+"&";
			p+='noCh='+$random(0,99999);
			L=p.length;
			if(mtd=='POST'){
				R.setRequestHeader("Content-type","application/x-www-form-urlencoded")
			}else{
				url+='?'+p;
				p=''
			}
			R.open(mtd,url,true);
			R.onreadystatechange=function(){
				if(R.readyState==4){
					ERR=R.status!=200?1:0;
					r=ERR?X+R.statusText:xml?R.responseXml:R.responseText;
					trg=="alert()"?alert(r):trg=="eval()"?eval(ERR?"alert(r)":r):!trg?"":html(trg,r);
					if(x)AjxR$[indx]=r;
					$exec(onComplete)
				}
			};
			R.setRequestHeader("Content-length",L);
			R.setRequestHeader("connection","close");
			R.send(p);
			return true
		}else{
			if(x)AjxR$[indx]=M;
			alert(M);
			return false
		}
	}
	
	// FUNZIONE che effettua una richiesta AJAX inviando i valori dei campi delimitati da un determinato BOX o FORM
	// INPUT:	1) (str ) idFrm --> id del BOX o FORM all'interno dei quali vi sono i valori dei campi da inviare
	//		2) (str ) url --> percorso dello script al quale inviare la richiesta ajax
	//		3) (str ) mtd [GET|POST] --> metodo della richiesta ajax
	//		4) (str ) trg [alert()|eval()|id|''] --> eventuale id dell'elemento del documento corrente dove vusializzare la corrente risposta ajax:
	//				A) "alert" -> se specificato, indica alla funzione di visualizzare in una finestra di dialogo alert() la risposta ajax
	//				B) "eval()" -> se specificato, indica alla funzione di eseguire (valutare) il codice JS restituito dalla risposta ajax
	//				C) id_elemento -> se specificato, indica alla funzione di visualizzare la risposta all'interno dell'elemento dell'elemento avente l'ID specificato
	//				D) '' -> se non viene specificato nulla, la funzione non visualizza il risultato dell'elaborazione ma lo esegue in background
	//		5) (fn  ) onLoading --> eventuale funzione da eseguire durante l'elaborazione della richiesta ajax
	//		6) (fn  ) onComplete --> eventuale funzione da eseguire al termine dell'elaborazione della richiesta ajax
	//		7) (int ) indx --> eventuale indice della richiesta corrente. Se non specificato, la risposta non viene indicizzata nell'array globale delle risposte e quindi non si potrà farvi riferimento al di fuori della funzione
	//		8) (bool) xml --> se impostato a true indica che la risposta alla richiesta sarà codificata in XML 
	//
	// OUTPUT: (bool) TRUE se la richiesta ajax ha avuto esito positivo, FALSE se si sono verificati problemi
	//
	// N.B: 	onde evitare che nella risposta appaiano dei caratteri incomprensibili, prima di "stampare" la risposta AJAX sul documento ...
	//		... accertarsi di effettuare (nello script che elabora la risposta) l'encode dei caratteri speciali "ES PHP --> htmlentities($testo_risposta)"
	function ajaxForm(idFrm,url,mtd,trg,onLoading,onComplete,indx,xml){
		var E=TAGS(['INPUT','TEXTAREA','SELECT'],idFrm),P={},i;
		for(i=0;i<E.length;i++)if(isValuable(E[i]))P[E[i].name]=getValue(E[i]);
		return ajaxRequest(url,P,mtd,trg,onLoading,onComplete,indx,xml)
	}
// [-] ---------------------------------------------------------------------------------------------------------------------------------------------------


// ### Info Client/Browser ###
// [+] ---------------------------------------------------------------------------------------------------------------------------------------------------
	// FUNZIONE che restituisce le informazioni sul documento e la pagina corrente
	// INPUT: nessuno
	//
	// OUTPUT: (arr) array contenente nell'ordine [titolo, url, referrer, dominio, data modifica, cookie attivi]
	function docInfo(){var d=document;return[d.title,d.URL,d.referrer,d.domain,d.lastModified,d.cookie]}
	
	// FUNZIONE che restituisce le informazioni sullo schermo del client
	// INPUT: nessuno
	//
	// OUTPUT: (arr) array contenente nell'ordine [larghezza, altezza, numero di colori]
	function screenInfo(){var s=screen;return[s.width,s.height,s.colorDepth||s.pixelDepth]}
	
	// FUNZIONE che restituisce l'user agent del browser
	function nav(){return lower(navigator.userAgent)}
	
	// FUNZIONE che verifica se il browser è DOM capable o meno
	function isDom(){return document.getElementById?true:false}
	
	// FUNZIONE che verifica se il browser è AJAX capable o meno
	function isAjax(){return XMLHttp()?true:false}
	
	// FUNZIONE che consente di navigare nella cronologia del browser
	// INPUT: 1) (int) --> numero (signed) della pagina precedente o successiva (visitate) alla quale tornare 
	// 
	// OUTPUT: nessuno, la funzione salta direttamente al numero di pagina selezionato
	function history(n){window.history.go(n)}
	
	// FUNZIONE che indica se il browser del client è Konqueror
	function isKonqueror(){return inString(nav(),'konqueror')}
	
	// FUNZIONE che indica se il browser del client è Safari
	function isSafari(){return inString(nav(),'safari')}
	
	// FUNZIONE che indica se il browser del client è Opera
	function isOpera(){return window.opera}
	
	// FUNZIONE che indica se il browser del client è WebTv
	function isWebTv(){return inString(nav(),'webtv')}
	
	// FUNZIONE che indica se il browser del client è Internet Explorer
	function isIe(){return inString(nav(),'msie')&&!isOpera()}
	
	// FUNZIONE che indica se il browser del client è Firefox
	function isFirefox(){return inString(nav(),'firefox')}
	
	// FUNZIONE che restituisce la versione del client Internet Explorer
	function ieVersion(){return navigator.appVersion.replace(/.*?MSIE (\d\.\d).*/g,'$1')/1}
	
	// FUNZIONE che restituisce la versione del client Opera
	function operaVersion(){return isOpera()?toFloat(nav().replace(/.*opera[ \/]/,"")):false}
	
	// FUNZIONE che determina se la versione di Internet Explorer è di tipo "vecchio" (cioè se va da 0 alla versione 6 compresa)
	function isOldIe(){return nav().match(/msie [0-6]/gi)?true:false}
	
	// FUNZIONE che indica se l'OS del client è Linux
	function isLinux(){return inString(nav(),'linux')}
	
	// FUNZIONE che indica se l'OS del client è Unix
	function isUnix(){return inString(nav(),'x11')}
	
	// FUNZIONE che indica se l'OS del client è Mac
	function isMac(){return inString(nav(),'mac')}
	
	// FUNZIONE che indica se l'OS del client è Windows
	function isWin(){return inString(nav(),'win')}
	
	// FUNZIONE che indica se il client è un iPhone
	function isIPhone(){return inString(nav(),'iPhone')}
// [-] ---------------------------------------------------------------------------------------------------------------------------------------------------


// ### Inclusioni dinamiche ###
// [+] ---------------------------------------------------------------------------------------------------------------------------------------------------
	// FUNZIONE che include nella sezione <head> del documento uno script JS
	function includeJS(src){insertInto(tagHead(),createDom('script',{'language':'javascript','type':'text/javascript','src':src}))}
	
	// FUNZIONE che include nella sezione <head> del documento un foglio di stile CSS
	function includeCss(src){insertInto(tagHead(),createDom('link',{'rel':'stylesheet','type':'text/css','href':src}))}
// [-] ---------------------------------------------------------------------------------------------------------------------------------------------------


// ### Form ###
// [+] ---------------------------------------------------------------------------------------------------------------------------------------------------

	// --- SET FORM OBJ --- //
	
	// FUNZIONE che crea un <form> di invio dati
	function setForm(nm,mtd,act,upl){var e=createDom('form',{'name':nm,'id':nm,'method':mtd,'action':act});if(upl)setProperty(e,'enctype','multipart/form-data');return e};
	
	// FUNZIONE che crea un oggetto generico <input>
	function setInput(type,nm,id,val,cls,sz,maxL){var e=createDom('input',{'type':type,'name':nm,'id':id,'value':val}),a={'class':cls,'size':sz,'maxlength':maxL},i;for(i in a)if(a[i])setProperty(e,i,a[i]);return e};
	
	// FUNZIONE che crea un oggetto <textarea>
	function setTextarea(nm,id,cols,rows,cls){return createDom('textarea',{'name':nm,'id':id,'cols':cols,'rows':rows,'class':cls})};
	
	// FUNZIONE che crea un oggetto <select>
	function setSelectbox(nm,id,cls){return createDom('select',{'name':nm,'id':id,'class':cls})};
	
	// --- GET Form Obj Values --- //
	
	// FUNZIONE che dato il nome di un gruppo di radio button ne restituisce il valore selezionato
	function getRadioGroupValue(grName){var R=TAG('input'),i;for(i=0;i<R.length;i++)if(R[i].type=='radio'&&R[i].checked&&R[i].name==grName)return R[i].value}
	
	// FUNZIONE che restituisce il valore o il testo della voce selezionata allinterno di una <select>
	// INPUT: 1) (var ) riferimento all'oggetto select
	//		2) (bool) txt [true|false/""] (default "") --> se impostato a true fa in modo che la funzione restituisca il testo della option selezionata
	// 
	// OUTPUT: (var) valore o testo della selezione
	function getSelected(el,txt){var e=ID(el);e.options[e.selectedIndex];return txt?e.text:e.value}
	
	// FUNZIONE che seleziona una voce della <select> a partire dal relativo valore
	function setSelected(el,v){var i,o=ID(el).options;for(i=0;i<o.length;i++)if(o[i].value==v)o[i].selected=true}
	
	// FUNZIONE che restituisce se l'oggetto form selezionato è diverso dal tipo 'radio' e 'checkbox'
	function isValuable(obj){var o=ID(obj);return isSet(o)&&(o.checked||!inArray(['radio','checkbox'],o.type))}
	
	// FUNZIONE che dato un'oggetto form qualsiasi, ne restituisce il relativo valore
	function getValue(obj){var v='',o=ID(obj);switch(getTag(o)){case'select':v=getSelected(o);break;case'textarea':v=o.value;break;case'input':if(isValuable(o))v=o.value;break;default:v=getRadioGroupValue(obj)}return v}
	
	// FUNZIONE che setta il valore dell'oggetto form selezionato
	function setValue(obj,v){obj=ID(obj);if(getTag(obj)=='select'){setSelected(obj,v)}else if(inArray(['checkbox','radio'],obj.type)){obj.checked=true}else{obj.value=v}}

	// FUNZIONE che indica se l'oggetto form 'radio' o 'checkbox' è spuntato o meno
	function isCheked(el){return ID(el).checked}
	
	// FUNZIONE che spunta o meno l'insieme degli oggetti o l'oggetto form 'radio' o 'checkbox' passati come argomento
	// INPUT: 1) (var ) el --> può essere:
	//				A) (str) riferimento ad un'unico oggetto
	//				B) (arr) riferimenti a più oggetti
	//		2) (bool) TF --> se true aggiunge il segno di spunta, altrimenti toglie il segno di spunta
	//
	// OUTPUT: nessuno
	function setChecked(el,TF){var A=toArr(el),i;for(i=0;i<A.length;i++)ID(A[i]).checked=TF}
	
	// FUNZIONE che disabilita/abilita l'insieme degli oggetti o l'oggetto form passati come argomento
	// Un oggetto disabilitato appare di colore grigio trasparente sul client
	// INPUT: 1) (var ) el --> può essere:
	//				A) (str) riferimento ad un'unico oggetto
	//				B) (arr) riferimenti a più oggetti
	//		2) (bool) TF --> se true disabilita l'oggetto, altrimenti abilita l'oggetto
	//
	// OUTPUT: nessuno
	function disAble(el,TF){var A=toArr(el),i;for(i=0;i<A.length;i++)ID(A[i]).disabled=TF}
	
	// FUNZIONE che disabilita/abilita l'insieme dei campi form presenti in un determinato box/form
	// Un oggetto disabilitato appare di colore grigio trasparente sul client
	// INPUT: 1) (var ) bx --> riferimento al box del quale disabilitare/abilitare i campi form
	//		2) (bool) TF --> se true disabilita, altrimenti abilita
	//
	// OUTPUT: nessuno
	function disAbleAllBox(bx,TF){disAble(TAGS(["button","input","select","textarea"],bx),TF)}
	
	// FUNZIONE che dato un'insieme di checkbox con lo stesso nome (tipo array PHP, es: "sel[]") consente di determinarne la selezione di gruppo
	// INPUT: 1) (var) frm --> identificativo o nome del form contenente l'insieme di checkbox
	//		2) (str) FldNm --> nome comune delle checkbox da selezionare
	//		3) (str) dir [all|none|inverse/""] (default "") --> indica la direttiva in base alla quale selezionare le checkbox
	//
	// OUTPUT: nessuno
	function checkAll(frm,FldNm,dir){var i,B=formId(frm).elements[FldNm];switch(dir){case'all':setChecked(B,true);break;case'none':setChecked(B,false);break;default:for(i=0;i<B.length;i++)B[i].checked=(B[i].checked)?false:true}}
	
	// FUNZIONE che dato un nome (str) restituisce l'identificativo del form
	function formId(nm){return document.forms[nm]||ID(nm)}
	
	// FUNZIONE che effettua il submit di un form 
	// INPUT: 1) (str) frm --> identificativo o nome del form
	//		2) (str) act (default "") --> eventuale action del form
	//		3) (str) mtd [post|get] (default "") --> eventuale method del form
	// 		** (act e mtd sono opzionali)
	//
	// OUTPUT: nessuno
	function submitFrm(frm,act,mtd){var f=formId(frm);if(act)f.action=act;if(mtd)f.method=mtd;f.submit()}
	
	// FUNZIONE che dato un elemento form identificabile tramite id, restituisce l'identificativo del form contenitore
	function getFormFromChild(el){var N=ID(el).parentNode;while(getTag(N)!="form")N=N.parentNode;return N}
	
	// FUNZIONE che seleziona il testo all'interno dei campi form di tipo file, text o textarea
	// INPUT: 1) (var) el --> riferimento all'oggetto form
	//
	// OUTPUT: (var) riferimento all'oggetto form
	function textSel(el){el=ID(el);el.focus();el.select();return el}
// [-] ---------------------------------------------------------------------------------------------------------------------------------------------------


// ### Scrolling ###
// [+] ---------------------------------------------------------------------------------------------------------------------------------------------------
	// FUNZIONE che restituisce le coordinate di scrolling della pagina [x,y]
	function getPageScroll(){var d=document,w=window,dB=d.body,dd=d.documentElement,L="scrollLeft",T="scrollTop",y=w.pageYOffset;return isNumber(y)?[w.pageXOffset,y]:(dB&&(dB[L]||dB[T]))?[dB[L],dB[T]]:(dd&&(dd[L]||dd[T]))?[dd[L],dd[T]]:[0,0]}

	// FUNZIONE che effettua lo scrolling al punto x,y del documento
	function setScroll(x,y){window.scrollTo(x,y)}
	
	// FUNZIONE che effettua lo scrolling in corripsondenza dell'elemento specificato
	function goToEl(el){var A=getPos(el);setScroll(A[0],A[1])}
// [-] ---------------------------------------------------------------------------------------------------------------------------------------------------

// ### Inibizioni ###
// [+] ---------------------------------------------------------------------------------------------------------------------------------------------------
	// FUNZIONE che disabilita la selezione del testo all'interno in un determinato elemento
	function disableSelection(el,curStyle){var e=ID(el),s=e.style,c=curStyle;e.onselectstart=function(){return false};e.unselectable="on";s.MozUserSelect="none";s.cursor=c?c:"default"}
	
	// FUNZIONE che disabilita il menu contestuale del browser (non funzione con opera)
	function disableContextMenu(el){(el?ID(el):tagBody()).oncontextmenu=function(){return false}}
// [-] ---------------------------------------------------------------------------------------------------------------------------------------------------


// ### Immagini ###
// [+] ---------------------------------------------------------------------------------------------------------------------------------------------------
	// FUNZIONE che carica un'immagine e ne restituisce l'identificativo
	// INPUT: 1) (str) src --> path dell'immagine da creare
	//		2) (arr) attr (default "") --> eventuale array associativocontenente gli attributi da associare all'immagine
	//		3) (fn ) OnL (default "") --> eventuale codice da eseguire dopo che l'immagine è stata caricata
	//
	// OUTPUT: (obj) riferimento all'oggetto immagine
	function newImg(src,attr,OnL){var i=new Image();i.src=src;if(attr)setProperties(i,attr);if(OnL)i.oncomplete=$exec(OnL);return i}
	
	// FUNZIONE che cambia gli attributi di un'immagine
	// INPUT: 1) (var) id --> riferimento all'immagine
	//		2) (arr) attr --> array contenente gli attributi da applicare/modificare all'immagine
	//		3) (fn ) OnL (default "") --> eventuale codice da eseguire dopo che l'immagine è stata caricata
	// 
	// OUTPUT: nessuno
	function modImg(id,attr,OnL){setProperties(id,attr);if(OnL)ID(id).oncomplete=$exec(OnL)}
	
	// FUNZIONE che effettua il preloading delle immagini passate come argomento
	// INPUT: N) (str) --> n argomenti (stringhe) ognuno corrispondente al percorso delle immagini da precaricare
	//
	// OUTPUT: nessuno
	function preloadImgs(/* 'img1','img2','imgN' */){foreach(arguments,function(I){newImg(I)})}
	
	// FUNZIONE che effettua il preloading delle immagini con la possibilità di visualizzare il contatore dinamico delle immagini caricate e di settare l'evento onload per il caricamento complessivo di queste
	// INPUT: 1) (arr) imgs --> array contenente i percorsi delle diverse immagini da precaricare es: ['img1','img2,'imgN']
	//		2) (var) cnt (default "") --> eventuale riferimento all'oggetto per la visualizzazione in "real time" dello stato di caricamento delle immagini
	//		3) (fn ) OnL (default "") --> eventuale codice da eseguire dopo che tutte le immagini specificate sono state caricate
	// 
	// OUTPUT: nessuno
	function loadImgs(imgs,cnt,OnL){
		var i,A=[],L=[],c=0;
		function chkL(){
			var j,I,T=A.length;
			if(c==T){if(OnL)$exec(OnL);$clear(I);return}
			for(j in A)if(!L[j]&&A[j].complete){L[j]=true;c++}
			if(cnt)html(cnt,'Immagine '+arrRecurrence(L,true)+' di '+T);
			I=timer(function(){chkL()},10)
		}
		for(i in imgs){A[i]=newImg(imgs[i]);L[i]=false}
		chkL()
	}
// [-] ---------------------------------------------------------------------------------------------------------------------------------------------------


// ### Temporizzatori ###
// [+] ---------------------------------------------------------------------------------------------------------------------------------------------------
	/*
	Che differenza c'è tra setTimeout() e setInterval() ?
		- setTimeout() esegue la funzione indicatagli una sola volta dopo il tempo prefissato, 
		- setInterval() esegue la funzione indicatagli periodicamente:
	
	ES: 	l'istruzione che segue, esegue "TuaFunzione()" dopo 3 secondi per una sola volta: [ timer = setTimeout('TuaFunzione()',3000); ]
		questa invece la esegue ogni 3 secondi: [ period = setInterval('TuaFunzione()',3000); ]
	
	Tutti e due i temporizzatori richiedono che il tempo sia espreso in millisecondi e possono essere bloccati usando rispettivamente:
	
	- clearTimeout(timer) per setTimeout() (la funzione non viene eseguita neanche una volta)
	- clearInterval(period) per setInterval() (la funzione non viene più eseguita)
	*/
	
	// FUNZIONE alias della fn JS "setTimeout()" per eseguire porzioni di codice un'unica volta dopo un tempo prefissato
	function timer(FN,ms){return setTimeout(FN,ms)}
	
	// FUNZIONE alias della fn JS "setInterval()" per eseguire porzioni di codice ciclicamente (ripetutamente) ad intervalli prefissati
	function loop(FN,ms){return setInterval(FN,ms)}
	
	// FUNZIONE che effettua il clear dei temporizzatori (sia Timeout che Interval)
	function $clear(i){clearTimeout(i);clearInterval(i)}
// [-] ---------------------------------------------------------------------------------------------------------------------------------------------------


// ### iFrame ###
// [+] ---------------------------------------------------------------------------------------------------------------------------------------------------
	// FUNZIONE che crea un iFrame dando la possibilità di settarne gli attributi
	// INPUT: 1) (str) id --> id da attribuire all'iframe
	//		2) (str) src --> percorso o url della pagina da caricare all'interno dell'iframe
	//		3) (fn ) onloading (default "") --> eventuale codice da eseguire durante il caricamento del contenuto dell'iFrame
	//		4) (fn ) oncomplete (default "") --> eventuale codice da eseguire al termine del caricamento del contenuto dell'iframe
	//		5) (arr) attrib (default "") --> eventuale array associativo contenente gli attributi del tag <iframe>
	//
	// OUTPUT: (var) riferimento all'oggetto iFrame appena creato ...
	// .. N.B: per inserire nel documento l'iframe così creato, utilizzare le funzioni: html() , insertInto() ,insertBefore(), insertAfter(), replaceDom()
	function setIframe(id,src,onloading,oncomplete,attrb){$exec(onloading);var i=setProperties(createDom('iframe',{'src':src,'id':id,'name':id}),attrb);if(isFunction(oncomplete)){addEvent(i,isIe()?'readystatechange':'load',oncomplete)}return i}

	// FUNZIONE che dall'interno di un iFrame restituisce il riferimento ad un elemento esterno del parent
	// INPUT: 1) (var) el --> riferimento all'elemento contenuto nel documento del parent dell'iframe
	//
	// OUTPUT: (var) riferimento ad un elemento esterno del parent
	//
	// N.B: Questa FN va richiamata dall'interno dell'iframe verso un elemento contenuto nel documento del parent.
	// ES : iframeParentEl('citta').value="Roma"; --> assegna dall'iframe all'elemento del documento parente con id 'citta' il valore "Roma"
	function iframeParentEl(el){el=ID(el);return parent.document.el}

	// FUNZIONE che restituisce il riferimento al document del contenuto dell'iFrame:
	// INPUT: 1) (var) ifr --> riferimento all'iframe
	//
	// OUTPUT: (var) riferimento al document del contenuto dell'iFrame
	//
	// N.B: Questa FN va richiamata dall'esterno dell'iframe.
	// ES : 	1) iframeDocument('ifrX').title --> restituisce il title del documento caricato all'interno dell'iFrame
	// 		2) ID('btn',iframeDocument('ifrX')).value --> restituisce il value dell'elemento con id 'btn' che è all'interno dell'iFrame 'ifrX'
	//		3) iframeDocument('ifrX').URL --> restituisce l'url del documento caricato all'interno dell'iframe
	function iframeDocument(ifr){var i=ID(ifr),d=i.contentWindow||i.contentDocument;if(d.document)d=d.document;return d}
// [-] ---------------------------------------------------------------------------------------------------------------------------------------------------


// ### LISTE ###
// [+] ---------------------------------------------------------------------------------------------------------------------------------------------------
	// FUNZIONE che restituisce riguardanti: profondità massima, l'eventuale distanza di un elemento dalla radice e l'eventuale distanza di un elemento dalla fine del proprio ramo 
	// INPUT: 1) (var) lst --> riferimento alla lista da scansire
	//		2) (var) toEl (default "") --> eventuale nodo del quale si voglia sapere il relativo posizionamento (nodo-foglia) all'interno della lista
	//
	// OUTPUT: (arr) [profondità max della lista, eventuale distanza dalla radice (-1 se non trovato/cercato), eventuale distanza dalla foglia (-1 se non trovato/cercato)]
	function getTreeDepth(lst,toEl){var L=0,c=-1,r=-1,l=ID(lst),s=ID(toEl),i,N=getTag(l),cl=TAG(N,l),ct,M=Math.max;for(i=0;cl[i];i++)L=M(L,getTreeDepth(cl[i])[0]+1);if(s){c++;r++;ct=TAG(N,s);for(i=0;ct[i];i++)r=M(r,getTreeDepth(lst,ct[i])[2]+1);while(s!=l){if(getTag(s)==N)c++;s=s.parentNode}}return[L,c,r]}
	
	// FUNZIONE che traccia a partire dalla radice della lista, il percorso dei nodi per raggiungere un determinato sotto-nodo
	// INPUT: 1) (var) lst --> riferimento alla lista
	//		2) (var) src --> riferimento al nodo/foglia da cercare all'interno della lista
	//
	// OUTPUT: array contenente i riferimenti dei nodi che è necessario percorrere per raggiungere "src" a partire dalla radice di "lst"
	function traceTree(lst,src){var R=[],l=ID(src);do{if(getTag(l)!=getTag(lst))R.push(l);l=l.parentNode}while(l!=ID(lst));return R.reverse()}
	
	// FUNZIONE che restituisce l'elenco degli elementi (<li>) base (figli) di una lista o di un nodo di questa
	// INPUT: 1) (var) lst --> riferimento alla lista
	//		2) (var) nId --> eventuale nodo della lista del quale ricavare i figli (se non specificato vengono restituiti i figli della lista
	//
	// OUTPUT: (arr) array contenente i primi nodi della lista (<li>)
	// ES: 
	/* 
		<ul id='lista'>
			<li id='n1'></li>
			<li id='n2'>
				<ul>
					<li id='n11'></li>
					<li id='n12'></li>
				</ul>
			</li>
			<li id='n3'>
				<ul>
					<li id='n21'></li>
				</ul>
			</li>
		</ul>
		
		// La funzione restituisce:
		1) getFirstLI('lista') --> (arr) [rif n1, rif n2, rif n3]
		2) getFirstLI('lista','n2') --> (arr) [rif n11, rif n12]
	*/
	function getFirstLI(lst,nId){var R=[],l=nId?getFirst(nId):lst,F=getFirst(l),L=getLast(l);R.push(F);while(F!=L)R.push(F=getNext(F));return R}
	
	// FUNZIONE che restituisce i riferimenti ai nodi di una lista
	// INPUT: 1) (var) lst --> riferimento alla lista da scansire
	//		2) (int) n (default 1) numero di parent da attraversare per determinare il nodo d'interesse
	//
	// OUTPUT: (arr) array contenente i riferimenti ai nodi della lista selezionata
	// USO: ES 1) utile per determinare all'interno di un menu, i nodi ai quali applicare il simbolo "nodo"
	function getSubNodes(lst,n){var N=TAG("ul",lst),i,A=[];for(i=0;i<N.length;i++)A.push(getParent(N[i],n));return A}
	
	// FUNZIONE che restituisce una collection contenente tutti gli elementi <li> di una lista XHTML
	// INPUT: 1) (var) lst --> Riferimento alla lista
	//
	// OUTPUT: (arr) collection contenente tutti gli elementi <li> di una lista XHTML
	function getAllLI(lst){return TAG('li',lst)}
// [-] ---------------------------------------------------------------------------------------------------------------------------------------------------


// ### DIV ###
// [+] ---------------------------------------------------------------------------------------------------------------------------------------------------
	// FUNZIONE che disabilita e abilita la scrollbar del browser
	// INPUT: 1) (bool) hide [true|false/""] (default "") --> se true disabilita e quindi elimina la scrollbar del browser altrimenti (false) la abilita
	//
	// OUTPUT: nessuno
	function disableScrollBar(hide){
		var S=getPageScroll();
		TAG('html')[0].style.overflow=hide?'hidden':'auto';
		setScroll(S[0],S[1]);
		//if(isOpera()){onMouseWheel(TAG('html')[0],hide?function(){setScroll(S[0],S[1])}:function(){return})}
	}
	
	// FUNZIONE che crea un DIV (se non presente), lo accoda nel relativo "parent" e ne restituisce il relativo identificativo
	// INPUT: 1) (str) iD --> nome da attribuire all'id del div
	//		2) (var) parent --> riferimanto all'elemento parent all'interno del quale inserire il DIV
	//		3) (str) cls (default "") --> eventuali classi CSS da attribuire al div
	//		4) (str) style (default "") --> eventuale stile da applicare al DIV
	//
	// OUTPUT: (var) riferimento al DIV
	// .. N.B: per inserire nel documento il DIV così creato, utilizzare le funzioni: html() , insertInto() ,insertBefore(), insertAfter(), replaceDom()
	function DIV(iD,parent,cls,style){
		var d=ID(iD);
		if(!d){insertInto(parent,createDom('div',{'id':iD,'class':cls||'','style':style||''}));d=ID(iD)}
		return d
	}
	
	// FUNZIONE che crea un layer (<div>), lo accoda nel relativo "parent" e ne restituisce il relativo identificativo
	// INPUT: 1) (str) iD --> nome dell'id che si vuole assegnare al layer
	//		2) (var) parent --> riferimento all'elemento parent all'interno del quale si vuole inserire il layer
	//		3) (str) cls (default "") --> eventuali classi CSS da attribuire al layer
	//		4) (int) x --> posizione x (completa di unità di misura)
	//		5) (int) y --> posizione y (completa di unità di misura)
	//		6) (str) style (default "") --> eventuale stile da applicare al DIV
	//
	// OUTPUT: (var) riferimento al layer appena creato
	//
	// Versione precedente della funzione:
	//
	//	function layer(iD,parent,cls,style){
	//		var d=DIV(iD,parent,cls,style);
	//		if(isOldIe()){hideShowSelect(true);hideShowSelect(false,d)}
	//		return d
	//	}
	function layer(iD,parent,cls,x,y,style){
		var d=DIV(iD,parent,cls,'position:absolute;left:'+x+';top:'+y);
		setStyles(d,style);
		if(isOldIe()){hideShowSelect(true);hideShowSelect(false,d)}
		return d
	}
	
	// FUNZIONE che crea un overlay (DIV full page al di sopra degli altri) all'interno del documento
	// INPUT: 1) (str) iD --> nome dell'id che si vuole assegnare al layer
	//		2) (str) bgcol --> codice esadecimale del colore di sfondo del layer
	//		3) (str) opacity (default "") --> trasparenza dell'overlay
	//		4) (int) zInd --> indice sovrapposizione nel documento
	//		5) (str) style (default "") --> eventuale stile da applicare
	//
	// OUTPUT: (var) riferimento all'overlay appena creato
	// 
	// Versione precedente della funzione:
	//
	//	function overlay(iD,bgcol,opacity,zInd,style){
	//		var d=DIV(iD,tagBody(),'',"position:fixed;z-index:"+(zInd||getMaxZindex('*')+1)+";background-color:"+bgcol+";opacity:"+opacity+";width:100%;height:100%;left:0;top:0"+(style?';'+style:''));
	//		if(isOldIe()){function B(){d.style.height=bodySize()[2]+'px'}d.style.position='absolute';hideShowSelect(true);hideShowSelect(false,d);B();addEvent(window,'resize',B)}
	//		return d
	//	}
	function overlay(iD,bgcol,opacity,zInd,style){
		var ieW=isOldIe()&&isWin();
		var d=DIV(iD,tagBody(),'',"position:"+(ieW?"absolute":"fixed")+";z-index:"+zInd+";background-color:"+bgcol+";opacity:"+opacity+";width:100%;height:100%;left:0;top:0");
		if(ieW){function B(){d.style.height=bodySize()[2]+'px'}hideShowSelect(true);hideShowSelect(false,d);B();addEvent(window,'resize',B)}
		return d
	}
	
	// FUNZIONE che crea un overlay (DIV full page al di sopra degli altri) all'interno del documento
	// INPUT: 1) (bool) show --> se true visualizza l'overlay, altrimenti lo nasconde
	//		2) (str ) bgcol --> codice esadecimale del colore di sfondo del layer
	//		3) (str ) opacity (default "") --> trasparenza dell'overlay
	//		4) (int ) zInd --> indice sovrapposizione nel documento
	//
	// OUTPUT: (var) riferimento all'overlay appena creato
	// 
	function advOverlay(show,bgcol,opacity,zInd){
		var d=overlay('darkScreen',bgcol||'#000000',opacity||'0.60',zInd,'overflow:hidden;display:none');
		setDisplay(d,!show);
		addEvent(d,'click',function(){hideLayer(d)});
		return d
	}
	
	// FUNZIONE che in un solo colpo nasconde i layer elencati
	// INPUT: 1) (var) iD --> singolo o insieme (array) dei riferimenti ai layer da nascondere
	// 
	// OUTPUT: nessuno
	function hideLayer(iD){iD=toArr(iD);for(var i in iD)setDisplay(iD[i],true);if(isOldIe())hideShowSelect(false)}
// [-] ---------------------------------------------------------------------------------------------------------------------------------------------------


// ### DATE/TIME ###
// [+] ---------------------------------------------------------------------------------------------------------------------------------------------------
	
	// -- [+] Set di array dei mesi e dei giorni
	var monthArrayIt=["","Gennaio","Febbraio","Marzo","Aprile","Maggio","Giugno","Luglio","Agosto","Settembre","Ottobre","Novembre","Dicembre"];
	var monthArrayEn=['','January','February','March','April','May','June','July','August','September','October','November','December'];
	var daysArray=["Domenica","Lunedì","Martedì","Mercoledì","Giovedì","Venerdì","Sabato"];
	// -- [-]
	
	// FUNZIONE che restiuisce il numero dei giorni del mese selezionato
	// INPUT: 1) (int) mese --> mese da considerare
	//		2) (int) anno --> anno da considerare
	//
	// OUTPUT: (int) numero di giorni del mese corrente
	function getMonthDays(mese,anno){return 32-new Date(anno,mese-1,32).getDate()}

	// FUNZIONE che verifica se l'anno specificato è bisestile
	// INPUT: 1) (int) --> anno di riferimento
	//
	// OUTPUT: (bool) la funzione restituisce true se l'anno è bisestile, false se non lo è
	function isLeap(anno){return getMonthDays(2,anno)==29}

	// FUNZIONE che converte data e ora forniti in input nella data formato JS 
	// INPUT: 1) (int) Y --> anno della data
	//		2) (int) M --> mese della data
	//		3) (int) D --> giorno della data
	//		4) (int) h --> ora della data
	//		5) (int) mn --> minuti della data
	//		6) (int) s --> secondi della data
	//
	// OUTPUT: (str) data in formato JS da dare in pasto alle funzioni che ne necessitano
	function date2str(Y,M,D,h,mn,s){return D+" "+monthArrayEn[M].slice(0,3)+" "+Y+" "+[h,mn,s].join(":")}

	// FUNZIONE che setta una data nel formato javascript -> "Fri Nov 30 2007 17:15:53 GMT+0100 (ora solare Europa occidentale)
	// INPUT: 1) (str) date (default "") --> eventuale data generata dalla funzione date2str()
	//
	// OUTPUT: (data) data in formato JS
	function dateSet(date){return date?new Date(date):new Date()}
	
	// FUNZIONE che a partire da una data restituisce un Array contenente data e ora scomposti
	// INPUT: 1) (data) date (default "") --> eventuale data nel formato JS. Se non specificata viene considerata la data odierna
	//		2) (bool) pad [true|false] (default false) --> se true indica di anteporre lo zero a mesi,giorni,ore,minuti e secondi quando questi sono minori di 10
	//
	// OUTPUT: (arr) array con la data scomposta nell'ordine: [YYYY, MM, DD, hh, mm, ss]
	function getArrDate(date,pad){var d=dateSet(date);T=[d.getFullYear(),d.getMonth()+1,d.getDate(),d.getHours(),d.getMinutes(),d.getSeconds()];if(pad==true)for(var i in T)T[i]=strPad(T[i],2,"0");return T}

	// FUNZIONE che a partire da una data JS restituisce la data "estesa"
	// INPUT: 1) (data) date (default "") --> eventuale data nel formato JS. Se non specificata viene considerata la data odierna
	//
	// OUTPUT: (str) data "estesa" es: "Sabato 01 DICEMBRE 2007"
	function dataEstesa(date){var D=getArrDate(date);return GetWeekDay(date)+" "+D[2]+" "+upper(monthArrayIt[D[1]])+" "+D[0]}

	// FUNZIONE che a partire da una dataOra JS restituisce la stessa in formato numerico (YYYYMMDDhhmmss)
	// INPUT: 1) (data) date (default "") --> eventuale dataOra nel formato JS. Se non specificata viene considerata la dataOra dell'istante
	//
	// OUTPUT: (int) data in formato numerico: YYYYMMDDhhmmss
	function date2Int(date){return toInt(getArrDate(date).join(''))}

	// FUNZIONE che consente di visualizzare un'orologio digitale dinamico a partire dalla data del server
	// INPUT: 1) (data) date --> data del server. Se PHP: <?php echo date("F d Y H:i:s") ?>
	//		2) (str ) out --> riferimento all'elemento destinato a visualizzare in realtime l'orologio dinamico
	//		3) (str ) lim --> separatore di ora,minuti,secondi
	//
	// OUTPUT: nessuno
	function liveClock(date,out,lim){html(out,arrKfilter(getArrDate(date,true),[3,4,5]).join(lim?lim:""));if(date){date=new Date(date);date.setSeconds(date.getSeconds()+1)}timer(function(){liveClock(date,out,lim)},1000)}

	// FUNZIONE che restituisce il giorno della settimana (Lunedì,Martedì,...) da una data
	// INPUT: 1) (date) data generata dalla funzione date2str() o dateSet()
	//
	// OUTPUT: (str) giorno della data (es. Mercoledì)
	// ES 1: GetDayWeek(date2str(2007,11,30)) --> Venerdì
	// ES 2: GetDayWeek(dateSet()) --> Mercoledì
	// ES 3: alert(GetDayWeek("26 Nov 2007 14:25:43")) // da lo stesso risultato di GetDayWeek("Mon, 26 Nov 2007 14:25:43"); perchè entrambi restituiscono "Lunedì"
	function GetWeekDay(date){return daysArray[dateSet(date).getDay()]}
	
	// FUNZIONE che genera una data in formato UTC
	// INPUT: 1) (int) Y --> anno della data
	//		2) (int) M --> mese della data
	//		3) (int) D --> giorno della data
	//		4) (int) h --> ora della data
	//		5) (int) mn --> minuti della data
	//		6) (int) s --> secondi della data
	//		7) (int) ms --> millisecondi della data
	//
	// OUTPUT: (int) data in formato UTC
	function time2UTC(y,m,d,h,mn,s,ms){return Date.UTC(y,m,d,h,mn,s|0,ms|0)}

	// FUNZIONE che converte una data in numero di millisecondi trascorsi dal 1 Gennaio 1970
	// INPUT: 1) (int) Y --> anno della data
	//		2) (int) M --> mese della data
	//		3) (int) D --> giorno della data
	//		4) (int) h --> ora della data
	//		5) (int) mn --> minuti della data
	//		6) (int) s --> secondi della data
	//		7) (int) ms --> millisecondi della data
	//
	// OUTPUT: (int) data in millisecondi trascorsi dal 1 Gennaio 1970
	function date2time(Y,M,D,h,mn,s,ms){return dateSet(date2str(Y,M,D,h,mn,s|0,ms|0)).getTime()}
	
	// FUNZIONE che calcola e restituisce la differenza fra due date generate con la funzione date2time() o time2UTC()
	// INPUT: 1) (int) A --> data 1 in formato time
	//		2) (int( B --> data 2 in formato time
	//
	// OUTPUT: (arr) array contenente le differenze: [anni, mesi, giorni, ore, minuti, secondi, millisecondi, ( "+" se A>B | "-" se B>A | "=" se A=B )]	
	// ES: alert( timeDiff( date2time(2007,11,06,12,30,0), date2time(2007,11,06,12,30,0) ) );
	function timeDiff(A,B){
		var R,F=Math.floor,s="=",m=1000,S=60*m,H=60*S,G=H*24;
		if(A>B){R=A-B;s="+"}else if(A==B){R=0}else{R=B-A;s="-"}
		return[F(R/G*1),F((R%G)/H*1),F(((R%G)%H)/S*1),F((((R%G)%H)%S)/m*1),F((((R%G)%H)%S)%m),s]
	}
	
	// FUNZIONE che scandisce lo scorrere perpetuo del tempo in riferimento ad una determinata data
	// INPUT: 1) (int) Y --> anno della data
	//		2) (int) M --> mese della data
	//		3) (int) D --> giorno della data
	//		4) (int) h --> ora della data
	//		5) (int) mn --> minuti della data
	//		6) (int) s --> secondi della data
	//		7) (var) out --> riferimento all'elemento all'interno del quale visualizzare il conteggio del tempo
	//		8) (fn ) FN (default "") --> eventuale codice da eseguire nell'istante in cui la data speficata coincide con quella attuale
	//
	// OUTPUT: nessuno
	function timeCountTo(Y,M,D,h,mn,s,out,FN){
		var dt=getArrDate(),df=timeDiff(date2time(dt[0],dt[1],dt[2],dt[3],dt[4],dt[5]),date2time(Y,M,D,h,mn,s));
//		df[5]=='-'?F="Mancano ":df[5]=='+'?F="Sono passati ":$exec(FN);
		if(df[5]=="=")$exec(FN);
		T=[df[0],df[1],df[2],df[3]];for(var i in T)T[i]=strPad(T[i],2,"0");
		html(out,df[5]+" "+T.join(":"));
//		html(out,F+df[0]+" giorni, "+df[1]+" ore, "+df[2]+" minuti e "+df[3]+" secondi");
		timer(function(){timeCountTo(Y,M,D,h,mn,s,out,FN)},1000)
	}

	// FUNZIONE che restituisce il numero della settimana di una data
	// INPUT: 1) (int ) Y --> anno
	//		2) (int ) M --> mese
	//		3) (int ) D --> giorno
	//		4) (bool) SUN --> indica se la settimana inizia con la Domenica:
	//			> true -> la settimana inizia con la domenica, 
	//			> false -> la settimana inizia con il lunedì
	//
	// OUTPUT: (int) numero della settimana
	function getWeek(Y,M,D,SUN){
		var a,y,m,jd,d4,L,dl,F=Math.floor;
		D=!SUN?D/1:(D/1)+1;
		Y/=1;
		M/=1;
		a=F((14-M)/12);
		y=Y+4800-a;
		m=M+(12*a)-3;
		jd=D+F(((153*m)+2)/5)+(365*y)+F(y/4)-F(y/100)+F(y/400)-32045;
		d4=(jd+31741-(jd%7))%146097%36524%1461;
		L=F(d4/1460);
		d1=((d4-L)%365)+L;
		return F(d1/7)+1
	}

	// FUNZIONE che effettua la conversione da secondi a millisecondi
	function s2ms(s){return s*1000}
	
	// FUNZIONE che effettua la conversione da minuti a secondi
	function m2s(m){return m*60}
	
	// FUNZIONE che effettua la conversione da ore a secondi
	function h2s(h){return h*3600}
	
	// FUNZIONE che effettua la conversione da giorni a secondi
	function d2s(d){return d*86400}
	
	// FUNZIONE che converte minuti, ore e giorni in secondi/millisecondi
	// INPUT: 1) (int ) n --> numero da convertire
	//		2) (str ) what --> indica il formato di origine di n:
	//			> "d" --> giorni
	//			> "h" --> ore
	//			> "m" --> minuti
	//		3) (bool) toMs [true|false] (default false) --> indica se convertire il tutto in millisecondi
	//
	// OUTPUT: (int) risultato della conversione
	function t2s(n,what,toMs){
		var a={'d':86400,'h':3600,'m':60},R=n*a[what];
		return toMs?R*1000:R
	}
// [-] ---------------------------------------------------------------------------------------------------------------------------------------------------
