var clientDetect = new ClientDetect();

function clientDetectInit() {
	//      BEGIN EDITABLE DATA      //
	
	// The following calls can be made on clientDetect.env to get different
	// restriction objects:
	//   base()                   No restriction.
	//   os(name)                 OS restriction.
	//   os(name, version)        OS and version restriction.
	//   browser(name)            Browser restriction.
	//   browser(name, version)   Browser and version restriction.
	//   plugin(name)             Plugin restriction.
	//   plugin(name, version)    Plugin and version restriction.
	// 
	// Each function can also be called on the result of another, to combine
	// requirements. The version parameter may be a number or string and, as a
	// string, may be prefixed with "<", "<=", ">" or ">=" to indicate the
	// comparison.
	
	// Base OSes.
	var Default = clientDetect.env.base();
	var Win     = clientDetect.env.os("Windows");
	var Mac     = clientDetect.env.os("Mac");
	
	// Specific OS versions.
	var Win98   = clientDetect.env.os("Windows", "<=3.98"); // Win98 or before.
	var WinME   = clientDetect.env.os("Windows", "3.99");
	var Win2000 = clientDetect.env.os("Windows", "5.0");
	var MacOS9  = clientDetect.env.os("Mac", "<10.0"); // OS9
	
	// Browsers.
	var WinIE   = Win.browser("Internet Explorer");
	var Firefox = clientDetect.env.browser("Firefox");
	var Safari  = clientDetect.env.browser("Safari");
	
	// Plugins.
	var Flash   = clientDetect.env.plugin("Flash");
	var WMP     = clientDetect.env.plugin("Windows Media Player");
	var QT      = clientDetect.env.plugin("Quicktime");
	var Real    = clientDetect.env.plugin("Real Player");
	var Acrobat = clientDetect.env.plugin("Acrobat Reader");
	
	// OS + Plugin combinations.
	var WinWMP      = Win.plugin("Windows Media Player");
	var Win98WMP    = Win98.plugin("Windows Media Player");
	var WinMEWMP    = Win98.plugin("Windows Media Player");
	var Win2000WMP  = Win98.plugin("Windows Media Player");
	var MacQT       = Mac.plugin("Quicktime");
	var MacOS9QT    = MacOS9.plugin("Quicktime");
	var MacOS9Flash = MacOS9.plugin("Flash");
	
	// These are the messages show for 1) below minimum, 2) minimum to below recommended and 3) recommended versions.
	var getLatestIE     = ["<a href='http://www.microsoft.com/ie'>Get the latest version of $name$</a>", "<a href='http://www.microsoft.com/ie'>Get the latest version of $name$</a>", "<a href='http://www.microsoft.com/ie'>About $name$</a>"];
	var getLatestFF     = ["<a href='http://www.mozilla.com/firefox'>Get the latest version of $name$</a>", "<a href='http://www.mozilla.com/firefox'>Get the latest version of $name$</a>", "<a href='http://www.mozilla.com/firefox'>About $name$</a>"];
	var getLatestSafari = ["<a href='http://www.apple.com/safari'>Get the latest version of $name$</a>", "<a href='http://www.apple.com/safari'>Get the latest version of $name$</a>", "<a href='http://www.apple.com/safari'>About $name$</a>"];
	var getLatestWMP    = ["<a href='http://www.microsoft.com/mediaplayer'>Get the latest version of $name$</a>", "<a href='http://www.microsoft.com/mediaplayer'>Get the latest version of $name$</a>", "<a href='http://www.microsoft.com/mediaplayer'>About $name$</a>"];
	var getLatestQT     = ["<a href='http://www.apple.com/quicktime'>Get the latest version of $name$</a>", "<a href='http://www.apple.com/quicktime'>Get the latest version of $name$</a>", "<a href='http://www.apple.com/quicktime'>About $name$</a>"];
	var getLatestFlash  = ["<a href='http://www.adobe.com/flashplayer'>Get the latest version of $name$</a>", "<a href='http://www.adobe.com/flashplayer'>Get the latest version of $name$</a>", "<a href='http://www.adobe.com/flashplayer'>About $name$</a>"];
	
	// Set up the preferences. Always call as
	//   setPref(restrictions, minVersion, recVersion, [messages]);
	// The restrictions indicate what cases this requirement applies - the
	// more limits placed into a requirement, the high it is in the order
	// searched. E.g. if a version is defined for the default case, an OS,
	// and an OS+version, they will be matched OS+version first, then OS,
	// then default. The first requirements match is what counts.
	
	// OS versions.
	clientDetect.setPref(Win        ,  5.0 ,  5.0); // Win2000, XP.
	clientDetect.setPref(Win98      ,  3.98,  5.0, ["", "$name$ $version$ is no longer supported by Microsoft.", ""]); // Win98 only, show as warning.
	clientDetect.setPref(Mac        ,  10.0 , 10.0, ["", "$name$ $version$ is no longer supported by Apple.", ""]); // Mac OS 9 only, show as warning.
	
	// Browser versions.
	clientDetect.setPref(WinIE      ,  6.0,  8.0, getLatestIE);
	clientDetect.setPref(Firefox    ,  3.0,  3.0, getLatestFF);
	// Can't tell Safari version, this is mostly pointless for now.
	clientDetect.setPref(Safari     ,  3.0,  3.0, getLatestSafari);
	
	// Global plugin versions.
	// Use WinWMP or it complains about not being installed on Mac.
	clientDetect.setPref(WinWMP     ,  7.1, 11.0, getLatestWMP);
	// Use MacQT or it complains about not being installed on Win.
	clientDetect.setPref(MacQT      ,  7.0,  7.0, getLatestQT);
	clientDetect.setPref(Flash      , 10.0, 10.0, getLatestFlash);
	
	// Specific OS/plugin combinations.
	clientDetect.setPref(Win98WMP   ,  7.1,  7.1, getLatestWMP);
	clientDetect.setPref(WinMEWMP   ,  7.1,  8.0, getLatestWMP);
	clientDetect.setPref(Win2000WMP ,  7.1,  8.0, getLatestWMP);
	clientDetect.setPref(MacOS9QT   ,  5.0,  5.0, getLatestQT);
	clientDetect.setPref(MacOS9Flash,  7.0,  7.0, getLatestFlash);
	
	// General messages.
	//clientDetect.addComment(Firefox.plugin("Windows Media Player"), null, "Firefox + WMP");
	//clientDetect.addComment(Firefox.plugin("Flash", "8.0"), null, "Firefox + Flash 8");
	//clientDetect.addComment(Firefox.plugin("Flash", ">8.0"), null, "Firefox + Flash >8");
	
//	clientDetect.addComment(Win, "above", "This message appears if you are running Windows.");
//	clientDetect.addComment(Mac, "above", "This message appears if you are running Mac.");
//	clientDetect.addComment(Win.browser("Firefox", 1.5), "below", "This message appears <em>only</em> on Firefox 1.5.");
//	clientDetect.addComment(Win.browser("Internet Explorer", 6.0), "below", "This message appears <em>only</em> on IE 6.0.");
//	clientDetect.addComment(Win.browser("Internet Explorer", 7.0), "below", "This message appears <em>only</em> on IE 7.0.");
//	clientDetect.addComment(Default, "below", "This message <em>always</em> appears.");
	
	// Fire Fox and Media Player messages.
	clientDetect.addComment(Firefox.os("Windows").plugin("Windows Media Player"), null, "An error has occurred. Please see details below.");
	clientDetect.addComment(Firefox.os("Windows").plugin("Windows Media Player"), "below", "This page has not been able to detect the version of Media player     installed on your workstation. If you are running windows XP please insure you have Media Player 10 or above. For windows 98 or 2000 we recommend you use version 7.1. for further details please see the <a href='http://www.espresso.co.uk/support/files/docs/Espresso_Minimum_Requirements_2007.pdf'>Espresso Minimum Requirements</a>.");
	
	
	//       END EDITABLE DATA       //
	// Do not edit below this point. //
	
	clientDetect.addPlugin("Flash",
			"application/x-shockwave-flash", /Flash ((\d+)\.(\d+)\s*r(\d+))/i,
			"ShockwaveFlash.ShockwaveFlash", 0, 0);
	
	clientDetect.addPluginHandler("Flash", _pluginhandler_flash);
	function _pluginhandler_flash(type) {
		// If Flash was found but without a version, load an instance to get it.
		if ((this.version == -1) && (typeof ActiveXObject != "undefined")) {
			var flash = new ActiveXObject(this.axComponent);
			if (flash) {
				this.versionStr = String(flash.GetVariable("$version"));
				var ary = this.versionStr.match(/ ([\d,]+)/);
				if (ary) {
					this.versionStr = String(ary[1]).replace(/,/g, ".");
					this.version = this.versionStr;
				}
			}
		}
	};
	
	clientDetect.addPlugin("Windows Media Player",
			"video/x-ms-asf-plugin" /*"application/x-mplayer2"*/, null,
			"WMPlayer.OCX", 0, 0);
	
	clientDetect.addPluginHandler("Windows Media Player", _pluginhandler_wmp);
	function _pluginhandler_wmp(type) {
		// If WMP was found but without a version, load an instance to get it.
		if ((this.version == -1) && (typeof ActiveXObject != "undefined")) {
			var wmp = new ActiveXObject(this.axComponent);
			if (wmp) {
				this.versionStr = String(wmp.versionInfo);
				var ary = this.versionStr.match(/([\d.]+)/);
				if (ary) {
					this.versionStr = String(ary[1]);
					this.version = this.versionStr;
				}
			}
		}
	};
	
	clientDetect.addPlugin("Quicktime",
			"video/quicktime", /Plug-in (\d+\.\d+)/i,
			"QuickTimeCheckObject.QuickTimeCheck", 0, 0);
	
	clientDetect.addPluginHandler("Quicktime", _pluginhandler_qt);
	function _pluginhandler_qt(type) {
		// If QT was found but without a version, load an instance to get it.
		if ((this.version == -1) && (typeof ActiveXObject != "undefined")) {
			var qt = new ActiveXObject(this.axComponent);
			if (qt && qt.IsQuickTimeAvailable(0)) {
				var ver = Number(qt.QuickTimeVersion).toString(16) / 100000;
				this.version = Math.floor(ver) / 10;
			}
		}
	};
	
	clientDetect.addPlugin("Real Player",
			"application/vnd.rn-realplayer-javascript", /(\d+\.\d+)/,
			"rmocx.RealPlayer G2 Control", 0, 0);
	
	clientDetect.addPluginHandler("Real Player", _pluginhandler_rp);
	function _pluginhandler_rp(type) {
		// If Real was found but without a version, load an instance to get it.
		if ((this.version == -1) && (typeof ActiveXObject != "undefined")) {
			var rp = new ActiveXObject(this.axComponent);
			if (rp) {
				this.versionStr = String(rp.GetVersionInfo());
				var ary = this.versionStr.match(/((\d+\.\d+)[\d.]+)/);
				if (ary) {
					this.versionStr = String(ary[1]);
					this.version = parseFloat(ary[2]);
				}
			}
		}
		
		// If Real was not found, try the older ActiveX component.
		if ((this.version == 0) && (typeof ActiveXObject != "undefined")) {
			var rp = new ActiveXObject("RealPlayer.RealPlayer(tm) ActiveX Control (32-bit)");
			if (rp) {
				this.versionStr = String(rp.GetVersionInfo());
				var ary = this.versionStr.match(/((\d+\.\d+)[\d.]+)/);
				if (ary) {
					this.versionStr = String(ary[1]);
					this.version = parseFloat(ary[2]);
				}
			}
		}
	};
	
	clientDetect.addPlugin("Shockwave",
			"application/x-director", /(\d+\.\d+)/,
			"SWCtl.SWCtl", 1, 15);
	
	clientDetect.addPluginHandler("Shockwave", _pluginhandler_director);
	function _pluginhandler_director(type) {
		// If Shockwave Director was found but without a version, load an instance to get it.
		if ((this.version == -1) && (typeof ActiveXObject != "undefined")) {
			var rp = new ActiveXObject(this.axComponent);
			if (rp) {
				this.versionStr = rp.ShockwaveVersion("");
				var ary = this.versionStr.match(/((\d+\.\d+)[\d.]+)/);
				if (ary) {
					this.version = parseFloat(ary[2]);
				}
			}
		}
	};
	
	clientDetect.addPlugin("Acrobat Reader",
			"application/pdf", /(\d+\.\d+)/,
			"AcroPDF.PDF", 1, 10);
	
	clientDetect.addPluginHandler("Acrobat Reader", _pluginhandler_ar);
	function _pluginhandler_ar(type) {
		
		// Fix the versions, which don't go in sequence
		// (but only for ActiveX type of version, type == 1).
		if ((type == 1) && (this.version > 0)) {
			this.version += 6;
		}
		
		// If Adobe Reader was not found, try the older ActiveX component.
		if ((this.version == 0) && (typeof ActiveXObject != "undefined")) {
			// This doesn't make much sense, but it is what all other scripts do.
			if (new ActiveXObject("PDF.PdfCtrl.1")) {
				this.version = 4;
			} else {
				for (var v = 2; v <= 10; v++) {
					if (new ActiveXObject("PDF.PdfCtrl." + v)) {
						this.version = v - 1;
					}
				}
			}
		}
	};
}

