/*----------------------------------------------------------------------------\
|							Askia Script Objects							  |
|-----------------------------------------------------------------------------|
|                          Created by Askia Company							  |
|							(http://www.askia.com)							  |
|-----------------------------------------------------------------------------|
| The AskiaScript is the main javascript library of Askia					  |
| It will manage integrate all needed javascript files of Askia				  |
|-----------------------------------------------------------------------------|
|							Copyright Askia © 1994-2010						  |
|-----------------------------------------------------------------------------|
| {No Dependencies}															  |
|-----------------------------------------------------------------------------|
| 2006-05-23 |V 1.0.0														  |
|			 |+ AUTO-LOAD THE RESOURCES										  |
|			 |	Load the Javascript files into the html page				  |
|			 |	Load the resources files of the Javascripts	(pictures...)	  |			
|-----------------------------------------------------------------------------|
| 2006-11-06 |V 1.1.0														  |
|			 |+ Add the management of custom control						  |
|-----------------------------------------------------------------------------|
| 2007-06-29 |V 1.0.1														  |
|			 |+ Add the cursor constants									  |
|-----------------------------------------------------------------------------|
| 2006-11-29 |V 1.1.0														  |
|			 |+ Add the XmlLoader object in the framework					  |
|			 |+ Management of Plug-Ins										  |
| 2007-01-11 |+ Corrrection: Block the previous of browser					  |
| 2007-11-13 |+ Add the ranking management into the default framework         |
| 2009-05-06 |+ Add management of Flash										  |
|			 |+ Add the urlEncode() urlDecode() format() methods		      |
|-----------------------------------------------------------------------------|
| 2009-10-20 |V 1.1.1														  |
|			 |+ Improve the management of versionning (files per version)     |
|			 |+ Change version: Calendar.js								      |
|-----------------------------------------------------------------------------|
| 2009-10-27 |V 1.1.2														  |
|			 |+ Change version: ToolTipText.js, Common.js, Ranking.js	      |
|-----------------------------------------------------------------------------|
| 2010-01-12 |V 1.1.3														  |
|			 |+ Add the event when the DOM is completly loaded			      |
|			 |+ Change version: Ranking.js									  |
|-----------------------------------------------------------------------------|
| 2010-02-19 |V 1.1.4														  |
|			 |+ For flash send init the itemCaption when there is one item in |
|			 | the loop														  |
|			 |+ Send the AllowDk to flash									  |
| 2010-03-24 |+ Fix a problem with the ranking button						  |
| 2010-04-15 |+ Load the plugin in the AskiaScript._onPageLoad method		  |
|-----------------------------------------------------------------------------|
| 2010-05-17 |V 1.1.5														  |
|			 |+ Filter list of response with the filter box					  |
|			 |+ Fix date validation with the new format 'MM/dd/yyyy'	      |
| 2010-06-02 |+ Fix Ranking button for FF and Chrome						  |
|-----------------------------------------------------------------------------|
| 2010-06-24 |V 1.1.6														  |
|			 |+ Add options in the filter list to hide responses by default	  |	
|			 |+ Add options in the filter list to search after n characters	  |
| 2010-06-25 |+ Fix: Retrieve the caption of responses in FF and Chrome		  |		
| 2010-06-28 |+ Fix: Problem with the flash and loop in IE					  |		
|-----------------------------------------------------------------------------|
| 2010-08-16 |V 1.1.7														  |
|			 |+ Fix issue with the ranking => doesn't display the right order |	
|-----------------------------------------------------------------------------|
| 2010-08-27 |V 1.1.8														  |
|			 |+ Fix ranking issue => doesn't display the label when post-back |
|-----------------------------------------------------------------------------|
| 2010-12-20 |V 1.1.9														  |
|			 |+ Add jQuery in the scripts									  |
|			 |+ Add the form serializer										  |
|			 |+ Fix the filterBox with skin									  |
|			 |+ Fix the problem to load translation for calendar			  | 
|-----------------------------------------------------------------------------|
| 2011-05-10 |V 1.1.10														  |
|			 |+ Add regional settings for date and number					  |
|-----------------------------------------------------------------------------|
| 2011-01-20 |V 1.2.0														  |
|			 |+ Compatibilities with the new XHtml 1.0 generation			  |
|-----------------------------------------------------------------------------|
| Created 2006-05-23 | All changes are in the log above. | Updated 2011-05-10 |
|-----------------------------------------------------------------------------|
|														All rights reserved	  |
|Askia - AskiaScript - API Version 1.2.0			Copyright Askia © 1994-2011   |
\---------------------------------------------------------------------------- */

