(function(){
	
	Code = {
		
		version: '1.0.0',
		websiteRoot: '/',
		resources: {},
		
		
		initialize: function(){
			
			// Set up quick shortcuts
			Code.ns = Code.registerNamespace;
			
			Code.UserAgent.initialize();
			
			Code.Location.initialize();
			
			// Remove css image flicker on IE<7
			if(Code.UserAgent.isIElt7){
				try{
					document.execCommand("BackgroundImageCache", false, true);
				}
				catch(e){}
			}
		
		},
		
		
		breakOutOfFrames: function(){
			if (top.location != self.location) {
				top.location = self.location.href;
			}
		},
		
		
		clone: function(obj) {
			return Code.extend({ }, obj);
		},


		coalesce: function(){
			for(var i=0; i<arguments.length; i++){
				if (!Code.Type.isNothing(arguments[i])){
					return arguments[i];
				}
			}
			return null;
		},
		

		extend: function(obj, properties){
			if (obj && properties && Code.Type.isObject(properties)){
				for(var prop in properties){
					obj[prop] = properties[prop];
				}
			}
			return obj;
		},
		
		
		extendIfNotExists: function(obj, properties){
			if(obj && properties && Code.Type.isObject(properties)){
				for(var property in properties){
					if(typeof obj[property] == "undefined"){ 
						obj[property] = properties[property]; 
					}
				}
			}
			return obj;
		},
		
		
		getResource: function(classKey, resourceKey, defaultValue){
			var resourceObj = Code.resources[classKey];
			if (defaultValue == null){
				defaultValue = 'Resource "#classKey#, #resourceKey#" not found.'
			}
			defaultValue = defaultValue
											.replace(/#classKey#/g, classKey)
											.replace(/#resourceKey#/g, resourceKey);
		
			if (resourceObj == null){
				return defaultValue;
			}
			
			var value = resourceObj[resourceKey];
			return (Code.Type.isNothing(value)) ? defaultValue : value;
		},
	
			
		redirect: function(url, delay){
			
			if (Code.Type.isNumber(delay)){
				setTimeout(function(){
					window.location = url;
				}, delay);
			}
			else{
				window.location = url;	
			}
			
		},
		
						
		registerNamespace: function (){
			var args = arguments, obj = null, i, j;
			for (i=0; i<args.length; ++i) {
				var ns = args[i];
				var nsParts = ns.split(".");
				var root = nsParts[0];
				eval('if (typeof ' + root + ' == "undefined"){' + root + ' = {};} obj = ' + root + ';');
				for (j=1; j<nsParts.length; ++j) {
					obj[nsParts[j]] = obj[nsParts[j]] || {};
					obj = obj[nsParts[j]];
				}
			}
	 	},
		
		
		resolveUrl: function(url){
			if (!Code.Type.isString(url)){
				return Code.websiteRoot;
			}
			return url.replace(/~\//, Code.websiteRoot);
		}
		
	};
	
	
	Code.Location = {
				
		queryString: {},
		isSecure: false,
		
		initialize: function(){
			this.queryString = 
				Code.QueryString.parse(location.search.substring(1,location.search.length));
			this.isSecure = window.location.href.toLowerCase().indexOf("https") === 0;
		},
		
		getQueryStringValue: function(key, defaultValue){
			if (!Code.Type.isString(defaultValue)){
				defaultValue = '';
			}
			return Code.coalesce(this.queryString[key], defaultValue);
		}

	};
	
	
	
	Code.QueryString = {
		
		parse: function(text, overwrite){
			
			if (!Code.Type.isString(text)){
				return {};
			}
			
			var obj = {};
			var pairs = text.split('&');
			var pair, name, value;
			for(var i = 0, len = pairs.length; i < len; i++){
				pair = pairs[i].split('=');
				name = decodeURIComponent(pair[0]);
				value = decodeURIComponent(pair[1]);
				if(overwrite !== true){
					if(Code.Type.isUndefined(obj[name])){
						obj[name] = value;
					}
					else if(Code.Type.isString(obj[name])){
						obj[name] = [obj[name]];
						obj[name].push(value);
					}
					else{
						obj[name].push(value);
					}
				}
				else{
					obj[name] = value;
				}
			}
			return obj;
			
		},
		
		
		stringify: function(obj){
			if(Code.Type.isNothing(obj)){
				return '';
			}
			var buf = [];
			for(var key in obj){
				var ov = obj[key], k = encodeURIComponent(key);
				if(Code.Type.isUndefined(ov)){
					buf.push(k, "=&");
				}
				else if(!Code.Type.isFunction(ov) && !Code.Type.isObject(ov)){
					buf.push(k, "=", encodeURIComponent(ov), "&");
				}
				else if(Code.Type.isArray(ov)){
					if (ov.length) {
						for(var i = 0, len = ov.length; i < len; i++) {
							buf.push(k, "=", encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
						}
					}
					else {
						buf.push(k, "=&");
					}
				}
			}
			buf.pop();
			return buf.join("");
		}
		
	};
	

	Code.String = {
		
		endsWith: function(str, pattern, ignoreCase) {
			if (!Code.Type.isString(str)){return '';}
			if (!Code.Type.isNothing(ignoreCase)){
				if (ignoreCase){
					str = str.toLowerCase();
					pattern = pattern.toLowerCase();
				}
			}
			var d = str.length - pattern.length;
			return d >= 0 && str.lastIndexOf(pattern) === d;
		},
	
		escapeHtml: function(str) {
			if (!Code.Type.isString(str)){return '';}
			return str.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
		},
		
		left: function(str, length){
			if (!Code.Type.isString(str)){return '';}
			return str.substring(0, length);
		},
		
		makeUrlSafe: function(str, toLower, wordSeparator){
			if (!Code.Type.isString(str)){return '';}
			// Replace non aplha-numeric characters with a space
			str = str.replace(/[^a-zA-Z0-9 ]/g,' ');
			// Replace multiple spaces with 1 space
			str = str.replace(/\s{2,}/g,' ');
			if (!Code.Type.isString(wordSeparator)){
				wordSeparator = '-';
			}
			str = str.replace(/\s/g, wordSeparator);
			if (Code.Type.isNothing(toLower)){
				toLower = true;
			}
			if (toLower){
				str = str.toLowerCase();
			}
			return str;
		},
		
		mid: function(str, start, end)
		{
			if (!Code.Type.isString(str)){return '';}
			if(!start){start=0};
			if(!end || end > str.length){end=str.length};
			if(end != str.length){end = start + end};
			return str.substring(start, end);
		},
		
		right: function(str, length)
		{
			if (!Code.Type.isString(str)){return '';}
			return str.substring((str.length - length), str.length);
		},
		
		startsWith: function(str, pattern, ignoreCase) {
			if (!Code.Type.isString(str)){return '';}
			if (!Code.Type.isNothing(ignoreCase)){
				if (ignoreCase){
					str = str.toLowerCase();
					pattern = pattern.toLowerCase();
				}
			}
			return str.indexOf(pattern) === 0;
		},
	
		stripWhitespace: function(str)
		{
			if (!Code.Type.isString(str)){return '';}
			var exp = new RegExp('\\s{1,}', 'gi');
			return str.replace(exp, '');
		},
		
		stripTags: function(str) {
			if (!Code.Type.isString(str)){return '';}
			return str.replace(/<\/?[^>]+>/gi, '');
		},
		
		times: function(str, count) {
			if (!Code.Type.isString(str)){return '';}
			return count < 1 ? '' : new Array(count + 1).join(str);
		},
		
		trim: function(str)
		{
			if (!Code.Type.isString(str)){return '';}
			return Code.String.trimEnd(Code.String.trimStart(str));
		},
		
		trimEnd: function (str)
		{
			if (!Code.Type.isString(str)){return '';}
			while(str.charAt((str.length -1))==" "){
				str = str.substring(0,str.length-1);
			}
			return str;
		},
		
		trimStart: function (str)
		{
			if (!Code.Type.isString(str)){return '';}
			while(str.charAt(0)==" "){
				str = str.replace(str.charAt(0),"");
			}
			return str;
		},
		
		truncate: function(str, length, truncation) {
			if (!Code.Type.isString(str)){return '';}
			length = length || 30;
			truncation = Code.Type.isNothing(truncation) ? '...' : truncation;
			return str.length > length ?
			str.slice(0, length - truncation.length) + truncation : String(str);
		},
		
		unescapeHtml: function(str) {
			if (!Code.Type.isString(str)){return '';}
			return str.replace(/&amp;/g,'&').replace(/&lt;/g,'<').replace(/&gt;/g,'>');
		}
		
	};

	Code.Type = {
		
		isArray: function(obj){
			return obj && Code.Type.isFunction(obj.pop);
		},
		
		isDate : function(obj){
			return obj && Code.Type.isFunction(obj.getFullYear);
		},
		
		isElement: function(obj){
			return obj && obj.nodeType == 1;
		},
		
		isFunction: function(obj){
			return typeof obj == "function";
		},
		
		isString: function(obj){
			return typeof obj == "string";
		},
		
		isNull: function(obj){
			return obj === null;
		},
		
		isNothing: function(obj){
			if(Code.Type.isUndefined(obj) || Code.Type.isNull(obj)){
				return true;
			}	
			return false;
		},
				
		isNumber: function(obj){
			return typeof obj == "number";
		},
		
		isObject: function(obj){
			return typeof obj == "object";
		},

		isUndefined: function(obj){
			return typeof obj == "undefined";
		}
		
	};

	
	Code.JSON = function(){function f(n){return n<10?'0'+n:n;}
Date.prototype.toJSON=function(key){return this.getUTCFullYear()+'-'+
f(this.getUTCMonth()+1)+'-'+
f(this.getUTCDate())+'T'+
f(this.getUTCHours())+':'+
f(this.getUTCMinutes())+':'+
f(this.getUTCSeconds())+'Z';};String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(key){return this.valueOf();};var cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,escapeable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,gap,indent,meta={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'},rep;function quote(string){escapeable.lastIndex=0;return escapeable.test(string)?'"'+string.replace(escapeable,function(a){var c=meta[a];if(typeof c==='string'){return c;}
return'\\u'+('0000'+
(+(a.charCodeAt(0))).toString(16)).slice(-4);})+'"':'"'+string+'"';}
function str(key,holder){var i,k,v,length,mind=gap,partial,value=holder[key];if(value&&typeof value==='object'&&typeof value.toJSON==='function'){value=value.toJSON(key);}
if(typeof rep==='function'){value=rep.call(holder,key,value);}
switch(typeof value){case'string':return quote(value);case'number':return isFinite(value)?String(value):'null';case'boolean':case'null':return String(value);case'object':if(!value){return'null';}
gap+=indent;partial=[];if(typeof value.length==='number'&&!(value.propertyIsEnumerable('length'))){length=value.length;for(i=0;i<length;i+=1){partial[i]=str(i,value)||'null';}
v=partial.length===0?'[]':gap?'[\n'+gap+
partial.join(',\n'+gap)+'\n'+
mind+']':'['+partial.join(',')+']';gap=mind;return v;}
if(rep&&typeof rep==='object'){length=rep.length;for(i=0;i<length;i+=1){k=rep[i];if(typeof k==='string'){v=str(k,value);if(v){partial.push(quote(k)+(gap?': ':':')+v);}}}}else{for(k in value){if(Object.hasOwnProperty.call(value,k)){v=str(k,value);if(v){partial.push(quote(k)+(gap?': ':':')+v);}}}}
v=partial.length===0?'{}':gap?'{\n'+gap+partial.join(',\n'+gap)+'\n'+
mind+'}':'{'+partial.join(',')+'}';gap=mind;return v;}}
return{stringify:function(value,replacer,space){var i;gap='';indent='';if(typeof space==='number'){for(i=0;i<space;i+=1){indent+=' ';}}else if(typeof space==='string'){indent=space;}
rep=replacer;if(replacer&&typeof replacer!=='function'&&(typeof replacer!=='object'||typeof replacer.length!=='number')){throw new Error('Code.JSON.stringify');}
return str('',{'':value});},parse:function(text,reviver){var j;function walk(holder,key){var k,v,value=holder[key];if(value&&typeof value==='object'){for(k in value){if(Object.hasOwnProperty.call(value,k)){v=walk(value,k);if(v!==undefined){value[k]=v;}else{delete value[k];}}}}
return reviver.call(holder,key,value);}
cx.lastIndex=0;if(cx.test(text)){text=text.replace(cx,function(a){return'\\u'+('0000'+
(+(a.charCodeAt(0))).toString(16)).slice(-4);});}
if(/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,'@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,']').replace(/(?:^|:|,)(?:\s*\[)+/g,''))){j=eval('('+text+')');return typeof reviver==='function'?walk({'':j},''):j;}
throw new SyntaxError('Code.JSON.parse');}};}();

		
	Code.UserAgent = {
		
		userAgentString: '',
		
		// Some quick common properties
		isIE: false,
		isIE5_5: false,
		isIE6: false,
		isIElt7: false,
		isIE7: false,
		isIE8: false,
		isSafari: false,
		isSafari2: false,
		isSafari3: false,
		isOpera: false,
		isFirefox: false,
		isFirefox2: false,
		isFirefox3: false,
		isGecko: false,
		isKHTML: false,
		isWebKit: false,
		
		hasFlash: false,
		hasFlash9: false,
		hasFlash8: false,
		hasFlash7: false,
		
		isWindows: false,
		isWindowsXP: false,
		isWindowsVista: false,
		isLinux: false,
		isMacOSX: false,
		
		
		browser: {
			id: 'unknown',
			version: '0.0',
			majorVersion: '0',
			minorVersion: '0',
			engine: 'unknown',
			engineVersion: '0.0',
			engineMajorVersion: '0',
			engineMinorVersion: '0',
			isStrict: false,
			isBorderBox: false
		},
		
		
		os: {
			id: 'unknown',
			version: '0.0'
		},
		
		
		flash: {
			status: 'unknown',
			version: '0'
		},
		
		
		initialize: function(){
			
			var ua = navigator.userAgent.toLowerCase();
			this.userAgentString = ua;
			
			// Browser details
			
			this.browser.isStrict = document.compatMode == "CSS1Compat";
			
			if (ua.search(/firefox[\/\s](\d+([\.-]\d)*)/) != -1) {
				// Firefox
				this.browser.id = "firefox";
				this.browser.version = ua.match(/firefox[\/\s](\d+([\.-]\d)*)/)[1];
				this.browser.engine = "gecko";
				this.browser.engineVersion = getGeckoVersion();
				this.isGecko = true;
				this.isFirefox = true;
				switch(parseInt(this.browser.version)){
					case 3:
						this.isFirefox3 = true;
						break;
					case 2:
						this.isFirefox2 = true;
						break;
					default:
						break;
				}
			}
			else if (ua.search(/safari\/(\d)*/) != -1) {
				// Safari
				this.browser.id = "safari";
				this.browser.version = ua.match(/safari\/(\d+(\.?\d*)*)/)[1];
				this.browser.engine = "webkit";
				this.browser.engineVersion = ua.match(/applewebkit\/(\d+(\.?\d*)*)/)[1];
				this.isSafari = true;
				this.isWebKit = true;
				if (ua.indexOf('webkit/5') != -1){
					this.isSafari3 = true;
				}
				else if (ua.indexOf('webkit/4') != -1){
					this.isSafari2 = true;
				}
			} 
			else if (ua.search(/opera[\/\s](\d+(\.?\d)*)/) != -1) {
				// Opera
				this.browser.id = "opera";
				this.browser.version = ua.match(/opera[\/\s](\d+(\.?\d)*)/)[1];
				this.browser.engine = "opera";
				this.browser.engineVersion = this.browser.version;
				this.isOpera = true;
			}
			else if (ua.search(/msie\s(\d+(\.?\d)*)/) != -1) {
				// MSIE
				this.browser.id = "ie";
				this.browser.version = ua.match(/msie\s(\d+(\.?\d)*)/)[1];
				this.browser.engine = "ie";
				this.browser.engineVersion = this.browser.version;
				this.isIE = true;
				switch(parseInt(this.browser.version)){
					case 8:
						this.isIE8 = true;
						break;
					case 7:
						this.isIE7 = true;
						break;
					case 6:
						this.isIE6 = true;
						this.isIElt7 = true;
						break;
					default:
						this.isIElt7 = true;
						if (this.browser.version == '5.5'){
							this.isIE5_5 = true;
						}
						break;
				}
				if (!this.browser.isStrict){
					this.browser.isBorderBox = true;
				}
			}
			else if (ua.search(/camino[\/\s](\d+([\.-]\d)*)/) != -1) {
				// Camino
				this.browser.id = "camino";
				this.browser.version = brs.match(/camino[\/\s](\d+([\.-]\d)*)/)[1];
				this.browser.engine = "gecko";
				this.browser.engineVersion = getGeckoVersion();
				this.isGecko = true;
			}
			else if (ua.search(/konqueror[\/\s](\d+([\.-]\d)*)/) != -1) {
				// Konqueror
				this.browser.id = "konqueror";
				this.browser.version = ua.match(/konqueror[\/\s](\d+([\.-]\d)*)/)[1];
				this.browser.engine = "khtml";
			}
			else if (brs.search(/netscape6[\/\s](\d+([\.-]\d)*)/) != -1) {
				// Netscape 6.x
				this.browser.id = "netscape";
				this.browser.version = ua.match(/netscape6[\/\s](\d+([\.-]s\d)*)/)[1];
				this.browser.engine = "gecko";
				this.browser.engineVersion = getGeckoVersion();
				this.isGecko = true;
			}
			else if (ua.search(/netscape\/(7\.\d*)/) != -1) {
				// Netscape 7.x
				this.browser.id = "netscape";
				this.browser.version = ua.match(/netscape\/(7\.\d*)/)[1];
				this.browser.engine = "gecko";
				this.browser.engineVersion = getGeckoVersion();
				this.isGecko = true;
			}
			else if (ua.search(/netscape4\/(\d+([\.-]\d)*)/) != -1) {
				// Netscape 4.x
				this.browser.id = "netscape";
				this.browser.version = ua.match(/netscape4\/(\d+([\.-]\d)*)/)[1];
				this.browser.engine = "mozold";
				this.browser.engineVersion = this.browser.version;
			} 
			else if ((ua.search(/mozilla\/(4.\d*)/) != -1) && (ua.search(/msie\s(\d+(\.?\d)*)/) == -1) ) {
				this.browser.id = "netscape";
				this.browser.version = ua.match(/mozilla\/(4.\d*)/)[1];
				this.browser.engine = "mozold";
				this.browser.engineVersion = this.browser.version;
			} 
			else if ((ua.search(/mozilla\/5.0/) != -1) && (ua.search(/gecko\//) != -1)) {
				// Mozilla Seamonkey
				this.browser.id = "mozsea";
				this.browser.version = ua.match(/rv\x3a(\d+(\.?\d)*)/)[1];
				this.browser.engine = "gecko";
				this.browser.engineVersion = getGeckoVersion();
				this.isGecko = true;
			}
			
			this.browser.majorVersion = getMajorVersion(this.browser.version);
			this.browser.minorVersion = getMinorVersion(this.browser.version);
			this.browser.engineMajorVersion = getMajorVersion(this.browser.engineVersion);
			this.browser.engineMinorVersion = getMinorVersion(this.browser.engineVersion);
			
			
			
			// Operating System details
			if ((ua.search(/windows/) != -1) || ((ua.search(/win9\d{1}/) != -1))) {
				this.isWindows = true;
				this.os.id = "windows";
				
				if (ua.search(/nt\s6\.0/) != -1) {
					this.os.version = "vista";
					this.isWindowsVista = true;
				} 
				else if (ua.search(/nt\s5\.1/) != -1) {
					this.os.version = "xp";
					this.isWindowsXP = true;
				} 
				else if (ua.search(/nt\s5\.0/) != -1) {
					this.os.version = "2000";
				} 
				else if ((ua.search(/win98/) != -1) || (ua.search(/windows\s98/) != -1)) {
					this.os.version = "98";
				} 
				else if (ua.search(/windows\sme/) != -1) {
					this.os.version = "me";
				}
				else if (ua.search(/nt\s5\.2/) != -1) {
					this.os.version = "2003";
				} 
				else if ((ua.search(/windows\s95/) != -1) || (ua.search(/win95/)!=-1)) {
					this.os.version = "95";
				} 
				else if ((ua.search(/nt\s4\.0/) != -1) || (ua.search(/nt4\.0/) ) != -1) {
					this.os.version = "nt4";
				}
			}
			else if (ua.search(/linux/) !=-1) {
				this.isLinux = true;
				this.os.id = "linux";
				try {
					this.os.version = ua.match(/linux\s?(\d+(\.?\d)*)/)[1];
				} catch (e) { }
			} 
			else if (ua.search(/mac\sos\sx/) !=-1) {
				this.isMacOSX = true;
				this.os.id = "macosx";
			}
			else if ((ua.search(/macintosh/) !=-1) || (brs.search(/mac\x5fpowerpc/) != -1)) {
				this.os.id = "macclassic";
			} 
			
			
			// Flash check
			if (this.isIE){
				
				for(var i=15; i>0; i--) {
					try {
						var flash = new ActiveXObject("ShockwaveFlash.ShockwaveFlash." + i);
						this.flash.version = i;
						break;
					} catch(e) { }
				}

				if (this.flash.version > 0) {
					this.flash.status = 'installed';
				} 
				else {
					this.flash.status = 'notinstalled';
				}
				
			}	
			else{
				
				var x,y;
				if (navigator.plugins && navigator.plugins.length) {
					x = navigator.plugins["Shockwave Flash"];
					if (x) {
						this.flash.status = 'installed';
						if (x.description) {
							y = x.description;
							this.flash.version = y.charAt(y.indexOf('.')-1);
						}
					} 
					else {
						this.flash.status = 'notinstalled';
					}
					if (navigator.plugins["Shockwave Flash 2.0"]) {
						this.flash.status = 'installed';
					}
				}
				else if (navigator.mimeTypes && navigator.mimeTypes.length) {
					x = navigator.mimeTypes['application/x-shockwave-flash'];
					if (x && x.enabledPlugin) {
						this.flash.status = 'installed';
					}
					else {
						this.flash.status = 'notinstalled';
					}
				}
				
			}
			
			if (this.flash.status == 'installed'){
				this.hasFlash = true;
				switch(parseInt(this.flash.version)){
					case 9:
						this.hasFlash9 = true;
						break;
					case 8:
						this.hasFlash8 = true;
						break;
					case 7:
						this.hasFlash7 = true;
						break;
					default:
						break;
				}
			}
		
			// Helper methods
			function getGeckoVersion(){
				return ua.match(/gecko\/([0-9]+)/)[1];
			}
			
			// Return browser's (actual) major version or -1 if bad version entered
			function getMajorVersion(v) {
				return (isEmpty(v) ? -1 : (hasDot(v) ? v : v.match(/(\d*)(\.\d*)*/)[1]))
			}
			
			// Return browser's (actual) minor version or -1 if bad version entered
			function getMinorVersion(v) {
				return (!isEmpty(v) ? (!hasDot(v) ? v.match(/\.(\d*([-\.]\d*)*)/)[1] : 0) : -1)
			}

			function isEmpty(input) {
				return (input==null || input =="")
			}

			function hasDot(input) {
				return (input.search(/\./) == -1)
			}
		}
		
	};
	
	Code.initialize();
	
})();