/**
* @copyright ScanFrame 2005-2011, All Rights Reserved.
* @author avo <dvlp@scanframe.nl>
* @package ScanFrame
* @category Page Classes
* @version $Revision: 1.56 $
* @cvs_source $Source: /export/cvs/primo/com/jscripts/commonlib.js,v $
* @cvs_author $Author: arjan $
* @purpose Common library for commmon javascript functions.
*/
//---------------------------------------------------------------------------
/**
* Static class to determine the type of browwser.
* @type Object
*/
var BrowserDetect =
{
	/**
	* Holds the browser name after initialization.
	* @type string
	*/
	browser: null,
	/**
	* Holds the browser version after initialization.
	* @type string
	*/
	version: null,
	/**
	* Holds the browser operatin system after initialization.
	* @type string
	*/
	OS: null,
	/**
	* Initializes this instance.
	* @returns void
	*/
	init: function ()
	{
		this.browser = this.searchString(this.dataBrowser) || "An unknown browser";
		this.version = this.searchVersion(navigator.userAgent)
			|| this.searchVersion(navigator.appVersion)
			|| "an unknown version";
		this.OS = this.searchString(this.dataOS) || "an unknown OS";
	},
	searchString: function (data)
	{
		for (var i = 0; i < data.length; i++)
		{
			var dataString = data[i].string;
			var dataProp = data[i].prop;
			this.versionSearchString = data[i].versionSearch || data[i].identity;
			if (dataString)
			{
				if (dataString.indexOf(data[i].subString) != -1)
					return data[i].identity;
			}
			else if (dataProp)
				return data[i].identity;
		}
		return '';
	},
	searchVersion: function (dataString)
	{
		var index = dataString.indexOf(this.versionSearchString);
		if (index == -1)
			return 0;
		return parseFloat(dataString.substring(index+this.versionSearchString.length+1));
	},
	dataBrowser:
	[
		{
			string: navigator.userAgent,
			subString: "OmniWeb",
			versionSearch: "OmniWeb/",
			identity: "OmniWeb"
		},
		{
			string: navigator.vendor,
			subString: "Apple",
			identity: "Safari"
		},
		{
			prop: window.opera,
			identity: "Opera"
		},
		{
			string: navigator.vendor,
			subString: "iCab",
			identity: "iCab"
		},
		{
			string: navigator.vendor,
			subString: "KDE",
			identity: "Konqueror"
		},
		{
			string: navigator.userAgent,
			subString: "Firefox",
			identity: "Firefox"
		},
		{
			string: navigator.vendor,
			subString: "Camino",
			identity: "Camino"
		},
		{		// for newer Netscapes (6+)
			string: navigator.userAgent,
			subString: "Netscape",
			identity: "Netscape"
		},
		{
			string: navigator.userAgent,
			subString: "MSIE",
			identity: "Explorer",
			versionSearch: "MSIE"
		},
		{
			string: navigator.userAgent,
			subString: "Chrome/",
			identity: "Chromium",
			versionSearch: "Chrome"
		},
		{
			string: navigator.userAgent,
			subString: "Gecko",
			identity: "Mozilla",
			versionSearch: "rv"
		},
		{ 		// for older Netscapes (4-)
			string: navigator.userAgent,
			subString: "Mozilla",
			identity: "Netscape",
			versionSearch: "Mozilla"
		}
	],
	dataOS:
	[
		{
			string: navigator.platform,
			subString: "Win",
			identity: "Windows"
		},
		{
			string: navigator.platform,
			subString: "Mac",
			identity: "Mac"
		},
		{
			string: navigator.platform,
			subString: "Linux",
			identity: "Linux"
		}
	]

};
// Initialize the BrowserDetect class.
BrowserDetect.init();
//---------------------------------------------------------------------------
/**
* Declare the SfLib instance to hold the libraries functions en data.
*/
var SfLib =
{
		/**
		* Holds the debugout put until it can be shown.
		* @type string
		*/
		DebugOutBackLog: '',
		/**
		* Caches the scrollbar width.
		* @type integer
		*/
		__GetScrollBarWidthResult__: null
};
//---------------------------------------------------------------------------
/**
* Function to make anchor tags do nothing.
* @return void
*/
SfLib.Void = function () {};
//---------------------------------------------------------------------------
/**
* Debugging function that appends to a part of the document en HTML
* encodes the message.
* @param string msg
* @param boolean alert_it
* @return boolean
*/
SfLib.DebugOut = function (msg, alert_it)
{
	if (opener != null && opener != window && opener.SfLib && typeof opener.SfLib.DebugOut == 'function')
		opener.SfLib.DebugOut(msg);
	var elem = document.getElementById('debug_info_javasccript');
	if (elem)
		elem.innerHTML += this.HtmlEncode(msg + "\n", true, 3);
	else
	{
		// Start event when loaded only once when the backlog is still empty.
		if (!this.DebugOutBackLog.length)
		{
			var self = this;
			// On load of the window call this function again.
			self.AddEvent(window, 'load', function (){self.DebugOut(self.DebugOutBackLog);self.DebugOutBackLog='';});
		}
		else
			this.DebugOutBackLog += "\n";
		// Attach message to the back log.
		this.DebugOutBackLog += msg;
	}
	// Should the message be alerted.
	if (alert_it)
		alert((msg!=null) ? msg.replace(/\t/g,'   ') : '<<empty message>>');
	// To prevent having to use a scope.
	return false;
};
//-----------------------------------------
/**
* Holds the value and the unit.
* @constructor
* @param number
* @param string
*/
function TValueUnit(value, unit)
{
	/**
	* Holds the number part.
	* @public
	* @type number
	*/
	this.Value = value;
	/**
	* Holds the unit part.
	* @public
	* @type string
	*/
	this.Unit = unit;
	/**
	* Returns the assembled value and unit sting using a multiplier.
	* @param number Defaults to 1.
	*/
	this.String = function (mult)
	{
		if (typeof mult != 'number')
			mult = 1;
		return '' + (this.Value * mult) + this.Unit;
	};
	/**
	* Assign the instance using a string wich is split into a value and unit.
	* @param string/number String like '12px' or '3em'. When the type is a number the unit defaults to 'px'.
	* @param string/number Default when the first param is not a string or number.
	* @returns TValueUnit
	*/
	this.Assign = function (value_unit, def)
	{
		// Depending on the type process.
		switch (typeof value_unit)
		{
			// When undefined or null return the default when a default is given.
			default:
			case 'undefined':
				return def ? (new TValueUnit()).Assign(def) : null;
			// When it is a string a unit is always present.
			case 'string':
				{
					var value = value_unit.match(/^([0-9]+|[0-9]+\.[0-9]+)(%|px|pt|em)$/);
					if (value)
						return new TValueUnit(parseInt(value[1]), value[2]);
					// Run into next statement when no unit was matched.
				}
			// When a numner a pixel unit is assumed.
			case 'number':
				return new TValueUnit(value_unit, 'px');
		}
		// Signal failure using the null object.
		return null;
	};
}
//-----------------------------------------
/**
* Splits the a position or size value into a value and a unit by returning
* a TValueUnit instance.
* @see TValue
* @param string/number
* @param string/number
*/
SfLib.GetValueUnit = function (value_unit, def)
{
	return new TValueUnit().Assign(value_unit, def);
};
//---------------------------------------------------------------------------
/**
* Returns the class name of the passed instance and false on failure.
* @param Object obj
* @returns string/boolean
*/
SfLib.GetClass = function(obj)
{
	if (!(obj instanceof Array)
		&& !(obj instanceof Function) && obj.constructor && obj != window)
	{
		var arr = obj.constructor.toString().match(/function\s*(\w+)/);
		if (arr && arr.length == 2)
		  return arr[1];
	}
	// Signal failure.
	return false;
};
//---------------------------------------------------------------------------
/**
* Function : Dump()
* Arguments: The data - array,hash(associative array),object
*    The level - OPTIONAL
* Returns  : The textual representation of the array.
* This function was inspired by the print_r function of PHP.
* This will accept some data as the argument and return a
* text that will be a more readable version of the
* array/hash/object that is given.
*
*/
SfLib.Dump = function (arr, level)
{
	var dumped_text = '';
	if(!level)
		level = 0;
	if (level > 1)
		return '';
	//The padding given at the beginning of the line.
	var level_padding = '';
	for(var j = 0; j < level + 1; j++)
		level_padding += "   ";
	//Array/Hashes/Objects
	if (typeof(arr) == 'object')
	{
		var first_item = null;
		for (var item in arr)
		{
			// Hack to break infinite loop.
			if (first_item == null)
				first_item = item;
			else if (first_item == item)
				break;
			//
			var value = null;
			try
			{
				value = arr[item];
			}
			catch(err)
			{
				return dumped_text;
			}
			//If it is an array,
			if (typeof(value) == 'object')
			{
				if (value === null)
					dumped_text += level_padding + "'" + item + "' => null\n";
				else
				{
					dumped_text += level_padding + "'" + item + "' ...\n";
					dumped_text += this.Dump(value, level + 1);
				}
			}
			else
			{
				switch (item)
				{
					case 'outerText':
					case 'innerText':
					case 'textContent':
					case 'innerHTML':
					case 'outerHTML':
						break;

					default:
						dumped_text += level_padding + "'" + item + "' => \"" +
							('' + value).replace(/\n/g, '\n' + level_padding) + "\"\n";
						break;
				}
			}
		}
	}
	else
	{
		//Stings/Chars/Numbers etc.
		dumped_text = "===>"+arr+"<===("+typeof(arr)+")";
	}
	return dumped_text;
};
//---------------------------------------------------------------------------
/**
* Opens a new browser window.
* @param string URL of the page to open.
* @param string name of the browser tab window top open.
*/
SfLib.OpenBrowserTab = function (url, trgname)
{
	var form_name = '__link_form';
	var link_form = document.forms[form_name];
	// Check if the form exists.
	if (!link_form)
	{
		// If not create the form.
		link_form = document.createElement('FORM');
		document.body.appendChild(link_form);
		link_form.name = form_name;
		// Set post method to have the action have some meaning.
		link_form.method = "POST";
	}
	// Assign the url.
	link_form.action = url;
	// Set the target name.
	link_form.target = trgname;
	if (BrowserDetect.browser == 'Explorer' && !event.ctrlKey)
	{
		alert('Press now the \'Ctrl\'-key for this link to open it in a new Tab?');
		if (!event.ctrlKey)
			return;
	}
	// Submit and open the browser in a new tab.
	link_form.submit();
};
//---------------------------------------------------------------------------
/**
* Opens a new browser window.
*/
SfLib.OpenBrowser = function (url, trgname, w_width, w_height)
{
	// When negative use the screen width.
	if (w_width < 0)
		w_width = screen.width * 0.6;
	if (w_height < 0)
		w_height = screen.height * 0.6;
	//
	if (BrowserDetect.browser == 'Firefox')
	{
		// Center on the main window.
		w_left = window.screenX + ((window.outerWidth - w_width) / 2);
		w_top = window.screenY + ((window.outerHeight - w_height) / 2);
	}
	else
	{
		w_left = (screen.width - w_width) / 2;
		w_top = (screen.height - w_height) / 2;
	}
	// Assemble the options,
	var opts = "alwaysRaised";
//	if (w_width != 0)
	{
		opts += "width=" + w_width;
		opts += ",left=" + w_left;
	}
//	if (w_height != 0)
	{
		opts += ",height=" + w_height;
		opts += ",top=" + w_top;
	}
	opts += ",scrollbars=yes";
	opts += ",status=yes";
	opts += ",location=yes";
	opts += ",copyhistory=no";
	opts += ",menubar=yes";
	opts += ",toolbar=yes";
	opts += ",directories=no";
	opts += ",resizable=yes";
	//this.DebugOut("window.open options: " + opts);
	return window.open(url, trgname, opts);
};
//---------------------------------------------------------------------------
/**
* Opens a new clean browser window used as an application extension.
*/
SfLib.OpenWindow = function (url, trgname, w_width, w_height)
{
	// Set the default target name when none is passed.
	if (typeof(trgname) == 'undefined')
		trgname = '_blank';
	// When negative use the screen width.
	if (typeof(w_width) == 'undefined' || w_width < 0)
		w_width = screen.width * 0.8;
	if (typeof(w_height) == 'undefined' || w_height < 0)
		w_height = screen.height * 0.8;
	//
	if (BrowserDetect.browser == 'Firefox')
	{
		// Center on the main window.
		w_left = window.screenX + ((window.outerWidth - w_width) / 2);
		w_top = window.screenY + ((window.outerHeight - w_height) / 2);
	}
	else
	{
		w_left = (screen.width - w_width) / 2;
		w_top = (screen.height - w_height) / 2;
	}
	// Assemble the options,
	var opts = '';
	opts += "width=" + w_width;
	opts += ",height=" + w_height;
	opts += ",left=" + w_left;
	opts += ",top=" + w_top;
	opts += ",alwaysRaised";
	opts += ",scrollbars=yes";
	opts += ",status=yes";
	opts += ",location=no";
	opts += ",copyhistory=no";
	opts += ",directories=no";
	opts += ",menubar=no";
	opts += ",toolbar=no";
	opts += ",resizable=yes";
	//this.DebugOut("window.open options: " + opts);
	var win = window.open(url, trgname, opts);
	// Focus the opened dialog in case it was already opened by a previous call.
	if (win)
		win.focus();
	return win;
};
//---------------------------------------------------------------------------
/**
* Opens a new clean browser window used as an application dialog extension.
*/
SfLib.OpenDialog = function (url, trgname, w_width, w_height)
{
	// Set the default target name when none is passed.
	if (typeof(trgname) == 'undefined')
		trgname = '_blank';
	// When negative use the screen width.
	if (typeof(w_width) == 'undefined' || w_width < 0)
		w_width = screen.width * 0.8;
	if (typeof(w_height) == 'undefined' || w_height < 0)
		w_height = screen.height * 0.8;
	//
	if (BrowserDetect.browser == 'Firefox')
	{
		// Center on the main window.
		w_left = window.screenX + ((window.outerWidth - w_width) / 2);
		w_top = window.screenY + ((window.outerHeight - w_height) / 2);
	}
	else
	{
		w_left = (screen.width - w_width) / 2;
		w_top = (screen.height - w_height) / 2;
	}
	// Assemble the options,
	var opts = '';
	opts += "width=" + w_width;
	opts += ",height=" + w_height;
	opts += ",left=" + w_left;
	opts += ",top=" + w_top;
	opts += ",alwaysRaised";
	opts += ",scrollbars=no";
	opts += ",status=no";
	opts += ",location=no";
	opts += ",menubar=no";
	opts += ",toolbar=no";
	opts += ",copyhistory=no";
	opts += ",directories=no";
	opts += ",resizable=no";
	//this.DebugOut("window.open options: " + opts);
	var win = window.open(url, trgname, opts);
	// Focus the opened dialog in case it was already opened by a previous call.
	win.focus();
	return win;
};
//---------------------------------------------------------------------------
/**
* Returns the inner width of the passed browser window.
* @param window
* @returns integer
*/
SfLib.GetWindowInnerWidth = function (window)
{
	// Window dimensions:
	if (window.innerWidth)
		width = window.innerWidth;
	else if (window.document.documentElement && window.document.documentElement.clientWidth)
		width = window.document.documentElement.clientWidth;
	else if (window.document.body)
		width = window.document.body.clientWidth;
	//
	return width;
};
//---------------------------------------------------------------------------
/**
* Returns the inner height of the passed browser window.
* @param window
* @returns integer
*/
SfLib.GetWindowInnerHeight = function (window)
{
	if (window.innerHeight)
		height = window.innerHeight;
	else if (window.document.documentElement && window.document.documentElement.clientHeight)
		height = window.document.documentElement.clientHeight;
	else if (window.document.body)
		height = window.document.body.clientHeight;
	//
	return height;
};
//---------------------------------------------------------------------------
/**
* Returns the width of scrollbar.
* @returns integer
*/
SfLib.GetScrollBarWidth = function ()
{
	if (this.__GetScrollBarWidthResult__)
	{
		var inner = document.createElement('p');
		inner.style.width = '100%';
		inner.style.height = '200px';

		var outer = document.createElement('div');
		outer.style.position = 'absolute';
		outer.style.top = '0px';
		outer.style.left = '0px';
		outer.style.visibility = 'hidden';
		outer.style.width = '200px';
		outer.style.height = '150px';
		outer.style.overflow = 'hidden';
		outer.appendChild (inner);

		document.body.appendChild (outer);
		var w1 = inner.offsetWidth;
		outer.style.overflow = 'scroll';
		var w2 = inner.offsetWidth;
		if (w1 == w2) w2 = outer.clientWidth;

		document.body.removeChild(outer);
		this.__GetScrollBarWidthResult__ = (w1 - w2);
	}
	//
	return this.__GetScrollBarWidthResult__;
};
//---------------------------------------------------------------------------
/**
* Toggles displaying of a container (f.e. a form, fieldset or div)
*
* @param  string elem_id ID of the element which is toggle displaying.
* @return boolean Returns true when visibale false when invisible.
*/
SfLib.ToggleDisplay = function (elem)
{
	if (typeof elem != 'object')
		elem = document.getElementById(elem);
	if (elem)
		elem.style.display = (elem.style.display == '') ? 'none' : '';
	return (elem.style.display == '');
};
//---------------------------------------------------------------------------
/**
* Reports if element is displayed or not.
* You can pass the element or the id.
*/
SfLib.IsDisplayed = function (elem)
{
	if (typeof elem != 'object')
		elem = document.getElementById(elem);
	if (elem)
		return (elem.style.display == '') ? true : false;
	return false;
};
//---------------------------------------------------------------------------
/**
* Reports if element is displayed or not.
* You can pass the element or the id.
*/
SfLib.Display= function (elem, show)
{
	if (typeof elem != 'object')
		elem = document.getElementById(elem);
	if (elem)
	{
		if (show)
			elem.style.display = '';
		else
			elem.style.display = 'none';
		return true;
	}
	return false;
};
//---------------------------------------------------------------------------
/**
* Toggles displaying of a container (f.e. a form, fieldset or div)
*
* @param  string elem_id ID of the element which is toggle displaying.
* @return boolean Returns true when visible false when invisible.
*/
SfLib.ToggleVisibility = function (elem)
{
	if (typeof elem != 'object')
		elem = document.getElementById(elem);
	if (elem)
		this.Visibility(elem, !this.IsVisible(elem))
	//
	return this.IsVisible(elem);
};
//---------------------------------------------------------------------------
/**
* Reports if element is displayed or not.
* You can pass the element or the id.
* @param HTMLElement elem
* @returns boolean
*/
SfLib.IsVisible = function (elem)
{
	if (typeof elem != 'object')
		elem = document.getElementById(elem);
	if (elem)
		return (elem.currentStyle.visibility != 'hidden');
	return false;
};
//---------------------------------------------------------------------------
/**
* Reports if element is displayed or not.
* You can pass the element or the id.
* @param HTMLElement elem
* @returns boolean
*/
SfLib.Visibility = function (elem, show)
{
	if (typeof elem != 'object')
		elem = document.getElementById(elem);
	if (elem)
	{
		if (show)
		{
			elem.style.visibility = 'visible';
			elem.style.position = 'static';
			elem.style.top = '0px';
			elem.style.left = '0px';
		}
		else
		{
			elem.style.visibility = 'hidden';
			elem.style.position = 'absolute';
			elem.style.top = '-100000px';
			elem.style.left = '-100000px';
		}
		return true;
	}
	return false;
};
//---------------------------------------------------------------------------
/**
* Checks/unchecks all checkbox in given conainer (f.e. a form, fieldset or div)
*
* @param   string   container_id
* The container id
* @param   boolean  state
* New value for checkbox (true or false)
* When not passed or null the first inverse value of the check box in the list is used.
* When -1 a question is asked.
* @return  boolean  always true
*/
SfLib.SetCheckboxes = function (container_id, state, msg)
{
	if (state == -1)
		state = confirm(msg);
	var checkboxes = document.getElementById(container_id).getElementsByTagName('input');
	for ( var i = 0; i < checkboxes.length; i++ )
		if ( checkboxes[i].type == 'checkbox' )
		{
			// When state is not passed use the first check pox to initialize it.
			if (state == null)
				state = !checkboxes[i].checked;
			checkboxes[i].checked = state;
		}
	return true;
};
//---------------------------------------------------------------------------
/**
* @param   string   container_id
* @returns HTMLInputElement[]
*/
SfLib.GetCheckboxes = function (container_id)
{
	var retval = Array();
	var checkboxes = document.getElementById(container_id).getElementsByTagName('input');
	for (var cb in checkboxes)
		if (cb.type == 'checkbox')
			retval.push(cb);
	return retval;
};
//---------------------------------------------------------------------------
/**
* Generates an MD5 hash of the passed string.
* @param   string
* @returns string
*/
SfLib.MD5 = function (string)
{
	function RotateLeft(lValue, iShiftBits) {	return (lValue << iShiftBits) | (lValue >>> (32 - iShiftBits));}

	function AddUnsigned(lX, lY)
	{
		var lX4, lY4, lX8, lY8, lResult;
		lX8 = (lX & 0x80000000);
		lY8 = (lY & 0x80000000);
		lX4 = (lX & 0x40000000);
		lY4 = (lY & 0x40000000);
		lResult = (lX & 0x3FFFFFFF)+(lY & 0x3FFFFFFF);
		if (lX4 & lY4)
			return (lResult ^ 0x80000000 ^ lX8 ^ lY8);
		if (lX4 | lY4)
		{
			if (lResult & 0x40000000)
				return (lResult ^ 0xC0000000 ^ lX8 ^ lY8);
			else
				return (lResult ^ 0x40000000 ^ lX8 ^ lY8);
		}
		else
			return (lResult ^ lX8 ^ lY8);
 	}

 	function F(x,y,z) { return (x & y) | ((~x) & z); }
 	function G(x,y,z) { return (x & z) | (y & (~z)); }
 	function H(x,y,z) { return (x ^ y ^ z); }
	function I(x,y,z) { return (y ^ (x | (~z))); }

	function FF(a,b,c,d,x,s,ac)
	{
		a = AddUnsigned(a, AddUnsigned(AddUnsigned(F(b, c, d), x), ac));
		return AddUnsigned(RotateLeft(a, s), b);
	};

	function GG(a,b,c,d,x,s,ac)
	{
		a = AddUnsigned(a, AddUnsigned(AddUnsigned(G(b, c, d), x), ac));
		return AddUnsigned(RotateLeft(a, s), b);
	};

	function HH(a,b,c,d,x,s,ac)
	{
		a = AddUnsigned(a, AddUnsigned(AddUnsigned(H(b, c, d), x), ac));
		return AddUnsigned(RotateLeft(a, s), b);
	};

	function II(a,b,c,d,x,s,ac)
	{
		a = AddUnsigned(a, AddUnsigned(AddUnsigned(I(b, c, d), x), ac));
		return AddUnsigned(RotateLeft(a, s), b);
	};

	function ConvertToWordArray(string)
	{
		var lWordCount;
		var lMessageLength = string.length;
		var lNumberOfWords_temp1=lMessageLength + 8;
		var lNumberOfWords_temp2=(lNumberOfWords_temp1-(lNumberOfWords_temp1 % 64)) / 64;
		var lNumberOfWords = (lNumberOfWords_temp2 + 1) * 16;
		var lWordArray=Array(lNumberOfWords - 1);
		var lBytePosition = 0;
		var lByteCount = 0;
		while (lByteCount < lMessageLength)
		{
			lWordCount = (lByteCount-(lByteCount % 4)) / 4;
			lBytePosition = (lByteCount % 4) * 8;
			lWordArray[lWordCount] = (lWordArray[lWordCount] | (string.charCodeAt(lByteCount)<<lBytePosition));
			lByteCount++;
		}
		lWordCount = (lByteCount-(lByteCount % 4)) / 4;
		lBytePosition = (lByteCount % 4) * 8;
		lWordArray[lWordCount] = lWordArray[lWordCount] | (0x80 << lBytePosition);
		lWordArray[lNumberOfWords - 2] = lMessageLength << 3;
		lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29;
		return lWordArray;
	};

	function WordToHex(lValue)
	{
		var WordToHexValue="",WordToHexValue_temp="",lByte,lCount;
		for (lCount = 0;lCount<=3;lCount++)
		{
			lByte = (lValue >>> (lCount*8)) & 255;
			WordToHexValue_temp = "0" + lByte.toString(16);
			WordToHexValue = WordToHexValue + WordToHexValue_temp.substr(WordToHexValue_temp.length-2,2);
		}
		return WordToHexValue;
	};

	function Utf8Encode(string)
	{
		string = string.replace(/\r\n/g,"\n");
		var utftext = "";
		for (var n = 0; n < string.length; n++)
		{
			var c = string.charCodeAt(n);
			if (c < 128)
				utftext += String.fromCharCode(c);
			else if((c > 127) && (c < 2048))
			{
				utftext += String.fromCharCode((c >> 6) | 192);
				utftext += String.fromCharCode((c & 63) | 128);
			}
			else
			{
				utftext += String.fromCharCode((c >> 12) | 224);
				utftext += String.fromCharCode(((c >> 6) & 63) | 128);
				utftext += String.fromCharCode((c & 63) | 128);
			}
		}
		return utftext;
	};

	var x = Array();
	var k,AA,BB,CC,DD,a,b,c,d;
	var S11=7, S12=12, S13=17, S14=22;
	var S21=5, S22=9 , S23=14, S24=20;
	var S31=4, S32=11, S33=16, S34=23;
	var S41=6, S42=10, S43=15, S44=21;
	string = Utf8Encode(string);
	x = ConvertToWordArray(string);
	a = 0x67452301; b = 0xEFCDAB89; c = 0x98BADCFE; d = 0x10325476;
	for (k=0; k < x.length; k += 16)
	{
		AA=a; BB=b; CC=c; DD=d;
		a=FF(a,b,c,d,x[k+0], S11,0xD76AA478); d=FF(d,a,b,c,x[k+1], S12,0xE8C7B756);
		c=FF(c,d,a,b,x[k+2], S13,0x242070DB); b=FF(b,c,d,a,x[k+3], S14,0xC1BDCEEE);
		a=FF(a,b,c,d,x[k+4], S11,0xF57C0FAF); d=FF(d,a,b,c,x[k+5], S12,0x4787C62A);
		c=FF(c,d,a,b,x[k+6], S13,0xA8304613);	b=FF(b,c,d,a,x[k+7], S14,0xFD469501);
		a=FF(a,b,c,d,x[k+8], S11,0x698098D8);	d=FF(d,a,b,c,x[k+9], S12,0x8B44F7AF);
		c=FF(c,d,a,b,x[k+10],S13,0xFFFF5BB1); b=FF(b,c,d,a,x[k+11],S14,0x895CD7BE);
		a=FF(a,b,c,d,x[k+12],S11,0x6B901122);	d=FF(d,a,b,c,x[k+13],S12,0xFD987193);
		c=FF(c,d,a,b,x[k+14],S13,0xA679438E);	b=FF(b,c,d,a,x[k+15],S14,0x49B40821);
		a=GG(a,b,c,d,x[k+1], S21,0xF61E2562);	d=GG(d,a,b,c,x[k+6], S22,0xC040B340);
		c=GG(c,d,a,b,x[k+11],S23,0x265E5A51);	b=GG(b,c,d,a,x[k+0], S24,0xE9B6C7AA);
		a=GG(a,b,c,d,x[k+5], S21,0xD62F105D);	d=GG(d,a,b,c,x[k+10],S22,0x2441453);
		c=GG(c,d,a,b,x[k+15],S23,0xD8A1E681);	b=GG(b,c,d,a,x[k+4], S24,0xE7D3FBC8);
		a=GG(a,b,c,d,x[k+9], S21,0x21E1CDE6);	d=GG(d,a,b,c,x[k+14],S22,0xC33707D6);
		c=GG(c,d,a,b,x[k+3], S23,0xF4D50D87);	b=GG(b,c,d,a,x[k+8], S24,0x455A14ED);
		a=GG(a,b,c,d,x[k+13],S21,0xA9E3E905);	d=GG(d,a,b,c,x[k+2], S22,0xFCEFA3F8);
		c=GG(c,d,a,b,x[k+7], S23,0x676F02D9);	b=GG(b,c,d,a,x[k+12],S24,0x8D2A4C8A);
		a=HH(a,b,c,d,x[k+5], S31,0xFFFA3942);	d=HH(d,a,b,c,x[k+8], S32,0x8771F681);
		c=HH(c,d,a,b,x[k+11],S33,0x6D9D6122);	b=HH(b,c,d,a,x[k+14],S34,0xFDE5380C);
		a=HH(a,b,c,d,x[k+1], S31,0xA4BEEA44);	d=HH(d,a,b,c,x[k+4], S32,0x4BDECFA9);
		c=HH(c,d,a,b,x[k+7], S33,0xF6BB4B60);	b=HH(b,c,d,a,x[k+10],S34,0xBEBFBC70);
		a=HH(a,b,c,d,x[k+13],S31,0x289B7EC6);	d=HH(d,a,b,c,x[k+0], S32,0xEAA127FA);
		c=HH(c,d,a,b,x[k+3], S33,0xD4EF3085);	b=HH(b,c,d,a,x[k+6], S34,0x4881D05);
		a=HH(a,b,c,d,x[k+9], S31,0xD9D4D039);	d=HH(d,a,b,c,x[k+12],S32,0xE6DB99E5);
		c=HH(c,d,a,b,x[k+15],S33,0x1FA27CF8);	b=HH(b,c,d,a,x[k+2], S34,0xC4AC5665);
		a=II(a,b,c,d,x[k+0], S41,0xF4292244);	d=II(d,a,b,c,x[k+7], S42,0x432AFF97);
		c=II(c,d,a,b,x[k+14],S43,0xAB9423A7);	b=II(b,c,d,a,x[k+5], S44,0xFC93A039);
		a=II(a,b,c,d,x[k+12],S41,0x655B59C3);	d=II(d,a,b,c,x[k+3], S42,0x8F0CCC92);
		c=II(c,d,a,b,x[k+10],S43,0xFFEFF47D);	b=II(b,c,d,a,x[k+1], S44,0x85845DD1);
		a=II(a,b,c,d,x[k+8], S41,0x6FA87E4F);	d=II(d,a,b,c,x[k+15],S42,0xFE2CE6E0);
		c=II(c,d,a,b,x[k+6], S43,0xA3014314);	b=II(b,c,d,a,x[k+13],S44,0x4E0811A1);
		a=II(a,b,c,d,x[k+4], S41,0xF7537E82);	d=II(d,a,b,c,x[k+11],S42,0xBD3AF235);
		c=II(c,d,a,b,x[k+2], S43,0x2AD7D2BB);	b=II(b,c,d,a,x[k+9], S44,0xEB86D391);
		a=AddUnsigned(a,AA); b=AddUnsigned(b,BB); c=AddUnsigned(c,CC); d=AddUnsigned(d,DD);
	}
	//
 	var temp = WordToHex(a) + WordToHex(b) + WordToHex(c) + WordToHex(d);
 	//
 	return temp.toLowerCase();
}
//---------------------------------------------------------------------------
/**
* Extend the string class with trim functions.
*/
String.prototype.trim = function()
{
	return this.replace(/^\s+|\s+$/g, '');
};
String.prototype.ltrim = function()
{
	return this.replace(/^\s+/, '');
};
String.prototype.rtrim = function()
{
	return this.replace(/\s+$/, '');
};
//---------------------------------------------------------------------------
/**
* Fix to parses a date string correctly for an IE browsers.
* @returns Date.parse() result.
*/
parseDate = function(dateStr)
{
	if (BrowserDetect.browser == 'Explorer')
		return Date.parse(dateStr.replace(/\-/ig, '/'));
	else
		return Date.parse(dateStr);
};
//---------------------------------------------------------------------------
/**
* Extend the Date class with format functions.
* Simulates PHP's date function
*/
Date.prototype.format = function(format)
{
	var returnStr = '';
	var replace = Date.replaceChars;
	for (var i = 0; i < format.length; i++)
	{
		var curChar = format.charAt(i);
		if (i - 1 >= 0 && format.charAt(i - 1) == "\\")
			returnStr += curChar;
		else if (replace[curChar])
			returnStr += replace[curChar].call(this);
		else if (curChar != "\\")
			returnStr += curChar;
	}
	return returnStr;
};