/* -----
	Working on:
		Internet Explorer 			   [Tested on 6 / 7]
		NetScape (since the version 6) [Tested on 6 / 7 / 8]
		Opera (since the version 7)	   [Tested on 7 / 8] (no calendar appear on version 7)
		FireFox						   [Tested on 1 / 2]

	Not working on: 
		Opera 3 / 5 / 6
		NetScape 4 
		
----- */


/* ====
	Set-up browser checks and add emulator
==== */
var isOpera   = /opera|opera/i.test(navigator.userAgent);
var isIE	  = !isOpera && /msie/i.test(navigator.userAgent);			// preventing opera to be identified as ie
var isMozilla = !isIE && !isOpera && /mozilla\/5/i.test(navigator.userAgent);	// preventing opera to be identified as mz
var isNS6	  = isMozilla && /Netscape6/i.test(navigator.userAgent);	

//Constants to have the version of script
var VERSION_OF_SCRIPTS="1.0.0";
var VERSION_OF_SCRIPTS_1_1 = "1.1.0";
var LATEST_VERSION_OF_SCRIPTS="1.2.0";

//Other constants
var UNDEFINED='undefined';

//Cursors
var CURSOR_WAIT="wait";

//Special keys of keyboard
var KEY_BACK=8;
var KEY_ENTER=13;
var KEY_PAGEUP=33;
var KEY_PAGEDOWN=34;
var KEY_END=35;
var KEY_HOME=36;
var KEY_LEFT=37;
var KEY_UP=38;
var KEY_RIGHT=39;
var KEY_DOWN=40;
var KEY_INS=45;
var KEY_DEL=46;


//Extension
var EXTENSION_CSS='css';

//Files
var FILENAME_SETTINGS_XML='AskiaScript.xml';
var FOLDER_PLUGINS='PLUGINS';
var FOLDER_SKINS='SKINS';

//Add method getElementById() in the document 
//(for IE4 and other browser which don't support the getElementById method)
if (isIE && document.getElementById == null) {	
	document.getElementById = function(sId) {
			return document.all[sId];
		};
	}

//Add new method in the Date object 
//(for NS6 and other browser which don't suppport the toDateString method)
if (typeof (Date.prototype.toDateString)==UNDEFINED){
		Date.__arrDays=['Sun','Mon','Tue','Wed','Thu','Fri','Sat'];
		Date.__arrMonths=['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']
		Date.prototype.toDateString=function(){
				var strDate=Date.__arrDays[this.getDay()] + ' ' + Date.__arrMonths[this.getMonth()] + ' ' + formatNumber(this.getDate()) + ' ' + this.getFullYear();
				
				//Format number with 2 digits
				function formatNumber(number){
						var sReturn=number;
						if (parseInt(number)<10)sReturn = "0" + parseInt(number);
						return sReturn;
					}
				return strDate;
			}
	}

/* ===
	Lock the previous button of browser
=== */
try {
		window.history.forward(1);
	}
catch(ex){/* Do nothing */}


/* ====
	AskiaLibrary
	Objects which content the name of different javascript files
==== */
var AskiaLibrary={
		//Mozilla emulator to retrieve some IE features into Mozilla
		MOZILLA_EMULATOR	:   'IEEmulatorForMoz.js',
		//Manage the Questions/Responses (Semi-open, ranking...)
		COMMON				:	'Common.js',
		//Manage the navigation (Previous/Next/Pause)
		NAVIGATION			:   'Nav.js',
		//Manage the validation of form
		VALIDATOR			:   'FieldValidator.js',
		//Manage the error messages
		ERROR_MESSAGES		:   'ErrorMessages.js',
		//Manage the live calculation
		CALCULATOR			:	'Calculator.js',
		//Manage the calendar
		CALENDAR			:   'Calendar.js',		
		//Manage the sliders
		SLIDER				:   'Slider.js',
		//Manage the ranking
		RANKING             :   'Ranking.js',
		//Manage the tool tip text
		TOOLTIPTEXT			:   'ToolTipText.js',
		//Manage the string
		STRINGBUILDER		:   'StringBuilder.js',
		//Manage the translation of script
		TRANSLATION			:	'Translation.js',
		//Manage the custom controls
		CUSTOMCONTROL		:   'CustomControl.js',
		//Manage the xml loader
		XMLLOADER			:   'XmlLoader.js',
		//Manage the plugins
		PLUGINS				:   'PlugIns.js',
		//Manage the flash integration
		FLASH				:   'Flash.js',
		//Manage the filter of responses
		FILTER_BOX			:   'FilterBox.js',
		//jQuery
		JQUERY				:   'jQuery.js'
	};
