function BrowserDetector(detectArr) {
	/// Constructor

	/// Private Error object is declared
	var E = new Error();

	/// Private array with return messages
	var javacodeArr = new Array();
	javacodeArr[0]	= 'Java version OK.';
	javacodeArr[1]	= 'Java not enabled.';
	javacodeArr[2]	= 'Could not load java applet.';
	javacodeArr[3]	= 'Java applet returned empty string.';
	javacodeArr[4]	= 'Java not initialised.';
	javacodeArr[5]	= 'Error in splitting string string from TDPC.';
	javacodeArr[6]	= 'Error in stripping java vendor name.';
	javacodeArr[7]	= 'Site ID and security ID expected not provided.';
	javacodeArr[8]	= 'Java version is in exception list.';
	javacodeArr[9]	= 'Java version is to old.'
	javacodeArr[10]	= 'Java vendor not supported';
	javacodeArr[11]	= 'iframe could not be created';
	javacodeArr[12]	= 'No call back function for java check';
	javacodeArr[javacodeArr.length] = 'Unexpected error';

	/// Create public property-collection
	this.item = new ItemArray();
	/// Define properties name and type and add them to the property-collection
	this.item.add(this.item.newItemObj('name', this.name = 'Browserdetector'));
	this.item.add(this.item.newItemObj('type', this.type = 'custom'));

	/// Validate input type: convert if necessary
	if (typeof(detectArr) == 'string' && detectArr == 'all')
		detectArr = ['all'];

	this.getSettings = function(detectItemsArr) {
		/// Loop through array
		if (typeof(detectItemsArr) == 'object')
			for (var paramIndex = 0; paramIndex < detectItemsArr.length; paramIndex++)
				switch(detectItemsArr[paramIndex].toLowerCase()) {
					case 'domparser':
						getDOMparser(this);
						break;
					case 'activex':
						getActiveX(this);
						break;
					case 'w3cdom':
						getW3cDOM(this);
						break;
					case 'pdf':
						getPdf(this);
						break;
					case 'cookies':
						getCookies(this);
						break;
					case 'screen':
						getScreen(this);
						break;
					case 'os':
						getOS(this);
						break;
					case 'browser':
						getBrowser(this);
						break;
					case 'javaisenabled':
						getJavaIsEnabled(this);
						break;
					case 'debug':
						this.debug = true;
						break;
					case 'all':
						getDOMparser(this);
						getActiveX(this);
						getW3cDOM(this);
						getPdf(this);
						getCookies(this);
						getScreen(this);
						getOS(this);
						getBrowser(this);
						getJavaIsEnabled(this);
						break;
					default:
						;
				}
	}

	this.getSettings(detectArr);

	/// End constructor

	/// Private methods for detecting various browser/client settings

	/// DOM parser
	/// getDOMparser sets the property DOMparser
	function getDOMparser(sender) {
		try {
			var xmlString = "<Test>content</Test>"

			if(document.implementation && document.implementation.createDocument) {
				var parser = new DOMParser();
				XMLdoc = parser.parseFromString(xmlString, "text/xml");
				sender.DOMparser = true;
			}
			else
				if(window.ActiveXObject) {
					XMLdoc = new ActiveXObject("Microsoft.XMLDOM");
					XMLdoc.async = 'false';
					XMLdoc.loadXML(xmlString);
					sender.DOMparser = true;
				}
				else
					sender.DOMparser = false;
		}
		catch(E) {
			sender.DOMparser = false;
			sender.errorMessage = 'Error in detecting DOM parser: ' + E.message;
			sender.item.add(sender.item.newItemObj('errorMessage', sender.errorMessage));
		}
		sender.item.add(sender.item.newItemObj('DOMparser', sender.DOMparser));
	} // End getDOMparser

	/// ActiveX
	/// getActiveX sets the property activeX
	function getActiveX(sender) {
		try {
			sender.activeX = (window.ActiveXObject != null);
		}
		catch (E) {
			sender.activeX = false;
			sender.errorMessage = 'Error in detecting ActiveX: ' + E.message;
			sender.item.add(sender.item.newItemObj('errorMessage', sender.errorMessage));
		}
		sender.item.add(sender.item.newItemObj('activeX', sender.activeX));
	} // End getActiveX

	/// w3c DOM
	/// getW3cDOM sets the property w3cDOM
	function getW3cDOM(sender) {
		try {
			if (document.getElementById && document.createElement)
				sender.w3cDOM = true;
			else
				sender.w3cDOM = false;
		}
		catch (E) {
			sender.w3cDOM = false;
			sender.errorMessage = 'Error in detecting w3cDOM: ' + E.message;
			sender.item.add(sender.item.newItemObj('errorMessage', sender.errorMessage));
		}
		sender.item.add(sender.item.newItemObj('w3cDOM', sender.w3cDOM));
	} // End getW3cDOM

	/// pdf supported (browser plugin or mime type
	/// getPdf sets the properties pdfPlugin, pdf and pdfVersion
	function getPdf(sender) {
		try {
			sender.pdfPlugin = false;
			if (window.ActiveXObject != null) {
				var pdfObj = null;
				var i = 0;
				do {
					try {
						pdfObj = new ActiveXObject(pdfObjArr[i].objStr);
						if (typeof(pdfObj) == 'object') {
							sender.pdfPlugin = true;
							sender.pdfVersion = getVersion(pdfObj.GetVersions(), 'ewh32=') || pdfObjArr[i].altVers;
						}
					}
					catch (E) {
						; // Do nothing. Try the next
					}
					i++;
				} while ((i < pdfObjArr.length) && (pdfObj == null));
			}
			else {
				navigator.plugins.refresh();
				sender.pdfPlugin = (navigator.plugins.length > 0 && navigator.plugins['Adobe Acrobat'] != null);
				if (sender.pdfPlugin)
					try {
						sender.pdfVersion = getVersion(navigator.plugins['Adobe Acrobat'].description, 'version ');
					}
					catch (E) {
						sender.errorMessage = 'Could not detect Acrobat Reader version: ' + E.message;
						sender.item.add(sender.item.newItemObj('errorMessage', sender.errorMessage));
					}
			}
		}
		catch (E) {
			sender.pdfPlugin = false;
			sender.errorMessage = 'Error in detecting pdf plugin: ' + E.message;
			sender.item.add(sender.item.newItemObj('errorMessage', sender.errorMessage));
		}

		try {
			sender.pdf = sender.pdfPlugin || (navigator.mimeTypes.length > 0 && navigator.mimeTypes['application/pdf'] != null);
		}
		catch (E) {
			sender.pdf = false;
			sender.errorMessage = 'Error in detecting pdf support: ' + E.message;
			sender.item.add(sender.item.newItemObj('errorMessage', sender.errorMessage));
		}
		sender.item.addList([sender.item.newItemObj('pdfPlugin', sender.pdfPlugin),
												 sender.item.newItemObj('pdf', sender.pdf),
												 sender.item.newItemObj('pdfVersion', sender.pdfVersion)]);
	} // End getPdf

	/// Persistent cookies supported
	/// getCookies sets the properties cookies
	function getCookies(sender) {
		try {
			if (navigator.cookieEnabled){
				var expire = new Date();
				// Cookie lives for 10 secs ... might have to be accepted first
				expire.setTime(expire.getTime() + 1000*10)
				document.cookie = 'BrowserDetectCookieTest=test;expires=' + expire.toGMTString();
				if (document.cookie.indexOf("BrowserDetectCookieTest") != -1)
					sender.cookies = true;
				else
					sender.cookies = false;
			}
			else
				sender.cookies = false;
		}
		catch (E) {
			sender.cookies = false;
			sender.errorMessage = 'Error in detecting cookies: ' + E.message;
			sender.item.add(sender.item.newItemObj('errorMessage', sender.errorMessage));
		}
		sender.item.add(sender.item.newItemObj('cookies', sender.cookies));
	} // End getCookies

	/// Screen resolution
	/// getScreen sets the properties screen to an object
	function getScreen(sender) {
		try {
			if (window.screen) {
				sender.screen = {
					name: window.screen.width + '*' + window.screen.height,
					width: window.screen.width,
					height: window.screen.height,
					color: window.screen.colorDepth
				};
				sender.screen.toString = function() {
					return sender.screen.name;
				}
			}
		}
		catch (E) {
			sender.errorMessage = 'Error in detecting screen resolution: ' + E.message;
			sender.item.add(sender.item.newItemObj('errorMessage', sender.errorMessage));
		}
		sender.item.add(sender.item.newItemObj('screen', sender.screen));
	} // End getScreen

	/// Determine the operating system
	/// getOS sets the properties osID and osName
	function getOS(sender) {
		try {
			var osObj = new searchOsString();
			sender.osID = osObj.osID;
			sender.osName = osObj.osName;
			sender.os64bit = osObj.os64bit;
		}
		catch (E) {
			sender.errorMessage = 'Error in detecting platform: ' + E.message;
			sender.item.add(sender.item.newItemObj('errorMessage', sender.errorMessage));
		}
		sender.item.addList([sender.item.newItemObj('osID', sender.osID),
												 sender.item.newItemObj('osName', sender.osName),
												 sender.item.newItemObj('os64bit', sender.os64bit)]);
	} // End getOS

	/// Get browsername and version
	/// getBrowser sets the properties browserID, browsername, browserVersion and browser
	function getBrowser(sender) {
		try {
			var browserObj = new Browser();
			sender.browserID = browserObj.browserID;
			sender.browsername = browserObj.browsername;
			sender.browserVersion = browserObj.browserVersion;
			if (browserObj.browserVersionInternal)
				sender.browserVersionInternal = browserObj.browserVersionInternal;
			if (sender.browserVersion)
				sender.browser = sender.browsername + ' ' + sender.browserVersion;
			else {
				sender.browser = sender.browsername;
				sender.item.add(sender.item.newItemObj('userAgent', navigator.userAgent));
			}
		}
		catch (E) {
			sender.errorMessage = 'Error in detecting browsername and version: ' + E.message;
			sender.item.add(sender.item.newItemObj('errorMessage', sender.errorMessage));
		}
		var itemList = new Array();
		itemList[0] = sender.item.newItemObj('browserID', sender.browserID);
		itemList[1] = sender.item.newItemObj('browsername', sender.browsername);
		if (sender.browserVersion)
			itemList[itemList.length] = sender.item.newItemObj('browserVersion', sender.browserVersion);
		if (sender.browserVersionInternal)
			itemList[itemList.length] = sender.item.newItemObj('browserVersionInternal', sender.browserVersionInternal);
		itemList[itemList.length] = sender.item.newItemObj('browser', sender.browser);
		sender.item.addList(itemList);
	}

	/// Is java enabled
	/// getJavaIsEnabled sets the property javaIsEnabled
	function getJavaIsEnabled(sender) {
		sender.javaIsEnabled = false;
		try {
			sender.javaIsEnabled = navigator.javaEnabled();
		}
		catch(E) {
			sender.errorMessage = 'Error in detecting if java is enabled: ' + E.message;
			sender.item.add(sender.item.newItemObj('errorMessage', sender.errorMessage));
		}
		sender.item.add(sender.item.newItemObj('javaIsEnabled', sender.javaIsEnabled));
	}

	/// Test detection of OS and browsername and version
	this.testUserAgents = function(testArr) {
		var orgOsString = new Array();
		var orgBrowserString = new Array();
		for (var i = 0; i < orgOsString.length; i++)
			orgOsString[i] = dataOS[i].string;
		for (var i = 0; i < orgBrowserString.length; i++)
			orgBrowserString[i] = dataBrowser[i].string;

		var returnArr = new Array();
		for (var i = 0; i < testArr.length; i++) {
			if (testArr[i].substr(0, 1) == '¤')
				returnArr[i] = {header: testArr[i].substr(1)};
			else {
				for (var j = 0; j < dataOS.length; j++)
					dataOS[j].string = testArr[i];
				for (var j = 0; j < dataBrowser.length; j++)
					dataBrowser[j].string = testArr[i];

				returnArr[i] = {os: new searchOsString(), browser: new Browser()};
			}
		}

		// reestablish data
		for (var i = 0; i < orgOsString.length; i++)
			dataOS[i].string = orgOsString[i];
		for (var i = 0; i < orgBrowserString.length; i++)
			dataBrowser[i].string = orgBrowserString[i];

		return returnArr;
	} // End testUserAgents

	///-------------------------------------------------------------------------///
	/// Test encryption
	///=========================================================================///
	/// Public method.
	/// Call initEncryption to initiate test of 128 bit encryption.
	/// The function will make a call-back to the specified function
	/// or (if not valid) a default named function called encryptInitComplete.
	/// It is possible to force a call-back in case of an error in loading the
	/// page detecting encryption. Set timeout to force call-back.
	///-------------------------------------------------------------------------///

	// Private reference to call-back function for encryption detection
	var _encryptCallbackFunction = null;
	// Private timeout reference used to cancel timeout
	var _encryptCallbackTimeout = null;

	/// initEncryption initiates encryption detection
	this.initEncryption = function(callbackFunction, timeout) {
		try {
			try {
				// Set call-back reference
				if (callbackFunction)
					_encryptCallbackFunction = callbackFunction;
				else
					_encryptCallbackFunction = encryptInitComplete;
			}
			catch(E) {
				this.errorMessage = 'No call back function for encryption check';
				throw E;
			}

			// Copy reference to 'this' to a global reference
			if (document.thisBdObj != this)
				document.thisBdObj = this;

			// Create iframe with html-page that detects encryption
			try {
				if (!document.getElementById('BrowserdetectEncryptionIframe'))
					createIframe('BrowserdetectEncryptionIframe', top.framesetpath + 'BrowserdetectEncryption.html');
				if (this.debug)
					this.item.add(this.item.newItemObj('Debug: Encryption iframe path', 'BrowserdetectEncryption.html'));
			}
			catch (E) {
				this.errorMessage = 'Error in creating iframe: ' + E.message;
				throw E;
			}

			//
			if (timeout)
				_encryptCallbackTimeout = window.setTimeout('if(window.document) window.document.encryptionCallbackTimedout();', timeout * 1000);
		}
		catch(E) {
			if (!this.errorMessage || this.errorMessage == '')
				this.errorMessage = 'Unexpected error: ' + E.message;
			this.item.add(this.item.newItemObj('errorMessage', this.errorMessage));
		}
	}

	/// encryption_onError is called, if an error event is raised loading an image with encryption
	this.encryption_onError = function() {
		try {
			this.encryptionOK = false;
		}
		catch (E) {
			this.errorMessage = 'Error in handling image error: ' + E.message;
			this.item.add(this.item.newItemObj('errorMessage', this.errorMessage));
		}
	}

	/// encryptionCallbackTimedout is called, when call-back in the iframe BrowserdetectEncryptionIframe
	/// times out according to the timeout set in function initEncryption.
	window.document.encryptionCallbackTimedout = function() {
		var callbackCopy = null;
		// Call the call-back function if the reference is valid
		if (_encryptCallbackFunction) {
			callbackCopy = _encryptCallbackFunction;
			_encryptCallbackFunction = null;
			callbackCopy('timeout');
		}
	}

	/// encryptionCallback is called, when the document in
	/// the iframe BrowserdetectEncryptionIframe is loaded
	this.encryptionCallback = function() {
		// Cancel timeout if set
		if (_encryptCallbackTimeout)
			window.clearTimeout(_encryptCallbackTimeout);

		// If property encryptionOK does not exists, no error event was raised loading the image
		if (this.encryptionOK == null)
			this.encryptionOK = true;

		this.item.add(this.item.newItemObj('encryptionOK', this.encryptionOK));

		// Call the call-back function if the reference is valid
		if (_encryptCallbackFunction)
			_encryptCallbackFunction();
	}

	///-------------------------------------------------------------------------///
	/// Test java
	///=========================================================================///
	/// Public method.
	/// Call initJava to initiate java test.
	/// The function will make a call-back to the specified function
	/// or (if not valid) a default named function called encryptInitComplete.
	/// It is possible to force a call-back in case of an error in loading the
	/// page detecting java version. Set timeout to force call-back.
	///-------------------------------------------------------------------------///

	// Private reference to call-back function for java detection
	var _javaCallbackFunction = null;
	// Private timeout reference used to cancel timeout
	var _javaCallbackTimeout = null;

	/// initJava initiates java detection
	this.initJava = function(callbackFunction, timeout) {
		var itemList = new Array();
		try {
			try {
				if (callbackFunction)
					_javaCallbackFunction = callbackFunction;
				else
					_javaCallbackFunction = javaInitComplete;
			}
			catch(E) {
				this.javaReturncode = 12;
				throw E;
			}

			if (this.javaIsEnabled == null)
				getJavaIsEnabled(this);
			if (!this.javaIsEnabled) {
				this.javaIsFunctional = false;
				this.javaReturncode = 1;
				throw new Error();
			}

			if (window.document.thisBdObj != this)
				window.document.thisBdObj = this;

			try {
				if (!document.getElementById('BrowserdetectJavaIframe'))
					createIframe('BrowserdetectJavaIframe', top.framesetpath + 'BrowserdetectJava.html');
				if (this.debug)
					this.item.add(this.item.newItemObj('Debug: Java iframe path', 'BrowserdetectJava.html'));
			}
			catch (E) {
				this.javaIsFunctional = false;
				this.javaReturncode = 11;
				throw new Error();
			}

			if (timeout)
				_javaCallbackTimeout = window.setTimeout('if(window.document) window.document.javaCallbackTimedout();', timeout * 1000);
		}
		catch(E) {
			itemList[0] = this.item.newItemObj('javaIsFunctional', this.javaIsFunctional = false);
			if (!this.javaReturncode)
				this.javaReturncode = javacodeArr.length - 1;
			this.javaDescription = javacodeArr[this.javaReturncode];
			itemList[1] = this.item.newItemObj('javaReturncode', this.javaReturncode);
			itemList[2] = this.item.newItemObj('javaDescription', this.javaDescription);
			this.item.addList(itemList);
		}
	} // End initJava

	/// javaCallbackTimedout is called, when call-back in the iframe BrowserdetectJavaIframe
	/// times out according to the timeout set in function initJava.
	window.document.javaCallbackTimedout = function() {
		var callbackCopy = null;
		// Call the call-back function if the reference is valid
		if (_javaCallbackFunction) {
			callbackCopy = _javaCallbackFunction;
			_javaCallbackFunction = null;
			callbackCopy('timeout');
		}
	}

	/// Handle callback from DetectorApplet.class
	/// for detecting java vendor and version
	function detectorAppletCallback(sender, javaVendor, javaVersion, itemList) {
		if (sender.debug)
			sender.item.add(sender.item.newItemObj('Debug: Info from DetectorApplet', javaVendor + '&&' + javaVersion));

		try {
			sender.javaVersion = '' + javaVersion;
			sender.javaVendor	 = '' + javaVendor;

			// Java called
			itemList[0] = sender.item.newItemObj('javaIsFunctional', sender.javaIsFunctional = true);
			itemList[1] = sender.item.newItemObj('javaReturncode', sender.javaReturncode = 0);
		}
		catch(E) {
			itemList[0] = sender.item.newItemObj('javaIsFunctional', sender.javaIsFunctional = false);
			if (!sender.javaReturncode)
				sender.javaReturncode = javacodeArr.length - 1;
			sender.javaDescription = javacodeArr[sender.javaReturncode];
			itemList[1] = sender.item.newItemObj('javaReturncode', sender.javaReturncode);
			itemList[2] = sender.item.newItemObj('javaDescription', sender.javaDescription);
		}
	}

	/// Handle callback in load of TDPC.class
	/// for detecting java vendor and version
	function TDPC_Loaded(sender, itemList) {
		var javaString = '';

		try {
			try {
				if(window.frames['BrowserdetectJavaIframe'].document.applets['TDPC'])
					javaString = window.frames['BrowserdetectJavaIframe'].document.applets['TDPC'].getInfo();
				else
					javaString = window.frames['BrowserdetectJavaIframe'].document.getElementsByName('TDPC').item(0).getInfo();
			}
			catch(E) {
				sender.javaReturncode = 2;
				throw new Error();
			}

			if (!javaString) {
				sender.javaReturncode = 3;
				throw new Error();
			}

			try {
				if (sender.debug)
					sender.item.add(sender.item.newItemObj('Debug: String from TDPC', javaString));

				var javaArr = javaString.split("&&");
				// "'' + " is a fix for other browsers that IE
				sender.javaVersion	= '' + javaArr[1];
				sender.javaVendor		= '' + javaArr[2];
				sender.javaPlatform	= '' + javaArr[3];
			}
			catch (E) {
				try {
					if (sender.debug)
						sender.item.add(sender.item.newItemObj('Debug: String split error message', E.message));

					sender.javaReturncode = 5;

					// Fix
					var tempStr = javaString;
					sender.TDPC_Result	= tempStr.substr(0, tempStr.indexOf('&&'));
					tempStr = tempStr.substr(tempStr.indexOf('&&') + 2);
					sender.javaVersion	= tempStr.substr(0, tempStr.indexOf('&&'));
					tempStr = tempStr.substr(tempStr.indexOf('&&') + 2);
					sender.javaVendor		= tempStr.substr(0, tempStr.indexOf('&&'));
					sender.javaPlatform	= tempStr.substr(tempStr.indexOf('&&') + 2);
				}
				catch (E) {
					throw new Error();
				}
			}

			// Java called
			itemList[0] = sender.item.newItemObj('javaIsFunctional', sender.javaIsFunctional = true);
			itemList[1] = sender.item.newItemObj('javaReturncode', sender.javaReturncode = 0);
		}
		catch(E) {
			itemList[0] = sender.item.newItemObj('javaIsFunctional', sender.javaIsFunctional = false);
			if (!sender.javaReturncode)
				sender.javaReturncode = javacodeArr.length - 1;
			sender.javaDescription = javacodeArr[sender.javaReturncode];
			itemList[1] = sender.item.newItemObj('javaReturncode', sender.javaReturncode);
			itemList[2] = sender.item.newItemObj('javaDescription', sender.javaDescription);
		}
	} // End TDPC_Loaded

	/// javaCallback is called, when the document in
	/// the iframe BrowserdetectJavaIframe is loaded
	this.javaCallback = function(appletName, javaVendor, javaVersion, liveConnect) {
		if (_javaCallbackTimeout)
			window.clearTimeout(_javaCallbackTimeout);

		var itemList = new Array();

		switch (appletName) {
			case 'DetectorApplet':
				detectorAppletCallback(this, javaVendor, javaVersion, itemList);
				break;
			case 'TDPC':
				TDPC_Loaded(this, itemList);
				break;
			default:
				;
		}

		itemList[itemList.length] = this.item.newItemObj('liveConnect', this.liveConnect = (liveConnect == true));
		this.item.addList(itemList);

		if (_javaCallbackFunction)
			_javaCallbackFunction();
	} // End this.javaCallback

	///-------------------------------------------------------------------------///
	/// Check java version
	///=========================================================================///
	/// Public method.
	/// Call checkJavaVersion to verify the client java version for a specific
	/// security-solution and site.
	/// The function checks if the java vendor is useable for the provided
	/// security/site.
	/// Next it checks, if the java version is in an exception list for the
	/// given security/site. If not the java version is compared to the
	/// required version for the security/site-combination.
	///-------------------------------------------------------------------------///
	this.checkJavaVersion = function(site, security) {
		try {
			if (this.javaVendor == '') {
				// The java information has not been retrieved
				this.javaReturncode = 4;
				throw new Error();
			}

			try {
				// Remove . and , from the java vendor name and replace spaces with _
				javaVendorStript = this.javaVendor.replace(/[\.,]/g, '').replace(/[ ]/g, '_').toLowerCase();
			}
			catch (E) {
				this.javaReturncode = 6;
				throw new Error();
			}

			if (!site || !security) {
				// Requirement check not possible
				this.javaReturncode = 7;
				throw new Error();
			}

			try {
				// Loop through the security-solutions
				for (var i = 0; i < javaRequirement.length && this.javaVersionOK != true; i++)
					if (javaRequirement[i].securityID == security.toUpperCase()) {
						// Loop through the sites specified for the security-solution
						for (var j = 0; j < javaRequirement[i].siteID.length; j++)
							if (javaRequirement[i].siteID[j] == site.toUpperCase()) {
								// Unfortunately not all versions higher than the required are valid,
								// so we need to compare the users version to an exception list
								for (var k = 0; k < javaRequirement[i].exceptions.length; k++)
									if ((javaRequirement[i].exceptions[k].name == javaVendorStript)
									 && (javaRequirement[i].exceptions[k].vers == this.javaVersion)) {
										this.javaReturncode = 8;
										throw new Error();
									}
								// If the java version isn't in the exception list we proceed  by looping
								// through java versions for the current site/security-combination
								for (var k = 0; k < javaRequirement[i].vendor.length; k++)
									if (javaRequirement[i].vendor[k].name == javaVendorStript) {
										// Compare the required java version to the client java version
										this.javaVersionOK = versionOK(javaRequirement[i].vendor[k].vers,
																						this.javaVersion);
										if (!this.javaVersionOK) {
											// The java version is to old
											this.javaReturncode = 9;
											throw new Error();
										}
									} // End if required vender == this vendor
							} // end if (site found)
					} // end if (security found)

				if (this.javaVersionOK)
					this.javaReturncode = 0;
				else {
					// Java vendor was not found for security/site-combination. Java version is not supported
					this.javaReturncode = 10;
					throw new Error();
				}
			}
			catch (E) {
				switch (this.javaReturncode) {
					case 8, 9:
						javacodeArr[this.javaReturncode] += ' (' + this.javaVendor + '\/' + this.javaVersion + ')';
						break;
					case 10:
						javacodeArr[this.javaReturncode] += ' ' + this.javaVendor + ' for ' + security + '@' + site;
						break;
					default:
						this.item.add(this.item.newItemObj('Unexpected error in checkJavaVersion', E.message));
						this.javaReturncode = javacodeArr.length - 1;
					}
				throw new Error();
			}
		} // End Outer try
		catch (E) {
			if (this.javaReturncode == null)
				this.javaReturncode = javacodeArr.length - 1;

			if (this.javaReturncode == 0)
				this.javaVersionOK = true;
			else {
				this.javaVersionOK = false;
			}
			this.javaDescription = javacodeArr[this.javaReturncode];
			if (this.javaReturncode == javacodeArr.length - 1)
				this.javaDescription += '. ' + E.message;
		}

		// Add the found results to the property-collection
		itemList = new Array();
		itemList[0] = this.item.newItemObj('javaVersionOK', this.javaVersionOK);
		itemList[1] = this.item.newItemObj('javaReturncode', this.javaReturncode);
		if (this.javaDescription && this.javaDescription != '')
			itemList[2] = this.item.newItemObj('javaDescription', this.javaDescription);
		if (this.javaVersion)
			itemList[itemList.length] = this.item.newItemObj('javaVersion', this.javaVersion);
		if (this.javaVendor)
			itemList[itemList.length] = this.item.newItemObj('javaVendor', this.javaVendor);
		if (this.javaPlatform)
			itemList[itemList.length] = this.item.newItemObj('javaPlatform', this.javaPlatform);

		this.item.addList(itemList);
	} // End detectJava

	this.toString =
		function() {
			return this.name;
		} // End function toString

	// Private support methods

	///-------------------------------------------------------------------------///
	/// getVersion
	///=========================================================================///
	/// Private method.
	/// The function retrieves the string following the input string to search
	/// for, terminated by a named character or to the end of the string in the
	/// input string to search in.
	///-------------------------------------------------------------------------///
	function getVersion(strToSearch, strToFind) {
		try {
			var startIndex = strToSearch.toLowerCase().indexOf(strToFind);
			if (startIndex == -1)
				return null;

			var endIndex1 = strToSearch.indexOf(";", startIndex + strToFind.length + 1);
			var endIndex2 = strToSearch.indexOf(",", startIndex + strToFind.length + 1);
			var endIndex3 = strToSearch.indexOf(" ", startIndex + strToFind.length + 1);
			var endIndex4 = strToSearch.indexOf(")", startIndex + strToFind.length + 1);
			var endIndex5 = strToSearch.indexOf("-v", startIndex + strToFind.length + 1);
			var endIndex6 = strToSearch.indexOf("N ", startIndex + strToFind.length + 1);

			var endIndex = getMinimum([endIndex1, endIndex2, endIndex3, endIndex4, endIndex5, endIndex6]);

			if (endIndex > -1)
				return strToSearch.substring(startIndex + strToFind.length, endIndex).replace(/^[ \/]/g, "");
			else
				return strToSearch.substr(startIndex + strToFind.length).replace(/^[ \/]/g, "");
		}
		catch (E) {
			return null;
		}

		// Local function
		function getMinimum(intArr) {
			var currentMin = 999;
			for (i = 0; i < intArr.length; i++)
				if ((intArr[i] > -1) && (intArr[i] < currentMin))
					currentMin = intArr[i];
			if (currentMin == 999)
				return -1;
			else
				return currentMin;
		}
	} // End getVersion

	///-------------------------------------------------------------------------///
	/// compareVersions
	///=========================================================================///
	/// Public method.
	/// Public entry for private funcion versionOK
	/// The function returns -1, 0 or 1:
	/// version1 < version2 -> returns -1
	/// version1 = version2 -> returns  0
	/// version1 > version2 -> returns  1
	/// The function throws an exception in case of an error.
	///-------------------------------------------------------------------------///
	this.compareVersions = function (version1, version2) {
		try {
			if (version1 == version2)
				return 0;
			else
				return versionOK(version2, version1)?1:-1;
		}
		catch (E) {
			this.errorMessage = 'Error in public version checker: ' + E.message;
			this.item.add(this.item.newItemObj('errorMessage', this.errorMessage));
			throw new Error();
		}
	} // End compareVersions

	///-------------------------------------------------------------------------///
	/// versionOK
	///=========================================================================///
	/// Private method.
	/// The function compares the two input version strings.
	/// If requiredVersion is less than or equal to versionToCheck,
	/// the function returns true otherwise false is returned.
	/// The function throws an exception in case of an error.
	///-------------------------------------------------------------------------///
	function versionOK(requiredVersion, versionToCheck) {
		try {
			reqArr		= requiredVersion.split(/[\._]/);
			checkArr	= versionToCheck.split(/[\._]/);
			var result = true;
			for (var i = 0; i < Math.min(reqArr.length, checkArr.length); i++) {
				if (parseInt(reqArr[i],10) < parseInt(checkArr[i],10))
					return true;
				else
					if (parseInt(reqArr[i],10) != parseInt(checkArr[i],10)) {
						result = (parseInt(reqArr[i],10) < parseInt(checkArr[i],10));
						break;
					}
			}
			return (result && reqArr.length <= checkArr.length);
		}
		catch (E) {
			this.errorMessage = 'Error in version checker: ' + E.message;
			this.item.add(this.item.newItemObj('errorMessage', this.errorMessage));
			throw new Error();
		}
	} // End versionOK

	///-------------------------------------------------------------------------///
	/// searchOsString
	///=========================================================================///
	/// Private class.
	/// The object loops through the array dataOS and tries to determine
	/// the operating system on witch the client is running.
	/// The object has two properties:
	/// - osID (unique identifier)
	/// - osName (name of the OS)
	///-------------------------------------------------------------------------///
	function searchOsString() {
		var indexMatch = -1;
		for (var i = 0; (i < dataOS.length) && (indexMatch == -1); i++) {
			for (var j = 0; j < dataOS[i].idSearch.length; j++)
				if (dataOS[i].string.toLowerCase().indexOf(dataOS[i].idSearch[j]) != -1) {
					indexMatch = i;
					this.os64bit = false;
					if (dataOS[i].bit64)
						for (var k = 0; k < dataOS[i].bit64.length; k++)
							if (dataOS[i].string.toLowerCase().indexOf(dataOS[i].bit64[k]) != -1) {
								this.os64bit = true;
								break;
							}
					break;
				}
		}

		if (indexMatch > -1) {
			this.osID = dataOS[indexMatch].id;
			this.osName = dataOS[indexMatch].name;
		}
	} // End searchOsString

	///-------------------------------------------------------------------------///
	/// Browser
	///=========================================================================///
	/// Private class.
	/// The object loops through the array dataBrowser and tries to determine
	/// the client (browser).
	/// The object has three properties:
	/// - browserID (unique identifier)
	/// - browsername (the name of the browser/client)
	/// - browserVersion (version number as string)
	///-------------------------------------------------------------------------///
	function Browser() {
		var indexMatch = -1;
		for ( var i = 0; (i < dataBrowser.length) && (indexMatch == -1); i++)
			if (dataBrowser[i].string.toLowerCase().indexOf(dataBrowser[i].idSearch) != -1) {
				// A match was found at the current array-index
				indexMatch = i;

				// Verify the match if additional string must be in the string to search
				if (dataBrowser[i].verifySrchIncl)
					if (dataBrowser[i].string.toLowerCase().indexOf(dataBrowser[i].verifySrchIncl) != -1)
						indexMatch = i;
					else
						indexMatch = -1;

				// Verify the match if additional string may not be in the string to search
				// Only do this, if the match is still valid
				if (dataBrowser[i].verifySrchExcl && (indexMatch != -1))
					if (dataBrowser[i].string.toLowerCase().indexOf(dataBrowser[i].verifySrchExcl) == -1)
						indexMatch = i;
					else
						indexMatch = -1;
			}

		if (indexMatch > -1) {
			this.browserID = dataBrowser[indexMatch].id;
			this.browsername = dataBrowser[indexMatch].name;
			this.browserVersion = getVersion(dataBrowser[indexMatch].string, dataBrowser[indexMatch].versionSearch)
												 || getVersion(navigator.userAgent, dataBrowser[indexMatch].versionSearch)
												 || getVersion(navigator.appVersion, dataBrowser[indexMatch].versionSearch);
			if (dataBrowser[indexMatch].versionMap) {
				this.browserVersionInternal = this.browserVersion;
				this.browserVersion = translateVersion(this.browserVersion, dataBrowser[indexMatch].versionMap);
			}
		}
	} // End Browser


	///-------------------------------------------------------------------------///
	/// translateVersion
	///=========================================================================///
	/// Private method.
	/// Some browsers/clients only include an internal version number in
	/// the string to search eg. navigator.userAgent.
	/// This function translates internal version numbers to external
	///-------------------------------------------------------------------------///
	function translateVersion(internalVersion, mapArr) {
		for (var i = 0; i < mapArr.length; i++) {
			if (internalVersion.replace(/\W$/, '') == mapArr[i].internal)
				return mapArr[i].external;
		}

		// External version not found
		// Trying to match major version
		for (var i = 0; i < mapArr.length; i++) {
			if (internalVersion.replace(/\D[\D\d]*/, '') == mapArr[i].internal.replace(/\D[\D\d]*/, ''))
				return mapArr[i].external.replace(/\D[\D\d]*/, '');
		}

		return '';
	}

	///-------------------------------------------------------------------------///
	/// ItemArray
	///=========================================================================///
	/// Private class.
	/// Implements a collection object.
	///-------------------------------------------------------------------------///
	function ItemArray() {
		var thisArr = new Array();
		thisArr.newItemObj = function(_name, _value) {
			return {name: _name, value: _value};
		}
		// Public method to add an element
		thisArr.add = function(newObject) {
			var overrideIndex = exists(newObject);
			if (overrideIndex > -1)
				thisArr[overrideIndex] = newObject;
			else
				thisArr[thisArr.length] = newObject;
		}
		// Public method to add a list of elements
		thisArr.addList = function(newObjectArr) {
			for (var i = 0; i < newObjectArr.length; i++)
				thisArr.add(newObjectArr[i]);
		}
		// Public method used to display the collecton content
		thisArr.showContent = function(seperator) {
			if (!seperator) seperator = ';';
			var resultStr = '';
			for(var i = 0; i < thisArr.length - 1; i++)
				resultStr += thisArr[i].name + ' = ' + thisArr[i].value + seperator;
			// Add the last element without the ending seperator
			resultStr += thisArr[i].name + ' = ' + thisArr[i].value;
			return resultStr;
		}
		// Private method to determine if an element already exists in the collection
		function exists(Object) {
			for (var i = 0; i < thisArr.length; i++)
				if (thisArr[i].name == Object.name)
					return i;

			return -1;
		}
		return thisArr;
	}

	///-------------------------------------------------------------------------///
	/// createIframe
	///=========================================================================///
	/// Private method.
	/// Create an html iframe in the document that uses the
	/// browserdetector object
	///-------------------------------------------------------------------------///
	function createIframe(_name, _src) {
		try {
			var iframeElement = document.createElement('iframe');
			iframeElement.id = _name;
			iframeElement.name = _name;
			iframeElement.style.width = '0';
			iframeElement.style.height = '0';
			iframeElement.style.border = 'none';
			iframeElement.src = _src;
			document.getElementById('sub-main-content').appendChild(iframeElement);
		}
		catch (E) {
			throw E;
		}
	}

} // End browserDetector

	/// Data arrays for finding pdf-plugin, OS and browser
	var javaRequirement = [
		{
			securityID:	'ESAFEKEY',
			siteID:			['DBNB', 'DBNBEN', 'DBNU', 'BGNB', 'BGNBEN', 'BGNU', 'FONB', 'OENB', 'NBNB', 'NINB', 'LUNB'],
			vendor:			[
										{
											name:	'sun_microsystems_inc',
											vers:	'0' // All versions are valid
										},
										{
											name: 'apple_computer_inc',
											vers: '0'
										},
										{
											name: 'apple_inc',
											vers: '0'
										},
										{
											name: 'microsoft_corp',
											vers: '0'
										}
									],
			exceptions:	[
									]
		},
		{
			securityID:	'ESECUREKEY',
			// siteID BAD is the BankID administration site
			siteID:			['DBNB', 'DBNBEN', 'DBNU', 'BGNB', 'BGNBEN', 'BGNU', 'FONB', 'OENB', 'NBNB', 'NINB', 'LUNB', 'DAB', 'SBNBFI', 'SBNBEN', 'SBNBSE'],
			vendor:			[
										{
											name:	'sun_microsystems_inc',
											vers:	'1.4.2'
										},
										{
											name: 'apple_computer_inc',
											vers: '1.4.2'
										},
										{
											name: 'apple_inc',
											vers: '0'
										}
									],
			exceptions:	[
									]
		},
		{
			securityID:	'ACTIVECARD',
			// siteID BAD is the BankID administration site
			siteID:			['DBNB', 'DBNBEN', 'DBNU', 'BGNB', 'BGNBEN', 'BGNU', 'FONB', 'OENB', 'NBNB', 'NINB', 'LUNB', 'DAB'],
			vendor:			[
										{
											name:	'sun_microsystems_inc',
											vers:	'1.4.2_2'
										},
										{
											name: 'apple_computer_inc',
											vers: '1.4.2_2'
										},
										{
											name: 'apple_inc',
											vers: '0'
										},
										{
											name: 'microsoft_corp',
											vers: '0'
										}
									],
			exceptions:	[
									]
		},
		{
			securityID:	'BANKID',
			siteID:			['FONB', 'FO3D'],
			vendor:			[
										{
											name:	'sun_microsystems_inc',
											vers:	'1.5.0_02'
										},
										{
											name: 'apple_computer_inc',
											vers: '1.4.2'
										},
										{
											name: 'apple_inc',
											vers: '0'
										}
									],
			exceptions:	[
									]
		}
	];

	var pdfObjArr = [
		{
			objStr:		'AcroPDF.PDF.1',
			altVers:	'7'
		},
		{
			objStr:		'PDF.PdfCtrl.6',
			altVers:	'6'
		},
		{
			objStr:		'PDF.PdfCtrl.5',
			altVers:	'5'
		},
		{
			objStr:		'PDF.PdfCtrl.1',
			altVers:	'4'
		}
	];

	var dataOS = [
		{
			string:		navigator.userAgent,
			idSearch:	['windows 95', 'win95'],
			id:				'win95',
			name:			'Windows 95'
		},
		{
			string:		navigator.userAgent,
			idSearch:	['windows 98', 'win98'],
			id:				'win98',
			name:			'Windows 98'
		},
		{
			string:		navigator.userAgent,
			idSearch:	['windows 9x 4.90'],
			id:				'winME',
			name:			'Windows ME'
		},
		{
			string:		navigator.userAgent,
			idSearch:	['windows nt 5.0'],
			id:				'win2000',
			name:			'Windows 2000'
		},
		{
			string:		navigator.userAgent,
			idSearch:	['windows nt 5.1', 'winxp', 'nt-5.1'],
			bit64:		['wow64', 'win64'],
			id:				'winXP',
			name:			'Windows XP'
		},
		{
			string:		navigator.userAgent,
			idSearch:	['windows nt 5.2'],
			id:				'win2003Serv',
			name:			'Windows 2003 Server'
		},
		{
			string:		navigator.userAgent,
			idSearch:	['windows nt 6.0'],
			id:				'winVista',
			name:			'Windows Vista'
		},
		{
			string:		navigator.userAgent,
			idSearch:	['windows nt 4', 'windows nt 3', 'windows nt 2', 'winnt'],
			id:				'winNT',
			name:			'Windows NT'
		},
		{
			string:		navigator.userAgent,
			idSearch:	['win'],
			id:				'win',
			name:			'Windows'
		},
		{
			string:		navigator.userAgent,
			idSearch:	['mac os x'],
			id:				'macOSX',
			name:			'Mac OS X'
		},
		{
			string:		navigator.userAgent,
			idSearch:	['mac os'],
			id:				'macOS',
			name:			'Mac OS'
		},
		{
			string:		navigator.userAgent,
			idSearch:	['mac'],
			id:				'mac',
			name:			'Macintosh'
		},
		{
			string:		navigator.userAgent,
			idSearch:	['inux'],
			bit64:		['x86_64'],
			id:				'linux',
			name:			'Linux'
		},
		{
			string:		navigator.userAgent,
			idSearch:	['bsd'],
			id:				'bsd',
			name:			'BSD'
		},
		{
			string:		navigator.userAgent,
			idSearch:	['os/2', 'ibm-webexplorer'],
			id:				'os2',
			name:			'OS/2'
		},
		{
			string:		navigator.userAgent,
			idSearch:	['sunos', 'irix', 'hp-ux', 'aix'],
			id:				'unix',
			name:			'UNIX'
		},
		{
			string:		navigator.userAgent,
			idSearch:	['beos'],
			id:				'beos',
			name:			'BeOS'
		},
		{
			string:		navigator.appVersion,
			idSearch:	['os/2'],
			id:				'os2',
			name:			'OS/2'
		}
	]; // End dataOS

	var dataBrowser = [
		{
			string:					navigator.userAgent,	// String to search
			idSearch:				'omniweb',						// String to search for
			versionSearch:	'omniweb',						// String followed by version (omit split characters like space and slash)
			versionMap:			[											// Translate internal version to external
												{internal: 'v563.34'   , external: '5.0.1'},
												{internal: 'v558.48'   , external: '5.0.1'},
												{internal: 'v558.46'   , external: '5.0'},
												{internal: 'v496'      , external: '4.5'},
												{internal: 'v496'      , external: '4.5'},
												{internal: '2.7-beta-3', external: '2.7-beta-3'},
												{internal: '4.2'       , external: '4.2'},
												{internal: '4.2.1'     , external: '4.2.1'}
											],
			id:							'omniweb',
			name:						'OmniWeb'							// Returned value
		},
		{
			string:					navigator.userAgent,
			idSearch:				'safari',
			versionSearch:	'safari',
			versionMap:			[
										          {internal: '523.15' , external: '3.0.4'},
												{internal: '523.12.2' , external: '3.0.4'},
												{internal: '523.12' , external: '3.0.4'},
												{internal: '523.10' , external: '3.0.4'},
												{internal: '419.3'  , external: '2.0.4'},
												{internal: '417.9.3', external: '2.0.3'},
												{internal: '417.9.2', external: '2.0.3'},
												{internal: '417.8'  , external: '2.0.3'},
												{internal: '417.2'  , external: '2.0'},
												{internal: '416.13' , external: '2.0.2'},
												{internal: '416.12' , external: '2.0.2'},
												{internal: '412.5'  , external: '2.0.1'},
												{internal: '412.2.2', external: '2.0'},
												{internal: '412.2'  , external: '2.0'},
												{internal: '412'    , external: '2.0'},
												{internal: '312.6'  , external: '1.3.2'},
												{internal: '312.5'  , external: '1.3.2'},
												{internal: '312.3.1', external: '1.3.1'},
												{internal: '312.3'  , external: '1.3.1'},
												{internal: '312'    , external: '1.3'},
												{internal: '125.1'  , external: '1.25.1'},
												{internal: '125.12' , external: '1.2.4'},
												{internal: '125.11' , external: '1.2.4'},
												{internal: '125.9'  , external: '1.2.3'},
												{internal: '125.8'  , external: '1.2.2'},
												{internal: '125.7'  , external: '1.2.2'},
												{internal: '100.1'  , external: '1.1.1'},
												{internal: '100'    , external: '1.1'},
												{internal: '85.8.1' , external: '1.0.3'},
												{internal: '85.8'   , external: '1.0.3'},
												{internal: '85.7'   , external: '1.0.2'},
												{internal: '85.5'   , external: '1.0'},
												{internal: '85'     , external: '1.0'},
												{internal: '74'     , external: 'build 74'},
												{internal: '51'     , external: 'build 51'}
											],
			id:							'safari',
			name:						'Safari'
		},
		{
			string:					navigator.userAgent,
			idSearch:				'opera',
			versionSearch:	'opera',
			id:							'opera',
			name:						'Opera'
		},
		{
			string:					navigator.userAgent,
			idSearch:				'icab',
			versionSearch:	'icab',
			id:							'icab',
			name:						'iCab'
		},
		{
			string:					navigator.userAgent,
			idSearch:				'konqueror',
			versionSearch:	'konqueror',
			id:							'konqueror',
			name:						'Konqueror'
		},
		{
			string:					navigator.userAgent,
			idSearch:				'firefox',
			versionSearch:	'firefox',
			id:							'firefox',
			name:						'Firefox'
		},
		{
			string:					navigator.userAgent,
			idSearch:				'firebird',
			versionSearch:	'firebird',
			id:							'firebird',
			name:						'Firebird'
		},
		{
			string:					navigator.userAgent,
			idSearch:				'thunderbird',
			versionSearch:	'thunderbird',
			id:							'thunderbird',
			name:						'Thunderbird'
		},
		{
			string:					navigator.userAgent,
			idSearch:				'phoenix',
			versionSearch:	'phoenix',
			id:							'phoenix',
			name:						'Phoenix'
		},
		{
			string:					navigator.userAgent,
			idSearch:				'camino',
			versionSearch:	'camino',
			id:							'camino',
			name:						'Camino'
		},
		{	// For newer Netscapes (6+)
			string:					navigator.userAgent,
			idSearch:				'netscape6',
			versionSearch:	'netscape6',
			id:							'ns',
			name:						'Netscape'
		},
		{	// For newer Netscapes (7+)
			string:					navigator.userAgent,
			idSearch:				'netscape',
			versionSearch:	'netscape',
			id:							'ns',
			name:						'Netscape'
		},
		{
			string:					navigator.userAgent,
			idSearch:				'msie',
			versionSearch:	'msie ',
			id:							'ie',
			name:						'Microsoft Internet Explorer'
		},
		{
			string:					navigator.userAgent,
			idSearch:				'seamonkey',
			versionSearch:	'seamonkey',
			id:							'seamonkey',
			name:						'SeaMonkey'
		},
		{
			string:					navigator.userAgent,
			idSearch:				'mozilla',
			verifySrchIncl:	'gecko\/',
			versionSearch:	'rv:',
			id:							'mozilla',
			name:						'Mozilla'
		},
		// For older Netscapes
		{
			string:					navigator.userAgent,
			idSearch:				'mozilla',
			verifySrchExcl:	'gecko',
			versionSearch:	'mozilla',
			id:							'nsOld',
			name:						'Netscape'
		}
	]; // End dataBrowser