Date.replaceChars = {
	shortMonths: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
	longMonths: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
	shortDays: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
	longDays: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],

	// Day
	d: function() { return (this.getDate() < 10 ? '0' : '') + this.getDate(); },
	D: function() { return Date.replaceChars.shortDays[this.getDay()]; },
	j: function() { return this.getDate(); },
	l: function() { return Date.replaceChars.longDays[this.getDay()]; },
	N: function() { return this.getDay() + 1; },
	S: function() { return (this.getDate() % 10 == 1 && this.getDate() != 11 ? 'st' : (this.getDate() % 10 == 2 && this.getDate() != 12 ? 'nd' : (this.getDate() % 10 == 3 && this.getDate() != 13 ? 'rd' : 'th'))); },
	w: function() { return this.getDay(); },
	z: function() { var d = new Date(this.getFullYear(),0,1); return Math.ceil((this - d) / 86400000); }, // Fixed now
	// Week
	W: function() { var d = new Date(this.getFullYear(), 0, 1); return Math.ceil((((this - d) / 86400000) + d.getDay() + 1) / 7); }, // Fixed now
	// Month
	F: function() { return Date.replaceChars.longMonths[this.getMonth()]; },
	m: function() { return (this.getMonth() < 9 ? '0' : '') + (this.getMonth() + 1); },
	M: function() { return Date.replaceChars.shortMonths[this.getMonth()]; },
	n: function() { return this.getMonth() + 1; },
	t: function() { var d = new Date(); return new Date(d.getFullYear(), d.getMonth(), 0).getDate();}, // Fixed now, gets #days of date
	// Year
	L: function() { var year = this.getFullYear(); return (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0)); },	// Fixed now
	o: function() { var d  = new Date(this.valueOf());  d.setDate(d.getDate() - ((this.getDay() + 6) % 7) + 3); return d.getFullYear();}, //Fixed now
	Y: function() { return this.getFullYear(); },
	y: function() { return ('' + this.getFullYear()).substr(2); },
	// Time
	a: function() { return this.getHours() < 12 ? 'am' : 'pm'; },
	A: function() { return this.getHours() < 12 ? 'AM' : 'PM'; },
	B: function() { return Math.floor((((this.getUTCHours() + 1) % 24) + this.getUTCMinutes() / 60 + this.getUTCSeconds() / 3600) * 1000 / 24); }, // Fixed now
	g: function() { return this.getHours() % 12 || 12; },
	G: function() { return this.getHours(); },
	h: function() { return ((this.getHours() % 12 || 12) < 10 ? '0' : '') + (this.getHours() % 12 || 12); },
	H: function() { return (this.getHours() < 10 ? '0' : '') + this.getHours(); },
	i: function() { return (this.getMinutes() < 10 ? '0' : '') + this.getMinutes(); },
	s: function() { return (this.getSeconds() < 10 ? '0' : '') + this.getSeconds(); },
	u: function() { var m = this.getMilliseconds(); return (m < 10 ? '00' : (m < 100 ?
'0' : '')) + m; },
	// Timezone
	e: function() { return "Not Yet Supported"; },
	I: function() { return "Not Yet Supported"; },
	O: function() { return (-this.getTimezoneOffset() < 0 ? '-' : '+') + (Math.abs(this.getTimezoneOffset() / 60) < 10 ? '0' : '') + (Math.abs(this.getTimezoneOffset() / 60)) + '00'; },
	P: function() { return (-this.getTimezoneOffset() < 0 ? '-' : '+') + (Math.abs(this.getTimezoneOffset() / 60) < 10 ? '0' : '') + (Math.abs(this.getTimezoneOffset() / 60)) + ':00'; }, // Fixed now
	T: function() { var m = this.getMonth(); this.setMonth(0); var result = this.toTimeString().replace(/^.+ \(?([^\)]+)\)?$/, '$1'); this.setMonth(m); return result;},
	Z: function() { return -this.getTimezoneOffset() * 60; },
	// Full Date/Time
	c: function() { return this.format("Y-m-d\\TH:i:sP"); }, // Fixed now
	r: function() { return this.toString(); },
	U: function() { return this.getTime() / 1000; }
};
//---------------------------------------------------------------------------
/**
* Returns an array of elements which tagnames are in the passed string array.
* prototype key word is not implemented.
* @param HTMLElement
* @param string[]
* @returns HTMLElement[]
*/
SfLib.GetElementsByTagNames = function (parentNode, tagnames)
{
	if (typeof tagnames != 'object')
		return false;
	// Initialize the return value.
	var retval = Array();
	// Iterate through the type names.
	for (var j in tagnames)
	{
		// Push all found elements in the returned array.
		var elems = parentNode.getElementsByTagName(tagnames[j]);
		for (var i = 0; i < elems.length; i++)
			retval.push(elems[i]);
	}
	//
	return retval;
};
//---------------------------------------------------------------------------
/**
* Extends the array class
* Is not working gives eception in any browser.
*/
/*
Array.prototype.in_array = function(p_val)
{
	for(var i = 0, l = this.length; i < l; i++)
		if(this[i] == p_val)
			return true;
	return false;
}
*/
SfLib.InArray = function (p_val, arr)
{
	for(var i = 0, l = arr.length; i < l; i++)
		if(arr[i] == p_val)
			return true;
	return false;
};
//---------------------------------------------------------------------------
/**
* support microsoft's styleFloat
* mimic microsoft's pixel representations of left/top/width/height
* the getters only work for values that are already pixels
*/
if (BrowserDetect.browser != 'Explorer' && BrowserDetect.browser != 'Konqueror')
{
	// Add IE compatibility in Firefox.
	HTMLElement.prototype.__defineGetter__("currentStyle", function()
	{
		return window.getComputedStyle(this, null);
	});
	HTMLElement.prototype.__defineGetter__("innerText", function()
	{
		return this.textContent;
	});
	HTMLElement.prototype.__defineGetter__("posX", function($value)
	{
		var elem = this;
		var x = 0;
		while (elem)
		{
			x += elem.offsetLeft;
			elem = elem.offsetParent;
		}
		return x;
	});
	HTMLElement.prototype.__defineGetter__("posY", function($value)
	{
		var elem = this.srcElement;
		var y = 0;
		while (elem)
		{
			y += elem.offsetTop;
			elem = elem.offsetParent;
		}
		return y;
	});
	CSSStyleDeclaration.prototype.__defineGetter__("styleFloat", function()
	{
	 return this.cssFloat;
	});
	CSSStyleDeclaration.prototype.__defineSetter__("styleFloat", function($value)
	{
	 this.cssFloat = $value;
	});
	CSSStyleDeclaration.prototype.__defineGetter__("pixelLeft", function()
	{
	 return parseInt(this.left) || 0;
	});
	CSSStyleDeclaration.prototype.__defineSetter__("pixelLeft", function($value)
	{
	 this.left = $value + "px";
	});
	CSSStyleDeclaration.prototype.__defineGetter__("pixelHeight", function()
	{
	 return parseInt(this.height) || 0;
	});
	CSSStyleDeclaration.prototype.__defineSetter__("pixelHeight", function($value)
	{
	 this.height = $value + "px";
	});
	CSSStyleDeclaration.prototype.__defineGetter__("pixelTop", function()
	{
	 return parseInt(this.top) || 0;
	});
	CSSStyleDeclaration.prototype.__defineSetter__("pixelTop", function($value)
	{
	 this.top = $value + "px";
	});
	CSSStyleDeclaration.prototype.__defineGetter__("pixelWidth", function()
	{
	 return parseInt(this.width) || 0;
	});
	CSSStyleDeclaration.prototype.__defineSetter__("pixelWidth", function($value)
	{
	 this.width = $value + "px";
	});
	CSSStyleSheet.prototype.__defineGetter__("rules", function()
	{
		return this.cssRules;
	});
	Event.prototype.__defineGetter__("offsetX", function($value)
	{
		// AVO: 20111219 Fix for firefox. Hope this will be fixed soon.
		if (BrowserDetect.browser != 'Firefox')
			return this.layerX | this.x;
		//
		return this.clientX - this.srcElement.posX;
	});
	Event.prototype.__defineGetter__("offsetY", function($value)
	{
	 	return this.layerY | this.y;
	});
	Event.prototype.__defineGetter__("srcElement", function()
	{
		return this.target;
	});
	MouseEvent.prototype.__defineGetter__("offsetX", function($value)
	{
		// AVO: 20111219 Fix for firefox. Hope this will be fixed soon.
		if (BrowserDetect.browser != 'Firefox')
			return this.layerX | this.x;
		//
		return this.clientX - this.srcElement.posX;
	});
	MouseEvent.prototype.__defineGetter__("offsetY", function($value)
	{
	 	return this.layerY | this.y;
	});
	MouseEvent.prototype.__defineGetter__("srcElement", function()
	{
	 return this.target;
	});
}
//---------------------------------------------------------------------------
/**
* Function to overcome problem with event or listner attaching between browsers.
* @param HTMLElement obj
* @param string evtype
* @param function fn
*/
SfLib.AddEvent = function (obj, evtype, fn)
{
	if (obj.addEventListener)
	{
		obj.addEventListener(evtype, fn, true);
		return true;
	}
	else if (obj.attachEvent)
	{
		var r = obj.attachEvent("on"+evtype, fn);
		return r;
	}
	else
		return false;
};
//---------------------------------------------------------------------------
/**
* Function to overcome problem with event or listner removing between browsers.
* @param HTMLElement obj
* @param string evtype
* @param function fn
*/
SfLib.RemoveEvent = function(obj, evtype, fn)
{
	if (obj.removeEventListener)
	{
		obj.removeEventListener(evtype, fn, true);
		return true;
	}
	else if (obj.detachEvent)
	{
		var r = obj.detachEvent("on"+evtype, fn);
		return r;
	}
	else
	{
		return false;
	}
};
//---------------------------------------------------------------------------
/**
* Object to call a function on another object.
* @example
* Usage:
*  new Closure({o:myobj, f:'MyMemberFunc'})
*  new Closure(myobj, 'MyMemberFunc')
*  new Closure('MyFunc')
*  AddEvent(window, 'resize', new Closure(this, 'EvResize').Call);
* @constructor
* @param object/string obj
* @param string/void func
*/
function Closure(obj, func)
{
	/*
	* Trick to access this objects members from the Call() function.
	* @private
	*/
	var self = this;
	// When the obj param is a string it is the function name.
	if (typeof obj != 'string')
	{
		// Object on which the function Func is called.
		this.Object = (typeof func == 'string') ? obj : obj.o;
		// Name of the function.
		this.Func = (typeof func == 'string') ? func : obj.f;
		// Create function which is called by the setTimeout() or addEventListner()
		this.Call = function(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9)
			{return eval("self.Object." + self.Func + "(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9)");};
	}
	else
	{
		// Assign the function name.
		this.Func = obj;
		// Create function which is called by the setTimeout() or addEventListner()
		this.Call = function(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9)
			{return eval(self.Func + "(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9)");};
	}
}
//---------------------------------------------------------------------------
/**
* Retrieve the child by id starting from the passed node.
* @param HTMLElement Node in the HTML DOM.
* @param string 'id' attribute of the element.
* @returns HTMLElement
*/
SfLib.GetChildById = function (node, id)
{
	if (node.getAttribute)
		if (node.getAttribute('id') == id)
			return node;
	//
	for (var i = 0; i < node.childNodes.length; i++)
	{
		var c = this.GetChildById(node.childNodes[i], id);
		if (c != null)
			return c;
	}
	return null;
};
//---------------------------------------------------------------------------
/**
* Retrieve the first child of this node from the passed type.
* @param HTMLElement Node in the HTML DOM.
* @param string 'type' attribute of the element.
* @returns HTMLElement
*/
SfLib.GetChildByType = function (node, type)
{
	if (node.getAttribute)
		if (node.getAttribute('type') == type)
			return node;
	//
	for (var i = 0; i < node.childNodes.length; i++)
	{
		var c = this.GetChildByType(node.childNodes[i], type);
		if (c != null)
			return c;
	}
	return null;
};
//---------------------------------------------------------------------------
/**
* Focusses the first visible none hidden form input.
* @param HTMLFormElement Form element.
* @returns HTMLInputElement
*/
SfLib.FormFirstInputFocus = function(form)
{
	// Try and catch for IE browsers.
	try {
	// When a string lookup the form name.
	if (typeof form == 'string')
		form = document.forms.namedItem(form);
	// When not valid bail out.
	if (!form)
		return null;
	//
	for (var i = 0; i < form.length; i++)
	if (!form[i].disabled && this.RegExpMatch(form[i].type, '/text|radio|select|checkbox|file/i'))
	{
		form[i].focus();
		return form[i];
	}
	}catch (e){
	}
	//
	return null;
};
//---------------------------------------------------------------------------
/**
* Get the parent of the specified tag.
* @param HTMLElement Node in the HTML DOM.
* @param string tagName of the element.
* @returns HTMLElement
*/
SfLib.GetParentByTag = function (node, tagname)
{
	if (!node)
		return null;
	node = node.parentNode;
	while (node && typeof node != 'undefined')
	{
		//this.DebugOut("Probing (" + typeof node + ")TAG: " + node.tagName + ' ID:' + node.id);
		if (node.tagName && node.tagName.toUpperCase() != tagname.toUpperCase())
			node = node.parentNode;
		else
			return node;
	}
	return null;
};
//---------------------------------------------------------------------------
/**
* Retrieve the first child of this node from the passed type.
* @param HTMLElement Node in the HTML DOM.
* @param string tagName of the element.
* @param integer Index of the child element.
* @returns HTMLElement
*/
SfLib.GetChildByTag = function (node, tagname, index)
{
	// When idex is not passed assign zero.
	if (typeof index == 'undefined')
		index = 0;
	if (!node || typeof node != 'object')
	{
		SfLib.DebugOut('GetChildByTag(): Invalid node');
		return null;
	}
	// Iterate throgh the elements child nodes.
	for (var i = 0; i < node.childNodes.length; i++)
		// If a child node is of element.
		if (node.childNodes[i].tagName && node.childNodes[i].tagName.toUpperCase() == tagname.toUpperCase())
			// Decrement the index until it is zero and return the child.
			if (!index--)
				return node.childNodes[i];
	//
	return null;
};
//---------------------------------------------------------------------------
/**
* Function to create an xml http object and returns it.
* @returns XMLHttpRequest
*/
SfLib.CreateXmlHttpObject = function ()
{
	var xmlhttp;
	// This below is no comment !!!!!!
	/*@cc_on @*/
	/*@if (@_jscript_version >= 5)
	try
	{
		xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
 	}
	catch (e)
	{
		try
		{
			xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
		}
		catch (E)
		{
		 xmlhttp=false;
		}
 	}
	@else
	xmlhttp = false
	@end @*/

	if (!xmlhttp && typeof XMLHttpRequest != 'undefined')
	{
		try
		{
			xmlhttp = new XMLHttpRequest();
		}
		catch (e)
		{
			xmlhttp = null;
		}
	}
	//
	if (!xmlhttp && window.createRequest)
	{
		try
		{
			xmlhttp = window.createRequest();
		}
		catch (e)
		{
			xmlhttp = null;
		}
	}
	return xmlhttp;
};
/**
* Checks if a XmlHttp is available for the browser.
*/
SfLib.XmlHttpAvailable = function ()
{
	var xmlhttp = this.CreateXmlHttpObject();
	if (xmlhttp == false)
	{
		document.write("Your browser doesn't support XML HTTP objects. Please enable javascript, or find a decent browser.");
		return false;
	}
	return true;
};
//---------------------------------------------------------------------------
/**
* Returns the content of a post request or false on failure.
* When a callback function has n=been passed the call is asynchrone and an
* object is returned. This object has a Cancel() function to cancel a
* pending call. It returns true whe a pending call was in deed cancelled.
* @param string url
* @param string to_post
* @param function callback
* @return boolean
*/
SfLib.GetByHttpPost = function (url, to_post, callback)
{
	var o =
	{
		// Determine if a function or closure was passed.
		async: (callback ? true : false) && typeof callback == 'function',
		url: url,
		to_post: to_post,
		callback: callback,
		result: false,
		counter: 10000,
		timer: null,
		xmlhttp: this.CreateXmlHttpObject(),
		// Returns true when a pending call was cancelled.
		Cancel: (function()
		{
			clearTimeout(this.timer);
			this.xmlhttp = null;
			return !this.result;
		})
	};
	// Check if request object is available.
	if (!o.xmlhttp)
		return false;
	// Intercept exception.
	try
	{
		// Initialize.
		o.xmlhttp.open(o.to_post ? 'POST' : 'GET', o.url, o.async);
		// Only add headers when posting.
		if (o.to_post)
		{
			// Set the request headers.
		  o.xmlhttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
		  o.xmlhttp.setRequestHeader('Connection', 'close');
		  o.xmlhttp.setRequestHeader('Content-length', o.to_post ? o.to_post.length : 0);
		}
		// Post the actual data
		o.xmlhttp.send(o.to_post);
	}
	catch(e)
	{
		this.DebugOut(e.message + "\nException: " + e.name + "\nURI: " + o.url);
		return false;
	}
	// Syncronous request.
	if (!o.async)
	{
		//this.DebugOut(o.xmlhttp.getAllResponseHeaders());
		// Check if there is a need to login.
		var login = o.xmlhttp.getResponseHeader('X-Need-To-Login');
		if (login)
		{
			if (navigator.language.substr(0,2) == 'nl')
				alert('Uw server sessie is verlopen.\nU moet opnieuw inloggen ...');
			else
				alert('Your server session has expired.\nYou need to login again...');
			// When a parent exists
			if (window.parent)
				window.parent.location.reload();
			else
				window.location.reload();
			//document.location = login;
			// Stop propagation by throwing an event.
			throw "'X-Need-To-Login:'";
		}
		// Return the infor from the HTTP request.
		return o.xmlhttp.responseText;
	}
	//
	function CheckReady()
	{
		// Clear the timer when it stil exists.
		if (o.timer)
		{
			clearTimeout(o.timer);
			o.timer = null;
		}
		// When cancelled.
		if (o.xmlhttp == null)
			return;
		//
		if (o.xmlhttp.readyState == 4 || o.counter-- < 0)
		{
			o.status = o.counter > 0;
			if (o.callback)
				o.callback(o.xmlhttp.responseText, o);
			o.xmlhttp = null;
		}
		else
			o.timer = window.setTimeout(CheckReady, 10);
	};
	// Assign handler any way.
	o.xmlhttp.onreadystatechange = CheckReady;
	// Check if ready info not schedule a call to check it until timed out.
	CheckReady();
	// Return object.
	return o;
};
//---------------------------------------------------------------------------
/**
* Submits a form to a iframe target and on the onload event calls the callback function
* which passes the returned content from the call.
* @param HTMLFormElement theform
* @param function callback
* @returns void
*/
SfLib.GetByForm = function (theform, callback)
{
	if (typeof callback != 'function')
		DebugOut('SfLib.GetByForm has no callback passed.', 1);
	// Find the needed submit element.
	var submit_elem = null;
	for (var inp in theform.elements)
	if (theform.elements[inp] && theform.elements[inp].type == 'submit')
	{
		submit_elem = theform.elements[inp];
		break;
	}
	// When an element was found.
	if (submit_elem)
	{
		if (callback)
		{
			// Create the iframe element.
			var ifr  = document.createElement('iframe');
			// Set the name of the frame so it can be targeted.
			ifr.name = '__collect_frame__';
			ifr.height = 0;
			ifr.width = 0;
			//
			theform.target = ifr.name;
			// Append it to the document body element.
			document.body.appendChild(ifr);
			// Set the callback function. And again is it for IE different.
			if (BrowserDetect.browser != 'Explorer')
				ifr.onload = function ()
				{
					callback(this.contentDocument.body.textContent);
					this.parentNode.removeChild(this);
				};
			else
				SfLib.AddEvent(ifr, 'load', function ()
				{
					callback(ifr.contentDocument.body.innerText);
					ifr.parentNode.removeChild(ifr);
				});
		}
		// Store current disabled state.
		var disabled = submit_elem.disabled;
		submit_elem.disabled = false;
		submit_elem.click();
		// Restore disabled state.
		submit_elem.disabled = disabled;
	}
	else
		SfLib.DebugOut("Validator.SubmitForm(): Could not find \'submit\' input in form '" +
			 theform.name + "'!", 1);
};
//---------------------------------------------------------------------------
/**
* Returns true when the passed string buffer contains a
* @param string Buffer containing partial HTML
* @param boolean notify Makes the function throw an exception on false
* @param string url Optional url.
* @return boolean
*/
SfLib.ContainsHtmlDocType = function (buf, notify, url)
{
	// When not a string return false.
	if (typeof buf != 'string')
		return false;
	// Check for an error by checking the HTML start tag.
	if (buf.indexOf("<!DOCTYPE ", 0) >= 0 || buf.substr(0, 5).toLowerCase() == '<html')
	{
		if (!url)	url = '???';
		buf = buf.replace(/<\S[^><]*>/g, '').trim();
		var msg = "Unexpected HTML in result in call to: '" + url + "'!\n\n" + buf.substr(0, 400);
		this.DebugOut(msg, notify);
		// Throw an exception to stop propagation.
		if (!notify)
			throw "ContainsHtmlDocType: Unexpected-HTML: " + url;
		// Signal HTML was found and not expected.
		return true;
	}
	return false;
};
//---------------------------------------------------------------------------
/**
* Returns a resulting object of a HTTP call.
* @param string url
* @param string post
* @return object (Raw, Result, Context)
*/
SfLib.GetResultByHttpPost = function (url, post)
{
	// Create an empty object.
	var retval = {Raw: null, Result: null, Context: null};
	// Get the raw result using a post.
	retval.Raw = this.GetByHttpPost(url, post);
	// Check for an error by looking for the DOCTYPE start tag.
	if (this.ContainsHtmlDocType(retval.Raw, true, url))
		return null;
	// Split the result from the message.
	var result = retval.Raw.split("\n\n");
	// If the result is empty signal by not returning null.
	if (result.length == 0)
		return null;
	// Assign the result value.
	retval.Result = result.shift().split("\n");
	// When a single result return only this one but not an array.
	if (retval.Result.length == 1)
		retval.Result = retval.Result[0];
	// Assemble the context of the result.
	if (result.length >= 1)
		retval.Context = result.join("\n\n");
	else
		retval.Context = '';
	//
	return retval;
};
//---------------------------------------------------------------------------
/**
* Returns a resulting object of a HTTP call using JSON.
* @param string url
* @param string post
* @return object (Raw, Result, Context)
*/
SfLib.GetJsonResultByHttpPost = function (url, post)
{
	// Create an empty object.
	var retval = {Raw: null, Result: null, Context: null};
	// Get the raw result using a post.
	retval.Raw = this.GetByHttpPost(url, post);
	// Check for an error by looking for the DOCTYPE start tag.
	if (this.ContainsHtmlDocType(retval.Raw, true, url))
		return null;
	// Split the result from the message.
	var result = JSON.decode(retval.Raw);
	// If the result is empty signal by not returning null.
	if (result.length == 0)
		return null;
	// Assign the fields.
	retval.Result = result.Result;
	retval.Context = result.Context;
	//
	return retval;
};
//---------------------------------------------------------------------------
/**
* Sets the innerHTML of an element.
* @param string/HTMLElement ID of the elemen object itself can be passed.
* @param string HTML content.
* @param boolean Makes the embeded javascript to be evaluated/executed.
* @returns boolean
*/
SfLib.SetInnerHtml = function (elem_id, content, evaluate)
{
	if (typeof elem_id == 'string')
		elem_id = document.getElementById(elem_id);
	if (!elem_id)
		return false;
	if (typeof elem_id == 'object')
	{
		if (typeof content == 'undefined')
			content = '';
		elem_id.innerHTML = content;
		//
		if (evaluate)
			this.EvaluateHtml(content);
		return true;
	}
	this.DebugOut("SfLib.SetInnerHtml(): Element '" + elem + "' could not be found!", true);
	return false;
};
//-----------------------------------------
/**
* Evaluate HTML enclosed javascripting.
* @param string html HTML containing the javascript.
* @param boolean use_elems Makes the it create DOM elements.
* @param boolean browser_depend Makes .
* @returns void
*/
SfLib.EvaluateHtml = function (html, use_elems)
{
	// Only Firefox 3 executes HTML embeded javascript when inserted into the DOM.
	if (BrowserDetect.browser == 'Firefox' &&	BrowserDetect.version < 4)
		return;
	//var re = '<script.*>[ \t\n\r]*\/\/<\!\[CDATA\[|[ \t\n\r]*\/\/\]\]>[ \t\n\r]*<\/script>';
	var re = '<script.*>[ \t\n\r]*|[ \t\n\r]*<\/script>';
	var chunks = html.split(new RegExp(re, 'gi'));
	for (var i = 1; i < chunks.length; i += 2)
	{
		if (typeof chunks[i] == 'undefined')
			continue;
		// When using elements.
		if (use_elems)
		{
			// Create a script element.
			var selem  = document.createElement('script');
			selem.lang = 'javascript';
			selem.type = 'text/javascript';
			selem.text  = chunks[i];
			// Append it to inpage element.
			elem.appendChild(selem);
		}
		// If not using DOM elements evaluate.
		else
			eval(chunks[i]);
	}
};
//---------------------------------------------------------------------------
/**
* Posts parameters to the passed url and sets the inner html of an element.
* @param string/HTMLElement ID of the elemen object itself can be passed.
* @param string URL to the content.
* @param string Parameters to post.
* @param boolean Makes the embeded javascript to be evaluated/executed.
* @returns boolean
*/
SfLib.SetInnerHtmlByHttpPost = function (elem_id, url, to_post, evaluate)
{
	if (BrowserDetect.browser != 'Explorer')
	{
		// Element is removed when SetInnerHtml is called.
		var elem = WaitOverlay.CreateElement(elem_id);
		var html = this.GetByHttpPost(url, to_post);
		WaitOverlay.RemoveElement(elem);
		if (this.ContainsHtmlDocType(html, true, url))
			return false;
		return this.SetInnerHtml(elem_id, html, evaluate);
	}
	// Regular for IE no fancy wait overlay.
	return this.SetInnerHtml(elem_id, this.GetByHttpPost(url, to_post), evaluate);
};
//---------------------------------------------------------------------------
/**
* Replaces the current document using the returned content of the post.
* @param string URL to the content.
* @param string Parameters to post.
* @returns void
*/
SfLib.SetDocumentByHttpPost = function (url, to_post)
{
	var content = this.GetByHttpPost(url, to_post);
	var newdoc = document.open("text/html", "replace");
	//newdoc.write("<!-- Generated from within other -->");
	newdoc.write(content);
	newdoc.close();
};
//---------------------------------------------------------------------------
/**
* URL-encodes string
* @param string
* @returns string
*/
SfLib.RawUrlEncode = function (str)
{
	var hash_map = {}, unicodeStr='', hexEscStr='';
	var ret = str.toString();
	var replacer = function (search, replace, str)
	{
		var tmp_arr = [];
		tmp_arr = str.split(search);
		return tmp_arr.join(replace);
	};
	// The hash_map is identical to the one in urldecode.
	hash_map["'"] = '%27';
	hash_map['('] = '%28';
	hash_map[')'] = '%29';
	hash_map['*'] = '%2A';
	hash_map['~'] = '%7E';
	hash_map['!'] = '%21';
	hash_map['\u20AC'] = '%80';
	hash_map['\u0081'] = '%81';
	hash_map['\u201A'] = '%82';
	hash_map['\u0192'] = '%83';
	hash_map['\u201E'] = '%84';
	hash_map['\u2026'] = '%85';
	hash_map['\u2020'] = '%86';
	hash_map['\u2021'] = '%87';
	hash_map['\u02C6'] = '%88';
	hash_map['\u2030'] = '%89';
	hash_map['\u0160'] = '%8A';
	hash_map['\u2039'] = '%8B';
	hash_map['\u0152'] = '%8C';
	hash_map['\u008D'] = '%8D';
	hash_map['\u017D'] = '%8E';
	hash_map['\u008F'] = '%8F';
	hash_map['\u0090'] = '%90';
	hash_map['\u2018'] = '%91';
	hash_map['\u2019'] = '%92';
	hash_map['\u201C'] = '%93';
	hash_map['\u201D'] = '%94';
	hash_map['\u2022'] = '%95';
	hash_map['\u2013'] = '%96';
	hash_map['\u2014'] = '%97';
	hash_map['\u02DC'] = '%98';
	hash_map['\u2122'] = '%99';
	hash_map['\u0161'] = '%9A';
	hash_map['\u203A'] = '%9B';
	hash_map['\u0153'] = '%9C';
	hash_map['\u009D'] = '%9D';
	hash_map['\u017E'] = '%9E';
	hash_map['\u0178'] = '%9F';
	// Begin with encodeURIComponent, which most resembles PHP's encoding functions
	ret = encodeURIComponent(ret);
	for (unicodeStr in hash_map)
	{
		hexEscStr = hash_map[unicodeStr];
		ret = replacer(unicodeStr, hexEscStr, ret); // Custom replace. No regexing
	}
	// Uppercase for full PHP compatibility
	return ret.replace(/(\%([a-z0-9]{2}))/g, function (full, m1, m2){return "%"+m2.toUpperCase();});
};
//---------------------------------------------------------------------------
/**
* Escapes all charaters excluding the '+' sign.
* @param string s
* @returns string
*/
SfLib.EscapeUrl = function (s)
{
	if (typeof(s) != 'string')
		return '';
	s = s.split('+');
	for (var i in s)
		s[i] = this.RawUrlEncode(s[i]);
	return s.join('%2B');
};
//---------------------------------------------------------------------------
/**
* Unescapes characters into HTML entities.
* @param string
* @returns string
*/
SfLib.UnescapeHtml = function (html)
{
	var htmlNode = document.createElement('div');
	htmlNode.innerHTML = html;
	if (typeof htmlNode.innerText == 'string')
		return htmlNode.innerText; // IE
	return htmlNode.textContent; // FF and the rest.
};
//---------------------------------------------------------------------------
/**
* Builds a query string of the passed form.
* @param HTMLFormElement/string Form element or id string.
* @returns string
*/
SfLib.GetFormPostQuery = function (theform)
{
	// When a string is passed look the form name up.
	if (typeof(theform) == 'string')
	{
		var s = theform;
		theform = document.forms[theform];
		if (!theform)
			return this.DebugOut("Form '" + s + "' does not exist.", true);
	}
	//
	var qs = '';
	if (!theform)
		return this.DebugOut("Form does not exist.");
	else
	{
		// Cannot be replace using for ... in statement!!!!
		for (e = 0; e < theform.elements.length; e++)
		{
			// Only inputs with a type are allowed and so filtering fieldset tags.
			if (typeof theform.elements[e].type == 'undefined')
				continue;
			// Only inputs with the name set are allowed.
			if (theform.elements[e].name == '' || theform.elements[e].disabled)
				continue;
			// Only get the one radio that is checked.
			if (theform.elements[e].type == 'radio' && !theform.elements[e].checked)
				continue;
			// Only get the one chweckbox that is checked.
			if (theform.elements[e].type == 'checkbox' && !theform.elements[e].checked)
				continue;
			// When it is a select with multiple selectedable items.
			if (theform.elements[e].type == 'select-multiple')
			{
			  for (i = 0; i < theform.elements[e].options.length; i++)
			  {
			    if (theform.elements[e].options[i].selected)
			    {
			    	qs += (!qs.length) ? '' : '&';
						qs += theform.elements[e].name + '=' + SfLib.RawUrlEncode(theform.elements[e].options[i].value);
			    }
			  }
				continue;
			}
			// Append the name and encoded value to the returned query string.
			var name = theform.elements[e].name;
			qs += (!qs.length) ? '' : '&';
			qs += name + '=' + SfLib.RawUrlEncode(theform.elements[e].value);
		}
	}
	return qs;
};
//---------------------------------------------------------------------------
/**
* Function to limit the maximum amount of characters in a text area field.
* @param HTMLAreaElement
* @param integer lengthmax
* @returns void
*/
SfLib.CheckTextAreaLength = function (self, lengthmax)
{
	if (self.value.length > lengthmax)
		self.value = self.value.substr(0, lengthmax);
};
//---------------------------------------------------------------------------
/**
* HTML-Encode the supplied input
* Parameters:
* (String)  source    The text to be encoded.
* (boolean) display   The output is intended for display.
*                     If true:
*                     * Tabs will be expanded to the number of spaces
*                       indicated by the 'tabs' argument.
*                     * Line breaks will be converted to <br />.
*                     If false:
*                     * Tabs and linebreaks get turned into &#____;
*                       entities just like all other control characters.
* (integer) tabs      The number of spaces to expand tabs to.  (Ignored
*                     when the 'display' parameter evaluates to false.)
*/
SfLib.HtmlEncode = function (source, display, tabs)
{
	function special(source)
	{
		var result = '';
		for (var i = 0; i < source.length; i++)
		{
			var c = source.charAt(i);
			if (c < ' ' || c > '~')
				c = '&#' + c.charCodeAt() + ';';
			result += c;
		}
		return result;
	}

	function format(source)
	{
		// Use only integer part of tabs, and default to 4
		tabs = (tabs >= 0) ? Math.floor(tabs) : 4;
		// split along line breaks
		var lines = source.split(/\r\n|\r|\n/);
		// expand tabs
		for (var i = 0; i < lines.length; i++)
		{
			var line = lines[i];
			var newLine = '';
			for (var p = 0; p < line.length; p++)
			{
				var c = line.charAt(p);
				if (c === '\t')
				{
					var spaces = tabs - (newLine.length % tabs);
					for (var s = 0; s < spaces; s++)
					{
						newLine += ' ';
					}
				}
				else
				{
					newLine += c;
				}
			}
			// If a line starts or ends with a space, it evaporates in html
			// unless it's an nbsp.
			newLine = newLine.replace(/(^ )|( $)/g, '&nbsp;');
			lines[i] = newLine;
		}
		// re-join lines
		var result = lines.join('<br />');
		if (BrowserDetect.browser == 'Explorer')
			result += '<br />';
		// break up contiguous blocks of spaces with non-breaking spaces
		result = result.replace(/  /g, ' &nbsp;');
		// tada!
		return result;
	}
	// Bailout when the source parameter is not a string.
	if (typeof source != 'string')
		return '';
	//
	var result = source;
	// ampersands (&)
	result = result.replace(/\&/g,'&amp;');
	// less-thans (<)
	result = result.replace(/\</g,'&lt;');
	// greater-thans (>)
	result = result.replace(/\>/g,'&gt;');
	//
	if (display)
	{
		// format for display
		result = format(result);
	}
	else
	{
		// Replace quotes if it isn't for display,
		// since it's probably going in an html attribute.
		result = result.replace(new RegExp('"','g'), '&quot;');
	}
	// special characters
	result = special(result);
	// tada!
	return result;
};
//---------------------------------------------------------------------------
/**
* Object handling the resizing of the background image of the given element.
* @constructor
* @param string/HTMLElement ID of the elemen object itself can be passed.
* @param function
* @param number Pixel width.
* @param number Pixel height.
* @param string Optional options passed to the funciton.
*/
function TBackgroundImageResizer(elem_id, urlfunc, width, height, options)
{
	if (typeof elem_id != 'string')
		alert('TBackgroundBgImageResizer(): Needs an element ID!');
	/**
	* Assign the function.
	* @type function
	*/
	this.UrlFunc = urlfunc;
	/**
	* @type string
	*/
	this.Options = options;
	/**
	* Holds the pixel height of the image.
	* @type number
	*/
	this.Height = height;
	/**
	* Holds the pixel width of the image.
	* @type number
	*/
	this.Width = width;
	/**
	* Holds the timer index.
	* @type integer
	*/
	this.Timer = null;
	/**
	* Holds the element having the background image.
	* @type string
	*/
	this.ElemId = elem_id;
	/**
	* Handle the windows resize event.
	* @param event Build-in event class.
	*/
	this.EvResize = function(ev)
	{
		// If a timeout is pending clear it.
		if (this.Timer != null)
		{
			clearTimeout(this.Timer);
			this.Timer = null;
		}
		this.Resize();
	};
	/**
	* Function call resize manually.
	* @public
	* @returns void
	*/
	this.Resize = function()
	{
		var elem = document.getElementById(this.ElemId);
		if (this.Height)
		{
			if (typeof this.Height == 'number')
				this.Height = '' + this.Height + 'px';
			elem.style.height = this.Height;
		}
		elem.style.backgroundRepeat = 'no-repeat';
		this.Timer = window.setTimeout(new Closure(this, 'DoResize').Call, 300);
	};
	/**
	* Private function.
	* @returns void
	*/
	this.DoResize = function()
	{
		var elem = document.getElementById(this.ElemId);
		if (elem)
		{
			// Only when the tab is visible update the image.
			if (SfLib.IsVisible(elem) && SfLib.IsVisible(elem.parentNode))
			{
				// Retrieve the url for the image.
				var url = this.UrlFunc(this.ElemId, elem.clientWidth, elem.clientHeight, this.Options);
				// Assign the url for the image.
				elem.style.backgroundImage = "url('" + url + "')";
			}
		}
	};
	// Attach event handler using closure for resizing this image.
	SfLib.AddEvent(window, 'resize', new Closure(this, 'EvResize').Call);
}
//---------------------------------------------------------------------------
/**
* @class Reduces the amount events like resize in the internet explorer.
* @constructor
* @param function Callback function
* @param integer Defaults to 100
*/
function TEventReducer(callback, time)
{
	// When time param was not passed default it to 100 ms.
	if (typeof time == 'undefined') time = 100;
	/*
	* Trick to access this objects members from the Call() function.
	* @private
	*/
	var self = this;
	/**
	* Store the passed params.
	* @private
	* @type integer
	*/
	this.Time = time;
	/**
	* Store the passed params.
	* @private
	* @type integer
	*/
	this.Callback = callback;
	/**
	* Holds the timer index.
	* @type integer
	*/
	this.Timer = null;
	/**
	* Handles the event call and sets or resets a timer.
	* @param event Build-in event class.
	* @public
	*/
	this.Call = function (ev)
	{
		// Store the event info.
		self.Event = ev;
		// If a timeout is pending clear it.
		if (self.Timer != null)
		{
			clearTimeout(self.Timer);
			self.Timer = null;
		}
		// Set a new timer event.
		//this.TheClosure.Call
		self.Timer = window.setTimeout((function(){self.Callback(self.Event);}), self.Time);
	};
	//
	return this;
}
//---------------------------------------------------------------------------
/**
* @class Class for handling validation of input values.
* @type Validator
* @example
* // Example to reimplement a valdition handler.
* // Make a copy of the previous handler.
* Validator.Validate_regexp_old = Validator.Validate_regexp;
* // Overload the original function.
* Validator.Validate_regexp = function (input, required, val_opts)
* {
*   this.Validate_regexp_old(input, required, val_opts);
* };
*/
var Validator =
{
	/**
	* @private
	* @type HTMLInputElement
	* Input which is actually visible when a hidden one is evaluated.
	*/
	VisibleInput: null,
	/**
	* Element which needs to be colored too.
	* @public
	* @type HTMLElement
	*/
	ColorElem: null,
	/**
	* @private
	* Holds the generate messages.
	* @type Array
	*/
	ErrorMsgs: Array(),
	/**
	* @private
	* Submits a form by simulating a click of a submit button even when hidden.
	* @param string inpname
	* @param string msg
	* @returns void
	*/
	AddMessage: function (input, msg, header)
	{
		// When not a string assume an element.
		if (typeof input != 'string')
			input = input.name;
		//
		SfLib.DebugOut(input + ': ' + msg);
		//
		if (!this.ErrorMsgs[input])
		{
			this.ErrorMsgs[input] = Array();
			this.ErrorMsgs[input].push('?header?');
		}
		// Update the first which is the header.
		if (header)
			this.ErrorMsgs[input][0] = msg;
		else
			this.ErrorMsgs[input].push(msg);
	},
	/**
	* Returns tghe formatted error message.
	*/
	GetErrorMsg: function (heading)
	{
		var retval = heading;
    for(var key in this.ErrorMsgs)
    {
    	retval += "\n\n\t" + SfLib.UnescapeHtml('&bull;&nbsp;') + this.ErrorMsgs[key][0] + "\t(" + key + ')';
    	for (var i = 1; i < this.ErrorMsgs[key].length; i++)
      	retval += "\n\t\t" + this.ErrorMsgs[key][i];
    }
    return retval;
	},
	/**
	* Submits a form by simulating a click of a submit button even when hidden.
	* @param HTMLFormElement theform
	* @returns void
	*/
	SubmitForm: function (theform)
	{
		var submit_elem = null;
		//
		for (var inp in theform.elements)
		{
			if (theform.elements[inp] && theform.elements[inp].type == 'submit')
			{
				submit_elem = theform.elements[inp];
				break;
			}
		}
		// When an element was found.
		if (submit_elem)
		{
			// Store current disabled state.
			var disabled = submit_elem.disabled;
			submit_elem.disabled = false;
			submit_elem.click();
			// Restore disabled state.
			submit_elem.disabled = disabled;
		}
		else
			SfLib.DebugOut("Validator.SubmitForm(): Could not find \'submit\' input in form '" +
				theform.name + "'!", 1);
	},
	/**
	* Returns true when the form inputs are validated succesfully.
	* @param HTMLFormElement theform
	* @param boolean notify
	* @returns boolean
	*/
	CheckForm: function (theform, notify)
	{
		var form  = null;
		// See if the name of the form was passed.
		if (typeof(theform) == 'string')
			form = document.forms[theform];
		// Asume the object was passed.
		else if (typeof(theform) == 'object')
			form = theform;
		// Check if
		if (form == null)
		{
			SfLib.DebugOut("Validator.CheckForm('" + theform + "'): The passed form does not exist.", true);
			return false;
		}
		var retval = true;
		// Reset the message array.
		this.ErrorMsgs = [];
		//
		for (var i = 0; i < form.elements.length; i++)
		{
			if (typeof(form.elements[i]) == 'object')
			{
				if (form.elements[i].getAttribute('validate') != null)
				{
					if (this.CheckInput(form.elements[i]) == false)
					{
						this.AddMessage(form.elements[i], this.VisibleInput.title, true);
						retval = false;
					}
				}
			}
		}
		// Notify when needed.
		if (!retval && notify)
		{
    	if (form.getAttribute('lang') != 'nl')
    		SfLib.DebugOut(this.GetErrorMsg('Form validation error(s) in field(s):'), true);
    	else
    		SfLib.DebugOut(this.GetErrorMsg('Formulier validatie fout(en) in de veld(en):'), true);
		}
		// Signal if there are errors.
		return retval;
	}
	,
	CheckInput: function(input, focused)
	{
		// Initialize the data member for this call.
		this.VisibleInput = input;
		this.ColorElem = null;
		// Check if the uinput is required.
		var required = input.getAttribute('__required') != null;
		// See if this input needs validated or not depending on the attribute.
		var validate = input.getAttribute('validate');
		// When no validation filter has been set use the default one.
		if (validate == null || validate.length == 0)
			validate = 'default:';
		var retval = true;
		// Split the attribute up in two values.
		if (validate.indexOf(':') == -1)
			var val_type = validate;
		else
			var val_type = validate.substring(0, validate.indexOf(':'));
		var val_opts = validate.substring(validate.indexOf(':') + 1, validate.length);
		// Look for a handler for the button clicked.
		var func = 'this.Validate_' + val_type;
		if (eval('typeof(' + func + ')') == 'function')
			retval = (eval(func + '(input, required, val_opts)'));
		else
			SfLib.DebugOut("Member function 'Validator.Validate_" + val_type + "' does not exist.", true);
		//
		var errcolbg = this.VisibleInput.getAttribute('errcolbg');
		if (errcolbg == null)	errcolbg = '#FFC0C0';
		var errcolborder = this.VisibleInput.getAttribute('errcolborder');
		if (errcolborder == null)	errcolborder = '#C000C0';
		// Set colors depending on the validation.
		if (retval || focused)
		{
			this.VisibleInput.style.backgroundColor = '';
			this.VisibleInput.style.borderColor = '';
			if (this.ColorElem)
			{
				this.ColorElem.style.backgroundColor = '';
				this.ColorElem.style.borderColor = '';
			}
		}
		else
		{
			this.VisibleInput.style.backgroundColor = errcolbg;
			this.VisibleInput.style.borderColor = errcolborder;
			if (this.ColorElem)
			{
				this.ColorElem.style.backgroundColor = errcolbg;
				this.ColorElem.style.borderColor = errcolborder;
			}
		}
		//
		//SfLib.DebugOut("Validated [" + retval + "] field ' " + input.name + "' with type '" + val_type + "' and options.'" + val_opts + "'");
		return retval;
	},
	/*
	* Returns true when a passed value checks out.
	*/
	Validate_default: function (input, required, val_opts)
	{
		// When this value is required blank is not accepted.
		if (required && input.value == '')
		{
    	if (input.form.getAttribute('lang') != 'nl')
    		this.AddMessage(input, 'The value is empty but required!');
    	else
    		this.AddMessage(input, 'De waarde is leeg maar is vereist!');
			return false;
		}
		// Accept the input.
		return true;
	},
	/*
	* Returns true when a passed value checks out.
	*/
	Validate_regexp: function (input, required, val_opts)
	{
		// When this value is required blank is not accepted.
		if (required && input.value == '')
		{
    	if (input.form.getAttribute('lang') != 'nl')
    		this.AddMessage(input, 'The value is empty but required!');
    	else
    		this.AddMessage(input, 'De waarde is leeg maar is vereist!');
			return false;
		}
		// When not required an the value is empty it is accepted.
		if (!required && input.value == '')
			return true;
		// Do the regexp match.
		if (!SfLib.RegExpMatch(input.value, val_opts))
		{
    	if (input.form.getAttribute('lang') != 'nl')
    		this.AddMessage(input, 'The value does not match regular expression \'' + val_opts + '\' !');
    	else
    		this.AddMessage(input, 'De waarde match niet met reguliere expressie \'' + val_opts + '\' !');
			return false;
		}
		return true;
	},
	/*
	* Returns true when a passed element is validated tiny mce editor.
	*/
	Validate_html: function(input, required, val_opts)
	{
		var id = input.getAttribute('id');
		// Check if the ID is from tiny MCE.
		if (SfLib.RegExpMatch(id, '/^timy_mce_editor_[0-9]+$/i'))
		{
			var maxlength = input.getAttribute('maxlength');
			maxlength = maxlength ? parseInt(maxlength) : 0;
			// Get the associated tiny MCE editor instance.
      var ed = tinyMCE.getInstanceById(id);
      // This happens with an inpage some how so we ignore it.
      if (!ed)
      	return true;
      // Check the max length of the instance when needed.
      if (maxlength && ed.getContent().length > maxlength)
      {
      	if (input.form.getAttribute('lang') != 'nl')
      		this.AddMessage(input, 'Length of text is too large. Maximum allowed length is ' + maxlength + '!');
      	else
      		this.AddMessage(input, 'Lengte van de tekst is te lang. Maximum toegestane lengte is ' + maxlength + '!');
      	return false;
      }
			// When this value is required blank is not accepted.
			// To check this strip the HTML tags from the HTML text.
			if (required && !SfLib.UnescapeHtml(ed.getContent().replace(/<\S[^><]*>/g, '')).trim().length)
			{
	    	if (input.form.getAttribute('lang') != 'nl')
	    		this.AddMessage(input, 'The value is empty but required!');
	    	else
	    		this.AddMessage(input, 'De waarde is leeg maar is vereist!');
	    	//
				return false;
			}
		}
		// Accept the input.
		return true;
	},
	/*
	* Returns true when a passed value checks out.
	*/
	Validate_range_int: function (input, required, val_opts)
	{
		var value = input.value.trim();
		// When this value is required blank is not accepted.
		if (required && value == '')
		{
    	if (input.form.getAttribute('lang') != 'nl')
    		this.AddMessage(input, 'The value is empty but required!');
    	else
    		this.AddMessage(input, 'De waarde is leeg maar is vereist!');
    	//
    	return false;
		}
		// When not required and the value is not empty.
		if (!required && !value.length)
			return true;
		// Convert string to integer value.
		var value = parseInt(value);
		// Check if a integer was parsed correctly.
		if (('' + value) == 'NaN')
		{
    	if (input.form.getAttribute('lang') != 'nl')
      	this.AddMessage(input, 'The value is not an integer number.!');
    	else
    		this.AddMessage(input, 'De waarde is geen integer nummer!');
			return false;
		}
		// Separate the options.
		var opts = val_opts.split(',');
		var minval = parseInt(opts[0]);
		var maxval  = parseInt(opts[1]);
		// Update the input value with a clipped value when configured.
		if (parseInt(opts[2]))
			input.value = Math.min(Math.max(minval, value), maxval);;
		// When not required and the value is empty it is accepted.
		if (value >= minval && value <= maxval)
			return true;
		//
  	if (input.form.getAttribute('lang') != 'nl')
  		this.AddMessage(input, 'The value is is not in the range of ' + minval +' .. ' + maxval + ' !');
  	else
  		this.AddMessage(input, 'De waarde is niet in het bereik van ' + minval +' .. ' + maxval + ' !');
		//
		return false;
	},
	/*
	* Returns true when a passed value checks out.
	*/
	Validate_range_float: function (input, required, val_opts)
	{
		var value = input.value.trim();
		// When this value is required blank is not accepted.
		if (required && value == '')
		{
    	if (input.form.getAttribute('lang') != 'nl')
    		this.AddMessage(input, 'The value is empty but required!');
    	else
    		this.AddMessage(input, 'De waarde is leeg maar is vereist!');
    	//
    	return false;
		}
		// When not required and the value is not empty.
		if (!required && !value.length)
    	return true;
		// Convert string to floating point value.
		var value = parseFloat(value);
		// Check if a floating point was parsed correctly.
		if (('' + value) == 'NaN')
		{
    	if (input.form.getAttribute('lang') != 'nl')
      	this.AddMessage(input, 'The value is not a floating point!');
    	else
      	this.AddMessage(input, 'De waarde is geen floating point!');
			return false;
		}
		// Separate the options.
		var opts = val_opts.split(',');
		var minval = parseFloat(opts[0]);
		var maxval  = parseFloat(opts[1]);
		// Update the input value with a clipped value when configured.
		if (parseInt(opts[2]))
			input.value = Math.min(Math.max(minval, value), maxval);
		// When not required and the value is empty it is accepted.
		if (value >= minval && value <= maxval)
			return true;
		//
  	if (input.form.getAttribute('lang') != 'nl')
  		this.AddMessage(input, 'The value is is not in the range of ' + minval +' .. ' + maxval + ' !');
  	else
  		this.AddMessage(input, 'De waarde is niet in het bereik van ' + minval +' .. ' + maxval + ' !');
		//
		return false;
	},
	/*
	* Returns true when a passed value checks out.
	*/
	Validate_range_date: function (input, required, val_opts)
	{
		var value = input.value.trim();
		// When this value is required blank is not accepted.
		if (required && value == '')
		{
    	if (input.form.getAttribute('lang') != 'nl')
    		this.AddMessage(input, 'Is empty but required!');
    	else
    		this.AddMessage(input, 'Is leeg maar is vereist!');
    	return false;
		}
		// When not required and the value is not empty.
		if (!required && !value.length)
		{
    	if (input.form.getAttribute('lang') != 'nl')
    		this.AddMessage(input, 'Is empty but required!');
    	else
    		this.AddMessage(input, 'Is leeg maar is vereist!');
    	return false;
		}
		// Regular expresion check for date formated string.
		var regexp = '/^(19|20)[0-9]{2}-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])$/';
		// Check if a date formatted srtring was passed correctly.
		if (!SfLib.RegExpMatch(value, regexp))
		{
    	if (input.form.getAttribute('lang') != 'nl')
  			this.AddMessage(input, "The value does represent a date in the form YYYY-MM-DD!");
    	else
  			this.AddMessage(input, "De waarde is geen datum in de form van JJJJ-MM-DD!");
			return false;
		}
		//
		value = parseDate(value);
		// Separate the options.
		var opts = val_opts.split(',');
		// Check the minimum value.
		if (!SfLib.RegExpMatch('' + opts[0], regexp))
		{
    	if (input.form.getAttribute('lang') != 'nl')
  			this.AddMessage(input, "Date filter range min value '" + opts[0] + "' does not match '" + regexp + "' !");
    	else
  			this.AddMessage(input, "Datum filter bereik minimum waarde '" + opts[0] + "' matcht '" + regexp + "' niet!");
			return false;
		}
		// Check the maximum value.
		if (!SfLib.RegExpMatch('' + opts[1], regexp))
		{
			this.AddMessage(input, "Date filter range max value '" + opts[1] + "' does match '" + regexp + "' !");
			return false;
		}
		// Convert al string to date values.
		var minval = parseDate(opts[0]);
		var maxval  = parseDate(opts[1]);
		// Update the input value with a clipped value when configured.
		if (parseInt(opts[2]))
			input.value = (new Date(Math.min(Math.max(minval, value), maxval))).format('Y-m-d');
		// When not required and the value is empty it is accepted.
		if (value >= minval &&  value <= maxval)
			return true;
		//
  	if (input.form.getAttribute('lang') != 'nl')
  		this.AddMessage(input, "Date '" + (new Date(value)).format('Y-m-d') +	"' out of range '" + opts[0] + " ... " + opts[1] + "' !");
  	else
  		this.AddMessage(input, "Datum '" + (new Date(value)).format('Y-m-d') +	"' is niet in het bereik van '" + opts[0] + " ... " + opts[1] + "' !");
		//
		return false;
	},
	/*
	* Returns true when a passed value checks out.
	*/
	Validate_select: function (input, required, val_opts)
	{
		// When the internet explorer is active the color must also be changed of the parentNode.
		if (input.getAttribute('usediv') != null)
			this.ColorElem = input.parentNode;
		// When this value is required blank is not accepted.
		if (required);
			return input.value != '';
		return true;
	},
	/*
	* Returns true when a passed value checks out.
	*/
	Validate_radio: function (input, required, val_opts)
	{
		var selected = false;
		// Get the last element.
		var last_elem = null;
		for( var i=0; i < input.form.elements.length; i++)
		{
			var elem = input.form.elements[i];
			//
			if (elem.type == 'radio' && input.name == elem.name)
			{
				last_elem = elem;
				// If an input is selected set the local variable.
				if (elem.checked)
					selected = true;
			}
		}
		// Only act on the last radio element.
		if (last_elem == null || last_elem != input)
			return true;
		// Set the color element which is the parent.
		if (input.getAttribute('usediv') != null)
		{
			this.ColorElem = input.parentNode;
			while (this.ColorElem.getAttribute('usediv') != null)
				this.ColorElem = this.ColorElem.parentNode;
		}
		// When this value is required blank is not accepted.
		if (required && ! selected)
		{
    	this.AddMessage(input, 'Selection has not been made but required!');
    	return false;
		}
		return true;
	},
	/*
	* Returns true when a passed value checks out.
	*/
	Validate_selectdlg: function (input, required, val_opts)
	{
		if (input.type == 'hidden')
			this.VisibleInput = SfLib.GetChildByTag(this.VisibleInput.parentNode, 'INPUT');
		// When this value is required blank is not accepted.
		if (required && input.value == '')
		{
			SfLib.DebugOut(input.value);
    	this.AddMessage(input, 'Selection has not been made but required!');
			return false;
		}
		return true;
	},
	/*
	* Returns true when a passed element is validated bank account number.
	*/
	Validate_banknum: function(input, required, val_opts)
	{
		// Check if number is a valid 7 digit 'Postbank' giro number (optionally prefixed with 'P'),
		// or more general 13 digit bank-number. Adds 'P' to 7 digit numbers.
		var text = input.value;
		if (!text.length)
			return !required;
		// Keep only the numbers.
		text = text.replace(/[^0-9]/gi,'');
		// Postbank.
		if (text.length >= 3 && text.length <= 7)
		{
			input.value = 'P' + text;
			return true;
		}
		input.value = text;
		// Do the 11-test on a banknumber with length 9 or 10.
		if (text.length != 9 && text.length != 10)
		{
			this.AddMessage(input, "Banknumber length error (" + text.length + ").");
			return false;
		}
		Sum = 0;
		Factor = text.length;
		for (i=0; i < text.length; i++)
		{
			Digit = parseInt(text.substring(i,i+1));
			Sum += parseInt(Factor-- * Digit);
		}
		if ((Sum % 11) != 0)
		{
			this.AddMessage(input, "Banknumber 11-check error!");
			return false;
		}
		//
		return true;
	}
};
//---------------------------------------------------------------------------
/**
* Imports/Replaces a javascript dynamically. Only functions and variables
* with a same name in the script are replaced.
* Beware a new decalred or replaced function can only be called after control
* is relinguised to the browser. IE and FF differ a bit but this rule
* applies to both. Use setTimeOut function to make a call in the same script.
* @param string Relative or absolute url to the script file.
* @param string Tag ID of the script in the header.
* @returns string
*/
SfLib.JavascriptImport = function(url, id, onload)
{
	//SfLib.DebugOut('Importing JavaScript: ' + url);
	var script = null;
	var replace_script = null;
	// Find the element ID when defined.
	if (typeof id != 'undefined')
		replace_script = document.getElementById(id);
	// When an url is specified create a new or replace the script element.
	if (url)
	{
		// Create a element when not found.
		var script = document.createElement('script');
		script.type = 'text/javascript';
		//script.src = url;
		// Set the ID when exists.
		if (typeof id != 'undefined')
			script.id = id;
		// When a callback has been passed assign it.
		if (onload)
		{
			if (BrowserDetect.browser != 'Explorer')
				this.AddEvent(script, 'load', onload);
			else
			{
				script.onreadystatechange = function (self)
				{
					if (this.readyState == 'loaded')
						onload();
				};
			}
		}
	}
	//
	if (script)
	{
		// When the to be replaced script exists.
		if (replace_script)
		{
			document.getElementsByTagName('head')[0].replaceChild(script, replace_script);
			// Assigning script url here will trigger executing the script.
			script.src = url;
		}
		else
		{
			document.getElementsByTagName('head')[0].appendChild(script);
			// Assigning script url here will trigger executing the script.
			script.src = url;
		}
	}
	else
	{
		if (replace_script)
		{
			document.getElementsByTagName('head')[0].removeChild(replace_script);
		}
	}
	//
	return script;
};
//---------------------------------------------------------------------------
/**
* Returns the base URL of the passed full URL string.
* When left empty the document location is used for passing the full URL.
* @param string (optional)
* @returns string
*/
SfLib.GetBaseUrl = function (href)
{
	var s, p;
	if (typeof href == 'string')
		s = href;
	else
		s = location.href;
	// Look for the start of parameters if it is there.
	p = s.indexOf('?');
	// When found strip the parameters.
	if (p >= 0)
		s = s.substring(0, p);
	// Find the last
	p = s.lastIndexOf('/');
	// When found strip the parameters.
	if (p >= 0)
		s = s.substring(0, p + 1);
	//
	return s;
};
//---------------------------------------------------------------------------
/**
* Imports/Replaces a link tag dynamically. Only functions and variables
* @param string url Relative or absolute url to the link file.
* @param string id Tag ID of the link in the header.
* @returns void
*/
SfLib.StylesheetImport = function (url, id)
{
	var link = null;
	var replace_link = null;
	// Find the element ID when defined.
	if (typeof id != 'undefined')
		replace_link = document.getElementById(id);
	// When an url is specified create a new or replacement link element.
	if (url)
	{
		// Create a element when not found.
		var link = document.createElement('link');
		link.type = 'text/css';
		link.rel = 'stylesheet';
		link.media = 'screen';
		// Set the ID when exists.
		if (typeof id != 'undefined')
			link.id = id;
	}
	//
	if (link)
	{
		// When the to be replaced link exists.
		if (replace_link)
		{
			document.getElementsByTagName('head')[0].replaceChild(link, replace_link);
			// Assigning link url here will trigger reading the link.
			link.href = url;
		}
		else
		{
			document.getElementsByTagName('head')[0].appendChild(link);
			// Assigning link url here will trigger reading the link.
			link.href = url;
		}
	}
	else
	{
		if (replace_link)
		{
			document.getElementsByTagName('head')[0].removeChild(replace_link);
		}
	}
	//
	return link;
};
//---------------------------------------------------------------------------
/**
* Tells if a key code is to ignore.
* @param event Buit-In key event.
* @returns boolean
*/
SfLib.IsKeyEventToIgnore = function (ev)
{
	return (ev.keyCode >= 16 && ev.keyCode <= 18) || (ev.keyCode == 91 && ev.charCode == 0);
};
//---------------------------------------------------------------------------
/**
* Returns the name of the key so it can be used in a case statment.
* @param event Buit-In key event.
* @returns string
*/
SfLib.GetKeyName = function (ev)
{
	var s = '';
	//
	if (ev.metaKey) s += 'M+';
	if (ev.shiftKey) s += 'S+';
	if (ev.ctrlKey) s += 'C+';
	if (ev.altKey) s += 'A+';
	//
	switch(ev.keyCode)
	{
		case 8: s += 'Backspace';break;
		case 9: s += 'Tab';break;
		case 13: s += 'Enter';break;
		case 16: s += 'Shift';break;
		case 17: s += 'Ctrl';break;
		case 18: s += 'Alt';break;
		case 19: s += 'Pause';break;
		case 27: s += "Esc";break;
		case 33: s += "PgUp";break;
		case 34: s += "PgDown";break;
		case 35: s += "End";break;
		case 36: s += "Home";break;
		case 37: s += "Left";break;
		case 38: s += "Up";break;
		case 39: s += "Right";break;
		case 40: s += "Down";break;
		case 45: s += "Insert";break;
		case 46: s += "Delete";break;
		case 112: s += "F1";break;
		case 113: s += "F2";break;
		case 114: s += "F3";break;
		case 115: s += "F4";break;
		case 116: s += "F5";break;
		case 117: s += "F6";break;
		case 118: s += "F7";break;
		case 119: s += "F8";break;
		case 120: s += "F9";break;
		case 121: s += "F10";break;
		case 122: s += "F11";break;
		case 123: s += "F12";break;
		default:
			{
				if (BrowserDetect.browser == 'Explorer')
				{
					if (ev.keyCode)
					{
						if (ev.keyCode >= 32 && ev.keyCode <= 127)
							s += String.fromCharCode(ev.keyCode).toUpperCase();
						else
							s += ev.keyCode;
					}
					else
						s += ev.keyCode;
				}
				else
				{
					if (ev.keyCode)
					{
						if (ev.keyCode >= 32 && ev.keyCode <= 127)
							s += String.fromCharCode(ev.keyCode).toUpperCase();
						else
							s += ev.keyCode;
					}
					else
						s += String.fromCharCode(ev.charCode).toUpperCase();
				}
			}
			break;
	}
	return s;
};
//---------------------------------------------------------------------------
/**
* Function to control the tabs of the tab control.
* @param HTMLElement
* @return boolean
*/
SfLib.ActivateTabPage = function(self)
{
	var selected = -1;
	// Get all the list items in a list.
	var elems = self.parentNode.parentNode.getElementsByTagName('LI');
	for (var i = 0; i < elems.length; i++)
	{
		// Deactivate the tab list item.
		elems.item(i).className = '';
		// When the item is the one clicked make it active.
		if (elems.item(i) == self.parentNode)
		{
			selected = i;
			self.parentNode.className = 'tabctrl_active';
			self.blur();
		}
	}
	var i = 0;
	if (selected < 0)
		return false;
	// Iterate through all the <div>'s contained by the parent of the <ul> tag.
	var nodes = self.parentNode.parentNode.parentNode.childNodes;
	for (var j = 0; j < nodes.length; j++)
		if (nodes.item(j).tagName == 'DIV')
			nodes.item(j).className = (i++ == selected) ? 'tabctrl_tab_active' : 'tabctrl_tab';
	return true;
};
//---------------------------------------------------------------------------
/**
* Installs a key event handler.
* @pram function Callback function.
*/
SfLib.AddKeyEventHandler = function(func)
{
	this.AddEvent(document, 'keydown', func);
};
//---------------------------------------------------------------------------
/**
* Stops propagation of the event.
* @param event Build-In event class.
* @returns boolean
*/
SfLib.StopPropagation = function (ev)
{
	// When event is handled stop further processing.
	if (BrowserDetect.browser == 'Explorer')
		ev.returnValue = false;
	else if (ev.preventDefault)
		ev.preventDefault();
	else if (ev.stopPropagation)
		ev.stopPropagation();
	// Return false by default so this function can be used in a return of a function for IE.
	return false;
};
//---------------------------------------------------------------------------
/**
* Evaluates an event handler
* Make an assigned event handler be called by evaluting the attached code.
* @param fucntion Event handler like 'elem.onclick'.
* @returns void
*/
SfLib.EvalEventHandler = function(handler)
{
	// Make the handler a string type.
	handler = '' + handler;
	var i = handler.indexOf('{');
	if (i >= 0)
		eval(handler.substring(i, handler.length));
};
//---------------------------------------------------------------------------
/**
* Returns true when a string is validated.
* the expression can be in the form i.e. /^[a-z]*$/i or ^[a-zA-Z]*$
* @param string Haystack.
* @param string Regular expression.
* @returns boolean
*/
SfLib.RegExpMatch = function(s, exp)
{
	var opts = '';
	// Check for delimiters and remove them preserving the options.
	if (exp.charAt(0) == '/')
	{
		var i = exp.lastIndexOf('/');
	 	opts = exp.substring(i + 1, exp.length);
	 	exp = exp.substring(1, i);
	}
	try
	{
		var regexp = new RegExp(exp, opts);
		var res = regexp.exec(s);
		return res ? (res.length > 0) : false;
	}
	catch (e)
	{
		this.DebugOut('Regular expression error "' + exp + '" ' + e + '!', 1);
		return false;
	}
};
//---------------------------------------------------------------------------
/**
* Returns the last style element in all the style sheets of the document.
* @param string selector Like 'DIV.content'
* @returns CSSStyleDeclaration object
*/
SfLib.GetStyleSheetStyleBySelector = function (selector)
{
	var retval = null;
	if(document.styleSheets)
		for (var i = 0; i < document.styleSheets.length; i++)
			for (var j = 0; j < document.styleSheets[i].rules.length; j++)
				if (document.styleSheets[i].rules[j].selectorText == selector)
					return retval = document.styleSheets[i].rules[j].style;
	return retval;
};
//---------------------------------------------------------------------------
/**
* Returns the property of the current style of an element.
* Only for none IE browsers.
* @param HTMLElment elem,
* @param string prop
* @returns scalar
*/
SfLib.GetStyleProperty = function(elem, prop)
{
//	if (BrowserDetect.browser == 'Explorer')
	{
		var path = prop.split('-');
		// Make a IE version CSS property name.
		for (var i = 1; i < path.length; i++)
		{
    	var f = path[i].charAt(0).toUpperCase();
    	path[i] = f + path[i].substr(1, path[i].length-1);
		}
		//if (typeof elem.currentStyle == 'object')
			return elem.currentStyle[path.join('')];
	}
	//return document.defaultView.
	return window.getComputedStyle(elem, null).getPropertyValue(prop);
};
//---------------------------------------------------------------------------
/**
* Shows the generated source of the current window in a new browser.
* @param string target
* @param integer width
* @param integer height
* @returns void
*/
SfLib.ShowGeneratedSource = function (target, width, height)
{
	var win = this.OpenWindow('', target, width, height);
	win.document.write('<html><head><title>Generated Source</title>');
	win.document.write('<head/><body style="font-family:monospace;font-size:10pt">');
	win.document.write(this.HtmlEncode(window.document.body.outerHTML, true, 2));
	win.document.write('</body></html>');
};
//---------------------------------------------------------------------------
/**
* When IE this function can return the clipboard content.
* @returns string
*/
SfLib.GetClipboard = function ()
{
	if ('undefined' != typeof(document.execCommand))
	{
		var elem = document.getElementById('__cliptext');
		if (!elem)
		{
			elem = document.createElement('textarea');
			elem.id = '__cliptext';
			elem.style.position = 'absolute';
			elem.style.left = '-100px';
			elem.style.height = '1px';
			elem.style.width = '1px';
			document.getElementsByTagName('body')[0].appendChild(elem);
		}
		if (elem.createTextRange)
		{
			elem.createTextRange().execCommand('paste');
			return elem.value;
		}
	}
	return null;
};
//---------------------------------------------------------------------------
/**
* Sets the clipboard.
* @returns string
*/
SfLib.SetClipboard = function (text)
{
	// When browser is IE.
	if(window.clipboardData && clipboardData.setData)
		window.clipboardData.setData('text',text);
	// Only for firefox ??
	else if (window.netscape)
	{
		try
		{
			netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
			// Create interface to clipboard.
			var clip = Components.classes['@mozilla.org/widget/clipboard;1'].createInstance(Components.interfaces.nsIClipboard);
			if (!clip)
			 	return;
			// Create a transferable.
			var trans = Components.classes['@mozilla.org/widget/transferable;1'].createInstance(Components.interfaces.nsITransferable);
			if (!trans)
			 	return;
			// Specify the encoding.
			trans.addDataFlavor('text/unicode');
			// Creeate to objects.
			var str = new Object();
			var len = new Object();
			var str = Components.classes["@mozilla.org/supports-string;1"].createInstance(Components.interfaces.nsISupportsString);
			var copytext = text;
			str.data = copytext;
			trans.setTransferData("text/unicode", str, copytext.length * 2);
			var clipid = Components.interfaces.nsIClipboard;
			if (!clip)
			 return false;
			clip.setData(trans, null, clipid.kGlobalClipboard);
		}
		catch (e)
		{
			this.DebugOut("Exception(" + e.name + ")\n" + e.message);
			alert('Enable in about:config \'signed.applets.codebase_principal_support\'.');
		}
	}
};
//---------------------------------------------------------------------------
/**
* Return the browser language as a language ISO code like en, nl or de.
* @returns string
*/
SfLib.GetBrowserLanguage = function ()
{
	if (BrowserDetect.browser == 'Explorer')
	{
		//navigator.userLanguage;
		//navigator.systemLanguage;
		return navigator.browserLanguage;
	}
	else
	{
		return navigator.language;
	}
};
//---------------------------------------------------------------------------
/**
* Implements function to determine the size of the box containing it.
* @param string text
* @param HTMLElement text
* @returns {integer: height, integer: width}
*/
SfLib.GetTextMetrics = function(text, el)
{
	if (!el)
		el = document.body;
	//
	var h = 0, w = 0;
	//
	var div = document.createElement('div');
	document.body.appendChild(div);
	div.style.position = 'absolute';
	div.style.left = 0;
	div.style.top = 0;
//	div.style.display = 'none';
	div.innerHTML = text;
	/*
	div.style.fontSize
	div.style.fontStyle
	div.style.fontWeight
	div.style.fontFamily
	div.style.lineHeight
	div.style.textTransform
	div.style.letterSpacing
	alert(Dump(div, 1));
		smooth: screen.fontSmoothingEnabled,
		style: Dump(div.currentStyle, 1),
	*/
	//
	var retval =
	{
		text: div.innerHTML,
		height: div.clientHeight,
		width: div.clientWidth
	};
	// Remove the temporary element.
	div.parentNode.removeChild(div);
	//
  return retval;
};
//---------------------------------------------------------------------------
/**
* Returns the selected text in the document/page.
* @returns string
*/
SfLib.GetSelectedText = function ()
{
	var txt = '';
	if (window.getSelection)
		txt += window.getSelection();
	else if (document.getSelection)
		txt += document.getSelection();
	else if (document.selection)
		txt += document.selection.createRange().text;
	return txt;
};
//---------------------------------------------------------------------------
/**
* Returns the input string repeat mult times
* @param string text
* @param integer multiplier
* @returns string
*/
SfLib.StrRepeat = function (text, multiplier)
{
  return new Array(multiplier + 1).join(text);
};
//---------------------------------------------------------------------------
/**
* @class Static class to hold static parameters.
* @type WaitOverlay
*/
var WaitOverlay =
{
	//----------------------------------------
	/**
	* Holds the style name.
	* @static
	* @type string
	*/
	StyleName: 'wait_overlay',
	/**
	* Holds the background style entry.
	* When null the back ground is not taken into the style.
	* @static
	* @type string
	*/
	Background: "center top repeat-y url('images/wait.gif') #FFF",
	/**
	* Holds the background color.
	* When null the border is not taken into the style.
	* @static
	* @type string
	*/
	Border: "1px dotted darkgray",
	/**
	* Holds opacity of the element.
	* When null the opacity is not taken into the style.
	* @static
	* @type float
	*/
	Opacity: 0.6,
	/**
	* Holds the style element when created and functions as a flag to create it only once.
	* @static
	* @type HTMLStyleElement
	*/
	StyleElement: null,
	//----------------------------------------
	/**
	* Creates the needed style element.
	* @private
	* @param string Stylename
	* @return string Style class name.
	*/
	CreateStyle: function()
	{
		// When the style element does not exist create one.
		if (!this.StyleElement)
		{
			// Assemble the rules for IE and FF.
			var rules = '';
			rules += "\n\tposition:absolute;";
			rules += "\n\tz-index:10000;";
			rules += "\n\ttop:0;";
			rules += "\n\tleft:0;";
			rules += "\n\twidth:99.5%;";
			rules += "\n\theight:99.5%;";
			rules += "\n\toverflow:hidden;";
			if (this.Background != null)
				rules += "\n\tbackground: " + this.Background + ";";
			if (this.Border != null)
				rules += "\n\tborder: " + this.Border + ";";
			if (this.Opacity != null)
			{
				rules += "\n\t-moz-opacity:" + this.Opacity + ";";
				rules += "\n\topacity:" + this.Opacity + ";";
			}
			//
			var style = null;
			var head = document.getElementsByTagName('head')[0];
			// Detect Explorer as the browser.
			if (BrowserDetect.browser == 'Explorer')
			{
				style = document.createStyleSheet();
				// Add rule for explorer because generates an warning in Firefox
				if (this.Opacity != null)
					rules += "\n\tfilter: alpha(opacity=" + (this.Opacity * 100) + ");";
				style.addRule("DIV." + this.StyleName, rules);
			}
			else if (BrowserDetect.browser == 'Chromium' || BrowserDetect.browser == 'Safari')
			{
				style = document.createElement('style');
				style.setAttribute('type', 'text/css');
				head.appendChild(style);
				document.styleSheets[document.styleSheets.length - 1].addRule("DIV." + this.StyleName, rules);
			}
			else
			{
				style = document.createElement('style');
				style.setAttribute('type', 'text/css');
				style.innerHTML = "DIV." + this.StyleName + "\n{\n" + rules + "\n}";
				head.appendChild(style);
			}
			this.StyleElement = style;
		}
		// Return the class name of the style.
		return this.StyleName;
	},
	//----------------------------------------
	/**
	* Removes the passed element from its parent child list.
	*/
	RemoveElement: function (elem)
	{
		if (elem && elem.parentNode)
		{
			// Restore the previous
			var style = elem.parentNode.getAttribute('__style_position');
			if (style != null)
				elem.parentNode.style.position = style;
			// Do the actual removal.
			elem.parentNode.removeChild(elem);
		}
	},
	//----------------------------------------
	/**
	* Creates a over lay div on the parent.
	* @param HTMLElement Parent node to attach the lement to.
	*/
	CreateElement: function(parent)
	{
		// Convert string to HTMLElement.
		if (typeof parent == 'string')
			parent = document.getElementById(parent);
		//
		if (!parent)
		{
			SfLib.DebugOut('WaitOverlay::CreateElement(): Invalid parent');
			return null;
		}
		// Needs this to limit the size of the overlay.
		if (parent.currentStyle.position == 'static')
		{
			// Store the original style position.
			parent.setAttribute('__style_position', parent.style.position);
			// Set the needed relative position.
			parent.style.position = 'relative';
		}
		// Create element that is used as the overlay.
		var elem = document.createElement('div');
		// Set the class for the element.
		elem.setAttribute('class', WaitOverlay.CreateStyle());
		elem.setAttribute('style', 'position:absolute');
		// When the parent has no height give the element zome hieght.
		height = SfLib.GetValueUnit(parent.currentStyle.height);
		if (!height.Value || (height.Value < 30 && height.Unit == 'px'))
			elem.style.height = '7em';
		// Append when a parent was passed.
		if (typeof parent == 'object')
			parent.appendChild(elem);
		// Return the created element.
		return elem;
	}
	//----------------------------------------
};
//---------------------------------------------------------------------------
/**
* Called when an inpuit needs to be converted during changes in HTML having en html input.
* @returns void
*/
SfLib.InitHtmlEditor = function (nodelay)
{
	if (nodelay && typeof AddaptTinyMCE == 'object')
		AddaptTinyMCE.Initialize();
	else
		setTimeout(function()	{if (typeof AddaptTinyMCE == 'object')
				AddaptTinyMCE.Initialize();}, 10);
};
//---------------------------------------------------------------------------
SfLib.JavascriptImport('jscripts/wddx.js', 'wddx');
SfLib.JavascriptImport('jscripts/json.js', 'json');
SfLib.JavascriptImport('jscripts/htmledit.js', 'htmledit');
//---------------------------------------------------------------------------
/*
* Create backward compatibility function entries using closures.
* Regexp to find function to prefix with 'SfLib.'.
* [^.a-zA-Z](<<function-names>>)\s*\(
'ActivateTabPage','AddEvent','AddKeyEventHandler','CheckTextAreaLength',
'ContainsHtmlDocType','CreateXmlHttpObject','DebugOut','Display','Dump',
'EscapeUrl','EvalEventHandler','EvaluateHtml','FormFirstInputFocus',
'GetBaseUrl','GetBrowserLanguage','GetByHttpPost','GetCheckboxes',
'GetChildById','GetChildByTag','GetChildByType','GetClass','GetClipboard',
'GetElementsByTagNames','GetFormPostQuery','GetJsonResultByHttpPost',
'GetKeyName','GetParentByTag','GetResultByHttpPost','GetScrollBarWidth',
'GetStyleProperty','GetStyleSheetStyleBySelector','GetTextMetrics',
'GetValueUnit','GetWindowInnerHeight','GetWindowInnerWidth','HtmlEncode',
'InArray','InitHtmlEditor','IsDisplayed','IsKeyEventToIgnore','IsVisible',
'JavascriptImport','OpenBrowser','OpenBrowserTab','OpenDialog','OpenWindow',
'RawUrlEncode','RegExpMatch','RemoveEvent','SetCheckboxes',
'SetDocumentByHttpPost','SetInnerHtml','SetInnerHtmlByHttpPost',
'ShowGeneratedSource','StopPropagation','StrRepeat','StylesheetImport',
'ToggleDisplay','ToggleVisibility','UnescapeHtml','Visibility','Void',
'XmlHttpAvailable'
*/
//Iterate through all functions and make them global.
if (!window['__common_lib_no_compat__'])
{
	for (var item in SfLib)
		if (typeof SfLib[item] == 'function')
			window[item] = new Closure(SfLib, item).Call;
	// Adjust wait overlay location.
	WaitOverlay.Background = "center top repeat-y url('/images/wait.gif') #FFF";
}
//---------------------------------------------------------------------------