// Internals:

function cdASSERT(cond, msg) {
	if (!cond) {
		//alert("Client Detect ASSERT failed:\n\n" + msg);
		throw new Error("Client Detect ASSERT failed:\n" + msg);
	}
}

function cdCompareVersions(v1, v2) {
	var v1a = String(v1).split(".");
	var v2a = String(v2).split(".");
	while (v1a.length < v2a.length) v1a.push(0);
	while (v1a.length > v2a.length) v2a.push(0);
	for (var i = 0; i < v1a.length; i++) {
		if (Number(v1a[i]) > Number(v2a[i])) return 1;
		if (Number(v1a[i]) < Number(v2a[i])) return -1;
	}
	return 0;
}

function ClientDetect() {
	this.env = new ClientDetectEnvironment();
	this.plugins = new Array();
	this.prefs = new Array();
	this.data = new Object();
}

ClientDetect.prototype.addPlugin =
function cd_addplugin(name, mime, regexp, axComponent, minVer, maxVer) {
	for (var i = 0; i < this.plugins.length; i++) {
		cdASSERT(this.plugins[i].name != name, "Already added plugin with name '" + name + "'");
	}
	this.plugins.push({ name: name, mime: mime, regexp: regexp, axComponent: axComponent, minVer: minVer, maxVer: maxVer });
}