//Revision number per file and per version
var AskiaLibraryRevision={
	CurrentVersion : 1.0,
	//JS library
	JS			:{
			//Version 1.1
			"1.1"		: {CALENDAR : 10, SLIDER : 2, TOOLTIPTEXT: 2, COMMON:9, RANKING: 5, FLASH: 9, PLUGINS: 4,FILTER_BOX:6, VALIDATOR:10, JQUERY : 9, FILTER_BOX : 9}
		},
	//CSS library
	CSS			: {},
	//Methodb to obtain the latest version of file
	getVersion	: function(fileKey,isCss){
			var strVersion=AskiaLibraryRevision.CurrentVersion.toString().replace(",",".");
			var v=(!isCss)?this.JS[strVersion]:this.CSS[strVersion];
			if (!v)return VERSION_OF_SCRIPTS;
			if (!v[fileKey])return VERSION_OF_SCRIPTS;
			return strVersion + "." + v[fileKey];
		}
};

var AskiaCSS={
		//CSS of ToolTip text
		TOOLTIPTEXT			:   'ToolTipText.css',
		//Css of calendar
		CALENDAR			:	'Calendar.css',
		//Css of ranking (for drag and drop
		RANKING             :   'Ranking.css'
	};

var eAskiaClass = false; // To be sure that everything works with the version 1.1 which not have this variable
						 // Should be overwrite by the Common.js
