﻿/*<script type="text/javascript" language="javascript"><!--*/
//#######################################
//####     F U N Z I O N I . J S     ####
//#######################################
//	08/06/2010	ver. 2.18.16.4	- [40] Funzione [HtmlPlus_PageScroller]: modificato la selezione dell'oggetto da muovere: prima si faceva un ssegnazione diretta
//				del primo nodo a partre dall'oggetto [animatedHtmlObject], siccome firefox consdera nodi anche gli spazi vuoti tra unt ag e l'atro abbiam dovuto 
//				aggiungere un ciclo che controlla se il nodo e un nodo di testo o un elemento.
//	18/05/2010	ver. 2.18.16.3	- [40] Funzione [HtmlPlus_DimensionFill]: messo TRY su invocazione comando [setExpression]. Il comando è obsoleto,
//				quindi la funzione sarà da modificare usando altri metodi per risettare la dimensione dinamicamente.
//	11/05/2010	ver. 2.18.16.2	- [40] Classe [HtmlPlus_SlideShow] funzione [Play]: aggiunto controllo sul numero di immagini, che se è una sola
//				modifico la property "repeat" in FALSE; così da fermare la ripetizione delle immagini dopo aver mostrato la prima.
//	07/05/2010	ver. 2.18.16.1	- [40] Funzioni [AddClassName] e [RemoveClassName]: corretto problema di spazi (ne aggiungeva in testa); messo ricerca
//				del ClassName non più con "Ignore Case".
//	05/05/2010	ver. 2.18.16	- [40] Modifica funzione [ReplaceArgDict]: aggiunto argomento "optO_TextArguments" che restituisce la lista degli
//				argomenti trovati nella stringa [Text]. Modificata la RegularExpression per cercare i parametri: ora accetto ogni carattere ASCII
//				dallo spazio in sù escluse le graffe.
//	13/04/2010	ver. 2.18.15	- [40] Aggiunto funzione [IsNull]; corretto classe [HtmlPlus_SlideShow]: dava problemi nel mostrare le immagini che
//				aveva già caricate.
//	13/04/2010	ver. 2.18.14	- [40] Classe [HtmlPlus_PageScroller] migliorato il funzionamento: ora è possibile indicare un "pageWidth" minore della
//				dimensione del DIV di scorrimento; ovvero posso avere 15 items, visibili 10 alla volta e indicare che ne voglio vedere 3 nuovi per pagina.
//	15/03/2010	ver. 2.18.13	- [40] Classe [HtmlPlus_Popup]: se la proprietà [abortOnClickOut] è TRUE allora il popup sichiuderà anche premendo ESC.
//	12/03/2010	ver. 2.18.12	- [40] Classe [HtmlPlus_Popup]: aggiunto possibilità di indicare se cliccando fuori dal Popup questo si deve chiduere;
//				per default la funzionalità è attivata (vedere proprietà [abortOnClickOut]).
//	02/03/2010	ver. 2.18.11.1	- [40] Corretto problema su [HtmlPlus_Popup], pulsante Abort che non funzionava in tutte le condizioni. Problema
//				sulla funzione [FindArrayItem], non funzionava proprio come doveva, rifatta da capo. Funzione [findParentObj]: migliorato il codice
//				interno e dato la possibilità di ricercare con RegExp anche sull'argomento [optTagNameFilter].
//	01/03/2010	ver. 2.18.11	- [40] Aggiunto funzioni [GetUID] e [GetLastUID], che restituiscono, come per FUNZIONI.ASP, un ID univoco. Questa
//				funzione non tiene conto della relativa funzione in VB lato server, quindi le due potrebbero, in rari casi, generare lo stesso valore.
//				Ho anche risolto un baco su [HtmlPlus_Popup], che si verificava quando si sfruttava la nuova funzionalità: apertura Popup in frame TOP.
//	18/02/2010	ver. 2.18.10	- [40] Aggiunta funzione [FindArrayItem]: cerca un Item in un array, su tutti i frame. Modificato [findObj] che ora
//				estende la sua ricerca. Modificato [HtmlPlus_Popup] che ora gli si può indicare se il popup deve apparire sul frame corrente o su [top].
//	08/02/2010	ver. 2.18.9		- [40] Aggiunta funzione [CStrRE] che codifica una stringa per poter essere cercata con una RegularExpression.
//	11/01/2010	ver. 2.18.8		- [40] Classe [HtmlPlus_ServerEval]: risolto problemi di comunicazione con "AspResponder"; migliorato modalità debug.
//	18/12/2009	ver. 2.18.7		- [40] Classe [HtmlPlus_BarcodeReader]: migliorato software, che ora ha per default (ed è in grado di accettare) una
//				lista di coppie di caratteri "preambolo"-"postambolo", per risolvere problemi con alcuni browser che interpretano alcuni caratteri ascii
//				come comandi sul browser stesso, come ad esempio "Refresh della pagina", "Aggiungi a preferiti", "Fullscreen" ecc.
//	24/11/2009	ver. 2.18.6.3	- [40] Corretto errore su [GetValue]: non riusciva a ottenere le varie parti del numero in certe condizioni.
//	24/11/2009	ver. 2.18.6.2	- [40] Corretto errore su [STDEvent]: non leggeva bene il valore [keyCode] da Firefox; corretto [getPos] che non calcolava
//				bene la posizione dell'oggetto in presenza di barre di scorrimento con "scrollLeft/Top" maggiori di ZERO.
//	17/11/2009	ver. 2.18.6.1	- [40] Corretto errore su [HtmlPlus_AutoScroll]: usavo GetCssStyle per leggere 'clientHeight', anzichè GetProperty.
//	13/11/2009	ver. 2.18.6		- [40] Aggiunta funzione [SetDailyTime] per settare l'ora ad un oggetto Date; corretto piccoli errori in varie procedure.
//	10/11/2009	ver. 2.18.5.1	- [40] Errore in [HtmlPlus_SlideShow]: calcolava la ridimensione dell'immagine credendo fosse per IMG1 anzichè IMG2; ho
//				risolto memorizzando le dimensioni delle immagini nell'item stessa.
//	23/10/2009	ver. 2.18.5		- [40] Modifica alla classe [HtmlPlus_Popup]: oggetto ombra ora è padre del contenuto, e ho dovuto togliere "opacity".
//	23/10/2009	ver. 2.18.4		- [40] Modifica alla classe [HtmlPlus_Popup], che ora usa sempre lo stile default, e poi aggiunge, se indicato, lo
//				stile personalizzato.
//	21/10/2009	ver. 2.18.3.2	- [40] Funzione [HtmlPlus_DimensionFill]: corretto baco, si usava impropriamente [GetCssStyle] per leggere "clientHeight",
//				ma questo appartiene all'oggetto HTML, e non all'oggetto [style].
//	21/10/2009	ver. 2.18.3.1	- [56] La funzione [GetCssStyle] se non esegue nessun comando restituisce [null] al posto di ['']
//	16/10/2009	ver. 2.18.3		- [40] Aggiunta funzione [GetDocInfo] che restituisce informazioni particolari sul documento; aggiunta funzione [GetCssStyle]
//				che restituisce l'effettivo valore di un attributi di stile; corretto errori di compatibilità con W3C sulle funzioni [ReplaceArgList],
//				[HtmlEncode] e [SetCssStyle], corretto problema di compatibilità su [HtmlPlus_DimensionFill], che ora usa [GetDocInfo], corretto problema
//				di compatibilità su [HtmlPlus_Positionator], che calcolava male le posizioni su Firefox.
//	13/10/2009	ver. 2.18.2		- [40] Aggiunta funzione [FileInclude]: aggiunge una inclusione di un file JS oppure CSS.
//	13/10/2009	ver. 2.18.1		- [40] Aggiunta classe [HtmlPlus_Positionator]: dato un oggetto (da posizionare), ed un insieme di altri oggetti, posiziona
//				il primo "attorno" oppure "all'interno" dell'area del secondo.
//	12/10/2009	ver. 2.18.0.1	- [40] Corretto bachi nelle procedure modificate precedentemente.
//	12/10/2009	ver. 2.18.0		- [40] Aggiunta funzione [GetValue]: dato un valore con unità di misura, restituisce il numero e UM divisi, in dictionary;
//				aggiunta funzione [CDateHtml_GetFormat], del tutto simile a quella in ASP; modificata funzione [CDateHtml], che ora supporta ogni formato
//				come in ASP; modifiche alla classe [HtmlPlus_Popup], che ora, il popup è completamente disegnato nell'elemento [content]; aggiunta al popup
//				della possibilità di usare "position:fixed": la classe non imposta più tale attributo di stile, che quindi dovrà essere fatto da CSS, su
//				valore "absolute" o "fixed"; aggiunta funzione [CDateHtml_GetFormatInfo], che restituisce informazioni sul formato data del browser;
//				modificata funzone [CDate]: ora usa [CDateHtml_GetFormat] per indicare il formato di data/ora.
//	02/10/2009	ver. 2.17.2		- [40] Aggiunta funzione [CStrXML], in analogia alla versione ASP.
//	25/07/2009	ver. 2.17.1.1	- [40] Funzione [CStrHtml]: non sostituiva gli a-capo con i relativi "<br>"; classe [HtmlPlus_Popup]: su invio comando
//				al Popup "Initialize" mancava un "CStrJS" per il valore da passare, serializzato.
//	24/07/2009	ver. 2.17.1		- [40] Classe [HtmlPlus_ServerEval]: aggiunto argomento "optDebugMode" al metodo [Run].
//	23/07/2009	ver. 2.17.0		- [40] Migliorata classe [HtmlPlus_ClipMaker] e [HtmlPlus_SlideShow].
//	23/07/2009	ver. 2.16.12	- [40] Aggiunto funzione [CDate], che cerca di convertire la data in stringa secondo il formato indicato.
//	01/07/2009	ver. 2.16.11.4	- [40] Risolto baco su [HtmlPlus_ClipMaker]: non lavorava il primo fotogramma, appena richiesto il Play.
//	26/06/2009	ver. 2.16.11.3	- [40] Funzione [CDateHtml]: corretto piccolo baco su calcolo formato "datetime".
//	16/06/2009	ver. 2.16.11.2	- [56] Modificato massimale di [HtmlPlus_VerticalFill] da 5000 a 50000px.
//	12/06/2009	ver. 2.16.11.1	- [40] Procedura [SetCookie]: corretto metodo per settare la scadenza del cookie con la scadenza della sessione.
//	05/06/2009	ver. 2.16.11	- [40] Modificata funzione [SetCookie]: aggiunto possibilità di indicare che il cookie deve scadere con lo scadere
//				della sessione, indicando l'argomento "Expire" su Null.
//	28/05/2009	ver. 2.16.10	- [40] Aggiunto funzioni [ReplaceArgList] e [ReplaceArgDict], che funzionano come quelle in "Funzioni.asp".
//	25/05/2009	ver. 2.16.9		- [56] Modificato funzione [OggettiRifDlgFind]
//	14/05/2009	ver. 2.16.8.1	- [40] Funzione [SetCssStyle]: consento che il valore di un attributo possa essere formato da ZERO caratteri; risolto
//				errore su [HtmlPlus_TextboxWithLabelInside]: il cursorse nel Textbox perdeva la posizione quando era settato un valore e successivamente
//				acquistava il focus.
//	30/03/2009	ver. 2.16.8		- [40] Aggiunta [SetClassName], che esegue le procedure [AddClassName] e [RemoveClassName] in base ad un
//				argomento.
//	26/03/2009	ver. 2.16.7.1	- [40] Risolti problemi alla funzione [HtmlPlus_DimensionFill].
//	26/03/2009	ver. 2.16.7		- [40] Aggiunta funzione [HtmlPlus_DimensionFill]: viene usata dalle HtmlPlus_VerticalFill e HtmlPlus_OrizzontalFill.
//	23/03/2009	ver. 2.16.6		- [40] Aggiunte funzioni [AddClassName], [RemoveClassName], [ContainsClassName]: servono per aggiungere, rimuovere
//				e verificare voci nel ClassName di un oggetto Html.
//	17/03/2009	ver. 2.16.5		- [40] Aggiunta funzione [CNumJS]; modificata funzione [CStrJS]: aggiunto argomento "AddDelimeters";
//				classe [STDEvent]: aggiunta possibilità di passare per argomento un altro oggetto [STDEvent], utile quando si deve invocare
//				una funzione creata per gestire un evento da un'altra procedura che gestisce già l'evento.
//	10/03/2009	ver. 2.16.4		- [40] Funzioni [HtmlPlus_OrizzontalFill] e [HtmlPlus_VerticalFill]: ora usa [SetProperty] per impostare i valori,
//				ottenendo così la possibilità di usare le funzioni anche su tag <DIV> e altri.
//	06/03/2009	ver. 2.16.3		- [40] Aggiunta funzione [CCurHtml], che per ora restituisce lo stesso valore di [CNumHtml].
//	13/02/2009	ver. 2.16.2.2	- [40] Funzioni [SerializeValue] e [DeserializeValue]: corretto problema di riconoscimento tipo
//				"Array"/"Dictionary"; aggiunto procedure [SerializeValue__ArrayColl_addArrayType] e [SerializeValue__ArrayColl_getArrayType].
//	10/02/2009	ver. 2.16.2.1	- [40] Funzioni [HtmlPlus_OrizzontalFill] e [HtmlPlus_VerticalFill]: non funzionavano correttamente quando venivano
//				usate su oggetti contenuti in un IFrame con Scrollbar dove quest'ultime non erano presenti per causa dell'oggetto controllato dalle
//				funzioni.
//	19/01/2009	ver. 2.16.2		- [56] Aggiunto funzioni[Traduci_Lingue_Index][Traduci_Lingue_LCID][Traduci_Lingue_Code][Traduci_Lingue_Count].
//	28/11/2008	ver. 2.16.1		- Funzione [CDateHtml]: aggiunto tipi formato "datetime" e "time".
//	28/11/2008	ver. 2.16.0		- Aggiunto procedure alla classe [Date] con l'uso di "prototype"; aggiunto [CreateList] e [CreateDictionary] per
//				creare oggetti Array con procedure aggiunte; rimosso classe [HtmlPlus_Grid], perchè spostata in file apposito.
//	16/09/2008	ver. 2.15.3.2	- Risolti problemi in [OggettiRif_DlgFind]: ora ho un parametro unico per configurare i comportamenti, chiamato CFG.
//	15/09/2008	ver. 2.15.3.1	- Classe [HtmlPlus_Popup]: risolto baco su calcolo posizione Popup, mancava un "break"; aggiunto controllo sui
//				valori di posizione calcolati: se la coordinata (X o Y) è miniore di 10 allora imposto a 10.
//	12/09/2008	ver. 2.15.3		- Aggiunta funzione [OggettiRif_DlgFind]: apre la maschera standard di ricerca di records OggettiRif; fatte anche
//				numerose migliorie grafiche e di funzionamento su [HtmlPlus_Popup]: aggiunta possibilità di definire la posizione del popup tramite
//				una percentuale, risolto problema dell'ombra per siti più piccoli del browser, aggiunta variabile THIS nel codice dell'IFRAME.
//	03/09/2008	ver. 2.15.2.1	- Classe [HtmlPlus_Popup]: risolto baco su ombra, che non veniva mostrata come tale in caso di animazione "Zoom".
//	25/08/2008	ver. 2.15.2		- Modifica classe [HtmlPlus_Grid]: aggiunte funzioni "SetTrSelect" e "SetTrViewed".
//	07/08/2008	ver. 2.15.1		- Modifica classe [HtmlPlus_Grid]: rinominata funzione "TrEvents_onDblClick" in "TrEvents_OpenRecord".
//	04/08/2008	ver. 2.15.0		- Aggiunta classe [HtmlPlus_Grid]: serve per dare funzionalità Java ad una tabella.
//	31/07/2008	ver. 2.14.3.1	- Corretto baco funzione [SerializeValue]
//	23/07/2008	ver. 2.14.3		- Classe [HtmlPlus_ServerEval]: aggiunta funzione [Parameters], che contiene l'array dei parametri passati; nella
//				classe [DevelopingMode_AddItem] aggiunta condizione: se "window.DevelopingMode" non è TRUE allora la classe non funziona.
//				Procedure [SerializeValue] e [DeserializeValue]: risolto baco su conversione valore EMPTY (stringa vuota).
//	11/07/2008	ver. 2.14.2		- Aggiunta classe [HtmlPlus_ServerEval]: serve ad invocare comandi lato server.
//	27/06/2008	ver. 2.14.1.3	- Modificato procedure [HtmlPlus_BarcodeReader] e [DevelopingMode_AddItem].
//	20/06/2008	ver. 2.14.1.2	- Procedure [SerializeValue] e [DeserializeValue]: risolti diversi bachi che si manifestavano quando un Array o
//				un Dictionary erano senza elementi; ho risolto anche il problema di capire in DeserializeValue se un oggetto è un Dictionary
//				o Array, soluzione però che funziona solo se l'oggetto è stato generato da SerializeValue.
//	19/06/2008	ver. 2.14.1.1	- Soluzione baco [DevelopingMode]: al momento è stata bloccata la procedura [DevelopingModeMenu_AddItem], e
//				presto si dovrà cercare il motivo dell'errore e risolverlo.
//	18/06/2008	ver. 2.14.1		- Aggiunta funzione [DevelopingModeMenu_AddItem] per gestire il menù DevelopingModeMenu, e aggiunto impiego nella
//				classe [HtmlPlus_BarcodeReader].
//	30/05/2008	ver. 2.14.0.3	- Corretti commenti qua e la..
//	20/03/2008	ver. 2.14.0.2	- Classe [HtmlPlus_Popup]: corretto baco: andava in loop poichè ogni volta richiamava l'evento OnLoad.
//	13/02/2008	ver. 2.14.0.1	- Funzione[DeserializeValue] risolto baco: non deserializzava gli Interi ma solo i Float.
//	18/01/2008	ver. 2.14.0		- Modificato Funzione [GetBrowserInfo] in modo che ritorni il tipo sistema operativo utilizzato per il dispositivo, e 
//				aggiunto funzione per vedere che tipo di hardware è utilizzato. Modificata Funzione [SetProperty] se settando opacity si utilizza un 
//				dispositivo non PC opacity non viene settata.
//	08/01/2008	ver. 2.13.0		- Aggiunta Funzione [CNumHTML], ha lo stesso funzionamento di quella esistente in VBScript.
//	27/12/2007	ver. 2.12.1.1	- Classe [HtmlPlus_Popup]: risolto baco per IE6 in caso che il contenuto sia un IFRAME.
//	27/12/2007	ver. 2.12.1		- Funzione [GetBrowserInfo]: aggiunto 'CpuSpeed' che restituisce un numero che indica la velocità del processore.
//	27/12/2007	ver. 2.12.0.2	- Funzione [toNumber]: corretto comportamento nel caso che non c'è alcun numero memorizzato nel testo passato;
//				Classe [HtmlPlus_Popup]: fatta correzione nella funzione di gestione del ridimensionamento del browser, in caso di isModal=true
//				e isOpen=false.
//	21/12/2007	ver. 2.12.0.1	- Procedure [SerializeValue] e [DeserializeValue]: corrette in caso di conversione in Array e Dictionary.
//	20/12/2007	ver. 2.12.0		- Aggiunte funzioni per la gestione dei [COOKIE], aggiunta classe [HtmlPlus_Popup], e aggiunte e corrette altre
//				piccole cose.
//	14/12/2007	ver. 2.11.1		- Aggiunta funzione [IsUndefined]. Funzione [toNumber]: corretto baco che si verificava se il numero passato era
//				già un numero.
//	07/12/2007	ver. 2.11.0		- Aggiunta classe [HtmlPlus_SlideShow] per la gestione degli slide show.
//	05/12/2007	ver. 2.10.0.1	- Corretto baco funzione CStrJS.
//	04/12/2007	ver. 2.10.0		- Aggiunta classe [HtmlPlus_ClipMaker] per la gestione delle animazioni.
//	03/12/2007	ver. 2.9.7		- Modificata funzione [HtmlPlus_Autoscroll], aggiunto la possibilità di far scorrere gli oggetti orizzontalmente.F
//	07/11/2007	ver. 2.9.6		- Aggiunta funzione [CStrJS], che funziona come quella fatta in VBScript. Aggiunta poi [ViewPointerPosition].
//	10/10/2007	ver. 2.9.5		- Aggiunta alla classe [UrlParserClass]: ho aggiunto la funzione [GetPartialUrl] che restituisce una parte percorso
//				secondo le indicazioni (true/false) passate negli argomenti.
//  03/10/2007	ver. 2.9.4.1	- Corretto baco in funzione [HtmlPlus_AnimationOnMouseEvents] e corretto baco nella funzione [ValueType]
//  18/09/2007	ver. 2.9.4		- Inserita nuova funzione [CPropertyJS] da utilizzare per trasformare il nome di una proprietà dal formato CSS
//				al formato JScript. Risolto baco su funzione [SetCssStyle], in pratica nella RegEx per segnalare un carattere "\", JScript ne
//				necessita 2. Es.: per passare "\s*" a RegEx si deve scrivere così "\\s*".
//  14/09/2007	ver. 2.9.3.2	- Modificate Funzioni [CStrUrlParam] e [StringToUrl] risolto dei bachi.
//  13/09/2007	ver. 2.9.3.1	- Modificate Funzione [SetProperty] e HtmlPlus_AnimationOnMouseEvents, risolto dei bachi.
//  06/09/2007	ver. 2.9.3		- Modificate Funzione [GetProperty], in caso che la proprietà sia 'opacity' controlliamo il browser e la settiamo
//				in base allo stesso.
//  31/08/2007	ver. 2.9.2		- Modificate le funzioni[CStrUrlParam] e [StringToUrl]  in quanto esistevano in java procedure apposite
//  27/07/2007	ver. 2.9.1		- Modificata Classe HtmlPlus_AnimationOnMouseEvents, per la gestione di parametri mozilla o Ie (vedi alpha opacity)
//  27/07/2007	ver. 2.9.0		- Aggiunte le funzioni LFill, RFill, HTMLEncode, HTMLDecode, SerializeValue, DeserializeValue. Testare la
//				serializzazione e la deserializzazione degli arary e delle dictionary.
//	23/07/2007	ver. 2.8.6		- Aggiunta funzione [TestiLiberi_OpenWindow].
//	19/06/2007	ver. 2.8.5		- Risolto Baco funzione [toNumber] aggiunto metodo .valueOf all'oggetto Number.
//	15/06/2007	ver. 2.8.4		- Aggiunta funzione [IfNull].
//	25/05/2007	ver. 2.8.3		- Funzione [GetBrowserInfo]: aggiunta Info "ScreenWidth" e "ScreenHeight".
//	23/05/2007	ver. 2.8.2.1	- Classe [HtmlPlus_AutoScroll]: risolto problema di incompatibilità con Firefox.
//	02/04/2007	ver. 2.8.2		- Classe [HtmlPlus_BarcodeReader]: ora l'Azione chiamata può sapere qual'è il KeyChars corrente.
//	30/03/2007	ver. 2.8.1		- Classe [HtmlPlus_BarcodeReader]: su lettura di un barcode, ho fatto in modo di eseguire solo una Azione.
//	28/03/2007	ver. 2.8.0		- Aggiunta classe [HtmlPlus_BarcodeReader] per leggere i codici a barre dal browser (non necessariamente da un
//				Textbox) e [IsTrue] [IsFalse] per riconoscere i valori dichiaratamente impostati su TRUE e su FALSE.
//	19/03/2007	ver. 2.7.0		- Classe [HtmlPlus_AutoScroll]: rifatta nuova versione, con possibilità di indicare un Html di separatore pagina.
//	22/01/2007	ver. 2.6.2		- Aggiunta funzione [GetBrowserInfo], e migliorata la funzione [GetProperty].
//	15/01/2007	ver. 2.6.1.1	- Modifica funzione [SetProperty]: resa compatibile con FireFox.
//	07/12/2006	ver. 2.6.1		- Aggiunte funzioni [Help_OpenWindow] e [CStrUrlParam]
//	06/12/2006	ver. 2.6.0.2	- Modifica funzione [HtmlPlus_TextboxWithLabelInside]: resa compatibile con FireFox.
//	27/11/2006	ver. 2.6.0.1	- Modifica della funzione [SetCssStyle].
//	24/11/2006	ver. 2.6.0		- Diverse modifiche. Tra cui aggiunta di STDEvent, HtmlPlus_PageScroller, GetProperty e SetProperty.
//	21/11/2006	ver. 2.5.2.1	- Modifica alla classe [UrlParserClass]: aggiunto campo objectType.
//	17/11/2006	ver. 2.5.2		- Modifica a [findObj]: aggiunta ricerca per getElementById.
//	06/10/2006	ver. 2.5.1.3	- Risolto baco IMPORTANTE nella funzione [Traduci_Varchar_Write]: non era in grado di salvare correttamente
//				il nuovo testo se questo non era la lingua di indice ZERO e se il valore Indice non era passato come numero ma come testo.
//				Ho anche migliorato in performance le procedure LTrim, RTrim e Trim.
//	11/08/2006	ver. 2.5.1.2	- Risolto piccolo problema alla funzione [SetHtmlControlValue].
//	11/08/2006	ver. 2.5.1.1	- Risolto un problema alla nuova classe [HtmlPlus_TextboxWithLabelInside]: se il form che ospita il textbox ha
//				un pulsante predefinito (che fa il send alla pressione del tasto INVIO) il textbox non riusciva a memorizzare il valore prima
//				dell'invio del form.
//	09/08/2006	ver. 2.5.1		- Sostituito "document.getElementById" con "findObj".
//	09/08/2006	ver. 2.5.0		- Aggiunta classe [HtmlPlus_TextboxWithLabelInside] per mostrare una etichetta nel Textbox quando questo è vuoto.
//	08/08/2006	ver. 2.4.0		- Aggiunte procedure [InArray] e altre per la ricerca di stringhe ed oggetti all'interno di un array;
//				corretto anche difetto alla classe [UrlParserClass]: la funzione GetPath restituiva '/' in situazioni particolari.
//	07/08/2006	ver. 2.3.1		- Migliorie alla classe [UrlParserClass]: aggiunta funxione ExistsProtocol.
//	05/07/2006	ver. 2.3.0		- Aggiunta classe [HtmlPlus_AnimationOnMouseEvents] per animare oggetti html.
//	05/07/2006	ver. 2.2.2		- Risolto piccolo problema alla funzione [SetHtmlControlValue].
//	15/06/2006	ver. 2.2.1		- Spostata procedura per aprire un allegato da Funzioni.ASP a questo file.
//	12/06/2006	ver. 2.2.0		- Aggiunte variabili che indicano il browser in uso; aggiunta classe per la riproduzione di suoni.
//	31/05/2006	ver. 2.1.2		- Migliorati i commenti...
//	03/05/2006	ver. 2.1.1		- Migliorati i commenti...
//	03/05/2006	ver. 2.1.0		- Aggiunta implementazione di funzioni ValueType e modificato SetHtmlControlValue: ora posso settare
//				un SELECT con Multisel passando un Array. Devo però implementare la funzionalità oppostua sulla funzione GetHtmlControlValue.

//Assegnano delle variabili per il riconoscimento del browser in uso.
var IE = (navigator.appVersion.indexOf("MSIE")!=-1 && document.all)? 1:0;
var NS = (navigator.appName=="Netscape" && navigator.plugins["LiveAudio"])? 1:0;
var ver4 = (IE || NS)? 1:0;

function GetBrowserInfo(InfoName) {
	var str1, cont1, cont2;
	switch (InfoName.toLowerCase()) {
		case 'name':			//il comando restituisce questo: IE7="MSIE", Firefox2="Netscape"
			str1 = navigator.appName;
			switch (str1) {
				case 'Microsoft Internet Explorer':
					return 'MSIE';
				case 'Netscape':
					return 'Netscape';
				default:
					return str1;
			}
		case 'version':			//il comando restituisce questo: IE7=4.0, Firefox2=5.0
			str1 = navigator.appVersion;
			switch (GetBrowserInfo('name')) {
				case 'MSIE':
					str1 = str1.substr(str1.indexOf(' MSIE ') + 6);
					return toNumber(str1, 0);
				case 'Netscape':
					return toNumber(str1, 0);
				default:
					return str1;
			}
		case 'screenwidth':		//restituisce la larghezza (in pixel) dell'area utile di lavoro dello schermo (tipicamente 1024)
			switch (GetBrowserInfo('name')) {
				case 'MSIE':
					return window.screen.availWidth;
				case 'Netscape':
					return window.screen.availWidth;
				default:
					return 0;
			}
		case 'screenheight':	//restituisce la larghezza (in pixel) dell'area utile di lavoro dello schermo (tipicamente 1024)
			switch (GetBrowserInfo('name')) {
				case 'MSIE':
					return window.screen.availHeight;
				case 'Netscape':
					return window.screen.availHeight;
				default:
					return 0;
			}
		case 'os':				//indica il sistema operativo. Può essere:  'Windows', 'Linux', 'Mac'
			if (navigator.platform.substr(0,3) == 'Win') {
				return 'Windows';
			} else if (navigator.platform.substr(0,3) == 'Mac') {
				return 'Mac';
			} else if (navigator.platform.substr(0,6) == 'Linux ') {
				return 'Linux';
			} else if (navigator.platform.substr(0,6) == 'CE.Net') {
				return 'WinCE';
			} else if (navigator.platform.substr(0,6) == 'Series') {
				return 'Symbian';
			} else {
				return null;
			}
		case 'hardwaretype':	//indica il tipo di hardware. Può essere:  'pc', 'palm', 'smartphone'
			switch (GetBrowserInfo('os')) {
				case 'Windows':
				case 'Mac':
				case 'Linux':
					return 'pc';
				case 'WinCE':
					return 'palm';
				case 'Symbian':
					return 'smartphone';
				default:
					return null;
			}
		case 'iscookieenabled':	//restituisce TRUE se i cookie sono abilitati
			return IsCookieEnabled();
		case 'cpuspeed':		//restituisce un numero che rappresenta la velocità di calcolo. Prove:  PC P4HT 3.2GHz -> 3.558 ;  Palmare PXA270 624MHz -> 0.25
			if (GetBrowserInfo('IsCookieEnabled')) {
				str1 = GetCookie('CpuSpeed.v1');
				if (str1 === null) {
					SetCookie('CpuSpeed.v1', 1, 365);
					cont2 = new Date();
					for (cont1 = 0; cont1 < 1000000; cont1++) str1 = 1000 / cont1;
					cont1 = new Date();
					str1 = 1000 / (cont1 - cont2);
					SetCookie('CpuSpeed.v1', str1, 365);
				}
			} else {
				//Se i cookie non sono abilitati non mi metto a calcolare la velocità del processore, perchè è una operazione che potrebbe chiedere
				//più di 1 secondo, a seconda del pc, o addirittura di più se l'hardware è un vecchio pc o un palmare (commento del 2007).
				switch (GetBrowserInfo('HardwareType')) {
					case 'pc':
						str1 = 1;
						break;
					default:
						str1 = 0.2;
						break;
				}
			}
			return str1;
		case 'recommendedfps':	//valore FPS consigliato, in base alle prestazioni del pc
			str1 = GetBrowserInfo('CpuSpeed');
			if (str1 < 1) {
				str1 = 10;
			} else if (str1 > 5) {
				str1 = 30;
			} else {
				str1 = 10 + (str1 - 1) / 4 * 20;
			}
			return str1;	//per ora non ho un sistema per intuire il valore da consigliare
		default:
			return null;
	}
}

function FileInclude(Fullname) {
	//Include un file JS o CSS nel documento corrente. Restituisce TRUE se il file è stato incluso, FALSE se non era necessario, NULL se ci sono errori.
	var vett1, obj1, i, tipo, fReturn;
	fReturn = null;
	if (document.getElementsByTagName) {
		tipo = Fullname.substr(Fullname.lastIndexOf('.') + 1);
		switch (tipo.toLowerCase()) {
			case 'js':	tipo = 'js'; break;
			case 'css':	tipo = 'css'; break;
			default:	tipo = null; break;
		}
		if (tipo) {
			if (!window.FileInclude__info) {
				window.FileInclude__info = {js:{}, css:{}};
				vett1 = document.getElementsByTagName("script");
				for (var i=0,len=vett1.length; i < len; i++) if (vett1[i].src) FileInclude__info.js[vett1[i].src] = true;
				vett1 = document.getElementsByTagName("link");
				for (var i=0,len=vett1.length; i < len; i++) if (vett1[i].href && vett1[i].rel.toLowerCase()=='stylesheet') FileInclude__info.css[vett1[i].href] = true;
			}
			fReturn = false;
			switch (tipo) {
				case 'js':
					if (!FileInclude__info.js[Fullname]) {
						obj1 = document.createElement('script');
						obj1.type = 'text/javascript';
						obj1.language = 'javascript';
						obj1.src = Fullname;
						FileInclude__info.js[Fullname] = true;
						document.getElementsByTagName('head')[0].appendChild(obj1);
						fReturn = true;
					}
					break;
				case 'css':
					if (!FileInclude__info.css[Fullname]) {
						obj1 = document.createElement('link');
						obj1.type = 'text/css';
						obj1.rel = 'stylesheet';
						obj1.media = 'all';
						obj1.href = Fullname;
						FileInclude__info.css[Fullname] = true;
						document.getElementsByTagName('head')[0].appendChild(obj1);
						fReturn = true;
					}
					break;
				default:
					fReturn = null;
			}
		}
	}
	return fReturn;
}

// ### ViewPointerPosition
// Passando un oggetto come parametro, restituisce le coodrinate del mouse rispetto all'oggetto passato e all'oggetto Window
function ViewPointerPosition(HtmlObject) {
	var obj1 = HtmlObject;
	if (ValueType(obj1) == 'string') obj1 = findObj(obj1);
	addEvent(obj1, 'mousemove', function (ev) {
					var eventObj = new STDEvent(ev);
					window.status = '[ViewPointerPosition] client = ' + eventObj.clientX + ', ' + eventObj.clientY + '; offset = ' + eventObj.offsetX + ', ' + eventObj.offsetY + '; screen = ' + eventObj.screenX + ', ' + eventObj.screenY + ';'  ;
					}
			);
}


//Aggiunge una nuova voce al menù [DevelopingMode]. Se quest'ultimo non esiste allora viene creato dalla funzione stessa. Argomenti:
//	Text :		il testo della voce di menù;
//	Function :	puntatore a funzione o stringa in JavaScript da eseguire su click sulla voce di menù.
function DevelopingModeMenu_AddItem(Text, Function) {
	this.objMenu = findObj('DivDevelopingModeMenu');
	this.objMenu_List;
	this.hideTimer;
	this._initialize = function() {
		var obj1;
		
		if (!this.objMenu) {
			this.objMenu = document.createElement('DIV');
			document.body.appendChild(this.objMenu);
			//alert('1'); return;
			this.objMenu.id = 'DivDevelopingModeMenu';
			this.objMenu.style.cssText = 'cursor:hand; position:absolute; z-index:10000; top:0px;right:0px; width:5px;height:5px; overflow:hidden; background-color:#ffff00; border:1px solid #ff0000; color:black; font-size:8pt; text-align:left;';
			this.objMenu.title = '[DevelopingModeMenu] clicca per aprire';
			addEvent(this.objMenu, 'click', this._DivMenu_Show);
			addEvent(this.objMenu, 'mouseout', this._DivMenu_Hide);
			
			this.objMenu._DivMenu_Hide__timeout = function () {
					this.style.overflow = 'hidden';
					this.style.width = '5px';
				}
			
			obj1 = document.createElement('DIV');
			this.objMenu.appendChild(obj1);
			obj1.innerHTML = '[DevelopingModeMenu]';
			obj1.style.cssText = 'font-weight:bold;';

			this.objMenu_List = document.createElement('UL');
			this.objMenu.appendChild(this.objMenu_List);
			this.objMenu_List.style.cssText = 'margin-top:0px;margin-left:20px;margin-right:0px;margin-bottom:0px;';
		} else {
			//alert('x'); return;
			this.objMenu = findObj('DivDevelopingModeMenu');
			this.objMenu_List = this.objMenu.getElementsByTagName('UL')[0];
		}
	}
	this._addItem = function(Text, Function) {
		var objItem, objItem_A;
		objItem = document.createElement('LI');
		this.objMenu_List.appendChild(objItem);
		
		objItem_A = document.createElement('A');
		objItem.appendChild(objItem_A);
		objItem_A.href = 'java' + 'script:void(0);';
		objItem_A.innerHTML = Text;
		
		switch (typeof(Function)) {
			case 'string':
				//addEvent(objItem_A, 'click', 'function() {' + Function + '}');
				objItem_A.href = 'javas'+'cript:' + Function + ';';
				break;
			case 'function':
				addEvent(objItem_A, 'click', Function);
				break;
		}
		addEvent(objItem, 'mousemove', this._DivMenu_Show);
		addEvent(objItem, 'mouseout', this._DivMenu_Hide);
	}

	this._DivMenu_Show = function () {
		if (this.hideTimer) window.clearTimeout(this.hideTimer);
		this.hideTimer = 0;
		if (objMenu.style.display != 'block') {
			objMenu.style.overflow = 'visible';
			objMenu.style.width = '300px'; 
			objMenu.style.height = 'auto';
		}
	}
	this._DivMenu_Hide = function () {
		if (!this.hideTimer) this.hideTimer = window.setTimeout('findObj(\'DivDevelopingModeMenu\')._DivMenu_Hide__timeout();', 1000);
	}
	this._DivMenu_Hide__timeout = function () {
		objMenu.style.width = '5px';
		objMenu.style.height = '5px';
		objMenu.style.overflow = 'hidden';
		hideTimer = 0;
	}
	if (window.DevelopingMode) {
		this._initialize();
		if (Text && Function) this._addItem(Text, Function);
	}
}


// ###   getPos - Info-Data Flavio Spezi (ver. 2.0 - 03/11/2005)   ###
// Restituisce la coordinata X o Y dell'oggetto HtmlElement.
// Parametri:	HtmlElement :		l'oggetto di cui conoscere le coordinate.
//				TopOrLeft :			la coordinata richiesta; se si passa TOP restituirà la coordinata Y, altrimenti X.
// ATTENZIONE: la procedura non funziona correttamente se l'oggetto passato si trova all'interno di una tabella, la quale
//		ha impostato l'attributo BORDER ad un valore maggiore di zero, non ha una configurazione STYLE che configura lo
//		spessore del bordo e la cella che contiene l'oggetto non ha una configurazione STYLE che configura lo spessore
//		del bordo. Per risolvere questo eventuale problema, impostare l'attributo POSITION dell'oggetto richiesto al
//		valore RELATIVE oppure ABSOLUTE.
function getPos(HtmlElement, TopOrLeft) {
	var fReturn = 0;
	var obj = HtmlElement;
	var topOrLeftValue = ((TopOrLeft.substring(0, 1).toLowerCase() == 't') ? 'Top' : 'Left');
	var styleVal;
	//var str1 = HtmlElement.tagName;		//riattivare per fare i test
	while (obj) {
		styleVal = obj['offset' + topOrLeftValue];
		if (styleVal) {
			styleVal = toNumber(styleVal.toString(), null);
			if (styleVal > 0) {
				fReturn += styleVal;
				//str1 += ' offset=' + styleVal;		//riattivare per fare i test
			}
		}
		//str1 += '\n';			//riattivare per fare i test
		obj = obj.offsetParent;
	}
	obj = HtmlElement.parentNode;
	while (obj && obj.tagName != 'BODY') {
		styleVal = GetProperty(obj, 'scroll' + topOrLeftValue);
		if (styleVal) {
			styleVal = toNumber(styleVal.toString(), null);
			if (styleVal > 0) {
				fReturn -= styleVal;
				//str1 += ' scroll(1)=' + styleVal;		//riattivare per fare i test
			}
		}
		obj = obj.parentNode;
	}
	//alert(str1);		//riattivare per fare i test
	return fReturn;
}

//Dato un oggetto DOCUMENT (o un oggetto HTML da cui si determinerà il rispettivo DOCUMENT), e dato un "INFO" restituisce il rispettivo valore.
//Informazioni disponibili (possibili valori per l'argomento NAME):
//	'RootElement' :		restituisce l'oggetto PARENT del documento.
//	'IsTopFrame' :		restituisce FALSE se [window] è disegnato in un FRAME, altrimenti restituisce TRUE.
function GetDocInfo(HtmlObject, Name) {
	var objDoc = (HtmlObject.tagName ? HtmlObject.ownerDocument : HtmlObject);
	switch (Name) {
		//Restituisce il primo elemento del documento, ossia quello su cui partono tutti i riferimenti di posizione
		case 'RootElement':		return (objDoc.compatMode == 'CSS1Compat' ? objDoc.documentElement : objDoc.body);
		//Restituisce FALSE se [window] è disegnato in un FRAME, altrimenti restituisce TRUE.
		case 'IsTopFrame':		return !((HtmlObject.parentWindow ? HtmlObject.parentWindow : HtmlObject.defaultView).frameElement);
		default:				return null;
	}
}

// Converte un nome di proprietà di stile css nel formato java.  Es.: "border-color" -> "borderColor".
// Se la proprietà è già scritta in stile Js la funzione restituisce PropertyName.
function CPropertyJS(PropertyName) {
	var fReturn;
	var indice;
	var arrayString;
	
	arrayString = PropertyName.split('-');

	fReturn = arrayString[0];
	for (indice = 1; indice < arrayString.length; indice++) {
		arrayString[indice] = arrayString[indice].substr(0, 1).toUpperCase() + arrayString[indice].substr(1);
		fReturn = fReturn.concat(arrayString[indice]);
	}
	return fReturn;
}

// ###   GetProperty - Info-Data Flavio Spezi (ver. 2.0 - 06/09/2007)
// Restituisce la proprietà richiesta. Se la proprietà non viene trovata, viene restituito il valore NULL.
// La ricerca avviene per stile e per proprietà.
// Testata su Internet Explorer 6 e su Mozilla Firefox 2.0.
function GetProperty(Obj, PropertyName, EmptyIsNotValid) {
	var nome, trovato, filtro;
	var ok, fReturn;
	var nomeProprieta;
	
	ok = false;
	if (Obj) {
		switch (PropertyName){ 
			case 'opacity' :
				// se la proprietà richiesta è opacity
				switch(GetBrowserInfo('name')){
					case 'MSIE':
						trovato = false;
						for (filtro in Obj.filters) {
							switch (filtro.toLowerCase()) {
								case 'alpha':
								case 'dximagetransform.microsoft.alpha' : 
									trovato = true;
									break;
							}
							if (trovato) {
								fReturn = Obj.filters(filtro).opacity;
								ok = true;
								break;
							}
						}
						break;
					case 'Netscape':
						fReturn = null;
						if (!fReturn) fReturn = GetProperty(Obj, '-moz-opacity', true);
						if (!fReturn) fReturn = GetProperty(Obj, 'OPACITY', true);
						if (fReturn) {
							fReturn = fReturn * 100;
							ok = true;
						}
						break;
					default : 
						fReturn = null;
						if (!fReturn) fReturn = GetProperty(Obj, 'OPACITY', true);
						if (fReturn) {
							fReturn = fReturn * 100;
							ok = true;
						}
						break;
				}
				break;
			case 'uniqueID':
				switch(GetBrowserInfo('name')){
					case 'MSIE':
						fReturn = Obj.uniqueID;
						break;
					default:
						//Pare che questa istruzione non funzioni, e che non esiste un "uniqueID" standard.
						fReturn = Obj.elementId;
						break;
				}
				break;
			default :
				nomeProprieta = CPropertyJS(PropertyName);
				if (!ok && Obj.style) {
					try {
						fReturn = Obj.style[nomeProprieta];
						ok = true;
					} catch (e) {
						ok = false;
					}
					if ((ok) && (!fReturn && fReturn!='') || (fReturn=='' && EmptyIsNotValid)) ok = false;
				}
				if (!ok) {
					try {
						fReturn = Obj[nomeProprieta];
						ok = true;
					} catch (e) {
						ok = false;
					}
					if (ok && !fReturn && fReturn!='') ok = false;
				}
				if (!ok && Obj.style) {
					try {
						for (nome in Obj.style) {
							if (nome.toLowerCase() == nomeProprieta.toLowerCase()) {
								fReturn = Obj.style[nome];
								ok = true;
								break;
							}
						}
					} catch (e) {
						ok = false;
					}
					if ((ok) && (!fReturn && fReturn!='') || (fReturn=='' && EmptyIsNotValid)) ok = false;
				}
				if (!ok) {
					try {
						for (nome in Obj) {
							if (nome.toLowerCase() == nomeProprieta.toLowerCase()) {
								fReturn = Obj[nome];
								ok = true;
								break;
							}
						}
					} catch (e) {
						ok = false;
					}
					if ((ok) && (!fReturn && fReturn!='') || (fReturn=='' && EmptyIsNotValid)) ok = false;
				}
				if (!ok && Obj.attributes) {
					try {
						fReturn = Obj.getAttribute(nomeProprieta);
						ok = true;
					} catch (e) {
						ok = false;
					}
					if ((ok) && (!fReturn && fReturn!='') || (fReturn=='' && EmptyIsNotValid)) ok = false;
				}
				if (false && !ok && Obj.currentStyle) {		//Disattivato, perchè inopportuno: esiste GetCssStyle per conoscere valori in questo modo.
					try {
						fReturn = Obj.currentStyle[nomeProprieta];
						ok = true;
					} catch (e) {
						ok = false;
					}
					if ((ok) && (!fReturn && fReturn!='') || (fReturn=='' && EmptyIsNotValid)) ok = false;
				}
				break;
		}
	}
	if (!ok) fReturn = null;
	//alert(Obj.tagName + ': ' + PropertyName + '=' + fReturn + '; ok=' + ok);
	return fReturn;
}


// ###   SetProperty - Info-Data Flavio Spezi (ver. 2.0 -27/08/2007)
// Setta la proprietà richiesta. Restituisce TRUE se è stato sovrascritto un valore di STILE o di TAG.
// Testata su Internet Explorer 6 e su Mozilla Firefox 2.0.
function SetProperty(Obj, PropertyName, PropertyValue) {
	var filtro, trovato, val1;
	var ok, fReturn;
	var nomeProprieta;
	
	fReturn = false;
	ok = false;
	if (Obj) {
		switch (PropertyName) {
			case 'opacity':
				// il valore "opacity" deve essere da 0 a 100 ossia da trasparente a completamente opaco
				switch (GetBrowserInfo('name')) {
					case 'MSIE':
						switch (GetBrowserInfo('hardwaretype')) {
							case 'pc':
								trovato = false;
								for (filtro in Obj.filters) {
									switch (filtro.toLowerCase()) {
										case 'alpha':
										case 'dximagetransform.microsoft.alpha':
											trovato = true;
											break;
									}
									if (trovato) break;
								}
								if (trovato) {
									Obj.filters(filtro).Opacity = parseInt(PropertyValue);
								} else {
									Obj.style.filter += ' progid:DXImageTransform.Microsoft.Alpha(Opacity=' + parseInt(PropertyValue) + ')';
								}
								fReturn = true;
								break;
							default:
								fReturn = true;
								break;
						}
						break;
					case 'Netscape':
						//Si deve usare "-moz-opacity" oppure "opacity" ?...
						//Utilizziamo "opacity" per le nuove versioni di Firefox.. 1.5 (versione ipotizzata)
						//Si utilizzava "-moz-opacity" per le vecchie versioni di Mozilla
						Obj.style.opacity = parseInt(PropertyValue) / 100;
						fReturn = true;
						break;
					default:
						Obj.style.opacity = parseInt(PropertyValue) / 100;
						fReturn = true;
				}
				break;
			default:
				nomeProprieta = CPropertyJS(PropertyName);
				if (!ok) {
					if (Obj.style) {
						if (Obj.style[nomeProprieta] !== undefined) {
							Obj.style[nomeProprieta] = PropertyValue;
							ok = true;
						}
					}
					if (Obj[nomeProprieta] !== undefined) {
						Obj[nomeProprieta] = PropertyValue;
						ok = true;
					}
				}
				if (!ok) {
					Obj.style[nomeProprieta] = PropertyValue;
				}
				freturn = true;
				break;
		}
	}
	//alert(Obj.tagName + ': ' + PropertyName + '=' + fReturn + '; ok=' + ok);
	return fReturn;
}

//Restituisce il valore CORRENTE dello stile, che sarà quello della collection STYLE se è definito, altrimenti sarà quello ereditato dai file CSS.
function GetCssStyle(HtmlObject, StyleName) {
    if (HtmlObject.tagName) {
		if (HtmlObject.currentStyle) {
			return HtmlObject.currentStyle[StyleName];
		} else if (window.getComputedStyle) {
			var compStyle = window.getComputedStyle(HtmlObject, '');
			return compStyle.getPropertyValue(StyleName);
		}
	}
    return null;
}


/*	----E' SOLO UNA IDEA, E' DA IMPLEMENTARE PER BENE---- (inizio)
//Restituisce il nome dello stile nel browser corrente. Se [optFromBrowser] è true significa che [StyleName] è il nome usato dal browser corrente, e
//la funzione restituirà il nome standard dello stile.
function STDStyleName(StyleName, optFromBrowser) {
	if (!window.STDStyleName__coll) {
		window.STDStyleName__coll = new Array();
		window.STDStyleName__coll['opacity'] = {'IE7':'', 'W3C':'opacity'};
	}
}	----E' SOLO UNA IDEA, E' DA IMPLEMENTARE PER BENE---- (fine)
*/

// Setta uno stile o un elenco di stili (formattati così come sarebbero formattati nell'attributo STYLE di un TAG)
// ad un oggetto HTML.
// FORSE OBSOLETA...perchè ora esiste "ObjHtml.style.cssText "
function SetCssStyle(HtmlObject, CssStyle) {
	var cssStyleSenzaStringhe;
	var cont1, cont2;
	var str1, str2;
	
	str1 = new String(CssStyle);
	str1 = str1.replace(/\\\\/g, '##');		//Sostituisco la doppia barra con doppio #
	//Sostituisco le stringhe con dei #, uno per carattere di stringa.
	cont1 = str1.search(/['"]/g);
	while (cont1 > -1) {
		str2 = str1.substr(cont1, 1);
		//Cerco la chiusura di stringa, escludendo quelle situazioni in cui il sepStringa è preceduro da uno Escape (\)
		for (cont2 = cont1+1; cont2 < str1.length; cont2++) {
			if (str1.substr(cont2, 1) == str2 && str1.substr(cont2-1, 1) != '\\') break;
		}
		str1 = str1.substr(0, cont1) + StringRepeater('#', cont2 - cont1 + 1) + str1.substr(cont2 + 1);
		cont1 = str1.search(/['"]/g);
	}
	cssStyleSenzaStringhe = str1;
	
	//Cerco le definizioni di stile e le applico all'oggetto.
	var re = new RegExp('([@:a-z][a-z\\-]+)\\s*:\\s*([^;]*)', 'gi');
	var reMatch;
	while ((reMatch = re.exec(cssStyleSenzaStringhe)) !== null) {
		//reMatch è un array che contiene informazioni sul match corrente.
		str1 = reMatch[1];	//reMatch[1] restituisce il nomeAttributo, che è sicuramente lo stesso valore che trovo come sottostringa di CssStyle a parità di posizione.
		str2 = RTrim(CssStyle.substr(reMatch.index + reMatch[0].length - reMatch[2].length, reMatch[2].length));
		SetProperty(HtmlObject, str1, str2);
		//HtmlObject.setAttribute(str1, str2);
		//eval('HtmlObject.style.' + str1 + ' = "' + str2 + '";');
	}
}



/* ==== AddClassName  /  RemoveClassName  /  ContainsClassName ==== */
//Procedure che aggiungono, tolgono e verificano la presenza di un ClassName in un oggetto.
//L'argomento HtmlObject può essere anche il valore ClassName di un oggetto.

//AddClassName: aggiunge il ClassName all'oggetto. Restituisce il nuovo valore dell'attributo.
//Se [optFirstPosition] è TRUE mette il ClassName come primo elemento, lo lo sposta se c'era già.
function AddClassName(HtmlObject, ClassName, optFirstPosition) {
	var cont1, str1, vett1, trovato, fReturn;
	//Lettura valore corrente
	switch (ValueType(HtmlObject)) {
		case 'string':	str1 = HtmlObject; break;
		case 'Object':	str1 = HtmlObject.className; break;
	}
	if (!str1) {
		fReturn = ClassName;
	} else {
		vett1 = str1.split(' ');
		trovato = false;
		fReturn = '';
		for (cont1=0; cont1 < vett1.length; cont1++) {
			if (vett1[cont1] == ClassName) {
				if (!optFirstPosition || cont1 == 0) {
					fReturn += ' ' + ClassName;
					trovato = true;
				}
			} else {
				fReturn += ' ' + vett1[cont1];
			}
		}
		if (trovato) {
			fReturn = fReturn.substr(1);
		} else {
			if (optFirstPosition) {
				fReturn = ClassName + fReturn;
			} else {
				fReturn = fReturn.substr(1) + ' ' + ClassName;
			}
		}
	}
	//Scrittura valore nell'oggetto HTML
	switch (ValueType(HtmlObject)) {
		case 'Object':	HtmlObject.className = fReturn; break;
	}
	return fReturn;
}
//RemoveClassName: rimuove il ClassName dall'oggetto. Restituisce il nuovo valore dell'attributo.
function RemoveClassName(HtmlObject, ClassName) {
	var cont1, str1, vett1, trovato, fReturn;
	//Lettura valore corrente
	switch (ValueType(HtmlObject)) {
		case 'string':	str1 = HtmlObject; break;
		case 'Object':	str1 = HtmlObject.className; break;
	}
	if (!str1) {
		fReturn = '';
	} else {
		vett1 = str1.split(' ');
		trovato = false;
		fReturn = '';
		for (cont1=0; cont1 < vett1.length; cont1++) {
			if (vett1[cont1] == ClassName) {
				trovato = true;
			} else {
				fReturn += ' ' + vett1[cont1];
			}
		}
		if (fReturn) fReturn = fReturn.substr(1);
	}
	//Scrittura valore nell'oggetto HTML
	switch (ValueType(HtmlObject)) {
		case 'Object':	HtmlObject.className = fReturn; break;
	}
	return fReturn;
}
//SetClassName: esegue [AddClassName] se l'argomento [Add] è True, oppure [RemoveClassName] se l'argomento [Add] è False.
function SetClassName(HtmlObject, ClassName, Add, optFirstPosition) {
	if (Add) {
		return AddClassName(HtmlObject, ClassName, optFirstPosition);
	} else {
		return RemoveClassName(HtmlObject, ClassName);
	}
}
//ContainsClassName: restituisce TRUE se viene trovato il ClassName indicato nell'omonimo attributi dell'oggetto.
function ContainsClassName(HtmlObject, ClassName) {
	var cont1, str1, vett1, trovato, fReturn;
	//Lettura valore corrente
	switch (ValueType(HtmlObject)) {
		case 'string':	str1 = HtmlObject; break;
		case 'Object':	str1 = HtmlObject.className; break;
	}
	if (!str1) {
		fReturn = false;
	} else {
		vett1 = str1.split(' ');
		trovato = false;
		for (cont1=0; cont1 < vett1.length; cont1++) {
			if (vett1[cont1].toLowerCase() == ClassName.toLowerCase()) {
				trovato = true;
				break;
			}
		}
		fReturn = trovato;
	}
	return fReturn;
}


/* ==== COOKIE ==== */
// NOTE: un Cookie creato dal browser è leggibile ma non modificabile dal server, e viceversa. Se entrambi scrivono un Cookie con medesimo nome
// succede che ci troveremo entrambi i Cookie. Quando si leggeranno i valori, il server leggerà il primo che incontra. Mentre il browser, non
// fornendo procedure per leggere i singoli valori, posso ottenere ciò che voglio.
// Per non trovarmi a dover scegliere quale valore leggere (se quello scritto dal client o dal server) nego la possibilità di scrittura di un
// cookie se questo è già stato scritto dal suo antagonista.
function GetCookie(Name) {
	var re = new RegExp('([;][ ])?([^=]+)=([^;]*)', 'g');
	var reMatch;
	while ((reMatch = re.exec(document.cookie)) !== null) {
		if (CStrByAscii(reMatch[2]) == Name) return DeserializeValue(CStrByAscii(reMatch[3].substr(1)));
	}
	return null;
}
function GetCookieOwner(Name) {
	//Restituisce "S", "C" o NULL in caso che il Cookie sia di proprietà del SERVER, CLIENT o se non esiste.
	//Restituisce "n" se il Cookie non è stato creato dalle procedure [SetCookie].
	//Attensione: per sapere se un Cookie è di proprietà di uno o l'altro, si deve leggere il primo catarrete, che puo essere "S" o "C". Quindi
	//questo meccanismo non garantisce in maniera assoluta se un Cookie è di una certa proprietà o se è stato creato con altre procedure e
	//casualmente il suo contenuto inizia con una di quelle lettere.
	var re = new RegExp('([;][ ])?([^=]+)=([^;]*)', 'g');
	var reMatch;
	while ((reMatch = re.exec(document.cookie)) !== null) {
		if (CStrByAscii(reMatch[2]) == Name) {
			return (('SC'.indexOf(reMatch[3].charAt(0)) > -1) ? reMatch[3].charAt(0) : 'n');
		}
	}
	return null;
}
function SetCookie(Name, Value, Expire) {
	//ATTENZIONE: questa funzione è autorizzata a scrivere Cookie solo se esso non è stato già creato dal server.
	switch (IfNull(GetCookieOwner(Name), 'C')) {
		case 'C':	//Cookie creato dal client o non esistente, autorizzazione concessa.
			var scadenza, percorso;
			switch (ValueType(Expire)) {
				case 'null':		//il cookie scadrà con lo scadere della sessione
					scadenza = '';	//new Date(); scadenza.setTime(scadenza.getTime() - 24 * 3600 * 1000 * 100);
					break;
				case 'Date':		//data esatta
					scadenza = Expire;
					break;
				case 'number':		//numero di giorni a partire da oggi
					scadenza = new Date();
					scadenza.setTime(scadenza.getTime() + 24 * 3600 * 1000 * Expire);
					break;
				default:			//fra 3 mesi
					scadenza = new Date();
					scadenza.setMonth(scadenza.getMonth() + 3);
					break;
			}
			if (ValueType(scadenza) == 'Date') scadenza = scadenza.toGMTString();
			document.cookie = CStrAscii(Name) + '=C' + CStrAscii(SerializeValue(Value)) + '; path=/;' + (scadenza ? ' expires='+scadenza+';' : '');
			return true;
		default:	//Cookie creato dal server o provenienza sconosciuta, autorizzazione negata.
			return false;
	}
}
function DelCookie(Name) {
	SetCookie(Name, '', -1);
}
function IsCookieEnabled() {
	var fReturn = true;
	if (fReturn) fReturn = SetCookie('testCookie', 'test', null);
	if (fReturn) fReturn = (GetCookie('testCookie') == 'test');
	return fReturn;
}



// ##	STD Event - Info-Data Flavio Spezi (ver. 1.0 - 24/11/2006)
// Interfaccia per oggetto Event. Istanziando questo oggetto, il primo argomento di un handler di evento, la classe restituisce le
// proprietà in stile IE. (info prese su http://www.javascriptkit.com/domref/domevent.shtml#e2)
// "STD" sta per "Standard".
function STDEvent(EventObjectByArgument) {
	//Preparazione variabili e setting variabili principali
	this.objectType = 'STDEvent';
	this._ie = (window.event ? true : false);
	this.eventObj;
	this.altKey;	this.ctrlKey;	this.shiftKey;		this.button;
	this.clientX;	this.clientY;	this.fromElement;	this.toElement;
	this.keyCode;	this.offsetX;	this.offsetY;		this.srcElement;
	this.type;
	
	this._initialize = function (EventObjectByArgument) {
		var fatto, fReturn;
		//Se l'argomento [EventObjectByArgument] è già un oggetto di tipo [STDEvent] allora lo restituisco senza fare altro.
		fatto = false;
		if (ValueType(EventObjectByArgument) == 'Object') {
			if (EventObjectByArgument.objectType == 'STDEvent') {
				fReturn = EventObjectByArgument;
				fatto = true;
			}
		}
		if (!fatto) {
			this._settingVariabili(EventObjectByArgument);
			fReturn = this;
		}
		return fReturn;
	}
	this._settingVariabili = function (EventObjectByArgument) {
		this.eventObj = (this._ie ? window.event : EventObjectByArgument);
		this.altKey = this.eventObj.altKey;
		this.ctrlKey = this.eventObj.ctrlKey;
		this.shiftKey = this.eventObj.shiftKey;
		if (this._ie) {
			this.button = this.eventObj.button;
		} else {
			switch (this.eventObj.button) {
				case 0: this.button = 1; break;
				case 2: this.button = 2; break;
				case 1: this.button = 4; break;
				default: this.button = 0;
			}
		}
		this.clientX = this.eventObj.clientX;
		this.clientY = this.eventObj.clientY;
		this.fromElement = this._scegliGiusto(this.eventObj.fromElement, this.eventObj.relatedElement);
		this.toElement = this._scegliGiusto(this.eventObj.toElement, this.eventObj.relatedElement);
		this.keyCode = (this.eventObj.keyCode ? this.eventObj.keyCode : this.eventObj.charCode);
		this.offsetX = this._scegliGiusto(this.eventObj.offsetX, this.eventObj.layerX);
		this.offsetY = this._scegliGiusto(this.eventObj.offsetY, this.eventObj.layerY);
		//this.srcElement = this._scegliGiusto(this.eventObj.srcElement, this.eventObj.target);		pare che non sia [target] ma [currentTarget]
		this.srcElement = this._scegliGiusto(this.eventObj.srcElement, this.eventObj.currentTarget);
		this.type = this.eventObj.type;
	}
	this._scegliGiusto = function (perIE, perAltri) {
		if (this._ie) {
			return perIE;
		} else {
			return perAltri;
		}
	}
	/*
	this.altKey = function () { return this.eventObj.altKey; }
	this.ctrlKey = function () { return this.eventObj.ctrlKey; }
	this.shiftKey = function () { return this.eventObj.shiftKey; }
	this.button = function () {
		if (this._ie) {
			return this.eventObj.button;
		} else {
			switch (this.eventObj.button) {
				case 0: return 1; break;
				case 2: return 2; break;
				case 1: return 4; break;
				default: return 0;
			}
		}
	}
	
	//Proprietà
	this.clientX = function () { return this.eventObj.clientX; }
	this.clientY = function () { return this.eventObj.clientY; }
	this.fromElement = function () { return this._scegliGiusto(this.eventObj.fromElement, this.eventObj.relatedElement); }
	this.toElement = function () { return this._scegliGiusto(this.eventObj.toElement, this.eventObj.relatedElement); }
	this.keyCode = function () { return this._scegliGiusto(this.eventObj.keyCode, this.eventObj.charCode); }
	this.offsetX = function () { return this._scegliGiusto(this.eventObj.offsetX, this.eventObj.layerX); }
	this.offsetY = function () { return this._scegliGiusto(this.eventObj.offsetY, this.eventObj.layerY); }
	this.srcElement = function () { return this._scegliGiusto(this.eventObj.srcElement, this.eventObj.target); }
	this.type = function () { return this.eventObj.type; }
	*/
	//Metodi
	this.cancelBubble = function(Valore) {
		if (this._ie) {
			this.eventObj.cancelBubble = ((Valore)? true : false);
		} else {
			this.eventObj.stopPropagation((Valore)? true : false);
		}
	}
	this.returnValue = function(Valore) {
		if (this._ie) {
			this.eventObj.returnValue = ((Valore)? true : false);
		} else {
			this.eventObj.preventDefault((Valore)? false : true);
		}
	}
	
	return this._initialize(EventObjectByArgument);
}



// ###   toNumber - Info-Data Flavio Spezi (ver. 2.0 - 03/11/2005)   ###
// Restituisce il numero dalla forma string alla forma numerica
// Parametri:	NumericString :		il numero da restituire.
//				ReturnIfInvalid :	se il numero indicato è errato, verrà restituito questo valore.
//				AnyError :			se TRUE, la procedura restituirà ReturnIfInvalid per qualsiasie errore;
//									se FALSE (default) restituisce la parte numerica valida.
function toNumber(NumericString, ReturnIfInvalid, AnyError) {
	// Costanti di programmazione
	var numeriValidi = '0123456789', segniValidi = '+-', sepDecimaliValidi = '.,';
	// Variabili di programmazione
	var strNumero, strCifra;
	var segno = '+', intero = '', decimale = '';
	var trovatoSegno = false, trovatoDecimale = false, err = 0;
	var i, fReturn;

	if (typeof(NumericString) == 'number') {
		fReturn = NumericString;
	} else if (!NumericString || NumericString == '') {
		fReturn = ReturnIfInvalid;
	} else {
		strNumero = '';
		try {
			strNumero = NumericString.toString();
		} catch(e) {
		}
		strCifra = strNumero.charAt(0);
		if (segniValidi.indexOf(strCifra) > -1) {
			segno = strCifra;
			trovatoSegno = true;
		}
		for (i = ((trovatoSegno)? 1 : 0); i < strNumero.length; i++) {
			strCifra = strNumero.charAt(i);
			if (numeriValidi.indexOf(strCifra) > -1) {
				if (!trovatoDecimale) {
					intero += strCifra;
				} else {
					decimale += strCifra;
				}
			} else if ((!trovatoDecimale) && (sepDecimaliValidi.indexOf(strCifra) > -1)) {
				trovatoDecimale = true;
			} else {
				err = 1;	//troppi separatori o carattere non riconosciuto
				break;
			}
		}
		if ((intero != '' || decimale != '') && (err == 0 || !AnyError)) {
			if (intero == '') intero = '0';
			if (decimale == '') decimale = '0';
			fReturn = (new Number(segno + intero + '.' + decimale)).valueOf();
		} else {
			fReturn = ReturnIfInvalid;
		}
	}
	return fReturn;
}


function IsNull(Value) {
	return ((Value === null || Value === void(0)) ? true : false);
}

function IfNull(Value, ValueIfNull) {
	if (IsNull(Value)) {
		return ValueIfNull;
	} else {
		return Value;
	}
}
function NullIf(Value, NullValue) {
	if (Value == NullValue || Value === NullValue) {
		return null;
	} else {
		return Value;
	}
}

function CNum(NumericString) {
	return toNumber(NumericString, null, true);
}
function CStrXML(Value) {
	return CStrXml(Value);
}
function CStrXml(Value) {
	var fReturn;
	if (Value === null || Value === void(0)) {
		fReturn = Value;
	} else {
		fReturn = HTMLEncode(Value);
	}
	return fReturn;
}
function CNumHTML(Value, Decimals) {
	//Restituisce il numero in formato stringa arrotondato al numero di cifre indicate
	var fReturn;
	fReturn = CNum(Value);
	if (fReturn === null || fReturn === void(0)) {
		fReturn = Value;
	} else {
		fReturn = Value.toFixed(Decimals);
	}
	return fReturn;
}
function CNumHtml(Value, Decimals) {
	return CNumHTML(Value, Decimals);
}
function CCurHTML(Value, Decimals) {
	//Restituisce il numero in formato stringa, arrotondato al numero di cifre indicate e con il separatore delle migliaia
	//Attezione: procedura da implementare.
	return CNumHTML(Value, Decimals);
}
function CCurHtml(Value, Decimals) {
	return CNumHTML(Value, Decimals);
}
function CStrHTML(Value) {
	return CStrHtml(Value);
}
function CStrHtml(Value) {
	var fReturn;
	if (Value === null || Value === void(0)) {
		fReturn = Value;
	} else {
		fReturn = HTMLEncode(Value);
		if (fReturn) fReturn = fReturn.replace(/\x20\x20/g, '&nbsp;');
		if (fReturn) fReturn = fReturn.replace(/\x0d\x0a/g, '<br/>');
		if (fReturn) fReturn = fReturn.replace(/(\x0d|\x0a)/g, '<br/>');
	}
	return fReturn;
}

function CStrJS(Value, AddDelimeters) {
	if (Value === null || Value === void(0)) {
		return (AddDelimeters ? 'null' : null);
	} else {
		return (AddDelimeters ? '\'' : '') + escape(Value).replace(/%/g, '\\x') + (AddDelimeters ? '\'' : '');
	}
}
function CNumJS(Value) {
	if (Value === null || Value === void(0)) {
		return 'null';
	} else {
		return Value.toString().replace(/,/g, '.');
	}
}
function CStrRE(Value) {
	//Sostituisce i caratteri escape del parametro [PatternString] con la corretta codifica per un pattern RegExp.
	//Es.  "Come stai? Bene, grazie."  ->  "Come stai\? Bene, grazie\."
	var re, reMatch, precPos, fReturn;
	re = new RegExp('[\\.\\$\\^\\{\\[\\(\\|\\)\\*\\+\\?\\\\]', 'g');
	precPos = 0;
	fReturn = '';
	while ((reMatch = re.exec(Value)) !== null) {
		fReturn += Value.substr(precPos, reMatch.index - precPos) + '\\' + reMatch[0];
		precPos = reMatch.index + 1;
	}
	fReturn += Value.substr(precPos);
	return fReturn;	
}

function CStrUrlParam(Testo) {
      //Converte l'argomento [Testo] in una stringa adatta per essere passata come "valore di parametro" di un percorso URL.
      //Per esempio, la stringa "Cip & ciop" viene convertita in: "Cip%20%26%20ciop".
      var fReturn = Testo;
      fReturn = encodeURIComponent(Testo);
      /*
      fReturn = fReturn.replace(/\x26/g, '%26');                       //"&"
      fReturn = fReturn.replace(/\x23/g, '%23');                       //"="
      fReturn = fReturn.replace(/\x25/g, '%25');                       //"%"
      fReturn = fReturn.replace(/\+/g, '%2B');							//"+"
      fReturn = fReturn.replace(/\x23/g, '%23');                       //"#"
      fReturn = fReturn.replace(/\x0D/g, '%0D');                       //vbCr
      fReturn = fReturn.replace(/\x0A/g, '%0A');                       //vbLf
      */
      return fReturn;
}
function CStrAscii(Value) {
	//NOTA: La funzione [escape] converte tutti i caratteri speciali nel rispettivo valore in forma "%hh", ad eccezione di questi: "@*/+".
	//		Questa è la lista dei caratteri riconosciuti come speciali: " ~!@#$%^&*(){}[]=:/,;?+'""\"
	var fReturn = escape(Value);
	fReturn = fReturn.replace(/\x40/g, '%40');	//Conversione "@"
	fReturn = fReturn.replace(/\x2A/g, '%2A');	//Conversione "*"
	fReturn = fReturn.replace(/\x2F/g, '%2F');	//Conversione "/"
	fReturn = fReturn.replace(/\x2B/g, '%2B');	//Conversione "+"
	fReturn = fReturn.replace(/\x2D/g, '%2D');	//Conversione "-"
	fReturn = fReturn.replace(/\x2E/g, '%2E');	//Conversione "."
	//fReturn = fReturn.replace(/\x2D/g, '%2D');	//Conversione "-"
	//fReturn = fReturn.replace(/%20/g, '+');		//Ripristino " " in "+"
	return fReturn;
}
function CStrByAscii(Value) {
	var fReturn = unescape(Value);
	fReturn = fReturn.replace(/\x2B/g, ' ');	//Conversione "+" in " "
	return fReturn;
}

function GetValue(Value) {
	//Dato un valore numerico con unità di misura, restituisce le due componenti separatamente. La stringa [Value] può essere formata così:
	//		"<numero><um>", "<numero> <um>", "<um><numero>", "<um> <numero>", "<numero>"
	//Il separatore decimale può essere: ".", ",".
	var re, reMatch, strReNum, strReUm, strReSep;
	var fReturn = {source:null, number:null, um:null};
	fReturn.source = Value;
	strReNum = '([0-9]*[\\.,][0-9]+|[0-9]+[\\.,]|[0-9]+)';
	strReUm = '([a-z]{1,4}|[%€\\$£#])';
	strReSep = '\\s*'
	re = new RegExp('^(' + strReNum + strReSep + strReUm + '|' + strReUm + strReSep + strReNum + '|' + strReNum + ')$', 'i');
	reMatch = re.exec(fReturn.source);
	if (reMatch) {
		if (reMatch[2]) {
			fReturn.number = toNumber(reMatch[2]);
			fReturn.um = reMatch[3];
		} else if (reMatch[4]) {
			fReturn.number = toNumber(reMatch[5]);
			fReturn.um = reMatch[4];
		} else if (reMatch[6]) {
			fReturn.number = toNumber(reMatch[6]);
			fReturn.um = null;
		}
	}
	return fReturn;
}

function GetUID() {
	var cont1, valPrec, fReturn;
	fReturn = (new Date()).CDateHtml('yyyymmddhhnnss');
	cont1 = 0;
	valPrec = GetLastUID();
	if (valPrec !== null) {
		if (fReturn == valPrec.substr(0, fReturn.length)) {
			cont1 = CNum(valPrec.substr(fReturn.length)) + 1;
		}
	}
	fReturn += LFill(cont1.toString(), '0', 3);
	SetCookie('JS.GetLastUID', fReturn, 1);
	return fReturn;
}
function GetLastUID() {
	var fReturn;
	fReturn = GetCookie('JS.GetLastUID');
	return fReturn;
}


function StringToUrl(Testo) {      //## OBSOLETA ##

      //Converte l'argomento [Testo] in una stringa adatta per essere usata come "argomenti" di un percorso URL.
      //Per esempio, la stringa "param1=Cip & ciop&param2=x = y - z" viene convertito in: "param1=Cip%20&%20ciop&param2=x%20=%20y%20-%20z".
      //ATTENZIONE: se i valori di parametro contengono caratteri come "&" questi non vengono convertiti. Quindi è preferibile NON UTILIZZARE
      //QUESTA PROCEDURA.
      var fReturn = Testo;
      fReturn = encodeURI(Testo);
      /*
      fReturn = fReturn.replace(/\x25/g, '%25');                        //"%"
      fReturn = fReturn.replace(/\x26/g, '%26');                        //"&"
      fReturn = fReturn.replace(/\+/g,   '%2B');						//"+"
      fReturn = fReturn.replace(/\x23/g, '%23');                        //"#"
      fReturn = fReturn.replace(/\x0D/g, '%0D');                        //vbCr
      fReturn = fReturn.replace(/\x0A/g, '%0A');                        //vbLf
      */
      fReturn = fReturn.replace(/\[Dialog_SepParam\]/g, '&');    //ripristino "&"
      return fReturn;
}


function LTrim(Stringa, optChars) {
	var str1 = Stringa.toString();
	var chr = (optChars) ? optChars : ' ';
	var cont1 = 0, limite = str1.length;
	if (limite > -1 ){
		while(chr.indexOf(str1.charAt(cont1)) > -1) {cont1++; if (cont1>=limite) break;}
		return str1.substr(cont1);
	} else {
		return str1;
	}
}
function RTrim(Stringa, optChars) {
	var str1 = Stringa.toString();
	var chr = (optChars) ? optChars : ' ';
	var cont1 = str1.length - 1, limite = -1;
	if (cont1 > -1 ){
		while(chr.indexOf(str1.charAt(cont1)) > -1) {cont1--; if (cont1<=limite) break;}
		return str1.substr(0, cont1 + 1);
	} else {
		return str1;
	}
}
function Trim(Stringa, optChars) {
	var str1 = Stringa.toString();
	var chr = (optChars) ? optChars : ' ';
	var cont1 = 0, cont2 = str1.length - 1;
	if (cont2 > -1 ){
		while(chr.indexOf(str1.charAt(cont1)) > -1) {cont1++; if (cont1>=cont2) break;}
		while(chr.indexOf(str1.charAt(cont2)) > -1) {cont2--; if (cont2<=cont1) break;}
		return str1.substr(cont1, cont2 - cont1 + 1);
	} else {
		return str1;
	}
}

function LFill(Testo, Carattere, Lunghezza) {
	//Aggiunge [Carattere] a sinistra di [Testo] fino ad arrivare a [Lunghezza].
	//Se la lunghezza di [Testo] è maggiore di [Lunghezza], allora restituisce [Testo] senza variazioni.
	var fReturn, k, cont1;
	
	fReturn = '';
	k = Testo.length;
	if (k > Lunghezza) {
		fReturn = Testo;
	}else{
		cont1 = 0;
		while (cont1 < Lunghezza - k){
			fReturn += Carattere;
			cont1 += 1;
		}
		fReturn += Testo;
	}
	return fReturn;
}
function RFill(Testo, Carattere, Lunghezza) {
	//Aggiunge [Carattere] a destra di [Testo] fino ad arrivare a [Lunghezza].
	//Se la lunghezza di [Testo] è maggiore di [Lunghezza], allora restituisce [Testo] senza variazioni.
	var fReturn, k, cont1;
	
	fReturn = '';
	k = Testo.length;
	if (k > Lunghezza) {
		fReturn = Testo;
	}else{
		cont1 = 0;
		fReturn += Testo;		
		while (cont1 < Lunghezza - k){
			fReturn += Carattere;
			cont1 += 1;
		}
	}
	return fReturn;
}

function StringRepeater(strInput, intCount) {
	var arrTmp = new Array(intCount + 1);
	return arrTmp.join(strInput);
}

function ReplaceArgList(Text, ArgumentList) {
	/*	Restituisce il [Text] indicato sostituendo gli argomenti presenti nel testo. Questi sono indicati in stile .NET.
		Esempi:  "Ciao {0}", "Ciao {0}, ti saluta {1}.", "Ciao {0}, ti saluta {1}. Scritto da {2} per {0}."
		Argomenti:
			Text :			testo da compilare; i segnaposti saranno indicati con questo formato: {<num.arg.base 0>}; per restituire "{" usare "{{";
							per restituire "}" usare "}}".
			ArgumentList :	lista degli argomenti; verranno sostituiti ai segnaposti in base alla posizione dell'elemento nell'array.
		Nota: se l'array non contiene l'argomento voluto dal segnaposto, questo non verrà sostituito.
		-- procedura convertita da quella di "Funzioni.asp" --
	*/
	var re, reMatch, reMatchPrec;
	var fReturn, cont1, noMatches;
	re = /(\{\{|}}|\{[0-9]+})/g;
	noMatches = true;
	fReturn = '';
	reMatchPrec = null;
	while ((reMatch = re.exec(Text)) !== null) {
		noMatches = false;
		if (reMatchPrec === null) {
			fReturn = Text.substr(0, reMatch.index);
		} else {
			cont1 = reMatchPrec.index + reMatchPrec[0].length;		//posizione dell'ultimo carattere del match precedente (base 1)
			fReturn += Text.substr(cont1, reMatch.index - cont1);
		}
		switch (reMatch[0]) {
			case '{{':
				fReturn += '{';
				break;
			case '}}':
				fReturn += '}';
				break;
			default:
				cont1 = CNum(reMatch[0].substr(1, reMatch[0].length - 2));
				if (cont1 === null) cont1 = -1;
				if (cont1 < 0 || cont1 >= ArgumentList.length) {
					fReturn += reMatch[0];
				} else {
					fReturn += ArgumentList[cont1];
				}
				break;
		}
		reMatchPrec = reMatch;
	}
	if (!noMatches) {
		cont1 = reMatchPrec.index + reMatchPrec[0].length;		//posizione dell'ultimo carattere del match precedente (base 1)
		fReturn += Text.substr(cont1);
	} else {
		fReturn = Text;
	}
	return fReturn;
}
function ReplaceArgDict(Text, ArgumentDictionary, optO_TextArguments) {
	var re, reMatch, noMatches;
	var gruppoCurr, gruppoPrec;
	var posizCurr, posizPrec;
	var argList, argInText;
	var cont1;
	var fReturn;
	re = /(\{([^\x00-\x1f\{}]+)})/g;
	noMatches = true;
	fReturn = '';
	posizPrec = -1;
	argList = new Array();		//argomenti da passare a [ReplaceArgList]
	argInText = (ValueType(optO_TextArguments) == 'Array' ? optO_TextArguments : new Array());	//argomenti trovati nella stringa [Text]
	while ((reMatch = re.exec(Text)) !== null) {
		noMatches = false;
		gruppoCurr = reMatch[2];				//restituisce il solo nome del gruppo
		if (IsNull(InArray(argInText, gruppoCurr))) argInText.push(gruppoCurr);
		posizCurr = reMatch.index + 1;			//aggiungo 1 perchè devo scavalcare il primo carattere, aperta graffa "{".
		//Accodo il testo al di fuori del gruppo, tra il gruppo precedente e quello corrente
		if (posizPrec == -1) {
			fReturn = Text.substr(0, posizCurr);
		} else {
			cont1 = posizPrec + gruppoPrec.length;		//posizione dell'ultimo carattere del match precedente (base 1)
			fReturn += Text.substr(cont1, posizCurr - cont1);
		}
		//Eseguo la sostituzione <nome> -> <indice>
		if (IsUndefined(ArgumentDictionary[gruppoCurr])) {
			fReturn += gruppoCurr;
		} else {
			argList.push(ArgumentDictionary[gruppoCurr]);
			cont1 = argList.length - 1;
			fReturn += cont1.toString();
		}
		//Mi tengo il Gruppo corrente da una parte
		gruppoPrec = gruppoCurr;
		posizPrec = posizCurr;
	}
	if (!noMatches) {
		cont1 = posizPrec + gruppoPrec.length;		//posizione dell'ultimo carattere del match precedente (base 1)
		fReturn += Text.substr(cont1);
	} else {
		fReturn = Text;
	}
	//if (ValueType(optO_TextArguments) == 'Array') optO_TextArguments.push(argInText);
	return ReplaceArgList(fReturn, argList);
}


function IsTrue(Value) {
	var str1;
	if (ValueType(Value) == 'undefined') str1 = ''; else str1 = Value.toString().toLowerCase();
	switch (str1) {
		case 't': case 'true':
		case 'v': case 'vero':
		case 'y': case 'yes':
		case 's': case 'si': case 'sì':
		case 'on':
		case '1': case '-1':
			return true;
		default:
			return false;
	}
}
function IsFalse(Value) {
	var str1;
	if (ValueType(Value) == 'undefined') str1 = ''; else str1 = Value.toString().toLowerCase();
	switch (str1) {
		case 'f': case 'false': case 'falso':
		case 'n': case 'no':
		case 'off':
		case '0':
			return true;
		default:
			return false;
	}
}
function IsUndefined(Value) {
	return (Value === void(0));
}


function CDate(DateString, optFormat) {
	var strFormato = optFormat;
	var cont1, cont2, str1;
	var fReturn = null;
	
	var creaPattern = function (StrFormato) {
		var pattern = '';
		var posiz = new Array();
		var subPts = {YEAR:'(\\d{1,4})', NUM:'(\\d{1,2})', sepd:'[/\\-]', sept:'[:\\.]', sep:'[ ]+', TMP:'[ ]?(am|pm|a|p)'};
		for (var cont1 = 0; cont1 < StrFormato.length; cont1++) {
			switch (StrFormato.charAt(cont1)) {
				case 'y':	pattern += subPts.YEAR;	posiz.push('y');	break;
				case 'm':	pattern += subPts.NUM;	posiz.push('m');	break;
				case 'd':	pattern += subPts.NUM;	posiz.push('d');	break;
				case 'h':	pattern += subPts.NUM;	posiz.push('h');	break;
				case 'n':	pattern += subPts.NUM;	posiz.push('n');	break;
				case 's':	pattern += subPts.NUM;	posiz.push('s');	break;
				case 't':	pattern += subPts.TMP;	posiz.push('t');	break;
				case '/':	pattern += subPts.sepd;	break;
				case '.':	pattern += subPts.sept;	break;
				case ' ':	pattern += subPts.sep;	break;
				case '\\':	pattern += '[' + StrFormato.charAt(cont1+1) + ']';	cont1++; break;
			}
		}
		return {'pattern':pattern, 'posiz':posiz};
	}
	
	switch (ValueType(DateString)) {
		case 'Date':
			fReturn = DateString;
			break;
		case 'string':
			//Ottengo grossomodo la stringa di formato
			if (strFormato) strFormato = strFormato.toLowerCase();
			if (!strFormato) strFormato = '';
			/* switch (strFormato) {
				case '':
				case 'date':		strFormato = 'd/m/y';			break;
				case 'time':		strFormato = 'h.n.s';			break;
				case 'datetime':	strFormato = 'd/m/y h.n.s';		break;
				case 'iso':			strFormato = 'y-m-d\\Th.n.s';	break;
			}	*/
			switch (strFormato) {
				case '':
				case 'date':		strFormato = CDateHtml_GetFormat(1, 1, 1, 0, 0, 0); break;
				case 'time':		strFormato = CDateHtml_GetFormat(0, 0, 0, 1, 1, 1); break;
				case 'datetime':	strFormato = CDateHtml_GetFormat(1, 1, 1, 1, 1, 1); break;
				case 'iso':			strFormato = 'y-m-d\\Th.n.s';	break;
			}
			//Standardizzo la stringa di formato
			str1 = 'ymdhnst ';
			for (cont1 = 0; cont1 < str1.length; cont1++) {
				strFormato = strFormato.replace(new RegExp('[' + str1.charAt(cont1) + ']', 'gi'), str1.charAt(cont1));
			}
			strFormato = strFormato.replace(/[/\-]+/g, '/');
			strFormato = strFormato.replace(/[:\.]+/g, '.');
			//Converto la stringa di formato in regularExpression
			var ricercheColl = new Array();
			var rePattern, rePattern_Pos;
			switch (strFormato) {
				case 'd/m/y':	case 'd/m/y h.n':	case 'd/m/y h.n.s':
					for (cont1 = 0; cont1 < Math.pow(2, 3); cont1++) {
						str1 = 'd/m/y h.n.st';
						if (cont1 % 2 > 0) str1 = str1.replace('/y', '');
						if (cont1 % 4 > 0) str1 = str1.replace('t', '');
						if (cont1 % 8 > 0) str1 = str1.replace('.s', '');
						str1 = Trim(str1);
						ricercheColl.push(creaPattern(str1));
					}
					ricercheColl.push(creaPattern('d/m/y'));
					ricercheColl.push(creaPattern('d/m'));
					break;
				case 'm/d/y':	case 'm/d/y h.n':	case 'm/d/y h.n.s':
					for (cont1 = 0; cont1 < Math.pow(2, 3); cont1++) {
						str1 = 'm/d/y h.n.st';
						if (cont1 % 2 > 0) str1 = str1.replace('/y', '');
						if (cont1 % 4 > 0) str1 = str1.replace('t', '');
						if (cont1 % 8 > 0) str1 = str1.replace('.s', '');
						str1 = Trim(str1);
						ricercheColl.push(creaPattern(str1));
					}
					ricercheColl.push(creaPattern('m/d/y'));
					ricercheColl.push(creaPattern('m/d'));
					break;
				case 'y/m/d':	case 'y/m/d h.n':	case 'y/m/d h.n.s':
					for (cont1 = 0; cont1 < Math.pow(2, 3); cont1++) {
						str1 = 'y/m/d h.n.st';
						if (cont1 % 2 > 0) str1 = str1.replace('y/', '');
						if (cont1 % 4 > 0) str1 = str1.replace('t', '');
						if (cont1 % 8 > 0) str1 = str1.replace('.s', '');
						str1 = Trim(str1);
						ricercheColl.push(creaPattern(str1));
					}
					ricercheColl.push(creaPattern('y/m/d'));
					ricercheColl.push(creaPattern('m/d'));
					break;
				default:
					ricercheColl.push(creaPattern(strFormato));
					break;
			}
			if (ricercheColl.length) {
				for (cont1 = 0; cont1 < ricercheColl.length; cont1++) {
					rePattern = ricercheColl[cont1].pattern;
					rePattern_Pos = ricercheColl[cont1].posiz;
					var re = new RegExp('^[ ]*' + rePattern + '[ ]*$', 'i');
					var reMatch = re.exec(DateString);
					if (reMatch) {
						var valori = {y:0, m:0, d:1, h:0, n:0, s:0, t:''};
						for (cont1 = 0; cont1 < rePattern_Pos.length; cont1++) {
							valori[rePattern_Pos[cont1]] = reMatch[cont1+1];
						}
						if (valori['y'] === 0) {
							if (valori['m'] > 0) valori['y'] = (new Date()).getFullYear();
						} else if (valori['y'].length < 3) {
							valori['y'] = CNum(valori['y']);
							valori['y'] += (valori['y'] > 50 ? 1900 : 2000);
						}
						if (valori['m'] !== 0) valori['m'] = CNum(valori['m']) - 1;
						if (valori['t'].toLowerCase() == 'pm') valori['h'] = CNum(valori['h']) + 12;
						fReturn = new Date(valori['y'], valori['m'], valori['d'], valori['h'], valori['n'], valori['s']);
						break;
					}
				}
			}
			break;
	}
	return fReturn;
}

function CDateHtml__OLD(Format, DateObj) {
	var dVal = (DateObj ? DateObj : this);
	var strFormato = Format;
	var fReturn;
	if (strFormato) strFormato = strFormato.toLowerCase();
	switch (strFormato) {
		case 'iso':
			fReturn = dVal.getFullYear() +
					'-' + (dVal.getMonth()<9?'0':'') + (dVal.getMonth()+1).toString() +
					'-' + (dVal.getDate()<10?'0':'') + dVal.getDate().toString() +
					'T' + (dVal.getHours()<10?'0':'') + dVal.getHours().toString() +
					':' + (dVal.getMinutes()<10?'0':'') + dVal.getMinutes().toString() +
					':' + (dVal.getSeconds()<10?'0':'') + dVal.getSeconds().toString();
			break;
		case '':
		case 'time':
			fReturn = (dVal.getHours()<10?'0':'') + dVal.getHours().toString() +
					':' + (dVal.getMinutes()<10?'0':'') + dVal.getMinutes().toString() +
					':' + (dVal.getSeconds()<10?'0':'') + dVal.getSeconds().toString();
		case 'datetime':
			fReturn = (dVal.getDate()<10?'0':'') + dVal.getDate().toString() +
					'/' + (dVal.getMonth()<9?'0':'') + (dVal.getMonth()+1).toString() +
					'/' + dVal.getFullYear() +
					' ' + (dVal.getHours()<10?'0':'') + dVal.getHours().toString() +
					':' + (dVal.getMinutes()<10?'0':'') + dVal.getMinutes().toString() +
					':' + (dVal.getSeconds()<10?'0':'') + dVal.getSeconds().toString();
			break;
		case 'date':
		default:
			fReturn = (dVal.getDate()<10?'0':'') + dVal.getDate().toString() +
					'/' + (dVal.getMonth()<9?'0':'') + (dVal.getMonth()+1).toString() +
					'/' + dVal.getFullYear();
			break;
	}
	return fReturn;
}
function CDateHtml(Format, DateObj) {
	/*Converte il valore di tipo DATETIME in una stinga. L'argomento [Formato] puo essere:
		- "date", "time", "datetime":	la funzione restituisce la data, l'ora o data-ora nel formato della lingua corrente;
		- "iso":		la funzione restituisce la data in un formato ordinabile (secondo lo standard ISO 8601);
		- "":			come con "date";
		- <lingua>:		passando una lingua gestita dal sito, restituisce la data nel formato della lingua indicata;
		- <formato data ora valido>:	passando una stringa di formattazione, si ottiene una stringa data-ora in formato personalizzato; la stringa
						converte questi caratteri in rispettivi informazioni DataOra (non è case-sensitive):
							y-anno  m-mese  d-giorno  w-settimana  h-ora  n-minuto  s-secondo  t-am/pm  ("\": carattere escape).
	*/
	var DataOra = (DateObj ? DateObj : this);
	var strFormato, lanCorrente, fReturn;
	var listaAmPm, isPomeriggio, numChars, primoVal, segnapostiTrovati;
	var cont1, str1, char1, valore;
	if (IsUndefined(DataOra) || DataOra === null) {
		fReturn = null;
	} else if (DataOra) {
		valore = DataOra;
		if (Format == window.Lan) {
			lanCorrente = Format;
			strFormato = CDateHtml_GetFormat(4, 2, 2, 0, 0, 0, 0);
		} else {
			lanCorrente = window.Lan;
			switch (IfNull(Format, '').toLowerCase()) {
				case '':
				case 'date'		: strFormato = CDateHtml_GetFormat(4, 2, 2, 0, 0, 0, 0); break;
				case 'time'		: strFormato = CDateHtml_GetFormat(0, 0, 0, 2, 2, 2, 0); break;
				case 'datetime'	: strFormato = CDateHtml_GetFormat(4, 2, 2, 2, 2, 2, 0); break;
				case 'iso'		: strFormato = 'yyyy-mm-dd\\Thh:nn:ss'; break;
				default			: strFormato = Format; break;
			}
		}
		listaAmPm = CDateHtml_GetFormatInfo().amPm;
		//Determino la lista dei segnaposti validi
		segnapostiTrovati = '';
		for (cont1 = 0; cont1 < strFormato.length; cont1++) {
			char1 = strFormato.charAt(cont1).toLowerCase();
			if (('ymdwhnst\\').indexOf(char1) > -1) {
				if (char1 == '\\') {
					cont1 += 1;
				} else if (segnapostiTrovati.indexOf(char1) == -1) {
					segnapostiTrovati += char1;
				}
			}
		}
		//Formatto la data
		fReturn = '';
		for (cont1 = 0; cont1 < strFormato.length; cont1++) {
			char1 = strFormato.charAt(cont1).toLowerCase();
			if (('ymdwhnst\\').indexOf(char1) > -1) {
				if (char1 == '\\') {
					cont1 += 1;
					str1 = strFormato.charAt(cont1);
				} else {
					for (numChars = cont1 + 1; numChars < strFormato.length; numChars++) {
						if (char1 != strFormato.charAt(numChars).toLowerCase()) break;
					}
					numChars = numChars - cont1;		//Ora, numChars indica il numero di caratteri consegutivi uguali.
					cont1 = cont1 + numChars - 1;		//Sposto il puntatore del For-To-Next al carattere successivo.
					switch (char1) {
						case 'y': if (numChars <= 2) numChars = 2; else numChars = 4; break;
						case 'm': if (numChars > 4) numChars = 4; break;
						case 'd': if (numChars > 2) numChars = 2; break;
						case 'w': if (numChars <= 2) numChars = 2; else if (numChars > 4) numChars = 4; break;
						case 'h': if (numChars > 2) numChars = 2; break;
						case 'n': if (numChars > 2) numChars = 2; break;
						case 's': if (numChars > 2) numChars = 2; break;
						case 't': numChars = 1; break;
					}
					switch (char1) {
						case 'y':
							str1 = valore.getFullYear().toString();
							str1 = str1.substr(str1.length - numChars);
							break;
						case 'm':
							if (numChars <= 2) {
								str1 = (valore.getMonth() + 1).toString();
								str1 = LFill(str1, '0', numChars);
							} else {
								str1 = valore.GetMonthName();
								if (numChars == 3) str1 = str1.substr(0, numChars);
								str1 = str1.substr(0, 1).toUpperCase() + str1.substr(1).toLowerCase();
							}
							break;
						case "d": str1 = LFill(valore.getDate().toString(), '0', numChars); break;
						case 'w':
							str1 = valore.GetWeekName();
							if (numChars <= 3) str1 = str1.substr(0, numChars);
							str1 = str1.substr(0, 1).toUpperCase() + str1.substr(1).toLowerCase();
							break;
						case 'h':
							str1 = valore.getHours();
							if (segnapostiTrovati.toLowerCase().indexOf('t') > -1) {
								isPomeriggio = (str1 >= 12);
								if (str1 == 0) {
									str1 = 12;
								} else if (str1 > 12) {
									str1 = str1 - 12;
								}
							}
							str1 = LFill(str1.toString(), '0', numChars);
							break;
						case 'n': str1 = LFill(valore.getMinutes().toString(), "0", numChars); break;
						case 's': str1 = LFill(valore.getSeconds().toString(), "0", numChars); break;
						case 't':
							if (segnapostiTrovati.toLowerCase().indexOf('h') > -1) {
								str1 = listaAmPm[(isPomeriggio ? 1 : 0)];
							} else {
								str1 = '';
							}
							break;
					}
				}
				fReturn += str1;
			} else {
				fReturn += char1;
			}
		}
		fReturn = CStrHtml(fReturn);
	} else {
		fReturn = DataOra;
	}
	return fReturn;
}
Date.prototype.CDateHtml = CDateHtml;

function DateAdd(TimeUnit, Value, DateObj) {
	var dVal = (DateObj ? DateObj : this);
	var newDate;
	switch (TimeUnit) {
		case 'ms':newDate = new Date(dVal); newDate.setMilliseconds(newDate.getMilliseconds() + Value); break;
		case 's': newDate = new Date(dVal); newDate.setSeconds(newDate.getSeconds() + Value); break;
		case 'n': newDate = new Date(dVal); newDate.setMinutes(newDate.getMinutes() + Value); break;
		case 'h': newDate = new Date(dVal); newDate.setHours(newDate.getHours() + Value); break;
		case 'd': newDate = new Date(dVal); newDate.setDate(newDate.getDate() + Value); break;
		case 'w': newDate = new Date(dVal); newDate.setDate(newDate.getDate() + Value * 7); break;
		case 'm': newDate = new Date(dVal); newDate.setMonth(newDate.getMonth() + Value); break;
		case 'y': newDate = new Date(dVal); newDate.setFullYear(newDate.getFullYear() + Value); break;
	}
	return newDate;
}
Date.prototype.DateAdd = DateAdd;

function DateAddUTC(TimeUnit, Value, DateObj) {
	var millisecond = 1;
	var second = millisecond * 1000;
	var minute = second * 60;
	var hour = minute * 60;
	var day = hour * 24;
	var week = day * 7;
	var dVal = (DateObj ? DateObj : this).valueOf();
	var newDate;
	
	switch (TimeUnit) {
		case 'ms':newDate = new Date(dVal + millisecond * Value); break;
		case 's': newDate = new Date(dVal + second * Value); break;
		case 'n': newDate = new Date(dVal + minute * Value); break;
		case 'h': newDate = new Date(dVal + hour * Value); break;
		case 'd': newDate = new Date(dVal + day * Value); break;
		case 'w': newDate = new Date(dVal + week * Value); break;
		case 'm': newDate = new Date(dVal); newDate.setUTCMonth(newDate.getUTCMonth() + Value); break;
		case 'y': newDate = new Date(dVal); newDate.setUTCFullYear(newDate.getUTCFullYear() + Value); break;
	}
	return newDate;
}
Date.prototype.DateAddUTC = DateAddUTC;

function GetWeekName(DateObj) {
	var objData = (DateObj ? DateObj : this);
	var vett1 = objData.toLocaleDateString().split(' ');
	var cont1;
	for (cont1=0; cont1<vett1.length; cont1++) {
		if (vett1[cont1].length > 2 && CNum(vett1[cont1]) != objData.getFullYear()) return vett1[cont1];
	}
}
Date.prototype.GetWeekName = GetWeekName;

function GetMonthName(DateObj) {
	var objData = (DateObj ? DateObj : this);
	var vett1 = objData.toLocaleDateString().split(' ');
	var cont1;
	for (cont1=1; cont1<vett1.length; cont1++) {
		if (vett1[cont1].length > 2 && CNum(vett1[cont1]) != objData.getFullYear()) return vett1[cont1];
	}
}
Date.prototype.GetMonthName = GetMonthName;

function SetDailyTime(Milliseconds, DateObj) {
	//Setta l'ora alla data corrente.
	var objData = (DateObj ? DateObj : this);
	var h, n, s, ms, val, resto;
	val = Milliseconds;
	resto = val % 3600000;	objData.setHours((val - resto) / 3600000);	val = resto;
	resto = val % 60000;	objData.setMinutes((val - resto) / 60000);	val = resto;
	resto = val % 1000;		objData.setSeconds((val - resto) / 1000);	val = resto;
	objData.setMilliseconds(val);
}
Date.prototype.SetDailyTime = SetDailyTime;


function CDateHtml_GetFormat(optYearDigits, optMonthDigits, optDayDigits, optHoutDigits, optMinuteDigits, optSecondDigits, optWeekDigits) {
	//Restituisce il formato di DATA-ORA per CDateHtml secondo la lingua indicata nel primo parametro. I successivi parametri sono
	//numerici, e va indicato il numero di cifre (zero per indicare nessun valore) da usare per quella info. Il mese e la settimana
	//posono essere anche a 3 o 4 cifre, che quindi restituirà il mese espresso in lettere, abbreviato a 3 o per esteso.
	var formatoDict, formato, sepData, sepOra;
	var fReturn, str1, cont1;
	
	//Cerco di determinare la posizione degli elementi della data, e il formato di ora.
	formatoDict = CDateHtml_GetFormatInfo();
	formato = formatoDict.format;
	sepData = formatoDict.dateSep;
	sepOra = formatoDict.hourSep;
	
	fReturn = '';
	for (cont1 = 0; cont1 < formato.length; cont1++) {
		switch (formato.charAt(cont1)) {
			case 'w': str1 = StringRepeater('w', (optWeekDigits ? optWeekDigits : 0)); break;
			case 'd': str1 = StringRepeater('d', (optDayDigits ? optDayDigits : 0)); break;
			case 'm': str1 = StringRepeater('m', (optMonthDigits ? optMonthDigits : 0)); break;
			case 'y': str1 = StringRepeater('y', (optYearDigits ? optYearDigits : 0)); break;
			case 'h': str1 = StringRepeater('h', (optHoutDigits ? optHoutDigits : 0)); break;
			case 'n': str1 = StringRepeater('n', (optMinuteDigits ? optMinuteDigits : 0)); break;
			case 's': str1 = StringRepeater('s', (optSecondDigits ? optSecondDigits : 0)); break;
			case 't': str1 = (optHoutDigits > 0 ? 't' : ''); break;
			case '/': str1 = (optMonthDigits > 2 ? ' ' : sepData); break;
			case '.': str1 = sepOra; break;
			case ' ': str1 = ' '; break;
			default:  str1 = ''; break;
		}
		fReturn += str1;
	}
	fReturn = Trim(fReturn, ' ' + sepData + sepOra);
	
	return fReturn;
}
function CDateHtml_GetFormatInfo() {
	//Restituisce un dictionary con informazioni su come è formattata la data ed ora nel pc del client. I valori ritornati sono:
	//	'format'	: il formato della data-ora, per determinare la posizione dei vari elementi; es: "w d/m/y h.n.s", "w m/d/y h.n.s";
	//	'dateSep'	: il separatore usato per separare i componenti della data;
	//	'hourSep'	: il separatore usato per separare i componenti dell'ora;
	//	'amPm'		: array con i valori usati per indicare AM e PM, in quest'ordine.
	var fReturn, re, reMatch;
	var str1, cont1, data1;
	var ora24, trovatoWeek;
	//Analizzo una data-ora, dove non rischio di scambiare un valore per un altro (giorno con mese e così via).
	//Attenzione: ho difficoltà a distinguere il mese con il giorno della settimana, quindi considero sempre che la settimana è la prima cosa che
	//deve apparire.
	data1 = new Date(2001, 3, 4, 17, 18, 19);
	re = new RegExp('(2001|01|3|4|17|5|18|19|[a-z]{2,20})', 'gi');
	fReturn = {format:'', dateSep:'/', hourSep:':', amPm:['am','pm']};
	fReturn.format = 'w ';
	//Inizio analisi data
	trovatoWeek = false;
	while ((reMatch = re.exec(data1.toLocaleDateString())) !== null) {
		switch (reMatch[1]) {
			case '2001':str1 = 'y'; break;
			case '01':	str1 = 'y'; break;
			case '3':	str1 = 'm'; break;
			case '4':	str1 = 'd'; break;
			default:
				if (!trovatoWeek) {
					trovatoWeek = true;
					str1 = '';
				} else {
					str1 = 'm';
				}
				break;
		}
		if (str1) fReturn.format += (fReturn.format.charAt(fReturn.format.length-1)==' ' ? '' : '/') + str1;
	}
	//Inizio analisi ora
	fReturn.format += ' ';
	while ((reMatch = re.exec(data1.toLocaleTimeString())) !== null) {
		switch (reMatch[1]) {
			case '17':	str1 = 'h'; ora24 = true; break;
			case '5':	str1 = 'h'; ora24 = false; break;
			case '18':	str1 = 'n'; break;
			case '19':	str1 = 's'; break;
			default:	str1 = ''; break;
		}
		if (str1) fReturn.format += (fReturn.format.charAt(fReturn.format.length-1)==' ' ? '' : '.') + str1;
	}
	if (!ora24) fReturn.format += ' t';
	//Determino il separatore delle ore (attenzione: non ho possibilità di conoscere il dateSep perchè javascript non mi restituisce la data in forma numerica)
	re = new RegExp('18(.)19', 'gi');
	reMatch = re.exec(data1.toLocaleTimeString());
	fReturn.hourSep = reMatch[1];
	return fReturn;
}


//###############################################################################
//####		Elenco di procedure per la gestione di valori all'interno di un array.


function CreateList(oArrayObj) {
	var fReturn = oArrayObj;
	if (!fReturn) fReturn = new Array();
	fReturn.objectType = function () {return 'List';}
	fReturn.Exists = function (Value) {
		for (var i in this) {if (this[i] == Value) return true;}
		return false;
	}
	SerializeValue__ArrayColl_addArrayType(fReturn, 'Array');
	return fReturn;
}
function CreateDictionary(oArrayObj) {
	var fReturn = oArrayObj;
	if (!fReturn) fReturn = new Array();
	fReturn.objectType = function () {return 'Dictionary';}
	fReturn.RemoveKeys = function (Keys) {
		var i, j, obj1, vett1;
		if (ValueType(Keys) == 'Array') {
			vett1 = Keys;
		} else {
			vett1 = new Array(); vett1.push(Keys);
		}
		for (i = 0; i < vett1.length; i++) {
			j = 0;
			for (obj1 in this) {
				if (obj1 == vett1[i]) {
					if (1*obj1 != obj1) {delete this[obj1];} else {this.splice(j, 1);}
				} else {
					j++;
				}
			}
		}
	}
	SerializeValue__ArrayColl_addArrayType(fReturn, 'Dictionary');
	return fReturn;
}


function InArray(ArrayObject, Value) {
	//Cerca il valore nell'array, e restituisce la rispettiva KEY. Se non viene trovato restituisce NULL.
	var str1, fReturn;
	fReturn = null;
	if (ValueType(ArrayObject) == 'Array') {
		if (typeof(Value) == 'object') {
			for (str1 in ArrayObject) {
				if (ArrayObject[str1] === Value) {
					fReturn = str1;
					break;
				}
			}
		} else {
			for (str1 in ArrayObject) {
				if (ArrayObject[str1] == Value) {
					fReturn = str1;
					break;
				}
			}
		}
	}
	return fReturn;
}
/*
function InArrayRev(ArrayObject, Value) {
	//Cerca il valore nell'array, e restituisce la rispettiva KEY. Se non viene trovato restituisce NULL.
	//La ricerca avviene in ordine inverso.
}
function InKeyArray(ArrayObject, KeyValue) {
	//Cerca la KEY nell'array, e restituisce la rispettiva posizione. Se non viene trovato restituisce NULL.
}
*/
function TextInArray(ArrayObject, String) {
	//Cerca il valore di tipo string nell'array (no case sensitive), 
	var str1, valore, fReturn;
	fReturn = null;
	valore = String.toString();
	if (ValueType(ArrayObject) == 'Array') {
		for (str1 in ArrayObject) {
			if (valore.localeCompare(ArrayObject[str1].toString()) == 0) {
				fReturn = str1;
				break;
			}
		}
	}
	return fReturn;
	
}
function FindArrayItem(ArrayName, ItemKey, optWindow) {
	//Cerca l'item [ItemKey] nell'array [ArrayName]. Argomenti:
	//	ArrayName:		nome dell'array su cui cercare l'item.
	//	ItemKey:		la chiave dell'item da restituire.
	//	optWindow:		(opzionale) oggetto [Window] su cui cercare.
	var p, i, x, y, objWin;
	if (!(objWin = optWindow)) objWin = window;
	if (!y && (x = objWin[ArrayName])) y = x[ItemKey];
	if (!y && objWin.frames && !optWindow) {
		if (!y && objWin.frames.top) {y = FindArrayItem(ArrayName, ItemKey, objWin.frames.top.window);}
		if (!y) for (i=0; i < objWin.frames.length && !y; i++) {y = FindArrayItem(ArrayName, ItemKey, objWin.frames[i].window);}
	}
	return y;
}


function ValueType(Value) {
	//Restituisce il tipo di valore o oggetto
	var fReturn;
	if (Value === void(0)) {
		fReturn = 'undefined';
	} else if (Value === null) {
		fReturn = 'null';
	} else if (Value === '') {
		fReturn = 'empty';
	} else {
		fReturn = typeof(Value);	//Può essere: string, number, boolean, object, function
		if (fReturn == 'object') {
			//Cerco di vedere se Value è uno di questi specifici oggetti. Notare che questi hanno la prima lettera maiuscola. Quindi si
			//può sfruttare questa informazione per sapere se il tipo restituito 'OBJECT' è un tipo generico oppure esattamente 'Object'.
			if (Value instanceof Array) {
				fReturn = 'Array';
			} else if (Value instanceof Date) {
				fReturn = 'Date';
			} else if (Value instanceof RegExp) {
				fReturn = 'RegExp';
			} else {	//if (Value instanceof Object) {
				fReturn = 'Object';
			}
		} else if (fReturn == 'function') {
			fReturn = 'Function';
		}
	}
	return fReturn;
}

function HTMLEncode(Value){
	// Converte la stringa passata nel formato HTML
	var k, cont1;		//cont1 mi serve per iterare sulla stringa
	var cont2;			//mi serve per memmorizzare il carattere di partenza pgni volta che trovo un carattere da codificare
	var chars, ascChars;
	var trovato;
	var fReturn;
	
	if (Value === void(0) || Value === null) {
		fReturn = null;
	} else {
		fReturn = '';
		k = Value.length;
		cont1 = 0;
		cont2 = 0;
		trovato = false;
		
		while (cont1 < k) {
			ascChars = Value.charCodeAt(cont1);
			if (ascChars >= 128) {
				chars = '&#' + ascChars + ';';
				trovato = true;
			} else {
				switch (Value.charAt(cont1)) {
					case '"':	chars = '&quot;';	trovato = true; break;
					case '&':	chars = '&amp;';	trovato = true; break;
					case '<':	chars = '&lt;';		trovato = true; break;
					case '>':	chars = '&gt;';		trovato = true; break;
				}
			}
			if (trovato) {
				fReturn += Value.substr(cont2, cont1 - cont2) + chars;
				cont2 = cont1 + 1;
				trovato = false;
			}
			cont1 += 1;
		}	
		if (!trovato) fReturn += Value.substr(cont2);
	}
	return fReturn;
}

function HTMLDecode(TestoHtml){
	// converte caratteri codificati da Html a Unicode
	var re, indice, reMatch, str1;
	var nuovoVal;
	var fReturn;
	
	indice = 0;
	fReturn = '';
	nuovoVal = -1;
	re = new RegExp('&(#x[0-9a-fA-F]+|#[0-9]+|[a-zA-Z]{1,9}[0-9]{0,3});', 'g');
	reMatch = re.exec(TestoHtml);
	while (reMatch !== null){
		str1 = reMatch[1];
		if (str1.substr(0,2) == '#x') {
			nuovoVal = parseInt(str1.substr(2), 16);
		} else if (str1.substr(0,1) == '#') {
			nuovoVal = str1.substr(1);
		} else {
			switch (str1){
				case 'quot'  : nuovoVal = 34; break;
				case 'amp'  : nuovoVal = 38; break;
				case 'lt'  : nuovoVal = 60; break;
				case 'gt'  : nuovoVal = 62; break;
				case 'nbsp'  : nuovoVal = 160; break;
				case 'iexcl'  : nuovoVal = 161; break;
				case 'cent'  : nuovoVal = 162; break;
				case 'pound'  : nuovoVal = 163; break;
				case 'curren'  : nuovoVal = 164; break;
				case 'yen'  : nuovoVal = 165; break;
				case 'brvbar'  : nuovoVal = 166; break;
				case 'sect'  : nuovoVal = 167; break;
				case 'uml'  : nuovoVal = 168; break;
				case 'copy'  : nuovoVal = 169; break;
				case 'ordf'  : nuovoVal = 170; break;
				case 'laquo'  : nuovoVal = 171; break;
				case 'not'  : nuovoVal = 172; break;
				case 'shy'  : nuovoVal = 173; break;
				case 'reg'  : nuovoVal = 174; break;
				case 'macr'  : nuovoVal = 175; break;
				case 'deg'  : nuovoVal = 176; break;
				case 'plusmn'  : nuovoVal = 177; break;
				case 'sup2'  : nuovoVal = 178; break;
				case 'sup3'  : nuovoVal = 179; break;
				case 'acute'  : nuovoVal = 180; break;
				case 'micro'  : nuovoVal = 181; break;
				case 'para'  : nuovoVal = 182; break;
				case 'middot'  : nuovoVal = 183; break;
				case 'cedil'  : nuovoVal = 184; break;
				case 'sup1'  : nuovoVal = 185; break;
				case 'ordm'  : nuovoVal = 186; break;
				case 'raquo'  : nuovoVal = 187; break;
				case 'frac14'  : nuovoVal = 188; break;
				case 'frac12'  : nuovoVal = 189; break;
				case 'frac34'  : nuovoVal = 190; break;
				case 'iquest'  : nuovoVal = 191; break;
				case 'Agrave'  : nuovoVal = 192; break;
				case 'Aacute'  : nuovoVal = 193; break;
				case 'Acirc'  : nuovoVal = 194; break;
				case 'Atilde'  : nuovoVal = 195; break;
				case 'Auml'  : nuovoVal = 196; break;
				case 'Aring'  : nuovoVal = 197; break;
				case 'AElig'  : nuovoVal = 198; break;
				case 'Ccedil'  : nuovoVal = 199; break;
				case 'Egrave'  : nuovoVal = 200; break;
				case 'Eacute'  : nuovoVal = 201; break;
				case 'Ecirc'  : nuovoVal = 202; break;
				case 'Euml'  : nuovoVal = 203; break;
				case 'Igrave'  : nuovoVal = 204; break;
				case 'Iacute'  : nuovoVal = 205; break;
				case 'Icirc'  : nuovoVal = 206; break;
				case 'Iuml'  : nuovoVal = 207; break;
				case 'ETH'  : nuovoVal = 208; break;
				case 'Ntilde'  : nuovoVal = 209; break;
				case 'Ograve'  : nuovoVal = 210; break;
				case 'Oacute'  : nuovoVal = 211; break;
				case 'Ocirc'  : nuovoVal = 212; break;
				case 'Otilde'  : nuovoVal = 213; break;
				case 'Ouml'  : nuovoVal = 214; break;
				case 'times'  : nuovoVal = 215; break;
				case 'Oslash'  : nuovoVal = 216; break;
				case 'Ugrave'  : nuovoVal = 217; break;
				case 'Uacute'  : nuovoVal = 218; break;
				case 'Ucirc'  : nuovoVal = 219; break;
				case 'Uuml'  : nuovoVal = 220; break;
				case 'Yacute'  : nuovoVal = 221; break;
				case 'THORN'  : nuovoVal = 222; break;
				case 'szlig'  : nuovoVal = 223; break;
				case 'agrave'  : nuovoVal = 224; break;
				case 'aacute'  : nuovoVal = 225; break;
				case 'acirc'  : nuovoVal = 226; break;
				case 'atilde'  : nuovoVal = 227; break;
				case 'auml'  : nuovoVal = 228; break;
				case 'aring'  : nuovoVal = 229; break;
				case 'aelig'  : nuovoVal = 230; break;
				case 'ccedil'  : nuovoVal = 231; break;
				case 'egrave'  : nuovoVal = 232; break;
				case 'eacute'  : nuovoVal = 233; break;
				case 'ecirc'  : nuovoVal = 234; break;
				case 'euml'  : nuovoVal = 235; break;
				case 'igrave'  : nuovoVal = 236; break;
				case 'iacute'  : nuovoVal = 237; break;
				case 'icirc'  : nuovoVal = 238; break;
				case 'iuml'  : nuovoVal = 239; break;
				case 'eth'  : nuovoVal = 240; break;
				case 'ntilde'  : nuovoVal = 241; break;
				case 'ograve'  : nuovoVal = 242; break;
				case 'oacute'  : nuovoVal = 243; break;
				case 'ocirc'  : nuovoVal = 244; break;
				case 'otilde'  : nuovoVal = 245; break;
				case 'ouml'  : nuovoVal = 246; break;
				case 'divide'  : nuovoVal = 247; break;
				case 'oslash'  : nuovoVal = 248; break;
				case 'ugrave'  : nuovoVal = 249; break;
				case 'uacute'  : nuovoVal = 250; break;
				case 'ucirc'  : nuovoVal = 251; break;
				case 'uuml'  : nuovoVal = 252; break;
				case 'yacute'  : nuovoVal = 253; break;
				case 'thorn'  : nuovoVal = 254; break;
				case 'yuml'  : nuovoVal = 255; break;
				case 'OElig'  : nuovoVal = 338; break;
				case 'oelig'  : nuovoVal = 339; break;
				case 'Scaron'  : nuovoVal = 352; break;
				case 'scaron'  : nuovoVal = 353; break;
				case 'Yuml'  : nuovoVal = 376; break;
				case 'fnof'  : nuovoVal = 402; break;
				case 'circ'  : nuovoVal = 710; break;
				case 'tilde'  : nuovoVal = 732; break;
				case 'Alpha'  : nuovoVal = 913; break;
				case 'Beta'  : nuovoVal = 914; break;
				case 'Gamma'  : nuovoVal = 915; break;
				case 'Delta'  : nuovoVal = 916; break;
				case 'Epsilon'  : nuovoVal = 917; break;
				case 'Zeta'  : nuovoVal = 918; break;
				case 'Eta'  : nuovoVal = 919; break;
				case 'Theta'  : nuovoVal = 920; break;
				case 'Iota'  : nuovoVal = 921; break;
				case 'Kappa'  : nuovoVal = 922; break;
				case 'Lambda'  : nuovoVal = 923; break;
				case 'Mu'  : nuovoVal = 924; break;
				case 'Nu'  : nuovoVal = 925; break;
				case 'Xi'  : nuovoVal = 926; break;
				case 'Omicron'  : nuovoVal = 927; break;
				case 'Pi'  : nuovoVal = 928; break;
				case 'Rho'  : nuovoVal = 929; break;
				case 'Sigma'  : nuovoVal = 931; break;
				case 'Tau'  : nuovoVal = 932; break;
				case 'Upsilon'  : nuovoVal = 933; break;
				case 'Phi'  : nuovoVal = 934; break;
				case 'Chi'  : nuovoVal = 935; break;
				case 'Psi'  : nuovoVal = 936; break;
				case 'Omega'  : nuovoVal = 937; break;
				case 'alpha'  : nuovoVal = 945; break;
				case 'beta'  : nuovoVal = 946; break;
				case 'gamma'  : nuovoVal = 947; break;
				case 'delta'  : nuovoVal = 948; break;
				case 'epsilon'  : nuovoVal = 949; break;
				case 'zeta'  : nuovoVal = 950; break;
				case 'eta'  : nuovoVal = 951; break;
				case 'theta'  : nuovoVal = 952; break;
				case 'iota'  : nuovoVal = 953; break;
				case 'kappa'  : nuovoVal = 954; break;
				case 'lambda'  : nuovoVal = 955; break;
				case 'mu'  : nuovoVal = 956; break;
				case 'nu'  : nuovoVal = 957; break;
				case 'xi'  : nuovoVal = 958; break;
				case 'omicron'  : nuovoVal = 959; break;
				case 'pi'  : nuovoVal = 960; break;
				case 'rho'  : nuovoVal = 961; break;
				case 'sigmaf'  : nuovoVal = 962; break;
				case 'sigma'  : nuovoVal = 963; break;
				case 'tau'  : nuovoVal = 964; break;
				case 'upsilon'  : nuovoVal = 965; break;
				case 'phi'  : nuovoVal = 966; break;
				case 'chi'  : nuovoVal = 967; break;
				case 'psi'  : nuovoVal = 968; break;
				case 'omega'  : nuovoVal = 969; break;								
				case 'thetasym'  : nuovoVal = 977; break;
				case 'upsih'  : nuovoVal = 978; break;
				case 'piv'  : nuovoVal = 982; break;
				case 'ensp'  : nuovoVal = 8194; break;
				case 'emsp'  : nuovoVal = 8195; break;
				case 'thinsp'  : nuovoVal = 8201; break;
				case 'zwnj'  : nuovoVal = 8204; break;
				case 'zwj'  : nuovoVal = 8205; break;
				case 'lrm'  : nuovoVal = 8206; break;
				case 'rlm'  : nuovoVal = 8207; break;
				case 'ndash'  : nuovoVal = 8211; break;
				case 'mdash'  : nuovoVal = 8212; break;
				case 'lsquo'  : nuovoVal = 8216; break;
				case 'rsquo'  : nuovoVal = 8217; break;
				case 'sbquo'  : nuovoVal = 8218; break;
				case 'ldquo'  : nuovoVal = 8220; break;
				case 'rdquo'  : nuovoVal = 8221; break;
				case 'bdquo'  : nuovoVal = 8222; break;
				case 'dagger'  : nuovoVal = 8224; break;
				case 'Dagger'  : nuovoVal = 8225; break;
				case 'bull'  : nuovoVal = 8226; break;
				case 'hellip'  : nuovoVal = 8230; break;
				case 'permil'  : nuovoVal = 8240; break;
				case 'prime'  : nuovoVal = 8242; break;
				case 'Prime'  : nuovoVal = 8243; break;
				case 'lsaquo'  : nuovoVal = 8249; break;
				case 'rsaquo'  : nuovoVal = 8250; break;
				case 'oline'  : nuovoVal = 8254; break;
				case 'frasl'  : nuovoVal = 8260; break;
				case 'euro'  : nuovoVal = 8364; break;
				case 'image'  : nuovoVal = 8465; break;
				case 'weierp'  : nuovoVal = 8472; break;
				case 'real'  : nuovoVal = 8476; break;
				case 'trade'  : nuovoVal = 8482; break;
				case 'alefsym'  : nuovoVal = 8501; break;
				case 'larr'  : nuovoVal = 8592; break;
				case 'uarr'  : nuovoVal = 8593; break;
				case 'rarr'  : nuovoVal = 8594; break;
				case 'darr'  : nuovoVal = 8595; break;
				case 'harr'  : nuovoVal = 8596; break;
				case 'crarr'  : nuovoVal = 8629; break;
				case 'lArr'  : nuovoVal = 8656; break;
				case 'uArr'  : nuovoVal = 8657; break;
				case 'rArr'  : nuovoVal = 8658; break;
				case 'dArr'  : nuovoVal = 8659; break;
				case 'hArr'  : nuovoVal = 8660; break;
				case 'forall'  : nuovoVal = 8704; break;
				case 'part'  : nuovoVal = 8706; break;
				case 'exist'  : nuovoVal = 8707; break;
				case 'empty'  : nuovoVal = 8709; break;
				case 'nabla'  : nuovoVal = 8711; break;
				case 'isin'  : nuovoVal = 8712; break;
				case 'notin'  : nuovoVal = 8713; break;
				case 'ni'  : nuovoVal = 8715; break;
				case 'prod'  : nuovoVal = 8719; break;
				case 'sum'  : nuovoVal = 8721; break;
				case 'minus'  : nuovoVal = 8722; break;
				case 'lowast'  : nuovoVal = 8727; break;
				case 'radic'  : nuovoVal = 8730; break;
				case 'prop'  : nuovoVal = 8733; break;
				case 'infin'  : nuovoVal = 8734; break;
				case 'ang'  : nuovoVal = 8736; break;
				case 'and'  : nuovoVal = 8743; break;
				case 'or'  : nuovoVal = 8744; break;
				case 'cap'  : nuovoVal = 8745; break;
				case 'cup'  : nuovoVal = 8746; break;
				case 'int'  : nuovoVal = 8747; break;
				case 'there4'  : nuovoVal = 8756; break;
				case 'sim'  : nuovoVal = 8764; break;
				case 'cong'  : nuovoVal = 8773; break;
				case 'asymp'  : nuovoVal = 8776; break;
				case 'ne'  : nuovoVal = 8800; break;
				case 'equiv'  : nuovoVal = 8801; break;
				case 'le'  : nuovoVal = 8804; break;
				case 'ge'  : nuovoVal = 8805; break;
				case 'sub'  : nuovoVal = 8834; break;
				case 'sup'  : nuovoVal = 8835; break;
				case 'nsub'  : nuovoVal = 8836; break;
				case 'sube'  : nuovoVal = 8838; break;
				case 'supe'  : nuovoVal = 8839; break;
				case 'oplus'  : nuovoVal = 8853; break;
				case 'otimes'  : nuovoVal = 8855; break;
				case 'perp'  : nuovoVal = 8869; break;
				case 'sdot'  : nuovoVal = 8901; break;
				case 'lceil'  : nuovoVal = 8968; break;
				case 'rceil'  : nuovoVal = 8969; break;
				case 'lfloor'  : nuovoVal = 8970; break;
				case 'rfloor'  : nuovoVal = 8971; break;
				case 'lang'  : nuovoVal = 9001; break;
				case 'rang'  : nuovoVal = 9002; break;
				case 'loz'  : nuovoVal = 9674; break;
				case 'spades'  : nuovoVal = 9824; break;
				case 'clubs'  : nuovoVal = 9827; break;
				case 'hearts'  : nuovoVal = 9829; break;
				case 'diams'  : nuovoVal = 9830; break;
				default :	nuovoVal = -1;
			}
			
		}
		if (nuovoVal > -1){ 
			fReturn += TestoHtml.substr(indice, reMatch.index - indice) + String.fromCharCode(nuovoVal);
			indice = reMatch.index + reMatch[0].length;
		}
		reMatch = re.exec(TestoHtml);
	}
	fReturn += TestoHtml.substr(indice);
	return fReturn
}


// Serializza il valore passato.
function SerializeValue(Valore){
	var cont1, cont2, cont3, str1, str2, k, y;
	var fReturn;
	
	switch (ValueType(Valore)){
		case 'null':
			fReturn = '#NULL';
			break;
		case 'empty':
			fReturn = '#EMPTY';
			break;
		case 'undefined':
			fReturn = '#NOTHING';
			break;
		case 'Object':
			fReturn = '#OBJECT';
			break;
		case 'Array':
			fReturn = '';
			str1 = SerializeValue__ArrayColl_getArrayType(Valore);
			if (!str1) {
				// Controllo se l'array ottenuto si tratta di un Array o di una Dictionary
				// in caso si tratti d un array si procede normalmente..
				// in caso si trattasse di una dictionary provvederemo a serializzare sia chiave che valore..
				cont2 = 0;
				str1 = 'Array';
				for (cont1 in Valore) {
					if (ValueType(Valore[cont1]) != 'Function') {
						if (cont1.toString() != cont2.toString()) {
							str1 = 'Dictionary';
							//alert('SerializeValue :' +  '\n   cont1 = ' + cont1 + '\n   cont2 = ' + cont2 + '\n   typeof= ' + ValueType(Valore[cont1]));
							break;
						}
						cont2 += 1;
					}
				}
			}
			switch (str1) {
				case 'Array':		// Stiamo serializzando un Array
					fReturn = '{';
					for (cont1=0; cont1<Valore.length; cont1++) {
						if (fReturn != '{') fReturn += ',';
						str1 = SerializeValue(Valore[cont1]);
						k = str1.length;
						fReturn += k + ':' + str1; 
					}
					fReturn = fReturn + '}';
					break;
				case 'Dictionary':	// Stiamo Serializzando un Dictionary
					fReturn = '[';
					for (cont1 in Valore) {
						if (typeof(Valore[cont1]) != 'function') {
							if (fReturn != '[') fReturn += ',';
							str1 = SerializeValue(cont1);
							str2 = SerializeValue(Valore[cont1]);
							y = str1.length;
							k = str2.length;
							fReturn += y + ':' + str1 + ',' + k + ':' + str2;
						}
					}
					fReturn = fReturn + ']';
					break;
			}
			break;
		case 'number':
			fReturn = 'F' + Valore.toString();
			break;
		case 'Date':
			fReturn = 'D' + Valore.getFullYear() + LFill((Valore.getMonth()+1).toString(), '0',2) + LFill(Valore.getDate().toString(), '0',2) + LFill(Valore.getHours().toString(),'0', 2)+ LFill(Valore.getMinutes().toString(),'0', 2) + LFill(Valore.getSeconds().toString(),'0', 2);
			break;
		case 'boolean':
			if ( IsTrue(Valore) == true) {
				fReturn = 'B' + '1'; 
			} else {
				fReturn = 'B' + '0';
			}
			break;
		case 'string':
			fReturn = 'S' + HTMLEncode(Valore);
			break;
		default:
			fReturn = '#tipo [' + ValueType(Valore) + '] non supportato.';
	}
	return fReturn;
}
//Deserializza il valore passato
function DeserializeValue(ValoreSerializzato) {
	var cont1, cont2, cont3, str1, str2, lunghezza, tipo, valore, fReturn;
	tipo = ValoreSerializzato.charAt(0);
	valore = ValoreSerializzato.substr(1);
	switch (tipo) {
		case '#':
			switch (valore) {
				case 'NULL':
					fReturn = null;
					break;
				case 'NOTHING':
					fReturn = void(0);
					break;
				case 'OBJECT':
					fReturn = null;
					break;
				case 'EMPTY':
					fReturn = '';
					break;
				default:
					fReturn = null;
					break;
			}
			break;
		case 'D':
			fReturn = new Date();
			fReturn.setFullYear(toNumber(valore.substr(0,4)));
			fReturn.setMonth(toNumber(valore.substr(4,2))-1);
			fReturn.setDate(toNumber(valore.substr(6,2)));
			fReturn.setHours(toNumber(valore.substr(8,2)));
			fReturn.setMinutes(toNumber(valore.substr(10,2)));
			fReturn.setSeconds(toNumber(valore.substr(12,2)));
			break;
		case 'S':
			fReturn = HTMLDecode(valore);
			break;
		case 'F':
		case 'I':
			fReturn = toNumber(valore,0, false);
			break;
		case 'B':
			fReturn = IsTrue(valore);
			break;
		case '{':
			fReturn = new Array();
			SerializeValue__ArrayColl_addArrayType(fReturn, 'Array');
			if (valore != '}') {
				cont1 = 0;
				cont3 = 0;
				do {
					cont1 += 1;
					cont2 = cont1 + 1 + ValoreSerializzato.substr(cont1 + 1).search(/:/);
					lunghezza = toNumber(ValoreSerializzato.substr(cont1, cont2 - cont1));
					str1 = ValoreSerializzato.substr(cont2 + 1, lunghezza);
					cont1 = cont2 + lunghezza + 1;
					//Setto il valore nell'array
					fReturn[cont3] = DeserializeValue(str1);
					cont3 += 1;
				} while (ValoreSerializzato.charAt(cont1) == ',');
			}
			break;
		case '[':
			fReturn = new Array();
			SerializeValue__ArrayColl_addArrayType(fReturn, 'Dictionary');
			if (valore != ']') {
				cont1 = 0;
				do {
					//Determino il nome dell'item
					cont1 += 1;
					cont2 = cont1 + 1 + ValoreSerializzato.substr(cont1 + 1).search(/:/);
					lunghezza = toNumber(ValoreSerializzato.substr(cont1, cont2 - cont1));
					str1 = ValoreSerializzato.substr(cont2 + 1, lunghezza);
					cont1 = cont2 + lunghezza + 1;
					//Determino il valore dell'item
					cont1 += 1;
					cont2 = cont1 + 1 + ValoreSerializzato.substr(cont1 + 1).search(/:/);
					lunghezza = toNumber(ValoreSerializzato.substr(cont1, cont2 - cont1));
					str2 = ValoreSerializzato.substr(cont2 + 1, lunghezza);
					cont1 = cont2 + lunghezza + 1;
					//Setto il valore nel dictionary
					fReturn[DeserializeValue(str1)] = DeserializeValue(str2);
				} while (ValoreSerializzato.charAt(cont1) == ',');
			}
			break;
		default:
			fReturn = null;
	}
	return fReturn;
}
//Aggiunge un oggetto Array alla collection di oggetti riconosciuti da [SerializeValue]/[DeserializeValue].
function SerializeValue__ArrayColl_addArrayType(ArrayObject, ObjectType) {
	if (!window.SerializeValue__ArrayColl) window.SerializeValue__ArrayColl = new Array();
	window.SerializeValue__ArrayColl.push(ArrayObject);
	window.SerializeValue__ArrayColl.push(ObjectType);
}
function SerializeValue__ArrayColl_getArrayType(ArrayObject) {
	var cont1, fReturn;
	if (window.SerializeValue__ArrayColl) {
		for (cont1=0; cont1<window.SerializeValue__ArrayColl.length; cont1+=2) {
			if (window.SerializeValue__ArrayColl[cont1] === ArrayObject) {
				fReturn = window.SerializeValue__ArrayColl[cont1 + 1];
				break;
			}
		}
	}
	return fReturn;
}



//####   GetHtmlControlValue   -   SetHtmlControlValue   ####
//####   Info-Data - Flavio Spezi - ver. 1.0	(17/11/2005)
//Leggono e scrivono il valore degli oggetti INPUT, TEXTAREA e SELECT. Parametri:
//		ControlObject:	è il riferimento all'oggetto oppure l'ID dell'oggetto. Se si tratta di INPUT type=radio,
//						il parametro può essere il riferimento ad uno degli oggetti INPUT type=radio del gruppo oppure il nome del
//						gruppo seguito dal nome del frame (es. FrmPrinc.OptSesso_M, 'OptSesso_F', 'FrmPrinc.OptSesso').
function GetHtmlControlValue(ControlObject, Checkbox_TrueFalse) {
	var obj, tipoCtrl, objForm;
	var tipoRadio_Nome, listaCtrl;
	var cont1;
	var fReturn = null;
	obj = ControlObject;
	if (typeof(obj) == 'string') {
		if (obj.indexOf('.') > -1) obj = obj.substr(obj.indexOf('.')+1);
		obj = findObj(obj);
		if (typeof(obj) != 'object' || !obj.tagName) obj = ControlObject;
	}
	switch (typeof(obj)) {
		case 'object':
			tipoCtrl = obj.tagName;
			if (tipoCtrl == 'INPUT') tipoCtrl += ' ' + obj.type.toLowerCase();
			break;
		case 'string':
			tipoCtrl = 'INPUT radio';
			break;
	}
	if (tipoCtrl != 'INPUT radio' && typeof(obj) != 'object') tipoCtrl = 'non valido';
	switch (tipoCtrl) {
		case 'INPUT checkbox':
			fReturn = ((obj.checked) ? obj.value : null);
			break;
		case 'INPUT hidden':
			fReturn = obj.value;
			break;
		case 'INPUT password':
			fReturn = obj.value;
			break;
		case 'INPUT radio':
			if (typeof(obj) == 'string') {
				objForm = findObj(obj.substr(0, obj.indexOf('.')));
				tipoRadio_Nome = obj.substr(obj.indexOf('.')+1).toLowerCase();
			} else {
				objForm = obj.form;
				tipoRadio_Nome = obj.name.toLowerCase();
			}
			listaCtrl = objForm.tags('INPUT');
			if (listaCtrl) {
				for (cont1 = 0; cont1 < listaCtrl.length; cont1++) {
					if (listaCtrl[cont1].type.toLowerCase() == 'radio'
							&& listaCtrl[cont1].name.toLowerCase() == tipoRadio_Nome
							&& listaCtrl[cont1].checked) {
						fReturn = listaCtrl[cont1].value;
						break;
					}
				}
			}
			break;
		case 'INPUT text':
			fReturn = obj.value;
			break;
		case 'SELECT':
			fReturn = obj.value;
			break;
		case 'TEXTAREA':
			fReturn = obj.value;
			break;
	}
	return fReturn;
}
//Stesso principio della procedura [GetHtmlControlValue]. Restituisce TRUE se l'operazione va a buon fine.
function SetHtmlControlValue(ControlObject, NewValue) {
	var obj, tipoCtrl, objForm;
	var tipoRadio_Nome, listaCtrl;
	var cont1, cont2;
	var fReturn = false;
	obj = ControlObject;
	if (typeof(obj) == 'string') {
		if (obj.indexOf('.') > -1) obj = obj.substr(obj.indexOf('.')+1);
		obj = findObj(obj);
		if (typeof(obj) != 'object' || !obj.tagName) obj = ControlObject;
	}
	switch (typeof(obj)) {
		case 'object':
			tipoCtrl = obj.tagName;
			if (tipoCtrl == 'INPUT') tipoCtrl += ' ' + obj.type.toLowerCase();
			break;
		case 'string':
			tipoCtrl = 'INPUT radio';
			break;
	}
	if (tipoCtrl != 'INPUT radio' && typeof(obj) != 'object') tipoCtrl = 'non valido';
	switch (tipoCtrl) {
		case 'INPUT checkbox':
			obj.checked = ((NewValue) ? true : false);
			fReturn = true;
			break;
		case 'INPUT hidden':
			obj.value = NewValue;
			fReturn = true;
			break;
		case 'INPUT password':
			obj.value = NewValue;
			fReturn = true;
			break;
		case 'INPUT radio':
			switch (typeof(obj)) {
				case 'string':
					objForm = findObj(obj.substr(0, obj.indexOf('.')));
					tipoRadio_Nome = obj.substr(obj.indexOf('.')+1).toLowerCase();
					break;
				case 'object':
					objForm = obj.form;
					tipoRadio_Nome = obj.name.toLowerCase();
					break;
			}
			listaCtrl = objForm.tags('INPUT');
			if (listaCtrl) {
				for (cont1 = 0; cont1 < listaCtrl.length; cont1++) {
					if (listaCtrl[cont1].type.toLowerCase() == 'radio'
							&& listaCtrl[cont1].name.toLowerCase() == tipoRadio_Nome
							&& listaCtrl[cont1].value == NewValue) {
						listaCtrl[cont1].checked = true;
						fReturn = true;
						break;
					}
				}
			}
			break;
		case 'INPUT text':
			obj.value = NewValue;
			fReturn = true;
			break;
		case 'SELECT':
			if (ValueType(NewValue) == 'Array') {
				obj.value = NewValue;
				if (obj.value == NewValue) {
					fReturn = true;
				} else {
					fReturn = 0;
					for (cont1=0; cont1<obj.options.length; cont1++) {
						for (cont2=0; cont2<NewValue.length; cont2++) {
							if (obj.options(cont1).value == NewValue[cont2]) {
								obj.options(cont1).selected = true;
								fReturn ++;
							}
						}
					}
					fReturn = (fReturn == NewValue.length);
				}
			} else {
				obj.value = NewValue;
				if (obj.value == NewValue) {
					fReturn = true;
				} else {
					fReturn = false;
					for (cont1=0; cont1<obj.options.length; cont1++) {
						if (obj.options(cont1).text == NewValue[cont2]) {
							obj.options(cont1).selected = true;
							fReturn = true;
							break;
						}
					}
				}
			}
			break;
		case 'TEXTAREA':
			obj.value = NewValue;
			fReturn = true;
			break;
		default:
			alert('Funzioni.js\n  function SetHtmlControlValue()\n    TipoCtrl non gestito: ' + tipoCtrl + '\n    Parametro ControlObject: ' + ControlObject);
	}
	return fReturn;
}


// ####  Funzioni di STANDARDIZZAZIONE BROWSERS  ##########

// Associa una funzione all'evento di un oggetto
function addEvent(obj, evType, fn) {
	if (obj.addEventListener) {
		obj.addEventListener(evType, fn, false);
		return true;
	} else if (obj.attachEvent) {
		var r = obj.attachEvent('on' + evType, fn);
		return r;
	} else {
		return false;
	}
}
function removeEvent(obj, evType, fn) {
	if (obj.removeEventListener) {
		obj.removeEventListener(evType, fn, false);
		return true;
	} else if (obj.detachEvent) {
		var r = obj.detachEvent('on' + evType, fn);
		return r;
	} else {
		return false;
	}
}
function fireEvent(obj, evType) {
	var esisteEvento;
	if (obj.fireEvent) {
		obj.fireEvent('on' + evType);
	} else {
		eval('esisteEvento = obj.on' + evType + ';');
		if (esisteEvento) eval('esisteEvento = obj.on' + evType + '();');
	}
}
function findObj(idObject, optDocument) {
	var p, i, x;
	if (!optDocument) optDocument = document;
	if ((p = idObject.toString().indexOf('?')) > 0 && parent.frames.length) {
		optDocument = parent.frames[idObject.substring(p + 1)].document;
		idObject = idObject.substring(0, p);
	}
	if (!(x = optDocument[idObject]) && optDocument.getElementById) x = optDocument.getElementById(idObject);
	if (!x && optDocument.parentWindow) x = optDocument.parentWindow[idObject];
	if (!x && optDocument.defaultView) x = optDocument.defaultView[idObject];
	if (!x && optDocument.all) x = optDocument.all[idObject];
	if (!x && optDocument.forms) for (i=0; i < optDocument.forms.length; i++) x = optDocument.forms[i][idObject];
	if (!x && optDocument.layers) for (i=0; i < optDocument.layers.length; i++) x = findObj(idObject, optDocument.layers[i].document);
	return x;
}
function findParentObj(HtmlObject, optTagNameFilter, optAttribNameFilter, optAttribValueFilter, optStopObject) {
	//Restituisce il padre che risponde alle caratteristiche indicate. Se non trovato restituisce NULL. Argomenti:
	//	HtmlObject:				riferimento all'oggetto di cui si deve trovare il padre;
	//	optTagNameFilter:		(opzionale)(regExp o stringa) valore "tagName" che deve avere il padre da cercare;
	//	optAttribNameFilter:	(opzionale)(stringa) il padre deve avere tale attributo impostato;
	//	optAttribValueFilter:	(opzionale)(regExp o stringa) è il valore che deve avere l'attributi indicato con "optAttribNameFilter";
	//	optStopObject:			(opzionale)(tagName o HtmlObject) è l'oggetto su cui cessare la ricerca.
	var trovato, fncCerca, fineRicerca;
	var fReturn = HtmlObject;
	trovato = false;
	fineRicerca = false;
	fncCerca = function(Value, Filter) {
		switch (ValueType(Filter)) {
			case 'string':	return (Value == Filter ? true : false); break;
			case 'RegExp':	return (Value.search(Filter) > -1 ? true : false); break;
			default:		return false;
		}
	}
	while (fReturn.tagName && trovato == false && fineRicerca == false) {
		trovato = true;
		if (trovato && optTagNameFilter) trovato = fncCerca(fReturn.tagName, optTagNameFilter);
		if (trovato && optAttribNameFilter) trovato = (fReturn[optAttribNameFilter] ? true : false);
		if (trovato && optAttribNameFilter && optAttribValueFilter) trovato = fncCerca(fReturn[optAttribNameFilter], optAttribValueFilter);
		if (!trovato) {
			fReturn = fReturn.parentNode;
			if (optStopObject) {
				switch (ValueType(optStopObject)) {
					case 'Object':
						fineRicerca = (fReturn === optStopObject ? true : false);
						break;
					case 'String':
						fineRicerca = (fReturn.tagName == optStopObject ? true : false);
						break;
				}
			} else if (fReturn.tagName == 'BODY') {
				fineRicerca = true;
			}
		}
	}
	return (trovato ? fReturn : null);
}


// ####  [Traduci_Varchar_Read] ,  [Traduci_Varchar_Write] ,  [Traduci_Text_Read] ,  [Traduci_Text_Write]  ####
// ####  Info-Data Flavio Spezi (ver. 2.0 - 04/11/2005)  ###
// Procedure per la lettura e la scrittura in lingua.
// Parametri:
// 	MultilanguageSource   :	Può essere il [testo intero] in tutte le lingue oppure l'oggetto da cui prendere il valore:
// 							se il parametro è di tipo [Object], verrà prelevato il valore dell'attributo Value;
// 							se il parametro è una stringa essa verrà usata come [testo intero];
// 							per le funzioni Xxx_Write, nel caso in cui il parametro passato è un [Object], il risultato
// 							dell'elaborazione verrà salvato all'interno dell'oggetto; e in ogni caso verrà restituito come
// 							stringa dalla funzione.
// 	LanguageCode		  : il codice della lingua (es: IT, EN).
// 	LanguageIndex		  : l'indice di posizione della lingua (a partire da zero).
// 	LanguageSource		  : per le funzioni Xxx_Write, settare questo parametro col valore del testo nella lingua indicata;
// 							se il parametro è di tipo [Object], verrà prelevato il valore dell'attributo Value;
// 							se il parametro è una stringa essa verrà usata come [testo della lingua].
// 	CharsPerLanguage	  : caratteri messi a disposizione per ogni lingua. A differenza del programma analogo lato server,
//							qui non posso consentire l'uso del valore -1 (in automatico leggendo lungezza campo nel db) per
//							ovvi motivi.
function Traduci_Varchar_Read(MultilanguageSource, CharsPerLanguage, LanguageIndex) {
	var numCaratteri = toNumber(CharsPerLanguage, null, true);
	var indiceLingua = toNumber(LanguageIndex, null, true);
	var sorgenteIsObj = typeof(MultilanguageSource) == 'object';
	var sorgenteTesto = ((sorgenteIsObj) ? MultilanguageSource.value : MultilanguageSource);
	var fReturn = RTrim(sorgenteTesto.substr(numCaratteri * indiceLingua, numCaratteri));
	return fReturn;
}
function Traduci_Varchar_Write(MultilanguageSource, CharsPerLanguage, LanguageIndex, LanguageSource) {
	var numCaratteri = toNumber(CharsPerLanguage, null, true);
	var indiceLingua = toNumber(LanguageIndex, null, true);
	var sorgenteIsObj = typeof(MultilanguageSource) == 'object';
	var sorgenteTesto = ((sorgenteIsObj) ? MultilanguageSource.value : MultilanguageSource);
	var sorgenteLanIsObj = typeof(LanguageSource) == 'object';
	var sorgenteLanTesto = ((sorgenteLanIsObj) ? LanguageSource.value : LanguageSource);
	var fReturn;
	
	while (sorgenteTesto.length < numCaratteri * indiceLingua) sorgenteTesto += ' ';
	while (sorgenteLanTesto.length < numCaratteri) sorgenteLanTesto += ' ';
	fReturn = sorgenteTesto.substr(0, numCaratteri * indiceLingua) +
			sorgenteLanTesto + 
			sorgenteTesto.substr(numCaratteri * (indiceLingua + 1));
	if (sorgenteIsObj) MultilanguageSource.value = RTrim(fReturn);
	return fReturn;
}
function Traduci_Text_Read(MultilanguageSource, LanguageCode) {
	//#	Costanti utili che sono dichiarante in FUNZIONI.ASP : #
	//	Traduci_ChrLingua, Traduci_ChrFormatoTesto, Traduci_Lingue_DefaultIndex, Traduci_Lingue_DefaultCode, Traduci_FormatoTestoDefault
	var sorgenteIsObj = typeof(MultilanguageSource) == 'object';
	var sorgenteTesto = ((sorgenteIsObj) ? MultilanguageSource.value : MultilanguageSource);
	var posizIni, posizFine;
	var formatoTesto;
	var fReturn;
	//Leggo e rimuovo la definizione del FormatoTesto dalla stringa.
	formatoTesto = Traduci_GetFormatoTesto(sorgenteTesto);
	if (!formatoTesto) {
		formatoTesto = Traduci_FormatoTestoDefault;
	} else {
		sorgenteTesto = Traduci_RemoveFormatoTesto(sorgenteTesto);
	}
	
	//Se NON trovo nemmeno un [Traduci_ChrLingua], significa che il testo non ha alcuna formattazione di lingua,
	//quindi imposterò tutto il testo alla lingua default [Traduci_Lingue_DefaultCode].                
	if (sorgenteTesto.substr(0, Traduci_ChrLingua.length) != Traduci_ChrLingua) sorgenteTesto = Traduci_ChrLingua + Traduci_Lingue_DefaultCode + sorgenteTesto;
	
    posizIni = sorgenteTesto.indexOf(Traduci_ChrLingua + LanguageCode);
    if (posizIni == -1) {
		fReturn = '';
	} else {
		posizIni += Traduci_ChrLingua.length + LanguageCode.length;
		posizFine = sorgenteTesto.indexOf(Traduci_ChrLingua, posizIni);
		if (posizFine == -1) posizFine = sorgenteTesto.length;
		fReturn = sorgenteTesto.substr(posizIni, posizFine - posizIni);
	}
	return fReturn;
}
function Traduci_Text_Write(MultilanguageSource, LanguageCode, LanguageSource) {
	//#	Costanti utili che sono dichiarante in FUNZIONI.ASP : #
	//	Traduci_ChrLingua, Traduci_ChrFormatoTesto, Traduci_Lingue_DefaultIndex, Traduci_Lingue_DefaultCode, Traduci_FormatoTestoDefault
	var sorgenteIsObj = typeof(MultilanguageSource) == 'object';
	var sorgenteTesto = ((sorgenteIsObj) ? MultilanguageSource.value : MultilanguageSource);
	var sorgenteLanIsObj = typeof(LanguageSource) == 'object';
	var sorgenteLanTesto = ((sorgenteLanIsObj) ? LanguageSource.value : LanguageSource);
	var posizIni, posizFine;
	var formatoTesto;
	var fReturn;
	//Leggo e rimuovo la definizione del FormatoTesto dalla stringa.
	formatoTesto = Traduci_GetFormatoTesto(sorgenteTesto);
	if (!formatoTesto) {
		formatoTesto = Traduci_FormatoTestoDefault;
	} else {
		sorgenteTesto = Traduci_RemoveFormatoTesto(sorgenteTesto);
	}
	
	//Se NON trovo nemmeno un [Traduci_ChrLingua], significa che il testo non ha alcuna formattazione di lingua,
	//quindi imposterò tutto il testo alla lingua default [Traduci_Lingue_DefaultCode].                
	if (sorgenteTesto.substr(0, Traduci_ChrLingua.length) != Traduci_ChrLingua) sorgenteTesto = Traduci_ChrLingua + Traduci_Lingue_DefaultCode + sorgenteTesto;
	
	posizIni = sorgenteTesto.indexOf(Traduci_ChrLingua + LanguageCode);
	if (posizIni == -1) {
		fReturn = sorgenteTesto + Traduci_ChrLingua + LanguageCode + sorgenteLanTesto;
	} else {
		posizIni += Traduci_ChrLingua.length + LanguageCode.length;
		posizFine = sorgenteTesto.indexOf(Traduci_ChrLingua, posizIni);
		if (posizFine == -1) posizFine = sorgenteTesto.length;
		fReturn = sorgenteTesto.substr(0, posizIni) +
				sorgenteLanTesto +
				sorgenteTesto.substr(posizFine);
	}
	fReturn = Traduci_SetFormatoTesto(fReturn, formatoTesto);
	if (sorgenteIsObj) MultilanguageSource.value = fReturn;
	return fReturn;
}
function Traduci_GetFormatoTesto(textString) {
	//  Restituisce il FormatoTesto memorizzato nella stringa di testo passata come parametro.
	//  Se la stringa di testo non possiede un FormatoTesto definito, la funzione restituisce NULL.
	var fReturn = null;
    if (textString.substr(textString.length-2, 1) == Traduci_ChrFormatoTesto) {
		fReturn = textString.substr(textString.length-1, 1);
    }
    return fReturn;
}
function Traduci_SetFormatoTesto(textString, newTextFormat) {
	//  Restituisce il Testo con il FormatoTesto modificato.
	//  Se la stringa di testo non possiede un FormatoTesto definito, questo verrà aggiunto.
	var fReturn;
	fReturn = Traduci_RemoveFormatoTesto(textString) + Traduci_ChrFormatoTesto + newTextFormat.toString().substr(0, 1);
    return fReturn;
}
function Traduci_RemoveFormatoTesto(textString, newTextFormat) {
	//  Restituisce il Testo senza il FormatoTesto.
	//  Se la stringa di testo non possiede un FormatoTesto definito, la funzione restituisce il Testo intero del parametro.
	var fReturn;
    if (textString.substr(textString.length-2, 1) == Traduci_ChrFormatoTesto) {
		fReturn = textString.substr(0, textString.length - 2);
    } else {
		fReturn = textString;
    }
    return fReturn;
}

function Traduci_Lingue_Count(){
	return Traduci_Lingue_List.length;
}
function Traduci_Lingue_Index(Code){
	var cont1;
	var fReturn;
	for (cont1 = 0; cont1 < Traduci_Lingue_Count(); cont1++){
		if (Traduci_Lingue_List[cont1] == Code){
			fReturn = cont1;
			break;
		}
	}
	return fReturn; 
}
function Traduci_Lingue_Code(Index){
	return Traduci_Lingue_List[Index];
}
function Traduci_Lingue_LCID(IndiceOCodiceLingua){
	var str1, fReturn;
	str1 = IndiceOCodiceLingua;
	switch(typeof(IndiceOCodiceLingua)){
		case 'number':
			str1 = Traduci_Lingue_Code(IndiceOCodiceLingua)
			break;
		case 'string':
			str1 = IndiceOCodiceLingua
			break;
	}
	if (str1 == ''){
		str1 = Lan;
	}
	switch (str1){
		case "IT":
			fReturn = 1040;		//1040 stà per la localizzazione italiana (formato data e ora, numerico ecc...)
			break;
		case "FR":
			fReturn = 1036;
			break;
		case "DE":
			fReturn = 1031;
			break;
		case "ES":	
			fReturn = 1034;
			break;
		case "RU":
			fReturn = 1049;
			break;
		case "GR": 
			fReturn = 1032;
			break;
		case "PR": 
			fReturn = 2070;
			break;
		default: 
			fReturn = 1033;
	}
	return  fReturn;
}
//######################################################################################
//####	Funzioni per la gestione dei DOMINI del sito (come nel file Funzioni.asp)	####
//######################################################################################
var Domini_Nomi_ArrayCacheValue;
function Domini_Nomi_ArrayCacheValue_Fill() {
	if (!Domini_Nomi_ArrayCacheValue) Domini_Nomi_ArrayCacheValue = Domini_Nomi_List.split(';');
}
function Domini_Nomi_Count() {
	Domini_Nomi_ArrayCacheValue_Fill();
	return Domini_Nomi_ArrayCacheValue.length;
}
function Domini_Nomi_Index(NomeDominio) {
	var str1, cont1;
	Domini_Nomi_ArrayCacheValue_Fill();
	str1 = NomeDominio.toString().toLowerCase();
	for (cont1=0; cont1<Domini_Nomi_ArrayCacheValue.length; cont1++) {
		if (str1 == Domini_Nomi_ArrayCacheValue[cont1]) return cont1;
	}
    return -1;
}
function Domini_Nomi_Name(IndiceDominio) {
	Domini_Nomi_ArrayCacheValue_Fill();
	return Domini_Nomi_ArrayCacheValue[IndiceDominio];
}
function Domini_Nomi_CurrentIndex() {
	return Domini_Nomi_Index(Domini_Nomi_CurrentName);
}
function Domini_Nomi_CurrentName() {
	var fReturn = window.location.hostname;
	if (window.location.port != DefaultProtocolIpPort(window.location.protocol)) fReturn += ':' + window.location.port;
	return fReturn;
}
function DefaultProtocolIpPort(Protocol) {
	switch (Protocol.toLowerCase()) {
		case 'http':		return 80;
		case 'https':		return 443;
		case 'ftp':			return 21;
		case 'smtp':		return 25;
		case 'pop3':		return 110;
		case 'imap':		return 143;
		case 'nntp':		return 119;
		case 'snmp':		return 161;
		case 'irc':			return 194;
		case 'sqlserver':	return 1433;
		case 'mysql':		return 3306;
		case 'pptp':		return 1723;			//Point to Point Tunneling Protocol
		case 'telnet':		return 23;
		case 'rdp':			return 3389;			//Remote Desktop Protocol
		case 'vnc':			return 5900;
		default:			return -1;
	}
}


//#################################
//####  Funzioni di HTML PLUS  ####
//#################################


//Procedure per aggiungere funzionalità ad oggetti Html


function HtmlPlus_Positionator(ID, Object, RelativeOf, Direction, Properties, DynamicMode, optRelOfBoxSizing) {
	/*Riposiziona/Ridimensiona l'oggetto indicato dinamicamente. Argomenti:
		ID :			valore ID dell'oggetto.
		Object :		l'oggetto da posizionare e/o ridimensionare.
		RelativeOf :	l'oggetto su cui basare i calcoli; può essere:  [window] rispetto alla visualizzazione corrente,  [document] rispetto all'intero
						documento,  <oggetto HTML> rispetto all'oggetto indicato (es. INPUT),  NULL rispetto al puntatore del mouse.
		Direction :		indica dove posizionare l'oggetto; può essere:  'IN' all'interno di [RelativeOf],  'SE' (sta per SOUTH-EAST) si deve posizionare
						sotto a [RelativeOf] allineato a sinistra,  'ES' (sta per EAST-SOUTH) si deve posizionare a destra di [RelativeOf] allineato
						in alto,  <altre combinazioni di N, S, E, W> ...,   'S' (sta per SOUTH) sotto a [RelativeOf] allineato al centro,
						N/E/W ...analogo, stessa cosa.
		Properties :	collection di valori per [style], in stile JavaScript. Le definizioni ammesse sono:  left, top, right, bottom, width, minWidth,
						maxWidth, height, minHeight, maxHeight, marginLeft, marginTop, marginRight, marginBottom;
						le definizioni 'left' e 'top' possono essere settate anche con valori percentuali: così facendo si indica che [Object] dovrà
						posizionarsi a tale percentuale rispetto a 'width'/'height' di [RelativeOf];
						alle definizioni standard si aggiungono:  position1, position2, margin1, margin2; queste possono essere usate al posto di
						left, top, marginXxxx quando si vuole indicare il valore di posizione/margine del primo o secondo punto cardinale; es. indicando
						la proprietà "position2=10px" e "Direction='SE'" si indica che [Object] sarà sotto a [RelativeOf], allineato a sinistra, e
						spostato di 10px verso destra; se "DynamicMode='visible'" e si determina che [Object] non sarebbe visibile con "Direction='SE'",
						allora l'opzione [DynamicMode] prevede che [Direction] diventa 'SW', quindi la posizione sarà sotto, allineato a destra, e
						spostato di 10px; i valori indicati in queste definizioni verrà sommato a quello indicato alle definizioni standard.
		DynamicMode :	modalità di calcolo dinamico degli attributi; può essere:
							NULL funzionalità disattivata, la posizione/dimensione viene determinata in base ai parametri indicati;
							'onetime' la posizione/dimensione viene determinata una sola volta, su lancio di [Run], e Direction viene modificato se
									l'oggetto non è immediatamente visibile;
							'onredraw' la posizione/dimensione viene ricalcolata in conseguenza ad una modifica di posizione o dimensione di [RelativeOf]:
							'visible' la posizione/dimensione (come per 'onredraw') viene ricalcolata su modifica di [RelativeOf] e in più se [Object] non
									è immediatamente visibile viene modificando l'argomento [Direction] con un valore più appropriato.
		optRelOfBoxSizing :		valore attributo [boxSizing] per l'oggetto [RelativeOf], indica il modo con cui viene determinata la posizione e la
						dimensione dell'oggetto per determinare la posizione di [Object]; se non indicato verrà considerato 'border-box' se [Direction]
						è settato con punti cardinali (es. 'SE', 'NE', 'E'...), e 'content-box' negli altri casi.
		*/
	this.id = ID;
	this.objectType = 'HtmlPlus_Positionator';			// Tipo di oggetto HtmlPlus
	this.object = Object;
	this.relativeOf = RelativeOf;
	this.direction = null;
	this.properties = Properties;
	this.dynamicMode = null;
	this.relativeOfBoxSizing = null;	this._relativeOfBoxSizing = null;		//Il primo contiene il valore di argomento, il secondo quello che verrà usato dalla classe
	this._html = null;
	this._htmlScroll = null;	//indicherà i valori scrollLeft e scrollTop in relazione a [Object]
	this._status = null;

	if (!window.HtmlPlus_PositionatorColl) window.HtmlPlus_PositionatorColl = new Array();
	window.HtmlPlus_PositionatorColl[this.id] = this;
	
	this._initialize = function() {
		//Caricamento variabili di configurazione
		this.direction = 'IN';
		if (Direction) {
			if (Direction.search(/^(IN|NE|NW|SE|SW|WN|WS|EN|ES|N|E|S|W)$/i) >= 0) this.direction = Direction.toUpperCase();
		}
		this.dynamicMode = null;
		if (DynamicMode) {
			if (DynamicMode.search(/^(onredraw|visible)$/i) >= 0) this.dynamicMode = DynamicMode.toLowerCase();
		}
		this.relativeOfBoxSizing = null;
		if (optRelOfBoxSizing) {
			if (optRelOfBoxSizing.search(/^(border-box|content-box)$/i) >= 0) this.relativeOfBoxSizing = optRelOfBoxSizing.toLowerCase();
		}
		this._relativeOfBoxSizing = this.relativeOfBoxSizing;
		if (!this._relativeOfBoxSizing) {
			this._relativeOfBoxSizing = (this.direction == 'IN' ? 'content-box' : 'border-box');
		}
		this._status = 'stop';
	}
	this._initialize_setBody = function() {
		//Caricamento variabili di funzionamento
		this._html = GetDocInfo(this.object, 'RootElement');
		this._htmlScroll = {left:0, top:0};
		switch (GetCssStyle(this.object, 'position')) {
			case 'absolute':
				this._htmlScroll.left = this._html.scrollLeft;
				this._htmlScroll.top = this._html.scrollTop;
				break;
			case 'fixed':
				this._htmlScroll.left = 0;
				this._htmlScroll.top = 0;
				break;
		}
	}
	this._addValue = function(CurrentValue, Operation_Sum_Subtract, NewValue, RelativeOfSize) {
		var operazione, valore, fReturn;
		fReturn = CurrentValue;
		switch (Operation_Sum_Subtract) {
			case '+': case 'sum':		operazione = 1; break;
			case '-': case 'subtract':	operazione = -1; break;
			default:			operazione = 0; break;
		}
		if (!IsUndefined(NewValue) && NewValue !== null) {
			valore = GetValue(NewValue);
			if (valore.number > 0 || valore.number < 0) {
				if (valore.um == '%') {
					fReturn += (RelativeOfSize * valore.number / 100) * operazione;
				} else {
					fReturn += valore.number * operazione;
				}
			}
		}
		return fReturn;
	}
	this._getObjInfo = function(Object) {
		var cont1, cont2, fReturn;
		fReturn = {left:null, top:null, width:null, height:null};
		fReturn.left = getPos(Object, 'left');
		fReturn.top = getPos(Object, 'top');
		fReturn.width = Object.offsetWidth;
		fReturn.height = Object.offsetHeight;
		//FORSE DEVO VERIFICARE IL VALORE DI QUESTO ATTRIBUTO PER RITOCCARE I VALORI OTTENUTI?  -->		switch (Object.style.position) {	}
		switch (this._relativeOfBoxSizing) {
			case 'border-box':
				break;
			case 'content-box':
				cont1 = 0;
				cont2 = 0;
				if (Object.style.borderLeftWidth > 0) cont1 += Object.style.borderLeftWidth;
				if (Object.style.borderRightWidth > 0) cont2 += Object.style.borderRightWidth;
				if (Object.style.paddingLeft > 0) cont1 += Object.style.paddingLeft;
				if (Object.style.paddingRight > 0) cont2 += Object.style.paddingRight;
				fReturn.left -= cont1;
				fReturn.width -= (cont1 + cont2);
				cont1 = 0;
				cont2 = 0;
				if (Object.style.borderTopWidth > 0) cont1 += Object.style.borderTopWidth;
				if (Object.style.borderBottomWidth > 0) cont2 += Object.style.borderBottomWidth;
				if (Object.style.paddingTop > 0) cont1 += Object.style.paddingTop;
				if (Object.style.paddingBottom > 0) cont2 += Object.style.paddingBottom;
				fReturn.top -= cont1;
				fReturn.height -= (cont1 + cont2);
				break;
		}
		return fReturn;
	}
	this.Run = function() {
		var direzione, numProva, calcolo;
		if (this._status == 'stop') {
			if (this.object) {
				//Calcolo i valori per [Object]
				this._initialize_setBody();
				direzione = this.direction;
				numProva = 0;
				do {
					calcolo = this.CalculateAttributes(direzione);
					if (this.IsVisible(calcolo.left, calcolo.top, calcolo.width, calcolo.height)) break;
					switch (numProva) {
						case 0:	case 2:
							switch (direzione.substr(direzione.length-1, 1)) {
								case 'N':	direzione = direzione.substr(direzione.length-2, 1) + 'S'; break;
								case 'S':	direzione = direzione.substr(direzione.length-2, 1) + 'N'; break;
								case 'E':	direzione = direzione.substr(direzione.length-2, 1) + 'W'; break;
								case 'W':	direzione = direzione.substr(direzione.length-2, 1) + 'E'; break;
							}
							break;
						case 1: case 3:
							switch (direzione.substr(0, 1)) {
								case 'N':	direzione = 'S' + this.direction.substr(1, 1); break;
								case 'S':	direzione = 'N' + this.direction.substr(1, 1); break;
								case 'E':	direzione = 'W' + this.direction.substr(1, 1); break;
								case 'W':	direzione = 'E' + this.direction.substr(1, 1); break;
							}
							break;
					}
					numProva += 1;
				} while (direzione != 'IN' && numProva < 4 && this.dynamicMode !== null);
				//Applico i valori
				if (calcolo.left !== null) this.object.style.left = calcolo.left.toString() + 'px';
				if (calcolo.top !== null) this.object.style.top = calcolo.top.toString() + 'px';
				if (calcolo.width !== null) this.object.style.width = calcolo.width.toString() + 'px';
				if (calcolo.height !== null) this.object.style.height = calcolo.height.toString() + 'px';
				//Attacco gli eventi
				//	DA IMPLEMENTARE
				
				//Setto lo stato
				switch (this.dynamicMode) {
					case 'onredraw':
					case 'visible':
						this._status = 'run';
						break;
				}
			}
		}
	}
	this.Stop = function() {
		//Disattivo gli eventi
		//	DA IMPLEMENTARE
		//Setto lo stato
		this.status = 'stop';
	}
	this.CalculateAttributes = function(Direction) {
		//Calcola gli attributi 'left','top','width','height' per [Object] per la [Direction] indicata
		var relativeOfInfo = {left:null, top:null, width:null, height:null};
		var objectInfo = {width:null, height:null};
		var fReturn = {left:null, top:null, width:null, height:null};
		var cont1, cont2, dict1;
		//Determino i valori di [relativeOfInfo]
		if (ValueType(this.relativeOf) == 'Array') {
			for (cont1 in this.relativeOf) {
				dict1 = this._getObjInfo(this.relativeOf[cont1]);
				dict1.right = dict1.width + dict1.left;
				dict1.bottom = dict1.height + dict1.top;
				if (!relativeOfInfo) {
					relativeOfInfo = dict1;
				} else {
					switch (this._relativeOfBoxSizing) {
						case 'border-box':
							if (relativeOfInfo.left > dict1.left) relativeOfInfo.left = dict1.left;
							if (relativeOfInfo.top > dict1.top) relativeOfInfo.top = dict1.top;
							if (relativeOfInfo.right < dict1.right) relativeOfInfo.right = dict1.right;
							if (relativeOfInfo.bottom < dict1.bottom) relativeOfInfo.bottom = dict1.bottom;
							break;
						case 'content-box':
							if (relativeOfInfo.left < dict1.left) relativeOfInfo.left = dict1.left;
							if (relativeOfInfo.top < dict1.top) relativeOfInfo.top = dict1.top;
							if (relativeOfInfo.right > dict1.right) relativeOfInfo.right = dict1.right;
							if (relativeOfInfo.bottom > dict1.bottom) relativeOfInfo.bottom = dict1.bottom;
							break;
					}
				}
			}
			relativeOfInfo.width = relativeOfInfo.right - relativeOfInfo.left;
			relativeOfInfo.height = relativeOfInfo.bottom - relativeOfInfo.top;
			relativeOfInfo.right = void(0);
			relativeOfInfo.bottom = void(0);
		} else {
			relativeOfInfo = this._getObjInfo(this.relativeOf);
		}
		/* è già presente in [this._getObjInfo]
			//FORSE DEVO VERIFICARE IL VALORE DI QUESTO ATTRIBUTO PER RITOCCARE I VALORI OTTENUTI?  -->		switch (this.relativeOf.style.position) {	}
			switch (this._relativeOfBoxSizing) {
				case 'border-box':
					break;
				case 'content-box':
					cont1 = 0;
					cont2 = 0;
					if (this.relativeOf.style.borderLeftWidth > 0) cont1 += this.relativeOf.style.borderLeftWidth;
					if (this.relativeOf.style.borderRightWidth > 0) cont2 += this.relativeOf.style.borderRightWidth;
					if (this.relativeOf.style.paddingLeft > 0) cont1 += this.relativeOf.style.paddingLeft;
					if (this.relativeOf.style.paddingRight > 0) cont2 += this.relativeOf.style.paddingRight;
					relativeOfInfo.left -= cont1;
					relativeOfInfo.width -= (cont1 + cont2);
					cont1 = 0;
					cont2 = 0;
					if (this.relativeOf.style.borderTopWidth > 0) cont1 += this.relativeOf.style.borderTopWidth;
					if (this.relativeOf.style.borderBottomWidth > 0) cont2 += this.relativeOf.style.borderBottomWidth;
					if (this.relativeOf.style.paddingTop > 0) cont1 += this.relativeOf.style.paddingTop;
					if (this.relativeOf.style.paddingBottom > 0) cont2 += this.relativeOf.style.paddingBottom;
					relativeOfInfo.top -= cont1;
					relativeOfInfo.height -= (cont1 + cont2);
					break;
			}
		*/
		//Determino i valori 'width' e 'height' per [fReturn]
		if (!IsUndefined(this.properties['width'])) {
			fReturn.width = this._addValue(0, '+', this.properties['width'], relativeOfInfo.width);
			if (!IsUndefined(this.properties['minWidth'])) {
				cont1 = this._addValue(0, '+', this.properties['minWidth'], relativeOfInfo.width);
				if (cont1 > fReturn.width) fReturn.width = cont1;
			}
			if (!IsUndefined(this.properties['maxWidth'])) {
				cont1 = this._addValue(0, '+', this.properties['maxWidth'], relativeOfInfo.width);
				if (cont1 < fReturn.width) fReturn.width = cont1;
			}
		}
		if (!IsUndefined(this.properties['height'])) {
			fReturn.height = this._addValue(0, '+', this.properties['height'], relativeOfInfo.height);
			if (!IsUndefined(this.properties['minHeight'])) {
				cont1 = this._addValue(0, '+', this.properties['minHeight'], relativeOfInfo.height);
				if (cont1 > fReturn.height) fReturn.height = cont1;
			}
			if (!IsUndefined(this.properties['maxHeight'])) {
				cont1 = this._addValue(0, '+', this.properties['maxHeight'], relativeOfInfo.height);
				if (cont1 < fReturn.height) fReturn.height = cont1;
			}
		}
		//Setto le info per [objectInfo]
		objectInfo.width = this.object.offsetWidth;
		if (fReturn.width > 0) {
			objectInfo.width = fReturn.width;
			//DA IMPLEMENTARE	-->		sommare bordo e padding
		}
		objectInfo.height = this.object.offsetHeight;
		if (fReturn.height > 0) {
			objectInfo.height = fReturn.height;
			//DA IMPLEMENTARE	-->		sommare bordo e padding
		}
		//Leggendo [Direction], determino un primo stadio di valori 'left' e 'top' per [fReturn]
		switch (Direction) {
			case 'IN':
				fReturn.left = relativeOfInfo.left;
				fReturn.top = relativeOfInfo.top;
				break;
			default:
				switch (Direction.substr(0, 1)) {
					case 'N':	fReturn.top = relativeOfInfo.top - objectInfo.height; break;
					case 'E':	fReturn.left = relativeOfInfo.left + relativeOfInfo.width; break;
					case 'S':	fReturn.top = relativeOfInfo.top + relativeOfInfo.height; break;
					case 'W':	fReturn.left = relativeOfInfo.left - objectInfo.width; break;
				}
				switch (Direction.substr(1, 1)) {
					case 'N':	fReturn.top = relativeOfInfo.top + relativeOfInfo.height - objectInfo.height; break;
					case 'E':	fReturn.left = relativeOfInfo.left; break;
					case 'S':	fReturn.top = relativeOfInfo.top; break;
					case 'W':	fReturn.left = relativeOfInfo.left + relativeOfInfo.width - objectInfo.width; break;
					default:
						switch (Direction.substr(0, 1)) {
							case 'N': case 'S':	fReturn.left = relativeOfInfo.left + (relativeOfInfo.width - objectInfo.width) / 2; break;
							case 'E': case 'W':	fReturn.top = relativeOfInfo.top + (relativeOfInfo.height - objectInfo.height) / 2; break;
						}
				}
				//Cerco property 'position1/2' e 'margin1/2' e modifico 'left' e 'top' di [fReturn]
				switch (Direction.substr(0, 1)) {
					case 'N':	fReturn.top = this._addValue(fReturn.top, '-', this.properties['position1'], relativeOfInfo.height); break;
					case 'E':	fReturn.left = this._addValue(fReturn.left, '+', this.properties['position1'], relativeOfInfo.width); break;
					case 'S':	fReturn.top = this._addValue(fReturn.top, '+', this.properties['position1'], relativeOfInfo.height); break;
					case 'W':	fReturn.left = this._addValue(fReturn.left, '-', this.properties['position1'], relativeOfInfo.width); break;
				}
				switch (Direction.substr(0, 1)) {
					case 'N':	fReturn.top = this._addValue(fReturn.top, '-', this.properties['margin1'], relativeOfInfo.height); break;
					case 'E':	fReturn.left = this._addValue(fReturn.left, '+', this.properties['margin1'], relativeOfInfo.width); break;
					case 'S':	fReturn.top = this._addValue(fReturn.top, '+', this.properties['margin1'], relativeOfInfo.height); break;
					case 'W':	fReturn.left = this._addValue(fReturn.left, '-', this.properties['margin1'], relativeOfInfo.width); break;
				}
				switch (Direction.substr(1, 1)) {
					case 'N':	fReturn.top = this._addValue(fReturn.top, '-', this.properties['position2'], relativeOfInfo.height); break;
					case 'E':	fReturn.left = this._addValue(fReturn.left, '+', this.properties['position2'], relativeOfInfo.width); break;
					case 'S':	fReturn.top = this._addValue(fReturn.top, '+', this.properties['position2'], relativeOfInfo.height); break;
					case 'W':	fReturn.left = this._addValue(fReturn.left, '-', this.properties['position2'], relativeOfInfo.width); break;
				}
				switch (Direction.substr(1, 1)) {
					case 'N':	fReturn.top = this._addValue(fReturn.top, '-', this.properties['margin2'], relativeOfInfo.height); break;
					case 'E':	fReturn.left = this._addValue(fReturn.left, '+', this.properties['margin2'], relativeOfInfo.width); break;
					case 'S':	fReturn.top = this._addValue(fReturn.top, '+', this.properties['margin2'], relativeOfInfo.height); break;
					case 'W':	fReturn.left = this._addValue(fReturn.left, '-', this.properties['margin2'], relativeOfInfo.width); break;
				}
				//Se "this.object.style.position == 'fixed'" allora...
				if (this.object.style.position == 'fixed') {
					fReturn.top -= this._html.scrollTop;
					fReturn.left -= this._html.scrollLeft;
				}
		}
		//Cerco property e modifico 'left' e 'top' di [fReturn]
		fReturn.left = this._addValue(fReturn.left, '+', this.properties['left'], relativeOfInfo.width);
		fReturn.left = this._addValue(fReturn.left, '-', this.properties['right'], relativeOfInfo.width);		//Questo attributo và implementato diversamente: se DIRECTION='IN' allora RIGHT=10px significa che si deve posizionare a 10px dal bordo destro.
		fReturn.left = this._addValue(fReturn.left, '+', this.properties['marginLeft'], relativeOfInfo.width);
		fReturn.left = this._addValue(fReturn.left, '-', this.properties['marginRight'], relativeOfInfo.width);
		fReturn.top = this._addValue(fReturn.top, '+', this.properties['top'], relativeOfInfo.height);
		fReturn.top = this._addValue(fReturn.top, '-', this.properties['bottom'], relativeOfInfo.height);		//Questo.... (vedi attributo RIGHT qui sopra).
		fReturn.top = this._addValue(fReturn.top, '+', this.properties['marginTop'], relativeOfInfo.height);
		fReturn.top = this._addValue(fReturn.top, '-', this.properties['marginBottom'], relativeOfInfo.height);
		//Fine calcoli
		return fReturn;
	}
	this.IsVisible = function(Left, Top, Width, Height) {
		//Restituisce TRUE se [Object], per la posizione e dimensione indicate negli argomenti, sarà visibile sul browser
		var valWidth = (Width !== null ? Width : this.object.offsetWidth);
		var valHeight = (Height !== null ? Height : this.object.offsetHeight);
		var fReturn = true;
		if (fReturn) if (this._htmlScroll.top > Top) fReturn = false;
		if (fReturn) if (this._htmlScroll.left > Left) fReturn = false;
		if (fReturn) if (this._htmlScroll.top + this._html.clientHeight < Top + valHeight) fReturn = false;
		if (fReturn) if (this._htmlScroll.left + this._html.clientWidth < Left + valWidth) fReturn = false;
		return fReturn;
	}
	this.Status = function() {
		return this._status;
	}
	
	this._initialize();
	return this;
}





function HtmlPlus_SlideShow(IdObject, BackGroundColor, ObjContainer, ImagesPath, ZoomType, PermanenceTime, TransactionTime, TransactionStyle, TransactionType, Fps){
	// Questa funzione serve per meccanizzare gli SlideShow in modo da non dover ogni volta ricominciare daccapo.
	// Gestisce 3 tipi di transazioni : trasparenza, transazione verticale, trasazione orizzontale. Sar possibile aggiungerne altre.
	// Ci sono per dei bug da risolvere che riguardano l'utilizzo non standard dei browser riguardo ad alcuni attributi di stile
	//	degli oggetti html come left, top, zIndex che sono da verificare bene.
	this.id = IdObject;								// Id dell'oggetto HtmlPlus
	this.objectType = 'HtmlPlus_SlideShow';			// Tipo di oggetto
	this.objectContainer = ObjContainer;			// Oggetto che contiene le immagini da visualizzare in slideshow
	this.imagesCollection = null;					// Array di path di immagini da visualizzare
	this.zoomType = ZoomType;						// Pu essere 'Fixed', 'Min' 'Max'
	this.permanenceTime = PermanenceTime;			// Durata della visualizzazione dell'immagine (in secondi); comprende anche il tempo di scambio.
	this.transactionTime = TransactionTime;			// Durata dello scambio (in secondi)
	this.transactionStyle = TransactionStyle;		// Style di transazione['opacity', 'left-right', 'right-left', 'top-bottom', 'bottom-top']
	this.transactionType = TransactionType;			// Tipo di transazione['sin', 'cos', 'square', 'triangle']
	this.transactionStyleFF = 'auto';				// Style di transazione per passare da una immagine successiva ad una precedente.
	this.preloadTimeout = 5;						// Tempo massimo per il preload di una immagine (in secondi)
	this.fps = Fps;									// Fotogrammi per secondo della transazione.
	this.repeat = true;								// se [False] alla fine del ciclo si ferma. se [True] ricomincia da capo
	this.startMethod = 'image';						// Puo essere ['image', 'transaction', '<url-img>']
	this.transactionMaker = null;					// Oggetto transazione per passare da una immagine ad un'altra.
	this.transactionMakerFF = null;					// (opzionale) Oggetto transazione per passare da una immagine successiva ad una precedente.
	this.backgroundColor = BackGroundColor;
	
	if (!window.HtmlPlus_SlideShowColl) window.HtmlPlus_SlideShowColl = new Array();
	window.HtmlPlus_SlideShowColl[this.id] = this;
	
	this._initialize = function() {
		var cont1;
		
		switch (this.zoomType.toLowerCase()) {
			case 'fixed':
			case 'min':
			case 'max':
				this.zoomType = this.zoomType.toLowerCase();
				break;
			default:
				this.zoomType = 'fixed';
				break;
		}
		
		if (this.permanenceTime < this.transactionTime) this.permanenceTime = this.transactionTime;
		
		switch (this.transactionStyle.toLowerCase()) {
			case 'opacity':
			case 'right-left':
			case 'left-right':
			case 'top-bottom':
			case 'bottom-top':
			case 'test':
				this.transactionStyle = this.transactionStyle.toLowerCase();
				break;
			default:
				this.transactionStyle = 'opacity';
				break;
		}
		if (ValueType(ImagesPath) == 'Array') {
			switch (ValueType(ImagesPath[0])) {
				case 'Object':
					// Gli elementi [Oggetto] devono avere gli attributi "alt", "src" e "onClick".
					this.imagesCollection = ImagesPath;
					break;
				case 'string':
					this.imagesCollection = new Array();
					for (cont1=0; cont1 < ImagesPath.length; cont1++) {
						this.imagesCollection.push( {src:ImagesPath[cont1], width:null, height:null, alt:'', onClick:''} );
					}
					break;
			}
		}
		if (ValueType(ImagesPath) != 'Array') this.imagesCollection = new Array();
		
		if (!this.fps) this.fps = GetBrowserInfo('RecommendedFps');
		
		if (typeof(this.objectContainer) == 'string') this.objectContainer = findObj(this.objectContainer);
		this.objectContainer.style.overflow = 'hidden';
		
		this.objectContainer_width = toNumber(GetProperty(this.objectContainer, 'clientWidth')) / (this.transactionStyle == 'test' ? 10 : 1);
		this.objectContainer_height = toNumber(GetProperty(this.objectContainer, 'clientHeight')) / (this.transactionStyle == 'test' ? 10 : 1);
		
		this._div1 = null;
		this._div2 = null;
		this._img_srcNone = '/images/shim.gif';
		this._img1 = null;
		this._img2 = null;
		this._imgLoad = null;
		this._currentPosition = 0;
		this._status = 'stop';
		this._tmr = null;
	}
	
	this._buildObjects = function(){
		var str1;
		
		// Se il comando era già stato eseguito allora esco dalla funzione.
		if (this._div1) return false;
		
		// Creo gli oggetti
		this._div1 = document.createElement('div');
		this._div2Base = document.createElement('div');
		this._div2 = document.createElement('div');
		this._img1 = document.createElement('img');
		this._img2 = document.createElement('img');
		this._div1.appendChild(this._img1);
		this._div2.appendChild(this._img2);
		this._div2Base.appendChild(this._div2);
		this.objectContainer.appendChild(this._div1);
		this.objectContainer.appendChild(this._div2Base);
		
		// Creo ed inizializzo l'immagine che mi serve per ridimensionare le immagini da mostrare
		this._imgLoad = document.createElement('img');
		this._imgLoad._HtmlPlus_SlideShowObj = this;
		this._imgLoad.style.visibility = 'hidden';
		addEvent(this._imgLoad, 'load', this._imgLoad_onLoad);
		
		this._div3 = document.createElement('div');
		this.objectContainer.appendChild(this._div3);
		this._div3.appendChild(this._imgLoad);
		
		// Inizializzo i div assegnandogli le giuste proprietà.
		//Il DIV1:  contenitore dell'immagine corrente, e durante la transazione contiene l'immagine che se ne va.
		this._div1.style.position = 'relative';
		this._div1.style.width = this.objectContainer_width.toString() + 'px';
		this._div1.style.height = this.objectContainer_height.toString() + 'px';
		this._div1.style.padding = '0 0 0 0';
		this._div1.style.overflow = 'hidden';
		this._div1.style.visibility = 'hidden';
		this._div1.style.zIndex = 1;
		this._div1.style.backgroundColor = this.backgroundColor;
		//Il DIV2: contenitore dell'immagine nuova, per il periodo della transazione. Dopodichè questo DIV verrà nascosto, e l'immagine contenuta passerà a DIV1.
		this._div2.style.position = 'relative';
		this._div2.style.width = this.objectContainer_width.toString() + 'px';
		this._div2.style.height = this.objectContainer_height.toString() + 'px';
		this._div2.style.padding = '0 0 0 0';
		this._div2.style.overflow = 'hidden';
		this._div2.style.visibility = 'visible';
		this._div2.style.zIndex = 3;
		this._div2.style.backgroundColor = this.backgroundColor;
		//Il DIV2BASE: padre di DIV2. Serve per risolvere problemi di posizionamento di DIV2.
		this._div2Base.style.position = 'relative';
		this._div2Base.style.width = this.objectContainer_width.toString() + 'px';
		this._div2Base.style.height = this.objectContainer_height.toString() + 'px';
		this._div2Base.style.padding = '0 0 0 0';
		this._div2Base.style.overflow = 'hidden';
		this._div2Base.style.left = '0px';
		this._div2Base.style.top = - toNumber(this.objectContainer_height) + 'px';
		this._div2Base.style.display = 'none';
		this._div2Base.style.zIndex = 2;
		this._div2Base.style.backgroundColor = 'transparent';
		
		this._img1.style.position = 'relative';
		this._img1.alt = '';
		this._img2.style.position = 'relative';
		this._img2.alt = '';
		
		if (this.zoomType == 'fixed') {
			this._img1.style.width = this.objectContainer_width.toString() + 'px';
			this._img1.style.height = this.objectContainer_height.toString() + 'px';
			this._img1.style.left = '0px';
			this._img1.style.top = '0px';
			this._img2.style.width = this.objectContainer_width.toString() + 'px';
			this._img2.style.height = this.objectContainer_height.toString() + 'px';
			this._img2.style.left = '0px';
			this._img2.style.top = '0px';
		}
		
		// Creazione funzione per la generazione delle transazioni
		var generaClipMaker = function (myThis, IDTransazione, Stile) {
			var fReturn;
			switch (Stile) {
				case '':
					break;
				case 'opacity':
					fReturn = new HtmlPlus_ClipMaker(CStrJS(IDTransazione), myThis.transactionTime, myThis.fps);
					fReturn.AppendMotion(myThis._div1, 'opacity', '', 0, 100, 100, 0, myThis.transactionType);
					fReturn.AppendMotion(myThis._div2, 'opacity', '', 0, 100, 0, 100, myThis.transactionType);
					break;
				case 'right-left':
					fReturn = new HtmlPlus_ClipMaker(CStrJS(IDTransazione), myThis.transactionTime, myThis.fps);
					fReturn.AppendMotion(myThis._div1, 'left', 'px', 0, 100, 0, -myThis.objectContainer_width, myThis.transactionType);
					fReturn.AppendMotion(myThis._div2, 'left', 'px', 0, 100, myThis.objectContainer_width, 0, myThis.transactionType);
					break;
				case 'left-right':
					fReturn = new HtmlPlus_ClipMaker(CStrJS(IDTransazione), myThis.transactionTime, myThis.fps);
					fReturn.AppendMotion(myThis._div1, 'left', 'px', 0, 100, 0, myThis.objectContainer_width, myThis.transactionType);
					fReturn.AppendMotion(myThis._div2, 'left', 'px', 0, 100, -myThis.objectContainer_width, 0, myThis.transactionType);	
					break;
				case 'top-bottom':
					fReturn = new HtmlPlus_ClipMaker(CStrJS(IDTransazione), myThis.transactionTime, myThis.fps);
					fReturn.AppendMotion(myThis._div1, 'top', 'px', 0, 100, 0, myThis.objectContainer_height, myThis.transactionType);
					fReturn.AppendMotion(myThis._div2, 'top', 'px', 0, 100, -myThis.objectContainer_height, 0, myThis.transactionType);
					break;
				case 'bottom-top':
					fReturn = new HtmlPlus_ClipMaker(CStrJS(IDTransazione), myThis.transactionTime, myThis.fps);
					fReturn.AppendMotion(myThis._div1, 'top', 'px', 0, 100, 0, -myThis.objectContainer_height, myThis.transactionType);
					fReturn.AppendMotion(myThis._div2, 'top', 'px', 0, 100, myThis.objectContainer_height, 0, myThis.transactionType);
					break;
				case 'test':
					fReturn = new HtmlPlus_ClipMaker(CStrJS(IDTransazione), myThis.transactionTime, myThis.fps);
					fReturn.AppendMotion(myThis._div1, 'left', 'px', 0, 100, 100, 100 - myThis.objectContainer_height, myThis.transactionType);
					fReturn.AppendMotion(myThis._div2, 'top', 'px', 0, 100, 100 + myThis.objectContainer_height, 100, myThis.transactionType);
					break;
				default:
					fReturn = Stile;
			}
			if (fReturn) fReturn.AppendEvent(100, 'HtmlPlus_SlideShowColl[\'' + CStrJS(myThis.id) +  '\']._transactionMaker_OnEnd();');
			return fReturn;
		}
		
		//Creazione oggetti ClipMaker per [transactionMaker]
		this.transactionMaker = generaClipMaker(this, this.id + '_transaction', this.transactionStyle);
		
		//Creazione oggetti ClipMaker per [transactionMakerFF]
		this.transactionMakerFF = null;
		if (this.transactionStyleFF == 'auto') {
			switch (this.transactionStyle) {
				case 'opacity':		str1 = ''; break;
				case 'right-left':	str1 = 'left-right'; break;
				case 'left-right':	str1 = 'right-left'; break;
				case 'top-bottom':	str1 = 'bottom-top'; break;
				case 'bottom-top':	str1 = 'top-bottom'; break;
				case 'test':		str1 = 'test'; break;
				default:			str1 = ''; break;
			}
		} else {
			str1 = this.transactionStyleFF;
		}
		this.transactionMakerFF = generaClipMaker(this, this.id + '_transactionFF', str1);
		
		return true;
	} 
	this._processoPlay_args = {tmr:null};
	this._processoPlay = function(Stato) {
		//Si occupa di gestire le transazioni e le permanenze delle immagini.
		var nextPos1, nextPos2, strFunc;
		if (this._status == 'play') {
			if (this._div1.style.visibility == 'hidden') this._div1.style.visibility = 'visible';
			switch (Stato) {
				case 'transaction':
					nextPos1 = this._getPosition(1);
					nextPos2 = this._getPosition(2);
					if (!IsNull(nextPos1)) {
						strFunc = 'HtmlPlus_SlideShowColl[\'' + CStrJS(this.id) +  '\']._processoPlay(\'permanence\');';
						this._processoTransac(true, nextPos1, nextPos2, strFunc);
					}
					break;
				case 'permanence':
					clearTimeout(this._processoPlay_args['tmr']);
					this._processoPlay_args['tmr'] = setTimeout('HtmlPlus_SlideShowColl[\'' + CStrJS(this.id) +  '\']._processoPlay(\'transaction\');',  (this.permanenceTime - this.transactionTime) * 1000);
					break;
				case 'pause':
					clearTimeout(this._processoPlay_args['tmr']);
					break;
			}
		}
	}
	this._processoTransac_args = {stato:'check', newItem:null, nextItem:null, onEndFunction:null, objTransac:null};
	this._processoTransac = function(IsStatoCheck, optNewItem, optNextItem, optOnEndFunction) {
		//Si occupa di controllare il processo di passaggio da un'immagine all'altra.
		//In un ciclo Step si lavora su 3 immagini: old (a video, da sostituire), new (sostituirà old), next (la prossima).
		//Descrizione degli stati:
		//  1) check :   Verifica per inizio transazione: si verifica che new sia stata caricata.
		//  2) start :   Inizio transazione: old verrà sostituita da new, e nel frattempo verrà iniziato il caricamento di next.
		//  3) end :     Inizio tempo visione di new: la transazione è finita, si attende la fine del tempo permanenceTime.
		var cont1, str1;
		if (IsStatoCheck) {
			this._processoTransac_args['stato'] = 'check';
			if (optNewItem >= 0) {
				this._processoTransac_args['newItem'] = this.imagesCollection[optNewItem];
				this._processoTransac_args['newItem'].index = optNewItem;
			} else {
				this._processoTransac_args['newItem'] = {src:optNewItem, width:null, height:null, alt:'', onClick:''};
				this._processoTransac_args['newItem'].index = -1;
			}
			if (IsNull(optNextItem)) {
				this._processoTransac_args['nextItem'] = null;
			} else {
				if (optNextItem >= 0) {
					this._processoTransac_args['nextItem'] = this.imagesCollection[optNextItem];
					this._processoTransac_args['nextItem'].index = optNextItem;
				} else {
					this._processoTransac_args['nextItem'] = {src:optNextItem, alt:'', onClick:''};
					this._processoTransac_args['nextItem'].index = -1;
				}
			}
			this._processoTransac_args['onEndFunction'] = optOnEndFunction;
			this._processoTransac_args['objTransac'] = null;
		}
		switch (this._processoTransac_args['stato']) {
			case 'check':
				if (this.OnCurrentPrositionChanging(this, this._currentPosition, this._processoTransac_args['newItem'].index)) {
					//Determino lo stato successivo
					if (this.startMethod == 'image') {
						str1 = (this._img1.src.indexOf(this._img_srcNone) == -1 ? 'start' : 'end');
					} else {
						str1 = 'start';
					}
					//Carico l'immagine per il preload
					this._imgLoad_preloadImg(this._processoTransac_args['newItem']);
					if (this._imgLoadInfo['isLoaded']) {	//l'immagine new è stata caricata, proseguo.
						this._processoTransac_args['stato'] = str1;
						this._processoTransac();
					} else {
						cont1 = this._imgLoadInfo['timeout'] - (new Date());	//Tempo passato dal preload, in msec.
						if (cont1 < 0) {	// scaduto il tempo di preload, proseguo.
							// annullo il timer di preload
							clearTimeout(this._imgLoadInfo['onPreloadEndTmr']);
							this._imgLoadInfo['onPreloadEndFunction'] = null;
							// eseguo lo step successivo
							this._processoTransac_args['stato'] = str1;
							this._processoTransac();
						} else {			//devo aspettare lo scadere del tempo di preload.
							this._imgLoadInfo['onPreloadEndFunction'] = 'HtmlPlus_SlideShowColl[\'' + CStrJS(this.id) +  '\']._processoTransac();';
							this._imgLoadInfo['onPreloadEndTmr'] = setTimeout(this._imgLoadInfo['onPreloadEndFunction'], cont1);
						}
					}
				} else {
					if (this.Status() == 'play') this._changeStatus('pause');
				}
				break;
			case 'start':
				if (this._div1.style.visibility == 'hidden') this._div1.style.visibility = 'visible';
				this._img1.alt = '';
				this._img1.onClick = '';
				if (this._currentPosition >= 0 && this._currentPosition > this._processoTransac_args['newItem'].index) {
					//La nuova posizione  posteriore alla corrente, quindi eseguo la transazione all'indietro.
					this._processoTransac_args.objTransac = (this.transactionMakerFF ? this.transactionMakerFF : this.transactionMaker);
				} else {
					//Eseguo la transazione all'avanti.
					this._processoTransac_args.objTransac = this.transactionMaker;
				}
				this._img2.src = this._processoTransac_args['newItem'].src;
				this._imgRedim(this._processoTransac_args['newItem'], this._img2);
				this._div2Base.style.display = 'block';
				this.OnTransactionBegin(this, this._currentPosition, this._processoTransac_args['newItem'].index);
				this._processoTransac_args.objTransac.Play();
				this._processoTransac_args['stato'] = 'end';
				if (this._processoTransac_args['nextItem']) this._imgLoad_preloadImg(this._processoTransac_args['nextItem']);
				break;
			case 'end':
				this._img1.src = this._processoTransac_args['newItem'].src;
				this._img1.alt = this._processoTransac_args['newItem'].alt;
				this._img1.onClick = this._processoTransac_args['newItem'].onClick;
				switch (this.zoomType){
					case 'fixed':
						break;
					default:
						this._imgRedim(this._processoTransac_args['newItem'], this._img1);
				}
				
				//ripristino il div1 e div2 e nascondo il div2
				this._div2Base.style.display = 'none';
				if (this._processoTransac_args.objTransac) this._processoTransac_args.objTransac.Stop();
				//Fine esecuzione
				this._processoTransac_args['stato'] = '';
				this._currentPosition = this._processoTransac_args['newItem'].index;
				this.OnCurrentPrositionChanged(this, this._currentPosition);
				if (this._processoTransac_args['onEndFunction']) eval(this._processoTransac_args['onEndFunction']);
				break;
		}
	}
	this._imgLoadInfo = {isLoaded:false, startTime:null, endTime:null, timeout:null, imgColl:[], onPreloadEndFunction:null, onPreloadEndTmr:null};
	this._imgLoad_preloadImg = function(ImageSource) {
		var objImg, src, caricare;
		if (ValueType(ImageSource) == 'Object') {
			objImg = ImageSource;
			src = objImg.src;
		} else {
			objImg = null;
			src = ImageSource;
		}
		caricare = true;
		if (caricare && this._imgLoad.src == src) caricare = false;
		if (caricare && objImg) caricare = true; (objImg.isLoaded ? false : true);
		if (caricare) {
			this._imgLoadInfo['imageSource'] = ImageSource;
			this._imgLoadInfo['image'] = objImg;
			this._imgLoadInfo['isLoaded'] = false;
			this._imgLoadInfo['startTime'] = new Date();
			this._imgLoadInfo['endTime'] = null;
			this._imgLoadInfo['timeout'] = this._imgLoadInfo['startTime'].DateAdd('s', this.preloadTimeout);
			this._imgLoad.src = src;
			this.OnPreloadBegin(this, this._imgLoadInfo['imageSource']);
		}
	}
	this._imgLoad_onLoad = function(ev) {
		var eventObj = new STDEvent(ev);
		var objSlide = eventObj.srcElement._HtmlPlus_SlideShowObj;
		var str1, objImg, obj1;
		if (objSlide) {
			objSlide._imgLoadInfo['isLoaded'] = true;
			objSlide._imgLoadInfo['endTime'] = new Date();
			objImg = objSlide._imgLoadInfo['image'];
			if (objImg) {
				objImg.isLoaded = true;
				if (!objImg.width) objImg.width = toNumber(GetProperty(objSlide._imgLoad, 'width', true));
				if (!objImg.height) objImg.height = toNumber(GetProperty(objSlide._imgLoad, 'height', true));
			}
			//Metto in cache un nuovo oggett IMAGE
			obj1 = document.createElement('IMG');
			obj1.src = eventObj.srcElement.src;
			objSlide._imgLoadInfo['imgColl'].push(obj1);
			//Lanco l'evento OnPreloadEnd
			objSlide.OnPreloadEnd(objSlide, objSlide._imgLoadInfo['imageSource']);
			if (objSlide._imgLoadInfo['onPreloadEndFunction']) {
				clearTimeout(objSlide._imgLoadInfo['onPreloadEndTmr']);
				str1 = objSlide._imgLoadInfo['onPreloadEndFunction'];
				objSlide._imgLoadInfo['onPreloadEndFunction'] = null;
				eval(str1);
			}
		}
	}
	this._imgRedim = function(ImageItem, Img) {
		var divW, divH, imgW, imgH;
		
		divW = this.objectContainer_width;
		divH = this.objectContainer_height;
		imgW = IfNull(ImageItem.width, divW);
		imgH = IfNull(ImageItem.height, divH);
		
		switch (this.zoomType){
			case 'fixed':
				break;
			case 'min':
				if ((divW / divH) > (imgW / imgH)) {
					// Calcolo le dimensioni
					Img.style.width = divW + 'px';
					Img.style.height = (imgH * divW / imgW) + 'px';
					// Centro l'immagine
					Img.style.top = Math.round(-(parseInt(Img.style.height, 0) - divH) / 2) + 'px';
					Img.style.left = '0px';
				} else {
					// Calcolo le dimensioni
					Img.style.height = divH + 'px';
					Img.style.width = (imgW * divH / imgH) + 'px';
					// Centro l'immagine
					Img.style.top = '0px';
					Img.style.left = Math.round(-(parseInt(Img.style.width, 0) - divW) / 2) + 'px';
				}
				break;
			case 'max':
				if ((divW / divH) < (imgW / imgH)) {
					// Calcolo le dimensioni dell'immagine
					Img.style.width = divW + 'px';
					Img.style.height = (imgH * divW / imgW) + 'px' ;
					// Centro l'immagine
					Img.style.left = '0px';
					Img.style.top = Math.round((divH - (parseInt(Img.style.height, 0))) / 2) + 'px';
				} else {
					// Calcolo le dimensioni dell'immagine
					Img.style.height = divH + 'px';
					Img.style.width = (imgW * divH / imgH) + 'px' ;
					// Centro l'immagine	
					Img.style.left = Math.round((divW -(parseInt(Img.style.width, 0))) / 2) + 'px';
					Img.style.top = '0px';
				}
				break;
		}
	}
	this._transactionMaker_OnEnd = function(){
		this.OnTransactionEnd(this, cont1,  this.GetCurrentPosition());
		this._processoTransac();
	}
	
	this._changeStatus = function (nuovoValore) {
		if (this._status != nuovoValore) {
			var str1 = this._status;
			this._status = nuovoValore;
			this.OnStatusChanged(this, str1, nuovoValore);
		}
	}
	this._getPosition = function(MoveForItems) {
		this._buildObjects();
		var posiz = this._currentPosition;
		if (this.imagesCollection.length < 1) {
			posiz = null;
		} else {
			posiz += MoveForItems;
			if (posiz < 0) {
				if (this.repeat) {
					while (posiz < 0) {
						posiz += this.imagesCollection.length;
					}
				} else {
					posiz = null;
				}
			} else if (posiz >= this.imagesCollection.length) {
				if (this.repeat) {
					while (posiz >= this.imagesCollection.length) {
						posiz -= this.imagesCollection.length;
					}
				} else {
					posiz = null;
				}
			}
		}
		return posiz;
	}
	this.GetPreviousPosition = function(){
		return this._getPosition(-1);
	}
	this.GetNextPosition = function(){
		return this._getPosition(1);
	}
	
	this.Play = function() {
		var str1;
		this._buildObjects();
		switch (this._status){
			case 'play':
				break;
			case 'pause':
				this._changeStatus('play');
				this._processoPlay('transaction');
				break;
			case 'stop':
				if (this.imagesCollection.length < 2) this.repeat = false;
				switch (this.startMethod){
					case 'image':
						this._img1.src = this._img_srcNone;
						this._img1.alt = '';
						this._img1.onClick = '';
						str1 = 'var objSlide = HtmlPlus_SlideShowColl[\'' + CStrJS(this.id) +  '\'];';
						str1 += 'objSlide._changeStatus(\'play\');';
						str1 += 'objSlide._processoPlay(\'permanence\');';
						this._processoTransac(true, 0, null, str1);
						break;
					case 'transaction': 
						this._changeStatus('play');
						this._currentPosition = -1;
						this._img1.src = this._img_srcNone;
						this._img1.alt = '';
						this._img1.onClick = '';
						this._processoPlay('transaction');
						break;
					default:
						this._changeStatus('play');
						this._currentPosition = -1;
						this._img1.src = this.startMethod;
						this._img1.alt = '';
						this._img1.onClick = '';
						this._processoPlay('transaction');
						break;
				}
				break;
		}
	}
	this.Pause = function(){
		this._buildObjects();
		switch (this._status){
			case 'play':
				this._processoPlay('pause');
				this._changeStatus('pause');
				break;
			case 'pause':
				break;
			case 'stop':
				break;
		}
	}
	this.Stop = function(){
		this._buildObjects();
		switch (this._status){
			case 'play':
				this._processoPlay('pause');
				this._changeStatus('stop');
				this.SetCurrentPosition(0);
				break;
			case 'pause':
				this._processoPlay('pause');
				this._changeStatus('stop');
				this.SetCurrentPosition(0);
				break;	
			case 'stop':
				break;
		}
	}
	
	this.GetCurrentPosition = function(){
		this._buildObjects();
		return this._currentPosition;
	}
	this.SetCurrentPosition = function(value){
		this._buildObjects();
		switch(this._status){
			case 'play':
				this.Pause();
				break;
			case 'pause':
				break;
			case 'stop':
				this.Pause();
				break;
		}
		this._processoTransac(true, value, null);
	}
	
	this.Status = function(){
		this._buildObjects();
		return this._status;
	}
	
	this.OnStatusChanged = function (SlideShow, OldStatusValue, NewStatusValue) {return void(0);};
	this.OnPreloadBegin = function (SlideShow, Src) {return void(0);};
	this.OnPreloadEnd = function (SlideShow, Src) {return void(0);};
	this.OnTransactionBegin = function (SlideShow, OldImageIndex, NewImageIndex) {return void(0);};
	this.OnTransactionEnd = function (SlideShow, OldImageIndex, NewImageIndex) {return void(0);};
	this.OnCurrentPrositionChanging = function (SlideShow, OldImageIndex, NewImageIndex) {return true;};
	this.OnCurrentPrositionChanged = function (SlideShow, NewImageIndex) {return void(0);};
	
	this._initialize();
	return this;
}


function HtmlPlus_VerticalFill(HtmlObject, DynamicMode, optOffset) {
	return HtmlPlus_DimensionFill(HtmlObject, 'height', DynamicMode, optOffset);
}
function HtmlPlus_OrizzontalFill(HtmlObject, DynamicMode, optOffset) {
	return HtmlPlus_DimensionFill(HtmlObject, 'width', DynamicMode, optOffset);
}
function HtmlPlus_DimensionFill(HtmlObject, WidthHeight, DynamicMode, optOffset) {
	//Dimensiona l'oggetto passato al fine di riempire lo spazio a disposizione senza far comparire le barre di scorrimento.
	//Mettendo NoDynamic a TRUE, il ridimensionamento viene impostato al valore secondo la dimensione attuale del browser, e su
	//ridimensionamento l'oggetto non viene ridimensionato.
	//ATTENZIONE: l'oggetto è consigliabile che sia posizionato in alto a sinistra rispetto al suo contenitore.
	var objHtml, objBody, argDynMode;
	var dimWH, clientWH, scrollWH, offsetWH;
	var nuovaDim, valOffset, str1;
	
	//Carico le variabili
	objHtml = (typeof(HtmlObject) == 'string' ? findObj(HtmlObject) : HtmlObject);
	objBody = objHtml.ownerDocument.body;
	objBody = GetDocInfo(objHtml, 'RootElement');
	switch (DynamicMode) {
		case 'NoDynamic':
		case 'NoDynamic+Offset':
		case 'DynamicRecalc':
		case 'Dynamic':
			argDynMode = DynamicMode;
			break;
		case true:		//serve per compatibilità all'indietro, dove il secondo argomento si chiamava "NoDynamic"
			argDynMode = 'NoDynamic';
			break;
		case false:		//serve per compatibilità all'indietro, dove il secondo argomento si chiamava "NoDynamic"
		default:
			argDynMode = 'Dynamic';
			break;
	}
	switch (WidthHeight) {
		case 'width':	dimWH = 'width'; break;
		default:		dimWH = 'height'; break;
	}
	switch (dimWH) {
		case 'width':	clientWH = 'clientWidth'; scrollWH = 'scrollWidth'; offsetWH = 'offsetWidth'; break;
		case 'height':	clientWH = 'clientHeight'; scrollWH = 'scrollHeight'; offsetWH = 'offsetHeight'; break;
	}
	
	if (window._HtmlPlus_DimensionFill_running) {
		str1 = 'HtmlPlus_DimensionFill(';
		str1 += 'findObj(\'' + CStrJS(GetProperty(objHtml, 'uniqueID')) + '\')';
		str1 += ', \'' + CStrJS(dimWH) + '\'';
		str1 += ', \'' + CStrJS(argDynMode) + '\'';
		if (optOffset) str1 += ', ' + optOffset.toString();
		str1 += ');';
		//setTimeout(str1, 200);
	} else {
		//Mi memorizzo sull'oggetto che è in corso una esecuzione di questa procedura, perchè c'è rischio che si crei una esecuzione a catena
		//dato che ci sono degli eventi associati.
		//window._HtmlPlus_VerticalFill_running = true;		DISATTIVATO, perchè non funziona. Vedi commento piu sotto su "addEvent".
		
		//Determino la nuova dimensione ed effettuo la modifica
		if (argDynMode == 'NoDynamic+Offset') {
			SetProperty(objHtml, dimWH, (toNumber(objBody[clientWH]) - optOffset) + 'px');
		} else {
			var scrVal1, scrVal2, scrVal3;
			var cacheDisp = GetCssStyle(objHtml, 'display');
			SetProperty(HtmlObject, dimWH, toNumber(objBody[clientWH]).toString() + 'px');
			objHtml.style.display = 'none';
			scrVal1 = toNumber(objBody[scrollWH]);
			objHtml.style.display = cacheDisp;
			scrVal2 = toNumber(objBody[scrollWH]);
			if (scrVal1 > toNumber(objBody[clientWH])) {	//Se la scrollbar ci sta anche senza objHtml allora...
				SetProperty(objHtml, dimWH, (1000 + toNumber(objBody[clientWH])) + 'px');	//50000
				scrVal3 = toNumber(objBody[scrollWH]);
				nuovaDim = toNumber(GetCssStyle(objHtml, dimWH)) - (scrVal3 - scrVal2);
			} else {
				nuovaDim = toNumber(GetCssStyle(objHtml, dimWH)) - (scrVal2 - toNumber(objBody[clientWH]));
			}
			if (nuovaDim > 0) SetProperty(objHtml, dimWH, nuovaDim + 'px');
			valOffset = toNumber(objBody[clientWH]) - nuovaDim;
		}
		//Verifico se devo creare eventi per la gestione dinamica della dimensione su ridimensionamento del Document
		switch (argDynMode) {
			case 'NoDynamic':
			case 'NoDynamic+Offset':
				break;
			case 'DynamicRecalc':
				//addEvent(window, 'resize', function() {HtmlPlus_VerticalFill(objHtml, 'NoDynamic');});
				//	'--- disattivato perchè il ridimensionamento verso 5000 per determinare di quanto si eccede non funziona: l'oggetto viene
				//		ridimensionato ma la pagina sembra che non venga ricalcolata. Di conseguenza non ho un valore valido per "scrollHeight".
				//		La soluzione sarebbe di spezzare la procedura in più parti, dando tempo al browser di rappresentare ciò che deve, oppure
				//		scoprire un comando che sappia eseguire un REFRESH. Al momento ripristino il vecchio meccanismo.
				try {
					objHtml.setExpression(dimWH, 'window.document.body.' + clientWH + ' - (' + valOffset + ')');
					//Attenzione: il comando [setExpression] è obsoleto. Sarà da modificare la funzione usando altri sistemi per risettare la proprietà
					//dell'oggetto dinamicamente. Magari completando lo sviluppo di HtmlPlus_Positionator e usando quest'ultimo.
				} catch (ex) {
				}
				break;
			case 'Dynamic':
				//objHtml.setExpression('height', 'Math.min(window.document.body.clientHeight, window.document.body.scrollHeight) - ' + offsetY);
				//objHtml.setExpression('height', 'window.document.body.clientHeight - ' + offsetY);
				//addEvent(window, 'resize', function() {HtmlPlus_VerticalFill(objHtml, 'NoDynamic+Offset', valOffset);});
				//  ^--- disattivato per lo stesso motivo indicato per argDynMode=DynamicRecalc
				try {
					objHtml.setExpression(dimWH, 'window.document.body.' + clientWH + ' - (' + valOffset + ')');
					//Attenzione:  --vedi commento sopra--
				} catch (ex) {
				}
				break;
		}
		
		//Indico la fine dell'esecuzione della procedura
		window._HtmlPlus_DimensionFill_running = false;
	}
}

function HtmlPlus_AutoScroll_AddPlusToObject(HtmlObject, ObjectHeight, PixelPerSec, NoAutoStart) {
	new HtmlPlus_AutoScroll('AutoScroll_' + HtmlObject.id, HtmlObject, ObjectHeight, PixelPerSec, NoAutoStart, null);
}
function HtmlPlus_AutoScroll(IdObject, ScrollerHtmlObject, ClientHeight, PixelPerSecond, NoAutoStart, HtmlPageSeparator, IsOrizzontal) {
	this.id = IdObject;
	this.objectType = 'HtmlPlus_AutoScroll';
	this.scrollerHtmlObject = ScrollerHtmlObject;	//Riferimento all'oggetto che effettuerà lo scrolling del suo contenuto;
	this.clientHeight = ClientHeight;				//Valore in Pixel o rif. a oggetto Html da cui determinare l'altezza di ScrollerHtmlObject;
	this.pixelPerSec = PixelPerSecond;				//Velocità di scorrimento;
	this.htmlPageSeparator = HtmlPageSeparator;		//Codice HTML che verrà usato come separatore fra pagine; se non definito il separatore sarà una
													//pagina bianca alta quanto [scrollerHtmlObject.clientHeight];
	this.isOrizzontal = IsOrizzontal;				//Se nullo o true la pagina simuove verticalmente altrimenti orizzontalmente
	this.autoStart = false;							//Se TRUE, lo scroll partirà quando verrà eseguito l'evento WINDOW.ONLOAD;
	this.fps = 0;									//Fotogrammi per secondo (qualità animazione);
	this.enabled = false;							//Tipicamente TRUE o FALSE, indica se l'animazione è attivata o disattivata;
	this._isPlay = false;							//Se TRUE, significa che l'animazione è accesa;
	this._tmp = null;								//Riferimento all'istanza "setInterval" che esegue l'animazione;

	if (!window.HtmlPlus_AutoScrollColl) {
		window.HtmlPlus_AutoScrollColl = new Array();
		addEvent(window, 'load', function() {
						var obj;
						for (obj in window.HtmlPlus_AutoScrollColl) {
							window.HtmlPlus_AutoScrollColl[obj].WINDOW_OnLoadHandler();
							break;
						}
					}
				 );
	}
	window.HtmlPlus_AutoScrollColl[this.id] = this;
	
	this._initialize = function() {
		var defaultPixelPerSec = 20;
		var defaultFps = GetBrowserInfo('RecommendedFps');
		
		this.scrollerHtmlObject.AutoScrollObject = this;
		if (!this.pixelPerSec) this.pixelPerSec = defaultPixelPerSec;
		this.autoStart = ((NoAutoStart) ? false : true);
		this.fps = defaultFps;
		this.enabled = 'toInitialize';

		if ( ! this.isOrizzontal ) {
			switch (typeof(this.clientHeight)) {
				case 'object':
					this.scrollerHtmlObject.style.height = toNumber(GetProperty(this.clientHeight, 'clientHeight')).toString() + 'px';
					break;
				case 'string':
					if (this.clientHeight.length > 10) {
						this.scrollerHtmlObject.style.height = toNumber(this.clientHeight, 0).toString() + 'px';
						break;
					}
				default:
					this.scrollerHtmlObject.style.height = toNumber(this.clientHeight, 0).toString() + 'px';
			}
		} else {
			switch (typeof(this.clientHeight)) {
				case 'object':
					this.scrollerHtmlObject.style.width = toNumber(GetProperty(this.clientHeight, 'clientWidth')).toString() + 'px';
					break;
				case 'string':
					if (this.clientHeight.length > 10) {
						this.scrollerHtmlObject.style.width = toNumber(this.clientHeight, 0).toString() + 'px';
						break;
					}
				default:
					this.scrollerHtmlObject.style.width = toNumber(this.clientHeight, 0).toString() + 'px';
			}
		}

		addEvent(this.scrollerHtmlObject, 'mouseover', function(ev) {
						var eventObj = new STDEvent(ev);
						var obj = eventObj.srcElement;
						while (obj.tagName != 'BODY') {
							if (obj.AutoScrollObject) {
								obj.AutoScrollObject.OnMouseOverHandler();
								break;
							} else {
								obj = obj.parentNode;
							}
						}
					}
				);
		addEvent(this.scrollerHtmlObject, 'mouseout', function(ev){
						var eventObj = new STDEvent(ev);
						var obj = eventObj.srcElement;
						while (obj.tagName != 'BODY') {
							if (obj.AutoScrollObject) {
								obj.AutoScrollObject.OnMouseOutHandler();
								break;
							} else {
								obj = obj.parentNode;
							}
						}
					}
				);
	}
	
	this.WINDOW_OnLoadHandler = function() {
		var obj;
		for (obj in window.HtmlPlus_AutoScrollColl) {
			if (window.HtmlPlus_AutoScrollColl[obj].autoStart) window.HtmlPlus_AutoScrollColl[obj].Start();
		}
	}
	this.OnMouseOverHandler = function() {
		this.Stop();
	}
	this.OnMouseOutHandler = function() {
		this.Start();
	}
	
	this.Start = function() {
		if (this.enabled == 'toInitialize') {
				//Inizializzo l'oggetto
			if (! this.isOrizzontal){
				if (this.scrollerHtmlObject.scrollHeight > this.scrollerHtmlObject.clientHeight) {
					if (this.htmlPageSeparator) {
						// Inserisco il SeparatoreDiPagina all'inizio del contenuto dello Scroller, poi duplico tutto il contenuto.
						var str1 = this.htmlPageSeparator + this.scrollerHtmlObject.innerHTML;
						this.scrollerHtmlObject.innerHTML = str1 + str1;
						this.scrollerHtmlObject.style.paddingTop = '0px';
						this.scrollerHtmlObject.style.paddingBottom = '0px';
					} else {
						// Aggiungo dello spazio vuoto in testa ed in coda al contenuto
						this.scrollerHtmlObject.style.paddingTop = this.scrollerHtmlObject.clientHeight + 'px';
						this.scrollerHtmlObject.style.paddingBottom = this.scrollerHtmlObject.clientHeight + 'px';
					}
					this.enabled = true;
				}
				this._tmr = '';
			} else {
				if (this.scrollerHtmlObject.scrollWidth > this.scrollerHtmlObject.clientWidth) {
					if (this.htmlPageSeparator) {
						// Inserisco il SeparatoreDiPagina all'inizio del contenuto dello Scroller, poi duplico tutto il contenuto.
						var str1 = '<table cellpadding="0" height="100%" cellspacing="0" border="0"><tr>';
						str1 = str1 + '<td align="left" valign="middle">' + this.htmlPageSeparator + '</td>' ;
						str1 = str1 + '<td>' + this.scrollerHtmlObject.innerHTML + '</td>';
						str1 = str1 + '<td align="left" valign="middle">' + this.htmlPageSeparator + '</td>';
						str1 = str1 + '<td>' + this.scrollerHtmlObject.innerHTML + '</td>';
						str1 = str1 + '</tr></table>';
						this.scrollerHtmlObject.innerHTML = str1;
						this.scrollerHtmlObject.style.paddingLeft = '0px';
						this.scrollerHtmlObject.style.paddingRight = '0px';
					} else {
						// Aggiungo dello spazio vuoto in testa ed in coda al contenuto
						this.scrollerHtmlObject.style.paddingLeft = this.scrollerHtmlObject.clientWidth + 'px';
						this.scrollerHtmlObject.style.paddingRight = this.scrollerHtmlObject.clientWidth + 'px';
					}
					this.enabled = true;
				}
				this._tmr = '';
			}
		}
		if (!this.isPlay && this.enabled) {
			this._tmr = setInterval('var obj = window.HtmlPlus_AutoScrollColl["' + this.id + '"]; obj._runStep();', 1000 / this.fps);
			this.isPlay = true;
		}
	}


	this.Stop = function() {
		if (this.isPlay) {
			this.isPlay = false;
			window.clearInterval(this._tmr);
			this._tmr = '';
		}
	}
		
	this._runStep = function() {
		var i;
		if (this.isPlay) {
			if ( ! this.isOrizzontal) {
				if (this.scrollerHtmlObject.scrollHeight <= this.scrollerHtmlObject.clientHeight) {
					this.Stop();
				} else {
					i = this.scrollerHtmlObject.scrollTop + Math.ceil(this.pixelPerSec / this.fps);
					if (this.htmlPageSeparator) {
						if ((i >= this.scrollerHtmlObject.scrollHeight / 2) || (i < 0)) {
							if (this.pixelPerSec > 0) {
								i = 0;
							} else {
								i = this.scrollerHtmlObject.scrollHeight / 2;
							}
						}
					} else {
						if ((i > this.scrollerHtmlObject.scrollHeight - this.scrollerHtmlObject.clientHeight) || (i < 0)) {
							if (this.pixelPerSec > 0) {
								i = 0;
							} else {
								i = this.scrollerHtmlObject.scrollHeight;
							}
						}
					}
					this.scrollerHtmlObject.scrollTop = i;
				}
			}else{
				if (this.scrollerHtmlObject.scrollWidth <= this.scrollerHtmlObject.clientWidth) {
					this.Stop();
				} else {
					i = this.scrollerHtmlObject.scrollLeft + Math.ceil(this.pixelPerSec / this.fps);
					if (this.htmlPageSeparator) {
						if ((i >= this.scrollerHtmlObject.scrollWidth / 2) || (i < 0)) {
							if (this.pixelPerSec > 0) {
								i = 0;
							} else {
								i = this.scrollerHtmlObject.scrollWidth / 2;
							}
						}
					} else {
						if ((i > this.scrollerHtmlObject.scrollWidth - this.scrollerHtmlObject.clientWidth) || (i < 0)) {
							if (this.pixelPerSec > 0) {
								i = 0;
							} else {
								i = this.scrollerHtmlObject.scrollWidth;
							}
						}
					}
					this.scrollerHtmlObject.scrollLeft = i;
				}
			}
		}
	}
	
	this._initialize();
	return this;
}



function HtmlPlus_ClipMaker(IdObject, TransactionTime, fps) {
	this.id = IdObject;
	this.objectType = 'HtmlPlus_ClipMaker';
	this.transactionTime = TransactionTime;		//Durata della transazione (in secondi).
	this.fps = fps;								//Fotogrammi per secondo della transazione.
	
		
	if (!window.HtmlPlus_ClipMakerColl) window.HtmlPlus_ClipMakerColl = new Array();
	window.HtmlPlus_ClipMakerColl[this.id] = this;
	
	this._initialize = function () {
		this._time = 0;
		this._speed = 1;
		this._status = 'stop';
		this._tmr = null;
		this._startTime = null;
		this._showFrame_running = false;
		this._showFrame_callPool = new Array();
		if (!this.fps) this.fps = GetBrowserInfo('RecommendedFps');
	}
	this.Motions = function () {
		return this._motions;
	}
	this.AppendMotion = function (AnimatedHtmlObject, AttributeName, AttributeUM_Format, StartTime, StopTime, StartValue, StopValue, TransactionType) {
		/*
		Aggiunge un oggetto Movimento all'array [Motions]. Parametri:
			AnimatedHtmlObject		Qggetto da animare.
			AttributeName			Attributo da modificare.
			AttributeUM_Format		L'unità di misura del valore che verrà impostato all'attributo; se la stringa contiene il carattere "#" allora
									la stringa verrà usata in modalità Format, sostituendo il carattere segnaposto "#" col valore numerico da settare;
									Es.:    AttributeUM_Format = 'alpha(opacity=#)'    l'attributo verra settato con:   'alpha(opacity=12)'.
			StartTime				Tempo in cui deve iniziare l'animazione (da 0 a 100, corrispondenti all'inizio e alla fine del clip).
			StopTime				Tempo in cui deve finire l'animazione (come per StartTime).
			StartValue				Valore di partenza dell'attributo.
			StopValue				Valore finale dell'attributo.
			TransactionType			Il tipo di transazione; può essere: 'square', 'triangle', 'sin', 'cos'.
		*/
		var obj1 = new Object();
		obj1.htmlObject = AnimatedHtmlObject;
		obj1.attributeName = AttributeName;
		obj1.attributeFormat = AttributeUM_Format;
		obj1.startTime = StartTime;
		obj1.stopTime = StopTime;
		obj1.startValue = StartValue;
		obj1.stopValue = StopValue;
		obj1.transactionType = TransactionType;
		obj1.enabled = true;
		
		if (typeof(obj1.htmlObject) != 'object') obj1.htmlObject = findObj(obj1.htmlObject);
		if (obj1.attributeFormat.indexOf('#') == -1) obj1.attributeFormat = '#' + obj1.attributeFormat;
		switch (obj1.transactionType) {
			case 'square': case 'triangle': case 'sin': case 'cos': break;
			default: obj1.transactionType = 'triangle';
		}
		
		if (!this._motions) this._motions = new Array();
		this._motions.push(obj1);
	}
	this.Events = function () {
		return this._events;
	}
	this.AppendEvent = function (Time, Action) {
		/*
		Aggiunge un oggetto Evento all'array [Events]. Parametri:
			Time					Il momento in cui deve eseguirsi l'evento (da 0 a 100, corrispondenti all'inizio e alla fine del clip).
			Action					L'azione che deve essere eseguita; può essere una stringa JavaScript oppure un puntatore a funzione.
		*/
		var obj1 = new Object();
		obj1.time = Time;
		obj1.action = Action;
		
		if (!this._events) this._events = new Array();
		this._events.push(obj1);
	}
	this.RecalcTransactionTime = function () {
		//Ricalcolo i tempi per spalmare i tempi da valori in secondo a valori in percentuale:
		//itera fra gli oggetti [motions] e [events], interpreta gli attributi Time come se fossero espressi in secondi, e li converte in percentuale;
		//il valore più alto che viene trovato verrà usato per risettare l'attributo [transactionTime].
		var valMax = -1;
		var cont1;
		if (this._motions) {
			for (cont1 = 0; cont1 < this._motions.length; cont1++) {
				if (valMax < this._motions[cont1].stopTime) valMax = this._motions[cont1].stopTime;
			}
		}
		if (this._events) {
			for (cont1 = 0; cont1 < this._events.length; cont1++) {
				if (valMax < this._events[cont1].time) valMax = this._events[cont1].time;
			}
		}
		this.transactionTime = valMax;
		if (this._motions) {
			for (cont1 = 0; cont1 < this._motions.length; cont1++) {
				this._motions[cont1].startTime = this._motions[cont1].startTime / valMax * 100;
				this._motions[cont1].stopTime = this._motions[cont1].stopTime / valMax * 100;
			}
		}
		if (this._events) {
			for (cont1 = 0; cont1 < this._events.length; cont1++) {
				this._events[cont1].time = this._events[cont1].time / valMax * 100;
			}
		}
		return true;
	}
	this.Play = function () {
		if (this._status != 'play') {
			var ora = new Date().getTime();
			if (this._tmr) window.clearInterval(this._tmr);
			if (this._status == 'stop') {
				this._time = ((this._speed > 0) ? -1 : 101);
			}
			this._startTime = ora - (this.transactionTime / this._speed) * 1000 * this._time / 100;
			this._status = 'play';
			this._showFrame();
			this._tmr = setInterval('var obj = window.HtmlPlus_ClipMakerColl[\'' + CStrJS(this.id) + '\']; obj._showFrame();', 1000 / this.fps);
			return true;
		} else {
			return false;
		}
	}
	this.Pause = function () {
		if (this._status == 'play') {
			if (this._tmr) window.clearInterval(this._tmr);
			this._status = 'pause';
			this._forceShowFrame(this._calculateCurrTime(), true);
			return true;
		} else {
			return false;
		}
	}
	this.Stop = function () {
		if (this._tmr) window.clearInterval(this._tmr);
		this._startTime = null;
		this._status = 'stop';
		this._forceShowFrame((this._speed > 0)? 0 : 100, true);
		return true;
	}
	this.GetTime = function () {
		//Percentuale di esecuzione. 0: inizio del clip; 100: fine del clip.
		//Se Speed è negativo, 100 corrisponderà sempre alla fine del filmato, che però, se il clip è in Play, decrementerà fino a 0.
		return this._time;
	}
	this.SetTime = function (TimeValue) {
		//Sposta il punto di esecuzione. Valore da 0 a 100.
		if (TimeValue >= 0 && TimeValue <= 100) {
			if (this._status == 'play') {
				this.Pause();
				this._forceShowFrame(TimeValue, true);
				this.Play();
			} else {
				this._forceShowFrame(TimeValue, true);
			}
		}
	}
	this.GetSpeed = function () {
		//Velocità di esecuzione. 1: velocità normale; 0.5: velocità dimezzata; 2: velocità doppia; -1: reverse; ecc..
		return this._speed;
	}
	this.SetSpeed = function (SpeedValue) {
		//Velocità di esecuzione. Valore minore o maggiore da 0.
		if (SpeedValue > 0 || SpeedValue < 0) this._speed = SpeedValue;
	}
	this.Status = function () {
		//Può essere: 'play', 'pause', 'stop'.
		return this._status;
	}
	
	this._calculateCurrTime = function () {
		//Calcolo il TIME corrente in base a quanto tempo è trascorso dall'inizio dell'animazione
		var fReturn;
		fReturn = (new Date().getTime() - this._startTime) / 1000 / (this.transactionTime / this._speed) * 100;
		if (fReturn < 0) {
			fReturn = 0;
		} else if (fReturn > 100) {
			fReturn = 100;
		}
		return fReturn;
	}
	this._forceShowFrame = function (newTime, optAbortSameTime) {
		var eseguire, risp;
		if (!optAbortSameTime) {
			eseguire = true;
		} else {
			eseguire = (newTime != this._time);
		}
		if (eseguire) {
			risp = this._showFrame(newTime, true);
			if (!risp) this._showFrame_callPool.push('window.HtmlPlus_ClipMakerColl[\'' + CStrJS(this.id) + '\']._showFrame(' + CNumJS(newTime) + ', true);');
		}
		//	setTimeout('window.HtmlPlus_ClipMakerColl[\'' + CStrJS(this.id) + '\']._forceShowFrame(' + newTime + ');', 50);
	}
	this._showFrame = function (newTime, optForceShow) {
		//Elabora un fotogramma. Il parametro [newTime] (opzionale) serve per indicare il TIME che si deve elaborare. Dopo l'elaborazione
		//la funzione setterà il valore TIME alla classe.
		var listaMotions = new Array();
		var listaMotions_oggetti = new Array();
		var listaEvents = new Array();
		var precTime, currTime;
		var cont1, cont2, str1, obj1, obj2;
		
		if (!this._showFrame_running) {
			this._showFrame_running = true;
			
			//Determino i TIME
			precTime = this._time;
			if (newTime >= 0 || newTime < 0) {
				currTime = newTime;
				if (currTime < 0) {
					currTime = 0;
				} else if (currTime > 100) {
					currTime = 100;
				}
			} else {
				currTime = this._calculateCurrTime();
			}
			
			if (currTime != precTime || optForceShow) {
				//Determino gli oggetti-attributi da modificare
				if (this._motions) {
					for (cont1 = 0; cont1 < this._motions.length; cont1++) {
						//Ottengo l'oggetto MOTION, prendendolo dalla testa o dalla coda a seconda della posizione del fotogramma corrente nella timeline.
						obj1 = this._motions[(precTime <= currTime ? cont1 : this._motions.length - cont1 - 1)];
						//Verifico se l'oggetto Motion esegue un movimento all'interno dell'intervallo  [precTime - currTime]
						if (precTime <= currTime && (obj1.startTime < currTime && obj1.stopTime > precTime || obj1.startTime == currTime)
								|| precTime > currTime && (obj1.startTime < precTime && obj1.stopTime > currTime || obj1.stopTime == currTime)) {
							//L'oggetto Motion è da prendere in considerazione.
							//Verifico se l'oggetto è già presente in [listaMotions_oggetti];
							cont2 = InArray(listaMotions_oggetti, obj1.htmlObject);
							if (cont2 === null) {
								cont2 = listaMotions_oggetti.length;
								listaMotions_oggetti.push(obj1.htmlObject);
							}
							//Verifico se l'oggetto-attributo è già presente in [listaMotions]:
							str1 = cont2.toString() + '.' + obj1.attributeName;
							if (listaMotions[str1]) {
								//è presente, quindi valuto se l'oggetto Motion presente nell'array ha un valore [expire] maggiore di quello corrente;
								//se così fosse allora sostituisco il Motion dell'array con quello corrente.
								obj2 = listaMotions[str1];
								cont2 = this._showFrame_calcolaExpire(currTime, precTime, obj1);
								if (cont2 < obj2.expire) {
									//Il valore [expire] del Motion corrente è minore; sostituisco il Motion dell'array con quello corrente.
									obj2.motion = obj1;
									obj2.expire = cont2;
								}
							} else {
								//non è presente, quindi creo un nuovo item.
								obj2 = new Object();
								obj2.motion = obj1;
								obj2.value = null;
								//setto [expire]: indica il tempo da cui è scaduto il movimento
								obj2.expire = this._showFrame_calcolaExpire(currTime, precTime, obj1);
							}
							listaMotions[str1] = obj2;
						}
					}
				}
				//Determino gli eventi da invocare
				if (this._events) {
					for (cont1 = 0; cont1 < this._events.length; cont1++) {
						//Ottengo l'oggetto EVENT, prendendolo dalla testa o dalla coda a seconda della posizione del fotogramma corrente nella timeline.
						obj1 = this._events[(precTime <= currTime ? cont1 : this._events.length - cont1 - 1)];
						//Verifico se l'oggetto Evento si verifica all'interno dell'intervallo  [precTime - currTime]
						if (precTime <= currTime && (precTime < obj1.time && currTime > obj1.time || currTime == obj1.time)
								|| precTime > currTime && (currTime < obj1.time && precTime > obj1.time || currTime == obj1.time)) {
							//L'oggetto Evento si verifica all'interno di questo intervallo temporale.
							listaEvents.push(obj1);
						}
					}
				}
				//Calcolo i valori per ogni animazione
				for (cont1 in listaMotions) {
					obj1 = listaMotions[cont1];
					if (currTime >= precTime && obj1.motion.stopTime <= currTime) {
						str1 = obj1.motion.stopValue;
					} else if (currTime < precTime && obj1.motion.startTime >= currTime) {
						str1 = obj1.motion.startValue;
					} else {
						//Calcolo il "fattore percentuale" della Motion corrente. Il valore che si ottiene và da 0 a 1.
						cont2 = (currTime - obj1.motion.startTime) / (obj1.motion.stopTime - obj1.motion.startTime);
						switch (obj1.motion.transactionType) {
							case 'square':		//si sposta con un unico fotogramma, che è quello centrale rispetto al tempo di transizione indicato.
								str1 = obj1.motion.startValue + ((obj1.motion.stopValue - obj1.motion.startValue) * Math.round(cont2));
								break;
							case 'sin':			//da riposo a MouseOver: parte veloce e si ferma lentamente
								str1 = obj1.motion.startValue + ((obj1.motion.stopValue - obj1.motion.startValue) * Math.sin(cont2 * Math.PI / 2));
								break;
							case 'cos':			//da riposo a MouseOver: parte lento e si ferma di scatto
								str1 = obj1.motion.stopValue - ((obj1.motion.stopValue - obj1.motion.startValue) * Math.cos(cont2 * Math.PI / 2));
								break;
							case 'triangle':	//movimento a velocità costante
							default:
								str1 = obj1.motion.startValue + ((obj1.motion.stopValue - obj1.motion.startValue) * cont2);
						}
					}
					obj1.value = obj1.motion.attributeFormat.replace('#', str1);
				}
				//Eseguo le animazioni
				for (cont1 in listaMotions) {
					obj1 = listaMotions[cont1];
					SetProperty(obj1.motion.htmlObject, obj1.motion.attributeName, obj1.value);
				}
				//Controllo [currTime] e valuto se sono arrivato alla fine del clip
				if (this._status == 'play') {
					if (this._speed > 0 && currTime == 100 || this._speed < 0 && currTime == 0) {
						this.Pause();
					}
				}
				this._time = currTime;
				//Eseguo gli eventi
				for (cont1 in listaEvents) {
					obj1 = listaEvents[cont1];
					switch (typeof(obj1.action)) {
						case 'function':
							this._showFrame_callPool.push([obj1.action, this, currTime]);
							//obj1.action(this, currTime);
							break;
						case 'string':
							str1 = obj1.action;
							str1 = str1.replace(/\[THIS.ID]/g, this.id);
							str1 = str1.replace(/\[THIS]/g, 'window.HtmlPlus_ClipMakerColl[\'' + CStrJS(this.id) + '\']');
							str1 = str1.replace(/\[CURRENT_TIME]/g, currTime);
							str1 = str1.replace(/\[CURRENT_STATUS]/g, this._status);
							//eval(str1);
							this._showFrame_callPool.push(str1);
							break;
					}
				}
			}
			//window.status = 'Status = ' + this.Status() + '   Speed = ' + this.GetSpeed() + '    Time = ' + this.GetTime();
			this._showFrame_running = false;
			this._showFrame_runCallPool();
			return true;
		} else {
			return false;
		}
	}
	this._showFrame_calcolaExpire = function (CurrTime, PrecTime, ObjMotion) {
		if (PrecTime <= CurrTime) {
			return ((ObjMotion.stopTime >= CurrTime) ? ObjMotion.stopTime - CurrTime : 0);
		} else {
			return ((ObjMotion.startTime <= CurrTime) ? CurrTime - ObjMotion.startTime : 0);
		}
	}
	this._showFrame_runCallPool = function () {
		var vett1 = this._showFrame_callPool.slice(0);
		var vett2;
		this._showFrame_callPool = new Array();
		for (cont1=0; cont1<vett1.length; cont1++) {
			vett2 = vett1[cont1];
			switch (ValueType(vett2)) {
				case 'Array':
					switch (vett2.length) {
						case 1: vett2[0](); break;
						case 2: vett2[0](vett2[1]); break;
						case 3: vett2[0](vett2[1], vett2[2]); break;
						case 4: vett2[0](vett2[1], vett2[2], vett2[3]); break;
						case 5: vett2[0](vett2[1], vett2[2], vett2[3], vett2[4]); break;
					}
					break;
				case 'string':
					eval(vett2);
					break;
			}
		}
	}
	
	this._initialize();
	return this;
}


function HtmlPlus_AnimationOnMouseEvents(IdObject, ControllerHtmlObject, AnimatedHtmlObject, AttributeName, AttributeUM_Format, ValueInMouseOut, ValueInMouseOver, TransactionType, TransactionTime, fps) {
	//Ogni oggetto [HtmlPlus_AnimationOnMouseEvents] può gestire una sola animazione, ma la classe è pensata per far si che si possano
	//agganciare più animazioni sugli stessi oggetti, animando attributi diversi, col medesimo oggetto ControllerHtmlObject.
	this.id = IdObject;
	this.objectType = 'HtmlPlus_AnimationOnMouseEvents';
	this.controllerHtmlObjectColl = ControllerHtmlObject;	//Riferimento all'oggetto che capterà gli eventi OnMouseOver e OnMouseOut (può essere un array di oggetti).
	this.animatedHtmlObject = AnimatedHtmlObject;			//Riferimento all'oggetto che deve essere animato.
	this.attributeName = AttributeName;			//Il nome dell'attributo che sarà modificato (es. 'left', 'top', 'width', 'height').
	this.attributeFormat = AttributeUM_Format;	//L'unità di misura del valore che verrà impostato all'attributo; se la stringa contiene il carattere "#" allora
												//la stringa verrà usata in modalità Format, sostituendo il carattere segnaposto "#" col valore numerico da settare;
												//Es.:    AttributeUM_Format = 'alpha(opacity=#)'    l'attributo verra settato con:   'alpha(opacity=12)'.
	this.valueInMouseOut = ValueInMouseOut;		//Il valore che deve avere l'attributo in posizione di riposo.
	this.valueInMouseOver = ValueInMouseOver;	//Il valore che deve avere l'attributo quando si verifica OnMouseOver su HtmlObject.
	this.transactionType = TransactionType;		//Il tipo di transazione; può essere: 'square', 'triangle', 'sin', 'cos'.
	this.transactionTime = TransactionTime;		//Durata della transazione (in secondi).
	this.fps = fps;								//Fotogrammi per secondo della transazione.
	this.enabled = true;						//Se impostato a FALSE, gli eventi OnMouseOver e OnMouseOut non produrranno alcun effetto.
	// -- eventi --
	this.OnAnimationEnd = null;					//Puntatore a funzione o comando JS da eseguire quando l'animazione è finita (vedere [_animateHtmlObject])
	
	
	if (!window.HtmlPlus_AnimationOnMouseEventsColl) window.HtmlPlus_AnimationOnMouseEventsColl = new Array();
	window.HtmlPlus_AnimationOnMouseEventsColl[this.id] = this;
	
	this._initialize = function () {
		var i;
		this._direzione = 0;
		this._currAction = '';
		this._tmr = null;
		this._startTime = null;
		this._perc = 0;
		if (!this.fps) this.fps = GetBrowserInfo('RecommendedFps');
		switch (ValueType(this.controllerHtmlObjectColl)) {
			case 'Object':
				i = this.controllerHtmlObjectColl;
				this.controllerHtmlObjectColl = [i];
				break;
			case 'Array':
				for (i in this.controllerHtmlObjectColl) {
					if (typeof(this.controllerHtmlObjectColl[i]) == 'string') this.controllerHtmlObjectColl[i] = findObj(this.controllerHtmlObjectColl[i]);
				}
				break;
			case 'string':
				this.controllerHtmlObjectColl = [findObj(this.controllerHtmlObjectColl)];
				break;
			default:
				this.controllerHtmlObjectColl = null;
		}
		if (typeof(this.animatedHtmlObject) != 'object') this.animatedHtmlObject = findObj(this.animatedHtmlObject);
		if (this.controllerHtmlObjectColl) {
			for (i in this.controllerHtmlObjectColl) {
				this._initializeControllerHtmlObject(this.controllerHtmlObjectColl[i]);
			}
		}
		if (this.attributeFormat.indexOf('#') == -1) this.attributeFormat = '#' + this.attributeFormat;
	}
	
	this._initializeControllerHtmlObject = function (ControllerHtmlObject) {
		var i;
		if (!ControllerHtmlObject.HtmlPlus_AnimationOnMouseEventsColl) {
			ControllerHtmlObject.HtmlPlus_AnimationOnMouseEventsColl = new Array();
			addEvent(ControllerHtmlObject, 'mouseover', function (ev) {
						var eventObj = new STDEvent(ev);
						for (i in eventObj.srcElement.HtmlPlus_AnimationOnMouseEventsColl) {
							eventObj.srcElement.HtmlPlus_AnimationOnMouseEventsColl[i].OnMouseOverHandler();
							break;
						}
					}
				);
			addEvent(ControllerHtmlObject, 'mouseout', function (ev) {
						var eventObj = new STDEvent(ev);
						for (i in eventObj.srcElement.HtmlPlus_AnimationOnMouseEventsColl) {
							eventObj.srcElement.HtmlPlus_AnimationOnMouseEventsColl[i].OnMouseOutHandler();
							break;
						}
					}
				);
		}
		if (!ControllerHtmlObject.HtmlPlus_AnimationOnMouseEventsColl[this.id]) {
			ControllerHtmlObject.HtmlPlus_AnimationOnMouseEventsColl[this.id] = this;
			if (ControllerHtmlObject.all) {
				for (i=0; i<ControllerHtmlObject.all.length; i++) this._initializeControllerHtmlObject(ControllerHtmlObject.all[i]);
			} else if (ControllerHtmlObject.childNodes) {
				for (i=0; i<ControllerHtmlObject.childNodes.length; i++) this._initializeControllerHtmlObject(ControllerHtmlObject.childNodes[i]);
			}
		}
	}
	this._setStatusVariables = function (NewAction, NewTransactionTime) {
		var ora = new Date().getTime();
		if (this._tmr) window.clearInterval(this._tmr);
		switch (this._currAction) {
			case '':
				this._startTime = ora;
				break;
			case 'ini':
				this._startTime = ora;
				break;
			case 'moved':
				if (NewAction == 'stop') {
					this._perc = 100 - (ora - this._startTime) / 1000 / NewTransactionTime * 100;
					this._startTime = ora - NewTransactionTime * 1000 * this._perc / 100;
				}
				break;
			case 'stop':
				if (NewAction == 'moved') {
					this._perc = 100 - (ora - this._startTime) / 1000 / NewTransactionTime * 100;
					this._startTime = ora - NewTransactionTime * 1000 * this._perc / 100;
				}
				break;
		}
		this._currAction = NewAction;
	}
	
	this.InitializeWithAnimation = function (InitializeValue, TransactionTime) {
		this._direzione = 1;
		SetProperty(this.animatedHtmlObject, this.attributeName, this.attributeFormat.replace('#',InitializeValue));
		this._setStatusVariables('ini', TransactionTime);
		this._tmr = setInterval('var obj = window.HtmlPlus_AnimationOnMouseEventsColl["' + this.id + '"]; obj._animateHtmlObject(' + InitializeValue + ', obj.valueInMouseOut, ' + TransactionTime + ');', 1000 / this.fps);
	}
	this.OnMouseOverHandler = function () {
		this.OnFiredEvent(true);
	}
	this.OnMouseOutHandler = function () {
		this.OnFiredEvent(false);
	}
	this.OnFiredEvent = function (IsBeginAnimation) {
		var i, j, obj, anim;
		for (i in this.controllerHtmlObjectColl) {
			obj = this.controllerHtmlObjectColl[i];
			for (j in obj.HtmlPlus_AnimationOnMouseEventsColl) {
				anim = obj.HtmlPlus_AnimationOnMouseEventsColl[j];
				if (anim._currAction != 'ini' && anim.enabled) {
					anim._direzione = ((IsBeginAnimation) ? 1 : -1);
					anim._setStatusVariables(((IsBeginAnimation) ? 'moved' : 'stop'), anim.transactionTime);
					anim._tmr = setInterval('var obj = window.HtmlPlus_AnimationOnMouseEventsColl["' + j + '"]; obj._animateHtmlObject(obj.valueInMouseOut, obj.valueInMouseOver, obj.transactionTime);', 1000 / this.fps);
				}
			}
		}
	}
	this._animateHtmlObject = function (StartValue, EndValue, TranslationTime) {
		var nuovoVal;
		var str1;
		var precAction;
		if (this._currAction != '') {
			//Incremento il valore [_PERC] di un tot per ogni esecuzione di questa funzione
			//this._perc = this._perc + 100 / (this.fps * TranslationTime);
			
			//Imposto il valore [_PERC] in base a quanto tempo è trascorso dall'inizio dell'animazione
			this._perc = (new Date().getTime() - this._startTime) / 1000 / TranslationTime * 100;
			if (this._direzione == -1) this._perc = 100 - this._perc;
			
			if (this._perc < 0) {
				this._perc = 0;
			} else if (this._perc > 100) {
				this._perc = 100;
			}
			switch (this._perc) {
				case 0:
					nuovoVal = StartValue;
					break;
				case 100:
					nuovoVal = EndValue;
					break;
				default:
					switch (this.transactionType) {
						case 'square':		//si sposta con un unico fotogramma, che è quello centrale rispetto al tempo di transizione indicato.
							nuovoVal = StartValue + ((EndValue - StartValue) * Math.round(this._perc / 100));
							break;
						case 'sin':			//da riposo a MouseOver: parte veloce e si ferma lentamente
							nuovoVal = StartValue + ((EndValue - StartValue) * Math.sin(this._perc * Math.PI / 200));
							break;
						case 'cos':			//da riposo a MouseOver: parte lento e si ferma di scatto
							nuovoVal = EndValue - ((EndValue - StartValue) * Math.cos(this._perc * Math.PI / 200));
							break;
						case 'triangle':	//movimento a velocità costante
						default:
							nuovoVal = StartValue + ((EndValue - StartValue) * (this._perc / 100));
					}

					break;
			}
			str1 = this.attributeFormat.replace('#', nuovoVal);
			SetProperty(this.animatedHtmlObject, this.attributeName, str1);
			if (this._perc==0 && this._currAction=='stop' || this._perc==100 && this._currAction!='stop') {
				//Fine animazione.
				
				//Reset delle variabili per la gestione dell'animazione
				precAction = this._currAction;
				if (this._currAction == 'ini') this._perc = 0;
				this._currAction = '';
				window.clearInterval(this._tmr);
				
				//Invoco l'evento [OnAnimationEnd], se gestito.
				if (this.OnAnimationEnd) {
					switch (typeof(this.OnAnimationEnd)) {
						case 'function':
							this.OnAnimationEnd(this, precAction);
							break;
						case 'string':
							str1 = this.OnAnimationEnd;
							str1 = str1.replace(/\[THIS.ID]/g, this.id);
							str1 = str1.replace(/\[THIS]/g, 'window.HtmlPlus_AnimationOnMouseEventsColl[\'' + this.id + '\']');
							str1 = str1.replace(/\[CURRENT_ACTION]/g, precAction);
							eval(str1);
							break;
					}
				}
			}
		}
	}
	
	this._initialize();
	return this;
}


function HtmlPlus_PageScroller(idObject, AnimatedHtmlObject, IsVerticalScroll, PageWidth, CurrentPage, TransactionType, TransactionTime, fps) {
	this.id = idObject;
	this.objectType = 'HtmlPlus_PageScroller';
	this.animatedHtmlObject = AnimatedHtmlObject;		//Riferimento all'oggetto che deve essere animato. Attenzione: deve avere un solo figlio.
	this.isVerticalScroll = IsVerticalScroll;	//Se TRUE, indica che lo scroll deve avvenire verticalmente, altrimenti sarà orizzontalmente.
	this.pageWidth = PageWidth;					//Dimensione della pagina (larghezza o altezza in base all'orientamento dello scroll)
	this.currentPage = CurrentPage;				//La pagina corrente, a base ZERO.
	this.transactionType = TransactionType;		//Il tipo di transazione; può essere: 'square', 'triangle', 'sin', 'cos'
	this.transactionTime = TransactionTime;		//Durata della transazione fra una pagnia ed un'altra adiacente (in secondi)
	this.fps = fps;								//Fotogrammi per secondo della transazione
	this.enabled = true;						//Se impostato a FALSE, i metodi GoTo####Page non produrranno alcun effetto

	if (!window.HtmlPlus_PageScrollerColl) window.HtmlPlus_PageScrollerColl = new Array();
	window.HtmlPlus_PageScrollerColl[this.id] = this;
	
	this._initialize = function () {
		var dimCorpo, objCorpo, ok, cont1;
		
		//Preparo l'oggetto [animatedHtmlObject]
		this.animatedHtmlObject.style.overflow = 'hidden';
		// abbiamo aggiunto questo ciclo al posto dell'assegnazione diretta 'ogetto = oggetto.childNodes[0]'
		// perchè firefox considera Nodi anche gli spazi vuoti tra i tag come spazi o tab.
		ok = false;
		cont1 = 0;
		while (!ok){
			objCorpo = this.animatedHtmlObject.childNodes[cont1];
			if (objCorpo.nodeType == 1) {
				ok = true;
			}
			cont1++;
		}
		//Creo e setto variabili pubbliche
		this.bodyWidth = (this.isVerticalScroll ? objCorpo.offsetHeight : objCorpo.offsetWidth);
		this.visibleWidth = GetValue(GetCssStyle(this.animatedHtmlObject, (this.isVerticalScroll ? 'height' : 'width'))).number;
		if (this.bodyWidth <= this.visibleWidth) {
			this.pages = 1;
		} else {
			this.pages = Math.ceil(this.bodyWidth / this.pageWidth) - (Math.floor(this.visibleWidth / this.pageWidth) - 1);
			//Se l'ultima pagina non è completamente piena, allora aggiungo un DIV per riempirla con spazio vuoto.
			dimCorpo = this.pageWidth * (this.pages - 1) + this.visibleWidth;
			if (dimCorpo != this.bodyWidth) {
				SetProperty(objCorpo, ((this.isVerticalScroll) ? 'height' : 'width'), dimCorpo.toString() + 'px');
			}
		}
		if (!this.fps) this.fps = GetBrowserInfo('RecommendedFps');
		//Creo e setto variabili private
		this._attributeName = ((this.isVerticalScroll) ? 'scrollTop' : 'scrollLeft');
		this._currAction = '';
		this._tmr = null;
		this._startTime = null;
		this._perc = 0;
		//Mi posiziono nella PAGINA CORRENTE indicata nella creazione dell'oggetto
		SetProperty(this.animatedHtmlObject, this._attributeName, this.pageWidth * this.currentPage);
	}
	this._setStatusVariables = function (NewAction, NewTransactionTime) {
		var ora = new Date().getTime();
		if (this._tmr) window.clearInterval(this._tmr);
		switch (this._currAction) {
			case '':		//Nessuna azione in corso.
				this._perc = 0;
				this._startTime = ora;
				break;
			case 'ini':		//Azione in corso, inizializzazione.
				this._perc = 0;
				this._startTime = ora;
				this.currentPage = this._getTemporaryCurrentPage();
				break;
			case 'move':	//Azione in corso, spostamento in nuova pagina.
				this._perc = 0;
				this._startTime = ora;
				this.currentPage = this._getTemporaryCurrentPage();
				break;
		}
		this._currAction = NewAction;
	}
	this._getTemporaryCurrentPage = function () {
		var currPx;
		currPx = toNumber(GetProperty(this.animatedHtmlObject, this._attributeName), 0);
		return currPx / this.pageWidth;
	}
	this._getTransactionTotalTime = function (Pixels, TransactionTime) {
		var pagine = Pixels / this.pageWidth;
		switch (this.transactionType) {
			case 'square':		//si sposta con un unico fotogramma, che è quello centrale rispetto al tempo di transizione indicato.
				return TransactionTime;
				break;
			case 'sin':			//parte veloce e si ferma lentamente, l'ultima pagina è a velocità variabile
				if (pagine <= 1) {
					return TransactionTime * pagine;
				} else {
					return TransactionTime + (pagine - 1) * TransactionTime * Math.sin(100 / (TransactionTime * this.fps) * Math.PI / 200);
				}
				break;
			case 'cos':			//parte lento e si ferma di scatto, la prima pagina è a velocità variabile
				if (pagine <= 1) {
					return TransactionTime * pagine;
				} else {
					return TransactionTime + (pagine - 1) * TransactionTime * Math.cos(100 / (TransactionTime * this.fps) * Math.PI / 200);
				}
				break;
			case 'triangle':	//movimento a velocità costante
			default:
				return TransactionTime * pagine;
		}
	}
	this._scrollPage = function (StartPixel, EndPixel, TransactionTime) {
		var nuovoVal, tempoTot, tempoTrascorso, cont1;
		if (this._currAction != '') {
			//Imposto il valore [_PERC] in base a quanto tempo è trascorso dall'inizio dell'animazione
			tempoTot = this._getTransactionTotalTime(Math.abs(StartPixel - EndPixel), TransactionTime);
			tempoTrascorso = (new Date().getTime() - this._startTime) / 1000;
			this._perc = tempoTrascorso / tempoTot * 100;
			if(this._perc<0) this._perc=0; else if(this._perc>100) this._perc=100;
			
			switch (this._perc) {
				case 0:
					nuovoVal = StartPixel;
					break;
				case 100:
					nuovoVal = EndPixel;
					break;
				default:
					switch (this.transactionType) {
						case 'square':		//si sposta con un unico fotogramma, che è quello centrale rispetto al tempo di transizione indicato.
							nuovoVal = StartPixel + ((EndPixel - StartPixel) * Math.round(this._perc / 100));
							break;
						case 'sin':			//parte veloce e si ferma lentamente, l'ultima pagina è a velocità variabile
											//...in realtà non son riuscito a farlo, mi ci voleva troppo.
							nuovoVal = StartPixel + ((EndPixel - StartPixel) * Math.sin(this._perc * Math.PI / 200));
							break;
						case 'cos':			//parte lento e si ferma di scatto, la prima pagina è a velocità variabile
							nuovoVal = EndPixel - ((EndPixel - StartPixel) * Math.cos(this._perc * Math.PI / 200));
							break;
						case 'triangle':	//movimento a velocità costante
						default:
							nuovoVal = StartPixel + ((EndPixel - StartPixel) * (this._perc / 100));
					}
					nuovoVal = Math.round(nuovoVal);
					break;
			}
			
			SetProperty(this.animatedHtmlObject, this._attributeName, nuovoVal);
			if (this._perc == 100) {
				window.clearInterval(this._tmr);
				this._currAction = '';
				cont1 = this.currentPage;
				this.currentPage = nuovoVal / this.pageWidth;
				this.OnAfterPageChanged(this, cont1, this.currentPage);
			}
		}
	}
	
	this.GoToPage = function (PageNumber, optIsRelative) {
		//Sposta la pagina corrente. Argomenti:
		//	PageNumber:		la nuova pagina in cui si viene spostati;
		//	optIsRelative:	se TRUE, l'argomento [PageNumber] è da intendersi come incremento/decremento rispetto alla pagina corrente.
		var nuovaPag, startPx, endPx;
		if (optIsRelative) {
			nuovaPag = this.currentPage + PageNumber;
		} else {
			nuovaPag = PageNumber;
		}
		if (nuovaPag < 0) nuovaPag = 0;
		if (nuovaPag >= this.pages) nuovaPag = this.pages - 1;
		if (this.enabled && (this._currentAction=='' && nuovaPag!=this.currentPage || this._currentAction!='' && nuovaPag!=this._getTemporaryCurrentPage())) {
			this.OnBeforePageChanging(this, this.currentPage, nuovaPag);
			this._setStatusVariables('move', this.transactionTime);
			startPx = toNumber(GetProperty(this.animatedHtmlObject, this._attributeName), 0);
			endPx = this.pageWidth * nuovaPag;
			this._tmr = setInterval('var obj = window.HtmlPlus_PageScrollerColl["' + this.id + '"]; obj._scrollPage(' + startPx.toString() + ', ' + endPx.toString() + ', obj.transactionTime);', 1000 / this.fps);
		}
	}
	this.GoToFirstPage = function () { this.GoToPage(0); }
	this.GoToPreviousPage = function () { this.GoToPage(-1, true); }
	this.GoToNextPage = function () { this.GoToPage(+1, true); }
	this.GoToLastPage = function () { this.GoToPage(this.pages - 1); }
	
	/* Definizione eventi */
	this.OnAfterPageChanged = function (PageScroller, OldPage, CurrentPage) {return void(0);}
	this.OnBeforePageChanging = function (PageScroller, CurrentPage, NewPage) {return void(0);}
	
	this._initialize();
	return this;
}


function HtmlPlus_TextboxWithLabelInside(IdObject, TextboxObject, ValueObject, LabelString, NullValue, TextboxModeCssStyle, LabelModeCssStyle) {
	this.id = IdObject;
	this.objectType = 'HtmlPlus_TextboxWithLabelInside';
	this.textboxObject = TextboxObject;		//L'oggetto TextBox che mostra la LABEL e dove vengono immessi i dati
	this.valueObject = ValueObject;			//L'oggetto "<input type=hidden" su cui viene memorizzato il valore vero
	this.label = LabelString;				//Il testo da mostrare quando il valore non è indicato
	this.nullValue = NullValue;				//Il valore da salvare quando non vi è un valore inserito
	this.textboxModeCssStyle = TextboxModeCssStyle;		//Lo stile del Textbox quando la modalità è 'textbox' (contiene un valore o ha focus)
	this.labelModeCssStyle = LabelModeCssStyle;			//Lo stile del Textbox quando la modalità è 'label' (non contiene un valore e non ha focus)
	this.currentMode = '';					//Può essere 'label' o 'textbox'. Indica cosa viene mostrato nel textbox e con quale stile.
	this.enabled = true;
	
	if (!window.HtmlPlus_TextboxWithLabelInsideColl) window.HtmlPlus_TextboxWithLabelInsideColl = new Array();
	window.HtmlPlus_TextboxWithLabelInsideColl[this.id] = this;
	
	this._initialize = function () {
		if (!this.textboxObject.TextboxWithLabelInsideObject) {
			this.textboxObject.TextboxWithLabelInsideObject = this;
			addEvent(this.textboxObject, 'focus', function (ev) {
						var eventObj = new STDEvent(ev);
						eventObj.srcElement.TextboxWithLabelInsideObject.OnFocusInHandler();
					}
				);
			addEvent(this.textboxObject, 'blur', function (ev) {
						var eventObj = new STDEvent(ev);
						eventObj.srcElement.TextboxWithLabelInsideObject.OnFocusOutHandler();
					}
				);
			addEvent(this.textboxObject, 'keydown', function (ev) {
						var eventObj = new STDEvent(ev);
						eventObj.srcElement.TextboxWithLabelInsideObject.OnKeyDownHandler(eventObj);
					}
				);
			this.currentMode = '';
			this.SetValue(this.GetValue());
		}
	}
	this.OnFocusInHandler = function () {
		var str1 = this.GetValue();
		if (str1 == '') {
			this.currentMode = 'textbox';
			SetCssStyle(this.textboxObject, this.textboxModeCssStyle);
		}
		this.SetValue(str1);
	}
	this.OnFocusOutHandler = function () {
		var str1 = this.GetValue(true);
		if (str1 == '') {
			this.currentMode = 'label';
			SetCssStyle(this.textboxObject, this.labelModeCssStyle);
		}
		this.SetValue(str1);
	}
	this.OnKeyDownHandler = function (eventObject) {
		if (eventObject.keyCode == 13) {
			this.SetValue(this.GetValue(true));
		}
	}
	this.GetValue = function (GetTextboxValue) {
		//La funzione restituisce il valore REALE del TextBox. Se il valore non è definito, restituisce <stringa-vuota>.
		var str1;
		if (GetTextboxValue) {
			str1 = this.textboxObject.value;
			str1 = ((str1 == this.label || str1 == this.nullValue) ? '' : str1);
		} else {
			str1 = this.valueObject.value;
			str1 = ((str1 == this.nullValue) ? '' : str1);
		}
		return str1;
	}
	this.SetValue = function (NewValue) {
		var str1 = NewValue.toString();
		if (str1 == '') {
			switch (this.currentMode) {
				case 'label':
					this.textboxObject.value = this.label;
					break;
				case 'textbox':
					this.textboxObject.value = '';
					break;
				default:
					this.textboxObject.value = this.label;
					SetCssStyle(this.textboxObject, this.labelModeCssStyle);
					this.currentMode = 'label';
			}
		} else {
			if (this.textboxObject.value != str1) this.textboxObject.value = str1;
			switch (this.currentMode) {
				case 'textbox':
					break;
				default:
					SetCssStyle(this.textboxObject, this.textboxModeCssStyle);
					this.currentMode = 'textbox';
			}
		}
		this.valueObject.value = ((str1 == '') ? this.nullValue : str1);
	}
	
	this._initialize();
	return this;
}

function HtmlPlus_BarcodeReader(IdObject, KeyChars, Action, MinLen, MaxLen, BarcodeConf_PreChar, BarcodeConf_PostChar) {
	this.id = IdObject;
	this.objectType = 'HtmlPlus_BarcodeReader';
	this.keyChars = KeyChars;				//Stringa CHIAVE. Il barcode letto verrà preso in esame solo se inizia con questa
											//stringa (può essere NULL).
	this.action = Action;					//Azione da eseguire quando viene letto un codice a barre; può essere String o Function.
	this.minLen = MinLen;					//(opz) Lunghezza minima del barcode.
	this.maxLen = MaxLen;					//(opz) Lunghezza massima del barcode.
	this.bcCfg_Pre = null;					//(opz) Carattere di preambolo. Verrà ritenuto "barcode" solo le battiture a tastiera
											//che iniziano con questo carattere.
	this.bcCfg_Post = null;					//(opz) Carattere di postambolo. Verrà ritenuto "barcode" solo le battiture a tastiera
											//che finiscono con questo carattere.
											//ATTENZIONE: i caratteri preambolo e postambolo devono essere gli stessi per tutti gli
											//oggetti [HtmlPlus_BarcodeReader].
	this.timeout = 500;						//Tempo massimo (in millisec) fra ogni pressione di tasto affinchè si possa ritenere
											//che si sta leggendo un "barcode" valido; dopodichè la lettura viene annullata.
	this.runOneAction = true;				//Se TRUE, quando si è letto un Barcode, verrà eseguita l'Azione appartenente al primo
											//oggetto [HtmlPlus_BarcodeReader] compatibile col Barcode letto, in ordine di lunghezza
											//di KeyChars, dal più lungo al più corto. Se FALSE verranno eseguite tutte le Azioni.
	
	this._initialize = function () {
		var primoBarcode = false;
		if (!window.HtmlPlus_BarcodeReaderColl) {
			window.HtmlPlus_BarcodeReaderColl = new Array();
			window.HtmlPlus_BarcodeReader__runtime_curKeybStrm = '';
			window.HtmlPlus_BarcodeReader__runtime_tmr = 0;
			primoBarcode = true;
		}
		window.HtmlPlus_BarcodeReaderColl[this.id] = this;
		if (primoBarcode) {
			addEvent(window.document, 'keypress', function(ev) {
						var i, objMaster;
						for (i in window.HtmlPlus_BarcodeReaderColl) {
							objMaster = window.HtmlPlus_BarcodeReaderColl[i];
							break;
						}
						objMaster.DOCUMENT_OnKeyPressHandler(ev);
					}
				);
			if (window.DevelopingMode) DevelopingModeMenu_AddItem('BarcodeReader - Test', 'window.HtmlPlus_BarcodeReaderColl[\'' + CStrJS(this.id) + '\'].DOCUMENT_RunBarcode(window.prompt("[HtmlPlus_BarcodeReader - Test] :  inserisci il codice barcode di cui simulare la lettura:", ""));');
		}
		if (!this.keyChars) this.keyChars = '';
		if (!this.minLen) this.minLen = 1;
		
		this._initialize_ObjMaster();
	}
	this._initialize_ObjMaster = function() {
		var objMaster = this._getObjMaster();
		objMaster.bcCfg_Pre = BarcodeConf_PreChar;
		objMaster.bcCfg_Post = BarcodeConf_PostChar;
		if (!objMaster.bcCfg_Pre) objMaster.bcCfg_Pre =		['\x02','\x02'];
		if (!objMaster.bcCfg_Post) objMaster.bcCfg_Post =	['\x03','\x04'];
		if (ValueType(objMaster.bcCfg_Pre) != 'Array') objMaster.bcCfg_Pre = new Array(objMaster.bcCfg_Pre);
		if (ValueType(objMaster.bcCfg_Post) != 'Array') objMaster.bcCfg_Post = new Array(objMaster.bcCfg_Post);
		objMaster._resetListener(false);
	}
	
	this.DOCUMENT_OnKeyPressHandler = function (ev) {
		var eventObj = new STDEvent(ev);
		var i, vett1, obj, chrLetto, barcodeLetto;
		var inLettura = false;
		chrLetto = String.fromCharCode(eventObj.keyCode);
		switch (this._readingInfo.state) {
			case 0:		//Non sono in stato LETTURA.
				if (InArray(this.bcCfg_Pre, chrLetto) !== null) {
					//Inizio LETTURA.
					this._resetListener(true);
					this._readingInfo.state = 1;
					this._readingInfo.preChar = chrLetto;
					this._readingInfo.postCharList = new Array();
					for (i = 0; i < this.bcCfg_Pre.length; i++) {
						if (this.bcCfg_Pre[i] == chrLetto) this._readingInfo.postCharList.push(this.bcCfg_Post[i]);
					}
					inLettura = true;
				}
				break;
			case 1:		//Ho letto il preambolo
			case 2:		//Sono in corso di lettura del barcode
				//...aspetto il carattere di POSTAMBOLO.
				inLettura = true;
				if (InArray(this._readingInfo.postCharList, chrLetto) === null) {
					this._readingInfo.keybStream += chrLetto;
					this._resetTimer(true);
				} else {
					//Sono alla fine della lettura.
					this.DOCUMENT_RunBarcode(this._readingInfo.keybStream);
					this._resetListener(false);
				}
				break;
		}
		if (inLettura) {
			eventObj.cancelBubble(true);
			eventObj.returnValue(null);
		}
	}
	this.DOCUMENT_OnTimeoutHandler = function () {
		this._resetListener(false);
	}
	this.DOCUMENT_RunBarcode = function (BarcodeString) {
		var i, obj;
		if (this.runOneAction) {
			//Cerco l'oggetto [HtmlPlus_BarcodeReader] che ha il parametro KeyChars più lungo
			var maxLenKeyChars = 0;
			var ok;
			for (i in window.HtmlPlus_BarcodeReaderColl) {
				obj = window.HtmlPlus_BarcodeReaderColl[i];
				if (obj.keyChars) {
					if (maxLenKeyChars < obj.keyChars.length) maxLenKeyChars = obj.keyChars.length;
				}
			}
			//Ora sfoglio tutti gli oggetti [HtmlPlus_BarcodeReader] in ordine di lunghezza KeyChars, dal più lungo al più corto
			ok = false;
			for (maxLenKeyChars=maxLenKeyChars; maxLenKeyChars >= 0; maxLenKeyChars--) {
				for (i in window.HtmlPlus_BarcodeReaderColl) {
					obj = window.HtmlPlus_BarcodeReaderColl[i];
					if (maxLenKeyChars == obj.keyChars.length) {
						ok = obj.RunAction(BarcodeString);
						if (ok) break;
					}
				}
				if (ok) break;
			}
		} else {
			for (i in window.HtmlPlus_BarcodeReaderColl) {
				obj = window.HtmlPlus_BarcodeReaderColl[i];
				obj.RunAction(BarcodeString);
			}
		}
	}
	
	this.CheckBarcodeCompatibility = function (BarcodeString) {
		var fReturn = true;
		fReturn = true;
		if (fReturn && this.keyChars) fReturn = ((BarcodeString.substr(0, this.keyChars.length) == this.keyChars) ? true : false);
		if (fReturn && this.minLen) fReturn = ((BarcodeString.length >= this.minLen) ? true : false);
		if (fReturn && this.maxLen) fReturn = ((BarcodeString.length <= this.maxLen) ? true : false);
		return fReturn;
	}
	this.RunAction = function (BarcodeString, optCheckBarcodeCompatibility) {
		//Attenzione: se il parametro [optCheckBarcodeCompatibility] è omesso, si intenderà TRUE.
		//Restituisce True se l'azione è stata eseguita.
		var ok, str1;
		if (IsFalse(optCheckBarcodeCompatibility)) {
			ok = true;
		} else {
			ok = this.CheckBarcodeCompatibility(BarcodeString);
		}
		if (ok) {
			switch (typeof(this.action)) {
				case 'string':
					str1 = this.action;
					str1 = str1.replace(/\[BARCODE]/g, BarcodeString);
					str1 = str1.replace(/\[KEYCHARS]/g, this.keyChars);
					eval(str1);
					break;
				case 'function':
					this.action(BarcodeString, this);
					break;
				default:
					alert('ERRORE in HtmlPlus_BarcodeReader: il parametro ACTION deve essere una function o una string contenente un comando JavaScript.');
					ok = false;
			}
		}
		return ok;
	}
	
	this._getObjMaster = function () {
		var objMaster, i;
		for (i in window.HtmlPlus_BarcodeReaderColl) {
			objMaster = window.HtmlPlus_BarcodeReaderColl[i];
			break;
		}
		return objMaster;
	}
	this._resetListener = function(StartTimer) {
		var objMaster = this._getObjMaster();
		this._resetTimer(false);
		objMaster._readingInfo = {tmr:null, state:0, keybStream:'', preChar:null, postCharList:null};
		if (StartTimer) objMaster._resetTimer(true);
	}
	this._resetTimer = function(StartTimer) {
		var objMaster = this._getObjMaster();
		if (objMaster._readingInfo) {
			if (objMaster._readingInfo.tmr) window.clearTimeout(objMaster._readingInfo.tmr);
		}
		if (StartTimer) {
			objMaster._readingInfo.tmr = setTimeout('var i, objMaster;' +
					'for (i in window.HtmlPlus_BarcodeReaderColl) {' +
						'objMaster = window.HtmlPlus_BarcodeReaderColl[i];' +
						'break;' +
					'}' +
					'objMaster.DOCUMENT_OnTimeoutHandler();', objMaster.timeout);
		}
	}
	
	this._initialize();
	return this;
}




function HtmlPlus_ServerEval(IdObject, Server, Code) {
	this.id = IdObject;
	this.objectType = 'HtmlPlus_ServerEval';
	this.server = Server;				// Può essere ASP oppure ASPX per indicare che deve invocare le pagine standard, oppure un percorso intero per indicare che deve invocare una pagina precisa.
	this.code = Code;					// Il codice da eseguire
	
	if (!window.HtmlPlus_ServerEvalColl) window.HtmlPlus_ServerEvalColl = new Array();
	window.HtmlPlus_ServerEvalColl[this.id] = this;
	
	this._initialize = function(){
		switch (this.server.toLowerCase()) {
			case 'asp':
				this.server = 'asp';
				break;
			case 'aspx':
				this.server = 'aspx';
				break;
			default:
				if (this.server.substr(0, 4) != 'http') this.server = R + this.server;
		}
		
		this._container = null;
		this._container_iFrame = null;
		
		this._parameters = null;
		this._isResponseAvailable = false;
		this._isResponseAbort = null;
		this._returnValue = null;
		this._isRun = false;
		this._generaFrame_onLoad_Eseguito = false;
		
	}
	
	this._generaFrame = function(srParameters, optDebugMode) {
		var cont1, str1, strJS;
		
		// Inizializzazione del DIV contenitore
		this._container = document.createElement('DIV');
		this._container.id = this.id;
		this._container.style.position = 'absolute';
		this._container.style.overflow = 'auto';
		this._container.style.zIndex = 10020;
		this._container.style.width = '330px';	this._container.style.height = '150px';
		this._container.style.left = '-600px';	this._container.style.top = '0px';
		if (optDebugMode) {
			cont1 = -1;
			for (str1 in HtmlPlus_ServerEvalColl) {
				cont1++; if (str1 == this.id) break;
			}
			this._container.style.left = (GetValue(this._container.style.width).number * cont1).toString() + 'px';
		}
		this._container.ObjServerEval = this;
		this._container.style.display = (optDebugMode?'block':'none');
		document.body.appendChild(this._container);
		
		// Creazione [contenuto] del DIV
		this._container_iFrame = document.createElement('IFRAME');
		this._container.appendChild(this._container_iFrame);
		switch (this.server) {
			case 'asp':
				this._container_iFrame.src = R + '_Include/AspResponder.asp?cli=Brw';
				break;
			case 'aspx':
				this._container_iFrame.src = R + '_Include/AspxResponder.aspx?cli=Brw';
				break;
			default:
				this._container_iFrame.src = this.server;
		}
		
		this._generaFrame_onLoad_Eseguito = false;
		strJS = 'addEvent(this._container_iFrame, \'load\', function(ev) {' + 
						'var eventObj = new STDEvent(ev);' +
						'eval(\'' + CStrJS('window.HtmlPlus_ServerEvalColl[\'' + CStrJS(this.id) + '\']._generaFrame_onLoad(\'' + CStrJS(srParameters) + '\');') + '\');' + 
					'}' +
				');';
		eval(strJS);
	}
	
	this._generaFrame_onLoad = function(srParameters) {
		var strJS;
		strJS = '';
		strJS += 'window.HtmlPlus_ServerEvalColl[\'' + CStrJS(this.id) + '\']._container_iFrame.contentWindow.Interface_HtmlPlus_ServerEval_OnSubmit = function (ReturnSerializedValue, IsAbort) {' +
					'window.HtmlPlus_ServerEvalColl[\'' + CStrJS(this.id) + '\'].End(DeserializeValue(ReturnSerializedValue), IsAbort);' +
				'};';
		strJS += 'window.HtmlPlus_ServerEvalColl[\'' + CStrJS(this.id) + '\']._container_iFrame.contentWindow.Interface_HtmlPlus_ServerEval_IsReady = function () {' +
					'return true;' +
				'};';
		eval(strJS);
		if (!this._generaFrame_onLoad_Eseguito) {
			this._container_iFrame.contentWindow.Interface_HtmlPlus_ServerEval_OnLoad(this.code, srParameters);
			this._generaFrame_onLoad_Eseguito = true;
		}
		this.OnRun(this);
	}
	
	this.Run = function(Parameters, optDebugMode) {
		//Lancia il comando server. Argomenti:
		//	Parameters :		array in stile "Dictionary" con la lista degli parametri da passare al server.
		if (this.IsRun()) {
			return false;
		} else {
			this._parameters = Parameters;
			this._isResponseAvailable = false;
			this._isResponseAbort = null;
			this._returnValue = null;
			this._isRun = true;
			
			//Generazione oggetti HTML e passaggio argomento [Parameters]
			if (!this._container) {
				this._generaFrame(SerializeValue(Parameters), optDebugMode);
			} else {
				this._container_iFrame.contentWindow.Interface_HtmlPlus_ServerEval_OnLoad(this.code, SerializeValue(Parameters));
				this.OnRun(this);
			}
			
			return true;
		}
	}
	this.Break = function() {
		//Termina il comando server e setta l'esito in ABORT.
		if (this.IsRun()) {
			this._isRun = false;
			this._isResponseAvailable = true;
			this._isResponseAbort = true;
			this._returnValue = null;
			
			this.OnEnd(this, this._returnValue, this._isResponseAbort);
			return true;
		} else {
			return false;
		}
	}
	this.End = function(ReturnValue, IsAbort) {
		//Chiude il comando server, ed imposta sia il [Valore] da restituire sia lo stato [IsAbort].
		if (this.IsRun()) {
			this._isRun = false;
			this._isResponseAvailable = true;
			this._isResponseAbort = ((IsAbort) ? true : false);
			this._returnValue = ReturnValue;
			
			this.OnEnd(this, this._returnValue, this._isResponseAbort);
			return true;
		} else {
			return false;
		}
	}
	this.Parameters = function() {
		return this._parameters;
	}

	this.IsRun = function() {
		return this._isRun;
	}
	this.IsResponseAvailable = function() {
		return this._isResponseAvailable;
	}
	this.IsResponseAbort = function() {
		return ((this._isResponseAvailable) ? this._isResponseAbort : null);
	}
	this.ReturnValue = function() {
		return ((this._isResponseAvailable) ? this._returnValue : null);
	}
	
	/* Definizione eventi */
	this.OnRun = function (ServerEval) {return void(0);}							//Invocata quando il metodo Run viene lanciato
	this.OnEnd = function (ServerEval, ReturnValue, IsAbort) {return void(0);}		//Invocata quando il Popup viene chiuso
	
	this._initialize();
	return this;
}



function HtmlPlus_Popup(IdObject, Title, Src, PopupWidth, PopupHeight, ContentWidth, ContentHeight, CssPrefix) {
	this.id = IdObject;
	this.objectType = 'HtmlPlus_Popup';
	this.cssPrefix = CssPrefix;			// Prefisso che serve per l'utilizzazione delle classi Css da utilizzare
	this.lblTitle = Title;				// E' il titolo della finestra
	this.lblClose = 'X';				// E' il testo del pulsante di chiusura
	this.src = Src;						// Può essere un percorso, o un testo HTML
	this.showInTopFrame = true;			// Se TRUE il popup verrà disegnato nel frame principale
	this.popupWidth = PopupWidth;		// Larghezza del contenitore
	this.popupHeight = PopupHeight;		// Larghezza del contenitore
	this.contentWidth = ContentWidth;	// Larghezza del contenitore
	this.contentHeight = ContentHeight;	// Altezza del contenitore
	this.container = null;				// contenitore Popup
	this.container_content = null;		// contenuto del Popup
	this.isModal = false;				// sarà TRUE se il Popup viene aperto in modalità Modale
	this.abortOnClickOut = true;		// se impostato su TRUE allora cliccando fuori dal Popup questo si chiuderà
	this.popupShadowWidth = 8;			// dimensione dell'ombra (sfasamento rispetto alla posizione del Popup)
	this.popupShadowValue = 25;			// opacità  del Div che disegna l'ombra
	
	/*	####    DETTAGLI SULL'ARGOMENTO [Src] :    ####
		L'argomento può essere un percorso URL o un testo HTML. La classe [HtmlPlus_Popup] interpreta l'argomento come HTML se vi trova il
		carattere "<", altrimenti sarà interpretato come percorso URL.
		Se viene interpetato come percorso URL la classe genererà un IFRAME nel popup, con l'argomento SRC dell'IFRAME settato con l'Src indicato.
		La pagina che viene aperta può ospitare 3 variabili JavaScript:
			window.Interface_HtmlPlus_Popup_OnLoad :
				(function) viene invocata dalla classe [HtmlPlus_Popup] alla fine del caricamento e generazione del popup. Gli argomenti sono:
					SendSerializedArgument :	è l'argomento SendArgument passato alla funzione HtmlPlus_Popup.Open, serializzato.
			window.Interface_HtmlPlus_Popup_OnSubmit
				(function) dev'essere invicata dalla pagina dell'IFRAME per chiudere il Popup. Gli argomenti sono:
					ReturnSerializedValue :		dev'essere riempito con l'argomento che si vuole restituire, serializzato;
					IsAbort :					dev'esssere settato a TRUE se è stato invocato un "Annulla", altrimenti FALSE.
			window.Interface_HtmlPlus_Popup_This
				(object) punta all'istanza HtmlPlus_Popup corrente. E' utile per invocare metodi come [SetTitle], per cambiare il titolo del popup,
				ma è anche utilizzabile per invocare il metodo [Close] al posto di [Interface_HtmlPlus_Popup_OnSubmit].
	*/
	
	/*	ATTENZIONE:
		- 18/02/2010 -  è stata fatta una modifica alla classe che aggiunge una potenzialità: disegnare il popup nel frame TOP. Questa modifica
		ha un baco sul pulsante ABORT:
		Abbiamo il frame TOP che contiene un IFRAME chiamato CHILD. Abbiamo già generato e chiuso un Popup da Top con ID "MioPopup". Creiamo un altro
		Popup da Child con lo stesso valore ID. A questo punto cliccando su Abort verrà scatenato l'evento Close del Popup in Top, invece del Popup
		che si trova in Child. Questo perchè viene usata la funzione [FindArrayItem] che cerca prima nel frame Top, poi in Frames.
		Per risolvere questo problema si dovrebbe appoggiare il riferimento a THIS in una qualche variabile, e l'eventi ONCLICK di ABORT dovrebbe
		utilizzare quel riferimento per referenziarvi.
		- 02/03/2010 -  il problema dovrebbe essere stato risolto.
	*/
	
	if (!window.HtmlPlus_PopupColl) window.HtmlPlus_PopupColl = new Array();
	window.HtmlPlus_PopupColl[this.id] = this;
	
	this._initialize = function(){
		this._uid = null;
		this._container2 = null;
		this._divContenuto2 = null;
		this._divOmbra = null;
		this._divModal = null;
		this._modal_resizeTmr = null;
		this._popupTmr = null;
		this._clipAppearance = null;
		
		this._isResponseAvailable = false;
		this._isResponseAbort = null;
		this._returnValue = null;
		this._isOpen = false;
		this._generaPopup_iFrame_onLoad_EseguitoPrimo = false;
		this._generaPopup_iFrame_onLoad_EseguitoInOpen = false;
		
		this.popupWidth = toNumber(this.popupWidth, null, false);
		this.popupHeight = toNumber(this.popupHeight, null, false);
		this.contentWidth = toNumber(this.contentWidth, null, false);
		this.contentHeight = toNumber(this.contentHeight, null, false);
	}
	
	this._generaPopup = function(SendArgument) {
		var strJS;
		
		//Determino il valore ID UNIVOCO dell'oggetto, verrà usato come prefisso per gli ID degli oggetti HTML.
		this._uid = this.id + '__' + GetUID();
		
		// Inizializzazione del DIV contenitore del Popup
		this.container = document.createElement('DIV');
		this.container.id = this._uid;
		this.container.className = 'Def_Popup_Container' + (this.cssPrefix ? ' ' + this.cssPrefix + '_Popup_Container' : '');
		this.container.style.zIndex = 10010;
		//if (this.popupWidth) this.container.style.width = this.popupWidth.toString() + 'px';
		//if (this.popupHeight) this.container.style.height = this.popupHeight.toString() + 'px';
		this.container.style.display = 'none';
		this._generaPopup_getDocument().body.appendChild(this.container);
		this.container.ObjPopup = this;
		
		this._divOmbra = document.createElement('DIV');
		//if (this.popupWidth) this._divOmbra.style.width = this.popupWidth.toString() + 'px';
		//if (this.popupHeight) this._divOmbra.style.height = this.popupHeight.toString() + 'px';
		this._divOmbra.className = 'Def_Popup_Container_Shadow' + (this.cssPrefix ? ' ' + this.cssPrefix + '_Popup_Container_Shadow' : '');
		this.container.appendChild(this._divOmbra);
		//SetProperty(this._divOmbra, 'opacity', this.popupShadowValue);
		
		this._container2 = document.createElement('DIV');
		if (this.popupWidth) this._container2.style.width = this.popupWidth.toString() + 'px';
		if (this.popupHeight) this._container2.style.height = this.popupHeight.toString() + 'px';
		this._container2.className = 'Def_Popup_Container2' + (this.cssPrefix ? ' ' + this.cssPrefix + '_Popup_Container2' : '');
		//this.container.appendChild(this._container2);
		this._divOmbra.appendChild(this._container2);
		
		this._divModal = document.createElement('DIV');
		this._divModal.style.position = 'absolute';
		this._divModal.style.left = '0px';
		this._divModal.style.top = '0px';
		this._divModal.style.zIndex = 10000;
		//alert(window.document.body.offsetWidth);
		//this._divModal.style.height = window.dialogHeight;
		this._divModal.className = 'Def_Popup_Container_BgModal' + (this.cssPrefix ? ' ' + this.cssPrefix + '_Popup_Container_BgModal' : '');
		this._divModal.style.display = 'none';
		this._generaPopup_getDocument().body.appendChild(this._divModal);
		SetProperty(this._divModal, 'opacity', 25);
		strJS = 'addEvent(window.HtmlPlus_PopupColl[\'' + CStrJS(this.id) + '\']._generaPopup_getDocument(), \'resize\', function(ev) {' + 
						'var eventObj = new STDEvent(ev); var obj1;' +
						'eval(\'' + CStrJS('obj1 = FindArrayItem(\'HtmlPlus_PopupColl\', \'' + CStrXML(CStrJS(this.id)) + '\');') + '\');' + 
						'obj1._generaPopup_divModal_window_onResize();' +
					'}' +
				');';
		if (this.abortOnClickOut) {
			strJS += 'addEvent(window.HtmlPlus_PopupColl[\'' + CStrJS(this.id) + '\']._divModal, \'click\', function(ev) {' + 
							'var eventObj = new STDEvent(ev); var obj1;' +
							'eval(\'' + CStrJS('obj1 = FindArrayItem(\'HtmlPlus_PopupColl\', \'' + CStrXML(CStrJS(this.id)) + '\');') + '\');' + 
							'obj1.Close(null, true);' +
						'}' +
					');';
			strJS += 'addEvent(window.HtmlPlus_PopupColl[\'' + CStrJS(this.id) + '\']._generaPopup_getDocument(), \'keypress\', function(ev) {' + 
							'var eventObj = new STDEvent(ev); var obj1;' +
							'if (eventObj.keyCode == 27 && eventObj.altKey == false && eventObj.ctrlKey == false && eventObj.shiftKey == false) {' +
								'eval(\'' + CStrJS('obj1 = FindArrayItem(\'HtmlPlus_PopupColl\', \'' + CStrXML(CStrJS(this.id)) + '\');') + '\');' + 
								'obj1.Close(null, true);' +
							'}' +
						'}' +
					');';
		}
		eval(strJS);
		
		this._container2.innerHTML = '' +
				'<div class="Def_Popup_Container3' + (this.cssPrefix ? ' ' + this.cssPrefix + '_Popup_Container3' : '') + '">' +
					'<div class="Def_Popup_TitleBar' + (this.cssPrefix ? ' ' + this.cssPrefix + '_Popup_TitleBar' : '') + '">' +
						'<table class="Def_Popup_TitleBar_Table' + (this.cssPrefix ? ' ' + this.cssPrefix + '_Popup_TitleBar_Table' : '') + '" cellpadding="0" cellspacing="0" border="0" width="100%">' +
							'<tr>' +
								'<td class="Def_Popup_TitleBar_Title' + (this.cssPrefix ? ' ' + this.cssPrefix + '_Popup_TitleBar_Title' : '') + '" id="' + CStrXML(this.container.id) + '_TdTitle">' + CStrHTML(this.lblTitle) + '</td>' +
								'<td class="Def_Popup_TitleBar_CmdAbort' + (this.cssPrefix ? ' ' + this.cssPrefix + '_Popup_TitleBar_CmdAbort' : '') + '">' +
									'<a href="javascript:void(0);" onclick="findParentObj(this, /DIV/i, \'className\', /^Def_Popup_Container( .+)?$/).ObjPopup.Close(null, true);" title="Close">' +
										CStrHTML(this.lblClose) +
									'</a>' +
								'</td>' +
							'</tr>' +
						'</table>' +
					'</div>' +
					'<div class="Def_Popup_Content' + (this.cssPrefix ? ' ' + this.cssPrefix + '_Popup_Content' : '') + '" id="' + HTMLEncode(this._uid) + '_Popup_Content"></div>' +
				'</div>';
		
		this.container_content = document.createElement((this.src.substr(0, 1) == '<') ? 'DIV' : 'IFRAME');
		this._divContenuto2 = findObj(this._uid + '_Popup_Content', this._generaPopup_getDocument());
		this._divContenuto2.appendChild(this.container_content);
		// Creazione [contenuto] del popup
		switch (this.container_content.tagName) {
			case 'DIV':
				this.container_content.innerHTML = this.src;
				this._generaPopup_iFrame_onLoad(SerializeValue(SendArgument));
				break;
			case 'IFRAME':
				this.container_content.src = this.src;
				SetProperty(this.container_content, 'frameborder', '0');
				SetProperty(this.container_content, 'marginwidth', '0');
				SetProperty(this.container_content, 'marginheight', '0');
				SetProperty(this.container_content, 'scrolling', 'no');
				
				this._generaPopup_iFrame_onLoad_EseguitoPrimo = false;
				strJS = 'addEvent(this.container_content, \'load\', function(ev) {' + 
								'var eventObj = new STDEvent(ev);' +
								'eval(\'' +
										CStrJS('window.HtmlPlus_PopupColl[\'' + CStrJS(this.id) + '\']._generaPopup_iFrame_onLoad(\'' + CStrJS(SerializeValue(SendArgument)) + '\');') +
									'\');' + 
							'}' +
						');';
				eval(strJS);
				break;
		}
		if (this.contentWidth) this.container_content.style.width = this.contentWidth.toString() + 'px';
		if (this.contentHeight) this.container_content.style.height = this.contentHeight.toString() + 'px';
		this.container_content.style.overflow = 'hidden';
	}
	this._generaPopup_getDocument = function() {
		var fReturn = window;
		if (this.showInTopFrame == true) {
			while (GetDocInfo(fReturn.document, 'IsTopFrame') == false) {
				fReturn = fReturn.parent.window;
			}
		}
		return fReturn.document;
	}
	this._posizionaPopup = function(Left, Top) {
		this.container.style.left = Left.toString() + 'px';
		this.container.style.top = Top.toString() + 'px';
		//this._divOmbra.style.left = (Left + this.popupShadowWidth).toString() + 'px';
		//this._divOmbra.style.top = (Top + this.popupShadowWidth).toString() + 'px';
	}
	
	this._generaPopup_iFrame_onLoad = function(SendSerializedArgument) {
		if (this.container_content.tagName == 'IFRAME') {
			this.container_content.contentWindow.Interface_HtmlPlus_Popup_This = this;
			eval('window.HtmlPlus_PopupColl[\'' + CStrJS(this.id) + '\'].container_content.contentWindow.Interface_HtmlPlus_Popup_OnSubmit = function (ReturnSerializedValue, IsAbort) {' +
						'window.HtmlPlus_PopupColl[\'' + CStrJS(this.id) + '\'].Close(DeserializeValue(ReturnSerializedValue), IsAbort);' +
					'}');
			if (!this._generaPopup_iFrame_onLoad_EseguitoInOpen) this.OnLoad(this);
			if (!this._generaPopup_iFrame_onLoad_EseguitoPrimo) {
				this.container_content.contentWindow.Interface_HtmlPlus_Popup_OnLoad(SendSerializedArgument);
				this._generaPopup_iFrame_onLoad_EseguitoPrimo = true;
			}
		} else {
			if (!this._generaPopup_iFrame_onLoad_EseguitoInOpen) this.OnLoad(this);
		}
		if (!this._generaPopup_iFrame_onLoad_EseguitoInOpen) this.OnOpen(this);
		this._generaPopup_iFrame_onLoad_EseguitoInOpen = true;
	}
	this._generaPopup_divModal_ridimensiona = function() {
		this._divModal.style.width = Math.max(this._generaPopup_getDocument().body.scrollWidth, this._generaPopup_getDocument().body.clientWidth).toString() + 'px';
		this._divModal.style.height = Math.max(this._generaPopup_getDocument().body.scrollHeight, this._generaPopup_getDocument().body.clientHeight).toString() + 'px';
	}
	this._generaPopup_divModal_window_onResize = function(ev) {
		if (this.isModal && this.IsOpen()) {
			if (this._divModal.style.display != 'none') this._divModal.style.display = 'none';
			if (this._modal_resizeTmr) clearTimeout(this._modal_resizeTmr);
			this._modal_resizeTmr = setTimeout('window.HtmlPlus_PopupColl[\'' + CStrJS(this.id) + '\']._generaPopup_divModal_window_onResize_timer();', 300);
		}
	}
	this._generaPopup_divModal_window_onResize_timer = function() {
		if (this.isModal && this._divModal.style.display == 'none') {
			this._generaPopup_divModal_ridimensiona();
			this._divModal.style.display = 'block';
		}
	}
	
	
	/* ####  PROCEDURE PUBLIC  #### */
	this.Open = function(SendArgument, Left, Top, IsModal, Timer, AppearanceType, AppearanceTime) {
		//Argomenti:
		//	SendArgument :		l'argomento che si vuole passare all'IFRAME del popup, attraverso la procedura "Interface_HtmlPlus_Popup_OnLoad".
		//	Left, Top :			la posizione del Popup.
		//	IsModal :			se True, la finestra sarà bloccata finchè non si chiude il Popup.
		//	Timer :				se indicato, numero di secondi dopo i quali il popup si chiuderà automaticamente, invocando il metodo Close con IsAbort=true.
		//	AppearanceType :	modalità con cui il popup apparirà; può essere: 0=none(default); 1=zoom; 2=fromLeft; 3=fromTop; <objClip>=verrà usato tale oggetto per gestire l'apparizione del Popup.
		//	AppearanceTime :	durata, in secondi, di apparizione del popup (se modalità è diverso da 0); default = 0.6 sec.
		var appearanceType, appearanceTime;
		var posX, posY;
		if (this.IsOpen()) {
			return false;
		} else {
			//Setting valori
			this._isResponseAvailable = false;
			this._isResponseAbort = null;
			this._returnValue = null;
			this._isOpen = true;
			this.isModal = ((IsModal) ? true : false);
			this._lastSendArgument = SendArgument;
			if (this._popupTmr) clearTimeout(this._popupTmr);
			//Determino [posX] e [posY]
			posX = Left;
			switch (ValueType(posX)) {
				case 'string':
					//Il valore [posX] è espresso in PERCENTUALE. Ciò significa che posizionerò il popup in base alla dimensione della finestra.
					if (posX.charAt(posX.length - 1) != '%') posX = '50%';
					posX = (Math.min(this._generaPopup_getDocument().body.scrollWidth, this._generaPopup_getDocument().body.clientWidth) - this.popupWidth) * posX.substr(0, posX.length - 1) / 100 + this._generaPopup_getDocument().body.scrollLeft;
					break;
				case 'number':
					if (posX > 0) {		//Posizionamento da sinistra
						posX = posX + this._generaPopup_getDocument().body.scrollLeft;
					} else {			//Posizionamento da destra
						posX = Math.min(this._generaPopup_getDocument().body.scrollWidth, this._generaPopup_getDocument().body.clientWidth) - this.popupWidth + posX + this._generaPopup_getDocument().body.scrollLeft;
					}
					break;
				default:
					posX = 10;
			}
			if (posX < 10) posX = 10;
			posY = Top;
			switch (ValueType(posY)) {
				case 'string':
					//Il valore [posY] è espresso in PERCENTUALE. Ciò significa che posizionerò il popup in base alla dimensione della finestra.
					if (posY.charAt(posY.length - 1) != '%') posY = '50%';
					posY = (Math.min(this._generaPopup_getDocument().body.scrollHeight, this._generaPopup_getDocument().body.clientHeight) - this.popupHeight) * posY.substr(0, posY.length - 1) / 100 + this._generaPopup_getDocument().body.scrollTop;
					break;
				case 'number':
					if (posY > 0) {		//Posizionamento dall'alto
						posY = posY + this._generaPopup_getDocument().body.scrollTop;
					} else {			//Posizionamento dal basso
						posY = Math.min(this._generaPopup_getDocument().body.scrollHeight, this._generaPopup_getDocument().body.clientHeight) - this.popupHeight + posY + this._generaPopup_getDocument().body.scrollTop;
					}
					break;
				default:
					posY = 10;
			}
			if (posY < 10) posY = 10;
			
			//Generazione oggetti HTML e passaggio argomento [SendArgument]
			this._generaPopup_iFrame_onLoad_EseguitoInOpen = false;
			if (!this.container) {
				this._generaPopup(SendArgument);
				this._posizionaPopup(posX, posY);
			} else {
				if (!IsUndefined(SendArgument) && this.container_content.tagName == 'IFRAME') {
					this.container_content.contentWindow.Interface_HtmlPlus_Popup_OnLoad(SerializeValue(SendArgument));
				}
				this._posizionaPopup(posX, posY);
				this.OnOpen(this);
			}
			if (this.isModal) {
				this._generaPopup_divModal_ridimensiona();
				this._divModal.style.display = 'block';
			}
			
			//Gestione della modalità di APPARENZA del POPUP.
			if (AppearanceType.objectType == 'HtmlPlus_ClipMaker') {
				this._clipAppearance = AppearanceType;
			} else {
				appearanceTime = ((AppearanceTime) ? AppearanceTime : 0.6);
				switch (AppearanceType) {
					case 1: case 2: case 3:
						this._clipAppearance = new HtmlPlus_ClipMaker('Popup_' + this._uid + '_appearance', appearanceTime);
						appearanceType = AppearanceType;
						break;
					default:
						this._clipAppearance = null;
						appearanceType = 0;
				}
				switch (appearanceType) {
					case 0:
						break;
					case 1:
						this._clipAppearance.AppendMotion(this.container, 'opacity', '', 0, 100, 0, 100, 'sin');
						/*
						this._clipAppearance.AppendMotion(this._divOmbra, 'opacity', '', 0, 100, 0, this.popupShadowValue, 'sin');
						this._clipAppearance.AppendMotion(this._divOmbra, 'zoom', '', 0, 100, 0.6, 1, 'sin');
						*/
						break;
					case 2:
						this._clipAppearance.AppendMotion(this.container, 'left', 'px', 0, 100, -this.popupWidth - this.popupShadowWidth, posX, 'sin');
						//this._clipAppearance.AppendMotion(this._divOmbra, 'left', 'px', 0, 100, -this.popupWidth, posX + this.popupShadowWidth, 'sin');
						break;
					case 3:
						this._clipAppearance.AppendMotion(this.container, 'top', 'px', 0, 100, -this.popupHeight - this.popupShadowWidth, posY, 'sin');
						//this._clipAppearance.AppendMotion(this._divOmbra, 'top', 'px', 0, 100, -this.popupHeight, posY + this.popupShadowWidth, 'sin');
						break;
					default:
				}
			}
			if (this._clipAppearance) {
				this._clipAppearance.AppendEvent(1, '' +
						'var obj1 = window.HtmlPlus_PopupColl[\'' + CStrJS(this.id) + '\'];' +
						'obj1.container.style.display = \'block\';' +
						'/*obj1._divOmbra.style.display = \'block\';*/' +
						'');
				if (Timer > 0) this._clipAppearance.AppendEvent(100, 'window.HtmlPlus_PopupColl[\'' + CStrJS(this.id) + '\']._popupTmr = setTimeout(\'' + CStrJS('window.HtmlPlus_PopupColl[\'' + CStrJS(this.id) + '\'].Close(null, true);') + '\', ' + (Timer * 1000) + ');');
				this._clipAppearance.Play();
			} else {
				this.container.style.display = 'block';
				//this._divOmbra.style.display = 'block';
				if (Timer > 0) this._popupTmr = setTimeout('window.HtmlPlus_PopupColl[\'' + CStrJS(this.id) + '\'].Close(null, true);', Timer * 1000);
			}
			return true;
		}
	}	
	this.Close = function(ReturnValue, IsAbort) {
		//Chiude il Popup, ed imposta sia il [Valore] da restituire sia lo stato [IsAbort].
		if (this.IsOpen()) {
			this.container.style.display = 'none';
			//this._divOmbra.style.display = 'none';
			this._divModal.style.display = 'none';
			if (this._popupTmr) clearTimeout(this._popupTmr);
			//document.body.removeChild(this.container);
			this._isOpen = false;
			this._isResponseAvailable = true;
			this._isResponseAbort = IsAbort;
			this._returnValue = ReturnValue;
			
			this.OnClose(this, ReturnValue, IsAbort);
			return true;
		} else {
			return false;
		}
	}
	this.SetTitle = function(htmlValue) {
		findObj(this.container.id + '_TdTitle', this._generaPopup_getDocument()).innerHTML = htmlValue;
	}
	this.LastSendArgument = function() {
		return this._lastSendArgument;
	}

	this.IsOpen = function() {
		return this._isOpen;
	}
	this.IsResponseAvailable = function() {
		return this._isResponseAvailable;
	}
	this.IsResponseAbort = function() {
		return ((this._isResponseAvailable) ? this._isResponseAbort : null);
	}
	this.ReturnValue = function() {
		return ((this._isResponseAvailable) ? this._returnValue : null);
	}
	
	/* Definizione eventi */
	this.OnLoad = function (Popup) {return void(0);}							//Invocata quando il Popup è stato generato o riaperto
	this.OnOpen = function (Popup) {return void(0);}							//Invocata quando il metodo Open viene eseguito con successo
	this.OnClose = function (Popup, ReturnValue, IsAbort) {return void(0);}		//Invocata quando il Popup viene chiuso
	
	this._initialize();
	return this;
}







function OggettiRif_DlgFind(OggettoRifCode, SqlFilter, CFG, optCssStyle) {
	var fReturn, parametri;
	var idObj = 'ObjRifPopUp' + ';' + OggettoRifCode + ';' + SqlFilter ;
	var TxtSearchValue = '';
	var cssStyle = (optCssStyle)? optCssStyle : '';
	parametri = '?ObjRifCode=' + OggettoRifCode;
	parametri += '&SqlFilter=' + ((SqlFilter)? CStrUrlParam(SqlFilter) : '');
	if (window.HtmlPlus_PopupColl) {
		if (window.HtmlPlus_PopupColl[idObj]) fReturn = HtmlPlus_PopupColl[idObj];
	}
	if (!fReturn) {
		fReturn = new HtmlPlus_Popup(idObj, 'Ricerca [Oggetto rif.]', R + 'WebAdmin/DevTools_OggettiRif_DlgFind.asp' + parametri, 420, 318, 420, 300, cssStyle);
	}
	if (CFG['fncOnClose']) {
		if (CFG['fncOnOpen']) eval('fReturn.OnOpen = function() {' + CFG['fncOnOpen'] + '(DeserializeValue(\'' + CStrJS(SerializeValue(CFG)) + '\'));}');
		fReturn.OnClose = CFG['fncOnClose'];
		fReturn.Open(TxtSearchValue, '50%', '30%', true, 0, 0, 0);
	}
	return fReturn;
}


//###################################
//####  Funzioni di MACRO MEDIA  ####
//###################################

function MM_displayStatusMsg(msgStr)  { //v3.0
	status=msgStr; document.MM_returnValue = true;
}

function MM_findObj(n, d) { //v3.0
  var p,i,x;  if(!d) d=document; if((p=n.indexOf("?"))>0&&parent.frames.length) {
    d=parent.frames[n.substring(p+1)].document; n=n.substring(0,p);}
  if(!(x=d[n])&&d.all) x=d.all[n]; for (i=0;!x&&i<d.forms.length;i++) x=d.forms[i][n];
  for(i=0;!x&&d.layers&&i<d.layers.length;i++) x=MM_findObj(n,d.layers[i].document); return x;
}
function MM_swapImage() { //v3.0
  var i,j=0,x,a=MM_swapImage.arguments; document.MM_sr=new Array; for(i=0;i<(a.length-2);i+=3)
   if ((x=MM_findObj(a[i]))!=null){document.MM_sr[j++]=x; if(!x.oSrc) x.oSrc=x.src; x.src=a[i+2];}
}
function MM_swapImgRestore() { //v3.0
  var i,x,a=document.MM_sr; for(i=0;a&&i<a.length&&(x=a[i])&&x.oSrc;i++) x.src=x.oSrc;
}

function MM_preloadImages() { //v3.0
 var d=document; if(d.images){ if(!d.MM_p) d.MM_p=new Array();
   var i,j=d.MM_p.length,a=MM_preloadImages.arguments; for(i=0; i<a.length; i++)
   if (a[i].indexOf("#")!=0){ d.MM_p[j]=new Image; d.MM_p[j++].src=a[i];}}
}


function MM_reloadPage(init) {  //reloads the window if Nav4 resized
  if (init==true) with (navigator) {if ((appName=="Netscape")&&(parseInt(appVersion)==4)) {
    document.MM_pgW=innerWidth; document.MM_pgH=innerHeight; onresize=MM_reloadPage; }}
  else if (innerWidth!=document.MM_pgW || innerHeight!=document.MM_pgH) location.reload();
}
//MM_reloadPage(true);



//##################################
//####	SoundPlayerClass		####
//##################################

function SoundPlayerClass(idObject) {
	this.id = idObject;
	this.objectType = 'SoundPlayer';
	this.PlayList = new Array();
	this.ObjCon = null;
	
	this.preLoad = function () {
		var i, objHtml, str1;
		if (!ver4) return;
		if (NS) {
			objHtml = new Layer(0,window);
		} else {
			document.body.insertAdjacentHTML('BeforeEnd', '<DIV ID="SoundPlayer_Div' + this.id + '" STYLE="position:absolute;"></DIV>');
			objHtml = findObj('SoundPlayer_Div' + this.id);
		}
		str1 = '';
		for (i in this.PlayList) {
			str1 += '<EMBED SRC="' + this.PlayList[i] + '" AUTOSTART="FALSE" HIDDEN="TRUE"></EMBED>';
		}
		if (IE) {
			objHtml.innerHTML = str1;
		} else {
			objHtml.document.open();
			objHtml.document.write(str1);
			objHtml.document.close();
		}
		if (IE) {
			this.ObjCon = document.createElement('<bgsound id="SoundPlayer_Tag' + this.id + '" volume="0" balance="0"></bgsound>');
			findObj('body').appendChild(this.ObjCon);
		} else {
			this.ObjCon = objHtml;
		}
		this.ObjCon.makeAction = function (index, play, fileName, vol, leftRight) {
			//vol:			è il volume da applicare. Deve essere fra 0 (silenzio) a +100 (volume max).
			//leftRight:	è il bilanciamento. Da -100 (canale L) a +100 (canale R).
			if (IE) {
				//if (vol) this.volume = 10000 * (vol / 100 - 1);		//Conversione lineare
				if (vol==0) {
					this.volume = -10000;
				} else {
					if (vol) this.volume = Math.log(vol / 100) * 2167;
				}
				if (leftRight==0) {
					this.balance = 0;
				} else {
					/*if (leftRight) {
						if (leftRight > 0) {
							this.balance = -Math.log(leftRight / 100) * 216;//* 2167;
						} else {
							this.balance = Math.log(-leftRight / 100) * 216; //* 2167;
						}
					}*/
					if (leftRight) this.balance = 10000 * (leftRight / 100);
				}
				this.src = play? fileName : '';
			} else {
				if (vol) eval('this.document.embeds[index].volume = ' + vol);	//Volume va da 0 a 100
				eval('this.document.embeds[index].' + (play? 'play()':'stop()'));
			}
		}
	}
	this.Play = function (index, volume, balance) {
		if (!this.ObjCon) this.preLoad();
		if (this.ObjCon) this.ObjCon.makeAction(index, true, this.PlayList[index], volume, balance);
	}
	this.Stop = function (index) {
		if (!this.ObjCon) this.preLoad();
		if (this.ObjCon) this.ObjCon.makeAction(index, false);
	}
}



//##################################
//####	UrlParserClass			####
//##################################

function UrlParserClass(UrlString) {
	this.objectType = 'UrlParserClass';
	this.Url = Trim(UrlString.toString());
	this.z_existsProtocol = null;
	this.z_protocol = null;
	this.z_domain = null;
	this.z_fullRequest = null;
	this.z_fullPath = null;
	this.z_path = null;
	this.z_fileName = null;
	this.z_parametersString = null;
	this.z_parameters = null;
	
	this.ExistsProtocol = function() {
		if (this.z_existsProtocol === null) this.z_existsProtocol = this.RecalcExistsProtocol();
		return this.z_existsProtocol;
	}
	this.GetPartialUrl = function(WithProtocol, WithDomain, WithPath, WithFileName, WithParametersString) {
		//ATTENZIONE: al momento funziona solo per protocolli HTTP e HTTPS
		var fReturn = '';
		switch (this.GetProtocol()) {
			case 'http':
			case 'https':
				if (WithProtocol) {
					fReturn += this.GetProtocol();
					if (WithDomain || WithPath || WithFileName) fReturn += '://';
				}
				if (WithDomain) {
					fReturn += this.GetDomain();
					if (WithPath || WithFileName) fReturn += '/';
				}
				if (WithPath) {
					fReturn += this.GetPath();
					if (WithFileName || WithParametersString) fReturn += '/';
				}
				if (WithFileName) fReturn += this.GetFileName();
				if (WithParametersString) {
					if (WithProtocol || WithDomain || WithPath || WithFileName) fReturn += '?';
					fReturn += this.GetParametersString();
				}
				break;
			case 'ftp':
				break;
			case 'javascript':
				break;
			case 'mailto':
				break;
		}
		return fReturn;
	}
	this.GetProtocol = function() {
		if (!this.z_protocol) this.z_protocol = this.RecalcProtocol();
		return this.z_protocol;
	}
	this.GetDomain = function() {
		if (!this.z_domain) this.z_domain = this.RecalcDomain();
		return this.z_domain;
	}
	this.GetFullRequest = function() {
		if (!this.z_fullRequest) this.z_fullRequest = this.RecalcFullRequest();
		return this.z_fullRequest;
	}
	this.GetFullPath = function() {
		if (!this.z_fullPath) this.z_fullPath = this.RecalcFullPath();
		return this.z_fullPath;
	}
	this.GetPath = function() {
		if (!this.z_path) this.z_path = this.RecalcPath();
		return this.z_path;
	}
	this.GetFileName = function() {
		if (!this.z_fileName) this.z_fileName = this.RecalcFileName();
		return this.z_fileName;
	}
	this.GetParametersString = function() {
		if (!this.z_parametersString) this.z_parametersString = this.RecalcParametersString();
		return this.z_parametersString;
	}
	this.GetParameters = function() {
		if (!this.z_parameters) this.z_parameters = this.RecalcParameters();
		return this.z_parameters;
	}
	this.GetParameter = function(Name, oIgnoreCase) {
		//Restituisce il valore del parametro richiesto. <null> se il parametro non è presente nell'array. Argomenti:
		//	Name :			(stringa) il nome del parametro da cercare;
		//	oIgnoreCase :	(boolean, opzionale, def.=False) se TRUE la ricerca avverrà in modalità IgnoreCase.
		var str1, str2, fReturn;
		if (!this.z_parameters) this.z_parameters = this.RecalcParameters();
		fReturn = null;
		if (oIgnoreCase) {
			str2 = Name.toLowerCase();
			for (str1 in this.z_parameters) {
				if (str1.toLowerCase() == str2) { fReturn = this.z_parameters[str1]; break; }
			}
		} else {
			for (str1 in this.z_parameters) {
				if (str1 == str2) { fReturn = this.z_parameters[str1]; break; }
			}
		}
		return fReturn;
	}
	
	this.RecalcExistsProtocol = function() {
		//Restituisce il protocollo (default: il protocollo usato nella pagina corrente)
		var cont1 = this.Url.indexOf(':');
		return ((cont1 == -1 || cont1 > 12) ? false : true);
	}
	this.RecalcProtocol = function() {
		//Restituisce il protocollo (default: il protocollo usato nella pagina corrente)
		if (this.ExistsProtocol()) {
			return this.Url.substr(0, this.Url.indexOf(':')).toLowerCase();
		} else {
			return window.location.protocol;
		}
	}
	this.RecalcDomain = function() {
		//Restituisce la parte [dominio], comprensivo di porta ip se diversa dalla porta di default del protocollo
		var cont1, cont2, fReturn;
		switch (this.GetProtocol()) {
			case 'http':
			case 'https':
			case 'ftp':
				fReturn = this.Url.substr(this.Url.indexOf(':')+1);
				if (fReturn.substr(0, 2) == '//') {
					fReturn = fReturn.substr(2);
					cont1 = fReturn.search(/[\/?#]/g);
					if (cont1 != -1) fReturn = fReturn.substr(0, cont1);
					//Verifico la presenza ed il valore della porta. Se è il valore di default lo tolgo dal valore da restituire
					cont1 = fReturn.indexOf(':');
					if (cont1 != -1) {
						cont2 = fReturn.substr(cont1 + 1);
						if (cont2 == DefaultProtocolIpPort(this.GetProtocol())) fReturn = fReturn.substr(0, cont1);
					}
				} else {
					fReturn = Domini_Nomi_CurrentName();
				}
				return fReturn;
				break;
			case 'javascript':
				//Non gestito. Usare le altre funzioni GetXxxx
				break;
			case 'mailto':
				//Restituisce il dominio del primo indirizzo valido
				fReturn = this.GetFullPath();
				if (fReturn) return fReturn.substr(fReturn.indexOf('@') + 1);
				break;
		}
		return null;
	}
	this.RecalcFullRequest = function() {
		//Restituisce la richiesta intera, senza dominio, porta ip e protocollo.
		var str1, str2, cont1, cont2, re, arr;
		var fReturn = this.Url.substr(this.Url.indexOf(':')+1);
		switch (this.GetProtocol()) {
			case 'http':
			case 'https':
			case 'ftp':
				if (fReturn.substr(0, 2) == '//') {
					fReturn = fReturn.substr(2);
					cont1 = fReturn.search(/[\/?#]/g);
					if (cont1 != -1) {
						if (fReturn.substr(cont1, 1) == '/') cont1 ++;
						return fReturn.substr(cont1);
					} else {
						fReturn = '';
					}
					return decodeURI(fReturn);
				} else {
					//Attenzione: il percorso deve essere assoluto
				}
				break;
			case 'javascript':
				//Restituisce l'intera invocazione alla procedura. (mi aspetto di trovare [NomeObj.]NomeFunzione([parametri]);)
				//Attenzione: la classe considera solo la prima chiamata a funzione trovata.
				fReturn = LTrim(fReturn);
				str1 = new String(fReturn);
				str1 = str1.replace(/\\\\/g, '##');		//Sostituisco la doppia barra con doppio #
				//Sostituisco le stringhe con dei #, uno per carattere di stringa.
				cont1 = str1.search(/['"]/g);
				while (cont1 > -1) {
					str2 = str1.substr(cont1, 1);
					//Cerco la chiusura di stringa, escludendo quelle situazioni in cui il sepStringa è preceduro da uno Escape (\)
					for (cont2 = cont1+1; cont2 < str1.length; cont2++) {
						if (str1.substr(cont2, 1) == str2 && str1.substr(cont2-1, 1) != '\\') break;
					}
					str1 = str1.substr(0, cont1) + StringRepeater('#', cont2 - cont1 + 1) + str1.substr(cont2 + 1);
					cont1 = str1.search(/['"]/g);
				}
				//Ora cerco la fine chiamata funzione, cercando la prima ParentesiChiusa seguita da PuntoVirgola o FineStringa
				cont1 = str1.search(/\)\s*($|;)/g);
				if (cont1 > -1) {
					return fReturn.substr(0, cont1 + 1) + ';';
				}
				break;
			case 'mailto':
				//Restituisce il primo indirizzo valido
				re = new RegExp('[^\\s,;]+\\@(\\[?)[a-zA-Z0-9\\-\\.]+\\.([a-zA-Z]{2,3}|[0-9]{1,3})(\\]?)');
				arr = re.exec(fReturn);
				if (arr.length) return arr[0];
				break;
		}
		return null;
	}
	this.RecalcFullPath = function() {
		//Restituisce il nome del file completo di percorso (senza eventuali parametri del protocollo).
		//Attenzione: per protocollo http, http, ftp il percorso deve essere assoluto.
		var str1, str2, cont1, cont2, re, arr;
		var fReturn = this.Url.substr(this.Url.indexOf(':')+1);
		switch (this.GetProtocol()) {
			case 'http':
			case 'https':
			case 'ftp':
				fReturn = this.GetFullRequest();
				if (fReturn) {
					re = new RegExp('^[^?#]*');
					arr = re.exec(fReturn);
					if (arr && arr.length) fReturn = arr[0];
				}
				return fReturn;
				break;
			case 'javascript':
				//Restituisce l'intera invocazione alla procedura, senza i parametri e le relative parentesi tonde.
				//Es: "javascript:nomeObj.nomeFunzione(param1, param2);"    restituisce   "nomeObj.nomeFunzione"
				fReturn = this.GetFullRequest();
				if (fReturn) {
					str1 = new String(fReturn);
					str1 = str1.replace(/\\\\/g, '##');		//Sostituisco la doppia barra con doppio #
					//Sostituisco le stringhe con dei #, uno per carattere di stringa.
					cont1 = str1.search(/['"]/g);
					while (cont1 > -1) {
						str2 = str1.substr(cont1, 1);
						//Cerco la chiusura di stringa, escludendo quelle situazioni in cui il sepStringa è preceduro da uno Escape (\)
						for (cont2 = cont1+1; cont2 < str1.length; cont2++) {
							if (str1.substr(cont2, 1) == str2 && str1.substr(cont2-1, 1) != '\\') break;
						}
						str1 = str1.substr(0, cont1) + StringRepeater('#', cont2 - cont1 + 1) + str1.substr(cont2 + 1);
						cont1 = str1.search(/['"]/g);
					}
					//Ora tolgo l'ultima coppia di parentesi tonde, conteggiando quante se ne aprono e quante se ne chiudono.
					cont2 = 0;		//num parentesi aperte
					for (cont1=str1.length-2; cont1>0; cont1--) {
						switch (str1.substr(cont1, 1)) {
							case '(': cont2--; break;
							case ')': cont2++; break;
						}
						if (cont2==0) return fReturn.substr(0, cont1);
					}
				}
				break;
			case 'mailto':
				return this.GetFullRequest();
				break;
		}
		return null;
	}
	this.RecalcPath = function() {
		//Restituisce il percorso.
		//Attenzione: se l'ultima parte restituita da GetFullPath comprende un punto, questa sarà intesa come file.
		var cont1, cont2, fReturn;
		switch (this.GetProtocol()) {
			case 'http':
			case 'https':
			case 'ftp':
				fReturn = this.GetFullPath();
				if (fReturn) {
					cont1 = fReturn.lastIndexOf('/');
					cont2 = fReturn.lastIndexOf('.');
					if (cont1 == -1 && cont2 > -1) {
						fReturn = '';
					} else if (cont1 > -1 && (cont1 < cont2 || cont2 == -1)) {
						fReturn = fReturn.substr(0, cont1);
					}
				}
				return fReturn;
				break;
			case 'javascript':
				//Restituisce il nome dell'oggetto per cui è stata invocata la funzione.
				//Es: "javascript:nomeObj.nomeFunzione(param1, param2);"    restituisce   "nomeObj"
				fReturn = this.GetFullPath();
				if (fReturn) {
					cont1 = fReturn.lastIndexOf('.');
					if (cont1 == -1) {
						fReturn = '';
					} else {
						fReturn = fReturn.substr(0, cont1);
					}
					return fReturn;
				}
				break;
			case 'mailto':
				//Non gestito. Usare GetFullPath, GetDomain, GetFileName.
				break;
		}
		return null;
	}
	this.RecalcFileName = function() {
		//Restituisce il nome del file.
		//Attenzione: se l'ultima parte restituita da GetFullPath comprende un punto, questa sarà intesa come file.
		var cont1, fReturn;
		switch (this.GetProtocol()) {
			case 'http':
			case 'https':
			case 'ftp':
				fReturn = this.GetFullPath();
				if (fReturn) {
					fReturn = fReturn.substr(this.GetPath().length);
					if (fReturn.substr(0, 1) == '/') fReturn = fReturn.substr(1);
				}
				return fReturn;
				break;
			case 'javascript':
				//Restituisce il nome della procedura chiamata. Privo di eventuale riferimento ad oggetto.
				//Es: "javascript:nomeObj.nomeFunzione(param1, param2);"    restituisce   "nomeFunzione"
				fReturn = this.GetFullPath();
				if (fReturn) {
					cont1 = fReturn.lastIndexOf('.');
					if (cont1 > -1) fReturn = fReturn.substr(cont1 + 1);
					return fReturn;
				}
				break;
			case 'mailto':
				fReturn = this.GetFullPath();
				if (fReturn) return fReturn.substr(0, fReturn.indexOf('@'));
				break;
		}
		return null;
	}
	this.RecalcParametersString = function() {
		//Restituisce i parametri del percorso URL, sottoforma di stringa.
		var cont1, str1, fReturn;
		switch (this.GetProtocol()) {
			case 'http':
			case 'https':
				//Se il primo parametro è un bookmark, lascerò il carattere # come primo carattere della stringa.
				fReturn = this.GetFullRequest();
				if (fReturn) {
					cont1 = fReturn.search(/[?#]/g);
					if (cont1 == -1) {
						fReturn = '';
					} else {
						if (fReturn.substr(cont1, 1) == '?') cont1 ++;
						fReturn = fReturn.substr(cont1);
					}
				}
				return fReturn;
				break;
			case 'ftp':
				//Potrei restituire un vettore con Username e Password... lo svilupperò se ne avrò bisogno.
				break;
			case 'javascript':
				//Restituisce l'elenco dei parametri, senza le parentesi.
				//Es: "javascript:nomeObj.nomeFunzione(param1, param2);"    restituisce   "param1, param2"
				fReturn = this.GetFullRequest();
				if (fReturn) {
					str1 = this.GetFullPath();
					cont1 = fReturn.indexOf(str1) + str1.length;
					fReturn = fReturn.substr(cont1 + 1, fReturn.length - cont1 - 3);
					return fReturn;
				}
				break;
			case 'mailto':
				//Non gestito. Usare GetFullPath, GetDomain, GetFileName.
				break;
		}
		return null;
	}
	this.RecalcParameters = function() {
		//Restituisce i parametri del percorso URL, sottoforma di Array
		var cont1, cont2, cont3, cont4, str1, strOrg, vett1, vett2, fReturn;
		switch (this.GetProtocol()) {
			case 'http':
			case 'https':
				fReturn = this.GetParametersString();
				if (fReturn) {
					strOrg = new String(fReturn);
					cont1 = strOrg.lastIndexOf('#');
					if (cont1 > -1) {
						str1 = strOrg.substr(cont1 + 1);
						strOrg = strOrg.substr(0, cont1);
					} else {
						str1 = '';
					}
					fReturn = new Array();
					if (strOrg) {
						vett1 = strOrg.split(/(&amp;|&)/g);			//ATTENZIONE: QUESTO METODO PER SEPARARE I PARAMETRI non mi piace, perchè non mi permette di elaborare adeguatamente il testo URL. Preferirei usare un metodo di JScript per codificare il testo, ma non lo trovo.
						for (cont1=0; cont1<vett1.length; cont1++) {
							if (vett1[cont1]) {
								vett2 = vett1[cont1].split('=', 2);
								if (vett2.length == 2) {
									fReturn[vett2[0].toString()] = vett2[1];
								} else {
									fReturn[vett2[0].toString()] = '';
								}
							}
						}
					}
					//Aggiungo l'eventuale Bookmark come se fosse un parametro
					if (str1) fReturn['#'] = str1;
				}
				return fReturn;
				break;
			case 'ftp':
				//Potrei restituire un vettore con Username e Password... lo svilupperò se ne avrò bisogno.
				break;
			case 'javascript':
				//Restituisce il nome della procedura chiamata. Privo di eventuale riferimento ad oggetto.
				//Es: "javascript:nomeObj.nomeFunzione(param1, param2);"    restituisce   Array[0] = "param1"; Array[1] = "param2"
				fReturn = this.GetParametersString();
				if (fReturn) {
					strOrg = new String(fReturn + ',');
					fReturn = new Array();
					
					str1 = new String(strOrg);
					str1 = str1.replace(/\\\\/g, '##');		//Sostituisco la doppia barra con doppio #
					//Sostituisco le stringhe con dei #, uno per carattere di stringa.
					cont1 = str1.search(/['"]/g);
					while (cont1 > -1) {
						str2 = str1.substr(cont1, 1);
						//Cerco la chiusura di stringa, escludendo quelle situazioni in cui il sepStringa è preceduro da uno Escape (\)
						for (cont2 = cont1+1; cont2 < str1.length; cont2++) {
							if (str1.substr(cont2, 1) == str2 && str1.substr(cont2-1, 1) != '\\') break;
						}
						str1 = str1.substr(0, cont1) + StringRepeater('#', cont2 - cont1 + 1) + str1.substr(cont2 + 1);
						cont1 = str1.search(/['"]/g);
					}
					//Scandaglio la stringa alla ricerca delle VIRGOLE, quindi carico fReturn.
					cont2 = 0;		//Num parametro corrente
					cont3 = 0;		//Num parentesi
					cont4 = -1;		//Posiz prec Virgola
					for (cont1=0; cont1<str1.length; cont1++) {
						switch (str1.substr(cont1, 1)) {
							case '(': cont3++; break;
							case ')': cont3--; break;
							case ',':
								if (cont3 == 0) {
									fReturn[cont2] = Trim(strOrg.substr(cont4+1, cont1-cont4-1));
									cont2++;
									cont4 = cont1;
								}
								break;
						}
					}
				} else if (fReturn == '') {
					fReturn = new Array();
				}
				return fReturn;
				break;
			case 'mailto':
				//Non gestito. Usare GetFullPath, GetDomain, GetFileName.
				break;
		}
		return null;
	}
}


//##########################################
//####	Funzioni per apertura PAGINE	####
//##########################################

function Images_OpenWindow(id, descr) {
	window.open(R + 'Images/Image_Visualizza.asp?ID=' + id + '&NoTemplate=yes&Description=' + descr, '_blank', 'width=400,height=300,toolbar=0,menubar=0,location=0,scrollbars=0,status=1,resizable=1');
}
function Help_OpenWindow(path) {
	window.open(R + '_HtmlTag/Help.asp?path=' + CStrUrlParam(path), '_blank', 'width=500,height=400,toolbar=0,menubar=0,location=0,scrollbars=1,status=1,resizable=1');
}
function TestiLiberi_OpenWindow(code) {
	window.open(R + 'Testo/Popup.asp?Code=' + code, 'Testo_Popup', 'width=600,height=500,toolbar=0,menubar=0,location=0,scrollbars=1,status=1,resizable=1');
}



//--></script>