ClientDetect.prototype.addPluginHandler =
function cd_addpluginhandler(name, handler) {
	for (var i = 0; i < this.plugins.length; i++) {
		if (this.plugins[i].name == name) {
			this.plugins[i].handler = handler;
			return;
		}
	}
	cdASSERT(false, "Plugin '" + name + "' not found while adding handler");
}

ClientDetect.prototype.setPref =
function cd_setpref(restrictions, minVersion, recVersion, messages) {
	var pref = new Object();
	
	pref.restrictions = restrictions;
	pref.item = restrictions.limits[restrictions.limits.length - 1];
	pref.minVersion = minVersion;
	pref.recVersion = recVersion;
	pref.messages = new Array();
	
	if (messages) {
		if (messages[0]) {
			// <min version.
			var restriction = restrictions.clone().addLimit({ type: pref.item.type, name: pref.item.name, version: "<" + minVersion });
			pref.messages.push({ restrictions: restriction, html: messages[0] });
		}
		if (messages[1]) {
			// Min-rec version.
			var restriction = restrictions.clone().addLimit({ type: pref.item.type, name: pref.item.name, version: ">=" + minVersion }).addLimit({ type: pref.item.type, name: pref.item.name, version: "<" + recVersion });
			pref.messages.push({ restrictions: restriction, html: messages[1] });
		}
		if (messages[2]) {
			// >=rec version.
			var restriction = restrictions.clone().addLimit({ type: pref.item.type, name: pref.item.name, version: ">=" + recVersion });
			pref.messages.push({ restrictions: restriction, html: messages[2] });
		}
	}
	
	this.prefs.push(pref);
	
	function _setpref_sort(a, b) {
		if (a.restrictions.limits.length < b.restrictions.limits.length)
			return -1;
		if (a.restrictions.limits.length > b.restrictions.limits.length)
			return 1;
		return 0;
	};
	this.prefs.sort(_setpref_sort);
}