/* ====
	AskiaScript object
====*/
var AskiaScript={
		//GLOBAL PROPERTIES OF SURVEY
		intNameOfSurvey				: '',
		extNameOfSurvey				: '',
		languageId					: null,
		
		//ARCHITECTURE OF SERVER
		pathOfResources				: '../Resources/',
		pathOfScripts				: '../Scripts/',
		pathSeparator				: '/',
		_CSSFolderName				: 'CSS',
		//
		_addedStyleSheet			: {},
		isLocal						: false,
		
		//LOAD THE DIFFERENT LIBRARIES
		load						: function(version, local){
				this.isLocal = local;

		        //Manage the load page
            	if (window.addEventListener){
                        window.addEventListener("load",function(){
                                AskiaScript._onPageLoad();
                            },false);
                }
                this._isPageLoaded();
                
                //Manage the version
                AskiaLibraryRevision.CurrentVersion =version;
				if (!AskiaLibraryRevision.CurrentVersion)AskiaLibraryRevision.CurrentVersion =1.0;
				if (parseFloat(AskiaLibraryRevision.CurrentVersion)==1.1)VERSION_OF_SCRIPTS=VERSION_OF_SCRIPTS_1_1;
				if (parseFloat(AskiaLibraryRevision.CurrentVersion)==1.2)VERSION_OF_SCRIPTS=LATEST_VERSION_OF_SCRIPTS;
				
				//Search the separator of path :
				// '\' or '/' (local or web)
				this.pathSeparator=(this.pathOfScripts.indexOf(":\\")>0)?"\\":"/";		
				//Load the skin first
				if (this.skinName!=''){
				        document.write('<script language="javascript" src="' + this.pathOfScripts + FOLDER_SKINS + this.pathSeparator + this.skinName +  this.pathSeparator  + this.skinName +  '.js"></script>');
				    }
				//Add scripts
				for (var lib in AskiaLibrary){
						//Don't write the Mozilla Emulator when we are in IE
						if (!isMozilla && AskiaLibrary[lib]==AskiaLibrary.MOZILLA_EMULATOR)continue;
						if (AskiaLibrary[lib]==AskiaLibrary.TRANSLATION)continue;
						document.write('<script language="javascript" src="' + this.pathOfScripts + 'v' + AskiaLibraryRevision.getVersion(lib) + this.pathSeparator + AskiaLibrary[lib] + '"></script>');
					}
				//At the end, add the scripts overwrite the translations
				//in all scripts
				if (this.languageId && this.languageId!=''){
						document.write('<script language="javascript" src="' + this.pathOfScripts + 'v' + VERSION_OF_SCRIPTS + this.pathSeparator + this.languageId + this.pathSeparator + AskiaLibrary.TRANSLATION + '"></script>');
					}
					
				//Add css
				for (var lib in AskiaCSS){
						this.addStyleSheet(this.pathOfScripts + 'v' + AskiaLibraryRevision.getVersion(lib,true) + this.pathSeparator + this._CSSFolderName + this.pathSeparator + AskiaCSS[lib]);
					}
			},
        //Indicates if the page is completly loaded
		isPageLoaded                    :false,
		_nextRoutingId					: 1000,
		executeLiveRouting				: function () {
			if (AskiaScript.isLocal) {
				// Increment the routing id
				this._nextRoutingId += 1;
				if (this._nextRoutingId > 9999) {
					this._nextRoutingId = 1000; // Reset it
				}

				// We have to send the query by chunk if the length of message is over 255 characters (avoid using window.navigate)
				var MAX_LENGTH = 200,
					MAX_CHUNK_LENGTH = 200, 
					ser = serializeForm("EvaluateRouting"),
					currentRoutingId = this._nextRoutingId,
					chunk,
					chunks = [],
					begin = 0, 
					end = MAX_CHUNK_LENGTH,
					i, 
					l;
				if (ser.length <= MAX_LENGTH) {
					window.navigate("admsg_" + serializeForm("EvaluateRouting"));
					return;
				}
				
				if (currentRoutingId != this._nextRoutingId) {
					return ; // Abort when another routing has sent
				}
				
				chunk = ser.slice(begin, end);
				while(chunk.length) {
					chunks.push(chunk);
					begin = end;
					end = end + MAX_CHUNK_LENGTH;
					chunk = ser.slice(begin, end);
				}

				if (currentRoutingId != this._nextRoutingId) {
					return ; // Abort when another routing has sent
				}
				for (i = 0, l = chunks.length; i < l; i += 1){
					if (currentRoutingId != this._nextRoutingId) {
						return ; // Abort when another routing has sent
					}
					if (i === 0) {
						// alert("adstart_" + currentRoutingId + "_" + chunks.length + "_" + chunks[i]);
						window.navigate("adstart_" + currentRoutingId + "_" + chunks.length + "_" + chunks[i]);
					} else {
						// alert("adchnk_" + currentRoutingId + "_" + (i + 1) + "_" + chunks[i]);
						window.navigate("adchnk_" + currentRoutingId + "_" + (i + 1) + "_" + chunks[i]);
					}
				}
			} else {
				$.ajax({
					url: "askiaext.dll",
					type : "POST",
					dataType : "script",
					data: serializeForm("EvaluateRouting")
				});
			}
		},
		//Fire when the page is loaded
		_onPageLoad                     : function(){
		        this.isPageLoaded=true;

				//Management of questions when the page is loaded
				for (var i=0;i<QuestionHandler.childNodes.length;i++){
					if (QuestionHandler.childNodes[i].isSorted){	
						  //Create ranking element after the page load
						  QuestionHandler.childNodes[i]._rankingElt=new Ranking(QuestionHandler.childNodes[i].id,QuestionHandler.childNodes[i].rankStyle);
						}		        
					}

				//Initialize the live routing
				if (eAskiaClass && eAskiaClass.live) {
					// Execute it now
					var hasLive = false;
					for(var i=0; i < QuestionHandler.childNodes.length; i++) {
						if (QuestionHandler.childNodes[i].isLive){
							hasLive = true;
							break;
						}
					}
					if (hasLive) {
						AskiaScript.executeLiveRouting();
					}
				}
				//Execute all events when the page is completly loaded
				for(var i=0;i<this._readyEvents.length;i++){
					this._readyEvents[i]();
				}
		    },
		//Add function to call when the page is ready to use
		addReadyEvent					: function(oFunction){
				this._readyEvents[this._readyEvents.length]=oFunction ;
			},
		//Array of events fires when the page is ready to use
		_readyEvents							:[],
		//Verify if the page is loaded or not
        _isPageLoaded                   : function(){
                if (!document.readyState || window.addEventListener)return;
                if(document.readyState=="complete"){
						//Load the plugins first
						PlugInHandler.load();
						//Load the rest
						setTimeout("AskiaScript._onPageLoad();",500);                
                    }
                else 
                    setTimeout("AskiaScript._isPageLoaded();" ,2);
		    },
        //Name of skin use by default
        skinName                        : '',
        //Collection of skins initiliazed in the document
        //Use the name of skin to retrieve it into the collection
        skinsCollection                 : {},
        initSkin                        : function(name){
                if (!this.skinsCollection[name])return;
                if (this.skinsCollection[name].isInit)return;
                var oSkin=new Object();
                oSkin.name=name;
                oSkin.single=CustomControl.fromSkin(name,'single');
                oSkin.multiple=CustomControl.fromSkin(name,'multiple');
                //Load the stylesheet now
                if (this.skinsCollection[name].single.useClass || this.skinsCollection[name].multiple.useClass){
                		var cssLink=this.pathOfScripts + FOLDER_SKINS + this.pathSeparator + name +  this.pathSeparator + name + '.css';
		                this.addStyleSheet(cssLink,true);
                    }
                oSkin.isInit=true;
                this.skinsCollection[name]=oSkin;
            },
		//Add style sheet into the document
		///<param name="onFly">Indicates if the stylesheet is added after the page load</param>
		addStyleSheet					: function(fileName,onFly){
				//Don't add a duplicate stylesheet
				if (this._addedStyleSheet[fileName])return;
				if (!onFly){
				        document.write('<link rel="stylesheet" href="' + fileName + '">');
				    }
                else {
                        //Double the backslash
		                var tmpBackSlash="__tmp__backslash__";
			                fileName=replace(fileName,'\\',tmpBackSlash);
			                fileName=replace(fileName,tmpBackSlash,'\\\\');
	                    //Import the style
	                    var st=document.styleSheets[0];
	                    if (typeof(st.addImport)!=UNDEFINED){
			                    st.addImport(fileName);
		                    }
	                    else{
			                    st.insertRule("@import url(" + fileName + ");", st.cssRules.length);
			                    if (isNS6){
					                    alert("You're browser not support the live importation of stylesheet.");
				                    }				
		                    }                        
                    } 
				this._addedStyleSheet[fileName]=true;
			},
		//State of navigation
		isNavigationInit			: false,
		
		//Init NavigatorHandler object
		initNavigation				: function(isFirstInit){
				if (this.isNavigationInit)return;
				if (this.initNavigation.__attemptsCount && !isFirstInit)return;
				
				//10 attempts (represent 5 seconds) to initialize the navigator
				if (!this.initNavigation.__attemptsCount){
						this.initNavigation.__attemptsCount=0;
					}
				if (this.initNavigation.__attemptsCount>=10)return;
				try{
						NavigatorHandler.init();
						this.isNavigationInit=true;
					}
				catch(ex){
						this.initNavigation.__attemptsCount++;
						setTimeout("AskiaScript.initNavigation(true);",500);					
					}
			},
		//Temporary stack of plug-in
		//Should be imported when the PlugInHandler is already loaded
		_tmpPlugInStack				: [],
		
		//Import a plug-in
		loadPlugIn					: function(plugInName){
				AskiaScript._tmpPlugInStack[AskiaScript._tmpPlugInStack.length]=plugInName;
			}
	};