ClientDetect.prototype.addComment =
function cd_setpref(restrictions, target, messages) {
	var pref = restrictions.limits[restrictions.limits.length - 1];
	var data;
	
	if (target) {
		data = this.getDataInternal("msg", target);
	} else {
		data = this.getDataInternal(pref.type, pref.name);
	}
	if (!data.messages) {
		data.messages = new Array();
	}
	
	data.messages.push({ restrictions: restrictions, html: messages });
}


ClientDetect.prototype.getStatus =
function cd_getstatus(type, name) {
	var data = this.data[type];
	if (typeof name != "undefined") {
		data = data[name];
	}
	
	if (data.min && data.rec) {
		return data;
	}
	
	data.ok = "";
	data.min = { name: data.name, version: 0 };
	data.rec = { name: data.name, version: 0 };
	
	for (var i = 0; i < this.prefs.length; i++) {
		if (this.prefs[i].item.type != type) continue;
		if (name && (this.prefs[i].item.name != name)) continue;
		
		// First one to match wins.
		if (this.prefs[i].restrictions.apply(this)) {
			data.min.version = this.prefs[i].minVersion;
			data.rec.version = this.prefs[i].recVersion;
			
			for (var j = 0; j < this.prefs[i].messages.length; j++) {
				data.messages.push(this.prefs[i].messages[j]);
			}
			
			if (data.version == -1) {
				data.ok = "warn";
			} else {
				if (cdCompareVersions(data.version, data.rec.version) >= 0) {
					data.ok = "good";
				} else if (cdCompareVersions(data.version, data.min.version) >= 0) {
					data.ok = "warn";
				} else {
					data.ok = "error";
				}
			}
			break;
		}
	}
	
	return data;
}

ClientDetect.prototype.formatVersion =
function cd_formatversion(obj, rec) {
	function formatVer(ver) {
		if ((typeof rec != "undefined") && rec) {
			if (ver ==  0) return "";
		} else {
			if (ver ==  0) return "Not detected";
			if (ver == -1) return "Installed";
		}
		if (ver == Math.floor(ver)) {
			ver = String(Number(ver)) + ".0";
		}
		return ver;
	};
	
	function formatOSVer(ver) {
		if (cdCompareVersions(ver, 0.0 ) <= 0) return "";
		if (cdCompareVersions(ver, 3.95) == 0) return "95";
		if (cdCompareVersions(ver, 3.98) == 0) return "98";
		if (cdCompareVersions(ver, 3.99) == 0) return "ME";
		if (cdCompareVersions(ver, 4.0 ) == 0) return "NT";
		if (cdCompareVersions(ver, 5.0 ) == 0) return "2000";
		if (cdCompareVersions(ver, 5.1 ) == 0) return "XP";
		if (cdCompareVersions(ver, 5.2 ) == 0) return "2003";
		if (cdCompareVersions(ver, 6.0 ) == 0) return "Vista";
		if (cdCompareVersions(ver, 6.1 ) == 0) return "7";
		return formatVer(ver);
	};
	
	function formatBrowserVer(ver) {
		if (cdCompareVersions(ver, 0.0) <= 0) return "";
		return formatVer(ver);
	};
	
	if (!obj) {
		return "<none>";
	}
	
	if (obj.versionStr) {
		return obj.versionStr;
	}
	if (obj.type == "os") {
		return formatOSVer(obj.version);
	}
	if (obj.type == "browser") {
		return formatBrowserVer(obj.version);
	}
	return formatVer(obj.version);
}

ClientDetect.prototype.formatObject =
function cd_formatobject(obj) {
	return obj.name + " " + this.formatVersion(obj);
}

ClientDetect.prototype.formatStatus =
function cd_formatstatus(fn, obj) {
	var html = fn;
	if (typeof this[fn] == "function") {
		html = this[fn](obj);
	}
	html = String(html).replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/\"/g, "&quot;");
	if (obj.ok) {
		html = "<SPAN CLASS='state_" + String(obj.ok).toLowerCase() + "'>" + html + "</SPAN>";
	}
	return html;
}

ClientDetect.prototype.getDataInternal =
function cd_getdatainternal(type, name) {
	if (typeof this.data[type] == "undefined") {
		this.data[type] = new Object();
		this.data[type].messages = new Array();
	}
	if (typeof name == "undefined") {
		return this.data[type];
	}
	
	if (typeof this.data[type][name] == "undefined") {
		this.data[type][name] = new Object();
		this.data[type][name].messages = new Array();
	}
	return this.data[type][name];
}