///<summary>
///Format text using the parameters
///</summary>
function serializeForm(action) {
	var i, l, dt= new Date(), array = $("form").serializeArray();

	for (i = 0, l = array.length; i < l; i +=1) {
		if (array[i].name && (array[i].name === "Action" || array[i].name === "MfcISAPICommand")){
			array[i].value = action; //Replace the action
		}
	}

	array.push({name : "dmy", value : dt.getUTCDay() + "" + dt.getUTCMilliseconds() });
	return $.param(array);
}
///<summary>
///Format text using the parameters
///</summary>
///<param value="text">Text to format</param>
///<param value="params">Paramaters</param>
function format(text,params){
        var sText=text;
        for (var i=0;i<params.length;i++){
                sText =replace(sText,"{" + i + "}",params[i]);
            }
        return sText;
    }	
    
//Function to replace all characters of string
//Example of use : 
//replace("Text With Three Spaces"," ","_");
//Will return: "Text_With_Three_Spaces"
function replace(text,match,replacement){
		var sReturn=text;
		if (match=='')return sReturn;
		if (!text)return '';
		if (match==replacement)return sReturn;
		while(sReturn.indexOf(match)!=-1){
				sReturn=sReturn.replace(match,replacement);
			}
		return sReturn;
	}

//Position of elements
var ePosition={
		left	: 'left',
		top		: 'top'
	};
//Return the position of HTMLElement
//Example of use :
//var left=getPosition(document.getElementById("MyElement"),ePosition.left);
//var top=getPosition(document.getElementById("MyElement"),ePosition.top);
//alert("Left=>" + left + "px,Top=>" + top + "px");
function getPosition(htmlElt,pos){
		switch (String(pos).toLowerCase()) { 
			case ePosition.left : 
				var l=htmlElt.offsetLeft;
				var parent=htmlElt.parentNode;
				while (parent.offsetLeft){
						l +=parent.offsetLeft;
						parent=parent.parentNode;
					}
				return l;
				break; 

			case ePosition.top : 
				var t=htmlElt.offsetTop;
				if (isNS6)return t;
				var parent=htmlElt.parentNode;
				var previous=htmlElt;
				while (parent.offsetTop){
						//Don't calculate the position twice
						//For example if my element is a TD, 
						//the offsetTop of TD is the same of the offsetTop of TR
						if (previous.offsetTop!=parent.offsetTop){
								t +=parent.offsetTop;
								previous=parent;
							}
						parent=parent.parentNode;
					}
				return t;
				break; 
		} 
	}
///<summary>
///Encode the value for the url
///</summary>
function urlEncode(text){
    if (text ==null || text == undefined)return "";
	// The Javascript escape and unescape functions do not correspond
	// with what browsers actually do...
	var SAFECHARS = "0123456789" +					// Numeric
					"ABCDEFGHIJKLMNOPQRSTUVWXYZ" +	// Alphabetic
					"abcdefghijklmnopqrstuvwxyz" +
					"éèêëïîàçùüû" +
					"-_.!~*'()";					// RFC2396 Mark characters
	var HEX = "0123456789ABCDEF";
	var encoded = "";
	var strText=text + ""; //Force to text format
	var i=0;
	while ( i < strText.length){
		var ch = strText.charAt(i);
	    if (ch == " ") {
		    encoded += "+";				// x-www-urlencoded, rather than %20
		} else if (SAFECHARS.indexOf(ch) != -1) {
		    encoded += ch;
		} else {
		    var charCode = ch.charCodeAt(0);
			if (charCode > 255) {
			    /*alert( "Unicode Character '" 
                        + ch 
                        + "' cannot be encoded using standard URL encoding.\n" +
				          "(URL encoding only supports 8-bit characters.)\n" +
						  "A space (+) will be substituted." );
				encoded += "+";*/
				encoded +=ch; //Change by Askia (keep the character)
			} else {
				encoded += "%";
				encoded += HEX.charAt((charCode >> 4) & 0xF);
				encoded += HEX.charAt(charCode & 0xF);
			}
		}
        i++;
	} // while
	return encoded;
}

///<summary>
///Decode the value from the url
///</summary>
function urlDecode(text){
    if (text ==null || text == undefined)return "";
    
   // Replace + with ' '
   // Replace %xx with equivalent character
   // Put [ERROR] in output if %xx is invalid.
   var HEXCHARS = "0123456789ABCDEFabcdef"; 
   var decoded = "";
   var i = 0;
   var strText=text +""; //Force to text
   while (i < strText.length) {
       var ch = strText.charAt(i);
	   if (ch == "+") {
	       decoded += " ";
		   i++;
	   } else if (ch == "%") {
			if (i < (strText.length-2) 
					&& HEXCHARS.indexOf(strText.charAt(i+1)) != -1 
					&& HEXCHARS.indexOf(strText.charAt(i+2)) != -1 ) {
				decoded  += unescape( strText.substr(i,3) );
				i += 3;
			} else {
				//alert( 'Bad escape combination near ...' + encoded.substr(i) );
				decoded += ch;//"%[ERROR]";
				i++;
			}
		} else {
		   decoded += ch;
		   i++;
		}
	} // while
   return decoded;
}