ClientDetect.prototype.getData =
function cd_getdata(type, name) {
	var ua = String(navigator.userAgent || "");
	var ve = String(navigator.vendor    || "");
	var ary;
	this.getDataInternal(type, name);
	
	if (typeof this.data[type].version == "undefined") {
		// OS and Browsers get populated when they're requested.
		if (type == "os") {
			// Detect Operating System.
			var os, osVer;
			
			if ((ary = ua.match(/Windows (NT)? ?(\d+\.\d+)/i))) {
				os = "Windows";
				osVer = parseFloat(ary[2]);
			} else if (ua.indexOf("Win16") != -1) {
				os = "Windows";
				osVer = 3.1;
			} else if (ua.match(/Win(dows)? ?95/i)) {
				os = "Windows";
				osVer = 3.95;
			} else if (ua.match(/Win(dows)? ?98/i)) {
				os = "Windows";
				osVer = 3.98;
			} else if (ua.match(/Win(dows)? ?ME/i)) {
				os = "Windows";
				osVer = 3.99;
			} else if (ua.match(/Win(dows)? ?NT/i)) {
				os = "Windows";
				osVer = 4.0;
			}
			if (ua.indexOf("Macintosh") != -1) {
				os = "Mac";
				osVer = -1;
				
				// Safari includes Mac OS X version since 3.1.
				if ((ary = ua.match(/Mac OS X (\d+[\._]\d+)/i))) {
					osVer = parseFloat(ary[1].replace(/_/g, "."));
				}
			}
			
			if (typeof this.data[type][os] != "undefined") {
				this.data[type] = this.data[type][os];
			}
			this.data[type].type    = type;
			this.data[type].name    = os;
			this.data[type].version = osVer;
			this.data[type][os]     = this.data[type];
			
		} else if (type == "browser") {
			// Detect Browser.
			var browser, browserVer, browserVS;
			
			if ((ary = ua.match(/MSIE (\d+\.\d+)/i))) {
				browser = "Internet Explorer";
				browserVer = parseFloat(ary[1]);
			} else if ((ary = ua.match(/Firefox\/([\d.]+)/i))) {
				browser = "Firefox";
				browserVer = parseFloat(ary[1]);
				browserVS = String(ary[1]);
			} else if ((ary = ve.match(/Apple/)) || ua.match(/Safari\//i)) {
				browser = "Safari";
				browserVer = -1;
				
				// Safari includes its own version since 3.0.
				if ((ary = ua.match(/Version\/([\d.]+)/i))) {
					browserVer = parseFloat(ary[1]);
				}
			}
			
			if (typeof this.data[type][browser] != "undefined") {
				this.data[type] = this.data[type][browser];
			}
			this.data[type].type       = type;
			this.data[type].name       = browser;
			this.data[type].version    = browserVer;
			this.data[type].versionStr = browserVS;
			this.data[type][browser]   = this.data[type];
		}
	}
	
	if (typeof name == "undefined") {
		this.getStatus(type);
		return this.data[type];
	}
	
	if (typeof this.data[type][name].version == "undefined") {
		// Individual plugins get populated when requested.
		if (type == "plugin") {
			function getPluginVersion(pluginData) {
				var ver1 = getMIMEPluginVersion(pluginData.mime, pluginData.regexp);
				// ver1 > 0 means it knows which version, so return.
				if (cdCompareVersions(ver1, 0) > 0) return [0, ver1];
				var ver2 = getActiveXVersion(pluginData.axComponent, pluginData.minVer, pluginData.maxVer);
				// ver1 must be -1 or 0, so if ver2 > 0, it wins.
				if (cdCompareVersions(ver2, 0) > 0) return [1, ver2];
				// Both ver1 and ver2 are -1 or 0. Return lower one.
				if (cdCompareVersions(ver1, 0) < 0) return [0, ver1];
				return [1, ver2];
			};
			
			function getMIMEPluginVersion(mime, regexp) {
				if (!mime || (typeof navigator.mimeTypes[mime] == "undefined")) {
					return 0;
				}
				var plugin = navigator.mimeTypes[mime].enabledPlugin;
				if (!plugin) {
					return 0;
				}
				if (regexp) {
					var ary = plugin.description.match(regexp);
					if (!ary) {
						ary = plugin.name.match(regexp);
					}
					if (ary && (ary.length == 2)) {
						return parseFloat(ary[1]);
					}
					if (ary && (ary.length > 2)) {
						var vp = new Array();
						for (var i = 2; i < ary.length; i++) {
							vp.push(parseInt(ary[i]));
						}
						return vp.join(".");
					}
				}
				return -1;
			};
			
			function getActiveXVersion(axComponent, minVer, maxVer) {
				if ((typeof ActiveXObject == "undefined") || !axComponent) {
					return 0;
				}
				for (var v = maxVer; v >= minVer; v--) {
					try {
						var o = new ActiveXObject(axComponent + "." + v);
						if (o) {
							return v;
						}
					} catch(ex) {
					}
				}
				try {
					var o = new ActiveXObject(axComponent);
					if (o) {
						return -1;
					}
				} catch(ex) {
				}
				return 0;
			};
			
			// Detect plugins version.
			for (var i = 0; i < this.plugins.length; i++) {
				if (this.plugins[i].name == name) {
					var ver = getPluginVersion(this.plugins[i]);
					this.plugins[i].version = ver[1];
					if (typeof this.plugins[i].handler == "function") {
						try {
							this.plugins[i].handler(ver[0]);
						} catch(ex) {
						}
					}
					for (var p in this.plugins[i]) {
						this.data[type][name][p] = this.plugins[i][p];
					}
					this.data[type][name].type = type;
				}
			}
		}
	}
	
	this.getStatus(type, name);
	return this.data[type][name];
}

ClientDetect.prototype.setData =
function cd_setdata(type, name, data) {
	this.getData(type, name);
	this.data[type][name] = data;
}


function ClientDetectEnvironment(clone) {
	this.limits = new Array();
	
	if (typeof clone == "object") {
		for (var i = 0; i < clone.limits.length; i++) {
			this.addLimit(clone.limits[i]);
		}
	}
}

ClientDetectEnvironment.prototype.base =
ClientDetectEnvironment.prototype.clone =
function cde_base() {
	return new ClientDetectEnvironment(this);
}

ClientDetectEnvironment.prototype.os =
function cde_os(name, version) {
	var cde = new ClientDetectEnvironment(this);
	cde.addLimit({ type: "os", name: name, version: String(version || "") });
	return cde;
}

ClientDetectEnvironment.prototype.browser =
function cde_browser(name, version) {
	var cde = new ClientDetectEnvironment(this);
	cde.addLimit({ type: "browser", name: name, version: String(version || "") });
	return cde;
}

ClientDetectEnvironment.prototype.plugin =
function cde_plugin(name, version) {
	var cde = new ClientDetectEnvironment(this);
	cde.addLimit({ type: "plugin", name: name, version: String(version || "") });
	return cde;
}

ClientDetectEnvironment.prototype.addLimit =
function cde_addlimit(limit) {
	cdASSERT(typeof limit == "object", "Restriction must be an object.");
	if (typeof limit.type    == "undefined") limit.type    = "";
	if (typeof limit.name    == "undefined") limit.name    = "";
	if (typeof limit.version == "undefined") limit.version = "";
	cdASSERT(typeof limit.type    == "string", "Restriction must have a 'type' string property.");
	cdASSERT(typeof limit.name    == "string", "Restriction must have a 'name' string property.");
	cdASSERT(typeof limit.version == "string", "Restriction must have a 'version' string property.");
	
	for (var i = 0; i < this.limits.length; i++) {
		cdASSERT((this.limits[i].type != limit.type) ||
		         (this.limits[i].name != limit.name) ||
		         (this.limits[i].version != limit.version),
		         "Restriction already defined in this environment.");
	}
	
	this.limits.push(limit);
	return this;
}

ClientDetectEnvironment.prototype.apply =
function cde_apply(clientDetect) {
	for (var i = 0; i < this.limits.length; i++) {
		var limit = this.limits[i];
		// Get data.
		var data = clientDetect.getData(limit.type, limit.name);
		// No data for item being checked ==> failed to match.
		if (!data.name) {
			return false;
		}
		if (limit.version) {
			// Compare versions.
			var ary = limit.version.match(/(<=?|>=?|)(\d+(\.\d+)*)/);
			cdASSERT(ary, "Version '" + limit.version + "' in restriction is invalid.");
			var cmp = ary[1];
			var ver = ary[2];
			if ((cmp == "") && (cdCompareVersions(data.version, ver) != 0)) {
				return false;
			}
			if ((cmp == ">") && (cdCompareVersions(data.version, ver) <= 0)) {
				return false;
			}
			if ((cmp == ">=") && (cdCompareVersions(data.version, ver) < 0)) {
				return false;
			}
			if ((cmp == "<") && (cdCompareVersions(data.version, ver) >= 0)) {
				return false;
			}
			if ((cmp == "<=") && (cdCompareVersions(data.version, ver) > 0)) {
				return false;
			}
		}
	}
	return true;
}

clientDetectInit();
