/*!
 * strictly.js JavaScript Library v1.0.1
 * http://www.strictly-software.com/
 *
 * Copyright (c) 2009 Rob Reid
 * Dual licensed under the MIT and GPL licenses.
 * 
 *
 * Date: 2009-03-16 17:34:21 - Rev 1
 * Date: 2009-07-25 19:23:12 - Rev 2
 * Revision: 2
 *
 * Rev 1: Created initial file
 * Rev 2: Updated file for use on main site included new HTML encode functions

 */

/*
 * Aim of this light weight framework is to encapsulate all the current jobboard JS libraries into one
 * object which will enable us to extend the jobboard codebase by using other frameworks if necessary without
 * conflict e.g prototype, YUI, JQuery.
 * The core of the framework is form related e.g validation
*/

/*
	options which control which checks within the strictly object are carried out. For example if you are also using JQuery
	then there is no reason to carry out a full check for CSS/Box model capabilities.
*/	

var _w = window, _d = document, _n = navigator;

(function(){

	undefined, //Aparently this speeds up references and checks for undefined (from jQuery)
	
	reEmail			= /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,	
	reWhitespace	= /^\s+$/,
	reInteger		= /^\d+$/,  //positive only
	reInteger2		= /^-?\d+$/, //negative and positve
	reReal			= /^[0-9]+\.?[0-9]?[0-9]?$/,
	reNumeric		= /^-?\d*\.?\d+$/,  //positive and negative floating point
	rePhone			= /(?:\s|^|:)[\(\)\d\+\- ]*[^#]?\d{5}[\(\)\d\+\- ]*(?:ext|extension)?[:;]?[\(\)\d\+\- ]*(?:\s|$)/,
	reGUID			= /^\{?[A-Z0-9]{8}-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{12}\}?$/,
	reALPHANUMERIC	= /^[a-zA-Z0-9]+$/, //validates alphanumeric	
	reALPHA			= /^[a-zA-Z]+$/, //validates alpha only
	reStrategiesURL	= /^(http|https):\/\/([a-zA-Z1-9-\.]{4,})\.ni\.(dev|strategiesuk\.net)$/, //looks for dev and demo URLS
	reUKPostcode	= /^[a-zA-Z]{1,2}\d{1,2}[a-zA-Z]?\s*\d[a-zA-Z]{2}$/,
	reURL			= /^[A-Za-z0-9\.\-]+\.[A-Za-z]{2,4}(:[0-9]+)?\/?.*$/,
	reDate			= /^[0-3]?[0-9]\/[0-1]?[0-9]\/[1-2]?[0-9]?[0-9][0-9]$/;  //used in conjunction with other checks

	// set up and override some common objects to enable us to have proper cross browser functionality and sexy shizzle

	//overide setTimeout and setInterval functions to allow for passing of parameters
	var _st = window.setTimeout;
	var _si = window.setInterval;

	window.setTimeout = function(fRef, mDelay) 
	{ 
		if(typeof fRef == "function")
		{  
			var argu = Array.prototype.slice.call(arguments,2); 
			var f = (function(){ fRef.apply(null, argu); }); 
			return _st(f, mDelay); 
		} 
		return _st(fRef,mDelay);
	}

	window.setInterval = function(fRef, mDelay) 
	{ 
		if(typeof fRef == "function")
		{  
			var argu = Array.prototype.slice.call(arguments,2); 
			var f = (function(){ fRef.apply(null, argu); }); 
			return _si(f, mDelay); 
		} 
		return _si(fRef,mDelay);
	}

	//override getElementsByTagName to allow older browsers to use this function and to make IE act like moz with *
	//needed so our getElementsByClassName will work.
	if(!document.getElementsByTagName('*').length){
		if(document.all){
			document.getElementsByTagName = function(tag){
				if(tag=="*"){
					return document.all;
				}else{
					//need to use capitals for older IE browsers for tagnames
					return document.all.tags(tag.toUpper());
				}
			}
		}
	}

	// indexOf is not supported in IE
	if (!Array.prototype.indexOf)
	{
		Array.prototype.indexOf = function(elt /*, from*/)
		{
			var len = this.length;
			var from = Number(arguments[1]) || 0;
			from = (from < 0) ? Math.ceil(from) : Math.floor(from);
			if (from < 0) { from += len;}
			for (; from < len; from++){
				if (from in this && this[from] === elt){return from;}
			}
			return -1;		
		}
	}

	// push not supported in IE 5
	if(!Array.prototype.push)
	{
		Array.prototype.push = function ()
		{
			for (var i = 0; i < arguments.length; i++) {
				this[this.length] = arguments[i];
			}
			return this.length;
		}
	}

	if(!Array.prototype.unshift)
	{
		Array.prototype.unshift = function()
		{
			var i = unshift.arguments.length;
			for (var j = this.length - 1; j >= 0; --j) {
				this[j + i] = this[j];
			}
			for (j = 0; j < i; ++j) {
				this[j] = unshift.argument[j];
			}
		}
	}

	if(!Array.prototype.shift)
	{
		Array.prototype.shift = function(str)
		{
			var val = this[0];
			for (var i = 1; i < this.length; ++i) {
				this[i-1] = this[i];
			}
			this.length--;
			return val;
		}
	}


	getElementsByClassName = function(clsName,node,tag){
//		ShowDebug("IN getElementsByClassName " + clsName + " - " + node + " - " + tag);
		node = node || document;
		tag = tag || "*";
		if(document.getElementsByClassName){
			// FF3 Safari Opera
			if(tag=="*"){
				return node.getElementsByClassName(clsName);
			}else{
				var cls = node.getElementsByClassName(clsName),
					els = [],
					tag=tag.toUpperCase();

				for(var x=0,l=cls.length;x<l;x++){
					if(cls[x].nodeName==tag){
						els.push(cls[x]);
					}
				}
				return els;
			}			
		}else{
			// IE and older Gecko
			var retVal = [], 
				els = (tag=="*" && node.all) ? node.all : node.getElementsByTagName(tag),
				re = new RegExp("(^|\\s)"+clsName.replace(/\-/,"\\-")+"(\\s|$)");
			for(var i=0,j=els.length;i<j;i++){
				re.test(els[i].className) ? retVal.push(els[i]) : "";
			}
			return retVal;
		}		
	}	
	
	
	document.getElementsByAttribute = function(att, val, node) {
		node = node || document;
		var n = the_node.getElementsByTagName('*');
		var results = new Array();
		for (i=0, j=0; i<n.length;i++) {
			if (n[i].hasAttribute(att)) {
				if (n[i].getAttribute(att) == val) {
					results[j] = n[i];
					j++;
				}
			}
		}
		return results;
	}

	
	// some event methods in case Jquery/Mootools not being used
	CancelEvent = function(e){
		if(e.preventDefault){
			e.preventDefault();
		}else if(_w.event){ //cannot check for e.returnValue
			e.returnValue = false;
		}
	}

	StopPropagation = function(e){
		if(e.stopPropagation){
			e.stopPropagation();
		}else if(e.cancelBubble){
			e.cancelBubble = true;
		}
	}

	StopEvent = function(e){
		//alert("STOP EVENT e = " + e)
		e=GetEvent(e);//get in case it wasnt passed in#
		//alert("STOP EVENT e.type = " + e.type)
		StopPropagation(e);
		CancelEvent(e);
	}

	// get correct reference to event object as this=window in IE however when in frames you need the correct window reference
	GetEvent = function(e,el){
		if(!el) el = this;
		return e || (((el.ownerDocument || el.document || el).parentWindow || _w).event);			
	}

	// Strictly object
	// All rights reserved Strictly-Software.com
	// This code can only be used, copied or reproduced on other sites external or internal with a written
	// confirmation giving the user permission to do so. This can be obtained by emailing the development team
	// at www.strictly-software.com

	S = Strictly = {
		
		Name : "Strictly",
	
		Version : "1.0.0",	
		
		EnhanceCSSDoc: true, //if on then if browser supports enhanced CSS whether to run the enhance function that modifies CSS classes
			
		FlashMaxCurVersion : 10, //the latest current version of flash available to download on web. Needed to check that user has flash installed
			
		FlashMinVersion: [6,65], //when using flash and checking for user version the min version they must have (will link to download page) [major,major+min] (eg 8.3 would be [8,83])

		EncodeType : "entity",
		
		Counter : 0,

		getCounter : function(){
			return this.Counter++;
		},	

		// returns an element from an HTML, XHTML or XML document
		getEl : function(el,doc){
			doc = doc || _d;

			//ShowDebug("typeof doc is it xml = " + this.isXML(doc));
			
			if(typeof(el)=="string"){		
				if(this.isXML(doc)){
					el = getElementById(el,doc);		
				}else{
					el = doc.getElementById(el);
				}
			}

			return el;
		},

		// gets an element by ID from an XML document if you know there maybe multiple then use getAttributes
		getElementById : function(el,doc){
			doc = doc || document;

			var n = doc.getElementsByTagName('*');
			for (i=0,l=n.length;i<l;i++) {
				if (n[i].hasAttribute('id')) {					
					if (n[i].getAttribute('id') == el) {						
						//ShowDebug("return " + n[i]);
						return n[i];
					}
				}
			}	
			return;
		},

		// returns an array of elements that match an attribute value
		getElementsByAttribute : function(att, val, node) {
			node = node || document;
			var n = the_node.getElementsByTagName('*');
			var results = new Array();
			for (i=0, j=0; i<n.length;i++) {
				if (n[i].hasAttribute(att)) {
					if (n[i].getAttribute(att) == val) {
						results[j] = n[i];
						j++;
					}
				}
			}
			return results;
		},

		//used in functions where either an object reference or an id to an element can be passed in
		getObj : function(el){
			return (!el)?_d:this.isString(el)?S.getEl(el):el;
		},


		getRadioVal : function(radName)
		{
			var retVal	= "";
			var inps	= document.getElementsByTagName('input');
			var len		= inps.length;

			for (i=0;i<len;i++)
			{
				if ((inps[i].type=="radio")&&(inps[i].name==radName)&&(inps[i].checked))
				{	        
				   retVal = inps[i].value;
				  
				}

			}
			return retVal;
		},

		setContent : function(el,txt){
			el = S.getObj(el);

			if(typeof(el.value)!=="undefined"){
				el.value = txt;				
			}else if(el.nodeType){
				el.innerHTML = txt;
			}			
			return;
		},

		setText : function(el,txt){
			el = S.getObj(el);
			if(el && txt){
				// I test in order of most common browser first for speed as 75% of users still use IE
				// try for w3c standard
				// IEs
				if(el.innerText){
					el.innerText = txt;
				// Moz
				}else if(el.textContent){
					el.textContent = txt;
				// w3c DOM implementation
				}else if(_d.createElement){
					if(el.firstChild){
						el.firstChild.nodeValue=txt;
					}else{
						el.appendChild(_d.createTextNode(txt));
					}
				}
			}
			return;
		},

		getText : function(el){
			el = S.getObj(el);
			var txt="";
			if(el){
				// I test in order of most common browser first for speed as 75% of users still use IE
				if(el.innerText){
					txt = el.innerText;
				}else if(el.textContent){
					txt = el.textContent;			
				}else if(el.firstChild && el.firstChild.nodeType==3){
					txt = el.firstChild.nodeValue;
				}
			}
			return txt;
		},

		getHTML : function(el){
			el = S.getObj(el);
			if(S.isXML(el)){
				return el.xml;
			}else if(el.jquery){
				return el.html();
			}else{
				return el.innerHTML;
			}
		},

		// Return a reference to a flash movie
		// Have to do some sniffing due to getElementById half working in Moz. It will get a pointer but not correctly.
		getFlashMovie : function(movie)
		{
			var flash;
			ShowDebug("IN getFlashMovie = " +movie);
			if(S.Browser.ie){ //for IE
				if(_d.getElementById){
					flash = _d.getElementById(movie)
					if(flash) return flash;
				}
				flash = (_w[movie]) ? _w[movie] : _d[movie];  //get using window or document
				return flash;
			}else{
				flash = _d[movie]; //can only ref flash through document object in Moz window will not work
				if(!flash && _d.embeds && _d.embeds[movie]){ //embeds should work in Moz if we have used them
					flash = _d.embeds[movie]; 
				}
				return flash;
			}
		},	


		// Return a reference to an iframe element
		getIframe : function(id){
			ShowDebug("IN getIframe iframe = " + id);
			var iframe;
			if(_d.getElementById){
				ShowDebug("return getElementById");
				return _d.getElementById(id);	
			}else if(_w.frames && _w.frames.length){
				ShowDebug("return frames[]");
				return _w.frames[id];
			}	
		},
			
		// Return a reference to an iframe window element
		getIframeWin : function(iframe){
			if(iframe){
				if(iframe.contentWindow){
					return iframe.contentWindow;
				}else if(iframe.contentDocument && S.Browser && S.Browser.opera){
					return iframe.contentDocument;		
				}else{
					return iframe;
				}		
			}
		},

		//Return a reference to the document inside an iframe
		getIframeDoc : function(iframe){
			//D.debug=true;
			iframe = (this.isString(iframe)) ? this.getIframe(iframe) : iframe;

			ShowDebug("IN getIframeDoc iframe = " + iframe + " - " + iframe.id + " - " + iframe.tagName);

			if(iframe){
				ShowDebug("iframe.contentDocument = " + iframe.contentDocument)
				ShowDebug("iframe.contentWindow = " + iframe.contentWindow)
				ShowDebug("iframe.contentWindow.document = " + iframe.contentWindow.document)
				ShowDebug("iframe.document = " + iframe.document)

				if(iframe.contentDocument){
					ShowDebug("return iframe.contentDocument");
					return iframe.contentDocument;
				}else if(iframe.contentWindow.document){
					ShowDebug("return iframe.contentWindow.document");
					return iframe.contentWindow.document;
				}else if(iframe.document){
					ShowDebug("return iframe.document");
					return iframe.document;
				}	
			}
			//D.debug=false;
		},

		// sets multiple attributes on an element
		setAttributes : function(obj,atts){
			obj = this.getObj(obj);
			if(obj && atts){
				for(var a in atts){
					// handle class specially
					if(a == "class" || a == "className"){
						obj.className = atts[a];
					}else{
						obj.setAttribute(a,atts[a]);
					}
				}
			}
			return obj;
		},

		// sets an object property to one or more values
		setProp : function(obj, prop, vals){

			obj = this.getObj(obj);

			if(!obj || !prop || !vals) return;
			if(!obj[prop]) return;

			if(this.isString(vals)){
				obj[prop] = vals;
			}else{
				for(var a in vals){					
					obj[prop] = vals[a];
				}
			}

			return;
		},

		// for setting multiple styles on an object pass in a hash array of style:value
		setStyles : function(obj,styles){
					
			var js;

			obj = this.getObj(obj);
			if(!obj || !styles) return;

			for(var a in styles){
				js = this.toCamelCase(a);				
				obj.style[js] = styles[a];
			}

			return;
		},

		// convert to camelcase
		toCamelCase : function (name){
			var camelCase = name.replace(/\-(\w)/g, function(all, letter){
						return letter.toUpperCase();
					});
			return camelCase
		},

		// convert to css-style
		toCSSProp : function (name){
			return name.replace( /([A-Z])/g, "-$1" ).toLowerCase();
		},


		getQuerystring : function(){
			var qry="";
			if(location.href){
				var q = _w.location.search;
				if(q && q.length>1){
					ShowDebug("get querystring ignore first char which will be ? = " + q)
					qry = q.substring(1,q.length);
				}
			}
			ShowDebug("Return " + qry);
			return qry;
		},
		
		getBody : function(){
			return _d.getElementsByTagName("body")[0] || _d.body;
		},

		isArray : function(o){
			return Object.prototype.toString.call(o)="[object Array]";
		},

		// tests for objects with array like properties (array/nodelist)
		isArrayLike : function(o){
			// The window, strings (and functions) also have 'length'
			return (o && o.length && !this.isFunction(o) && !this.isString(o) && o!==window);
		},

		isFunction : function(o){
			return (typeof(o)=="function");
		},
	
		isNumber : function(o){
			return (typeof(o)=="number");
		},

		isBoolean : function(o){
			return (typeof(o)=="boolean");
		},

		isString : function(o){
			return (typeof(o)=="string");
		},

		isObject : function(o){
			return (typeof(o)=="object");
		},

		isDOMobj : function(o){
			if(this.isObject(o)){
				if(o.nodeType){
					return true;
				}
			}
			return false;
		},
		
		isHTML: function(o){
			return this.isDOMobj(o) && !this.isXML(o);
		},

		isXML : function(o){
			return o.nodeType === 9 && o.documentElement.nodeName !== "HTML" || !!o.ownerDocument && this.isXML( o.ownerDocument );
		},

		makeArray: function( a ) {
			var ret = [];

			if( a != null ){				
				// The window, strings (and functions) also have 'length'
				if(!this.isArrayLike(a)){
					ret[0] = a;
				}else{
					var i = a.length;
					while( i ){ret[--i] = array[i];}
				}
			}

			return ret;
		},

		inArray : function( item, arr){
			var p = this.posArray( item, arr );
			return (p > -1) ? true : false;
		},

		posArray : function( item, arr ) {
			for ( var i = 0, x = arr.length; i < x; i++ ){
				if ( arr[i] === item ){
					return i;
				}
			}
			return -1;
		},

		enc : function(val){
			if (typeof(encodeURIComponent)=="function"){
				return encodeURIComponent(val);
			}else{
				return escape(val);
			}
		},

		denc : function(val){
			if (typeof(decodeURIComponent)=="function"){
				return decodeURIComponent(val);
			}else{
				return unescape(val);
			}
		},

		isEmpty : function(val){
			if(val){
				return ((val===null) || val.length==0 || reWhitespace.test(val));
			}else{
				return true;
			}
		},

		// used for feeds which can supply values such as "null"
		isEmptyVal : function(val){
			if (this.isEmpty(val) || (this.isString(val) && val == "null" || val == "undefined")){
				return true;
			}else{
				return false;
			}
		},

		addClass : function(e,c)
		{	
			if(e){
				if (this.isEmpty(e.className)){
					e.className = c;
				}else{
					if (!this.hasClass(e,c)) e.className += ' ' + c;
				}				
			}
		},

		delClass : function(e,c)
		{
			if (e && !this.isEmpty(e.className)){
				if (e.className.split(' ').length > 1){
					e.className = e.className.replace(new RegExp(' ' + c + '\\b'), '');
				}else{
					e.className = e.className.replace(new RegExp(c + '\\b'),'');
				}
			}
		},

		hasClass : function(e,c)
		{
			if (e && e.className!='')
			{
				cs = e.className.split(' ');
				for(i=0; i<cs.length; i++)
					if (cs[i]==c) return true;
			}
			return false;
		},

		toggleClass : function(e,c)
		{
			if(e){
				if (this.hasClass(e,c)){
					this.delClass(e,c);
				}else{
					this.addClass(e,c);
				}				
			}
		},

		convertToBool : function(v)
		{	
			v=v.toLowerCase();
			if(v=="true" || v=="on" || v=="yes" || v=="1"){return true;}
			else if(v=="false" || v=="off" || v=="no" || v=="0"){return false;}
			return null;
		},

		convertFromBool : function(b){
			if(this.isBoolean(b)){
				if(b){ return "Yes" }else{ return "No" }
			}
		},

		removeChildren : function(el){
			if(el){
				while ( el.hasChildNodes() )
				{
					el.removeChild( el.firstChild );       
				}
			}
			return el;
		},

		// traverse skipping white space
		getNextSibling : function(o){
			ShowDebug("IN getNextSibling object = " +o);
			do o = o.nextSibling;				
			while(o && o.nodeType != 1)
			ShowDebug("return " + o);
			return o;	
		},

		getPreviousSibling : function(o){
			do o = o.previousSibling;
			while(o && o.nodeType != 1)
			return o;	
		},

		// Encoding Functions

		
		// Convert HTML entities into numerical entities
		HTML2Numerical : function(s){
			var arr1 = new Array('&nbsp;','&iexcl;','&cent;','&pound;','&curren;','&yen;','&brvbar;','&sect;','&uml;','&copy;','&ordf;','&laquo;','&not;','&shy;','&reg;','&macr;','&deg;','&plusmn;','&sup2;','&sup3;','&acute;','&micro;','&para;','&middot;','&cedil;','&sup1;','&ordm;','&raquo;','&frac14;','&frac12;','&frac34;','&iquest;','&agrave;','&aacute;','&acirc;','&atilde;','&auml;','&aring;','&aelig;','&ccedil;','&egrave;','&eacute;','&ecirc;','&euml;','&igrave;','&iacute;','&icirc;','&iuml;','&eth;','&ntilde;','&ograve;','&oacute;','&ocirc;','&otilde;','&ouml;','&times;','&oslash;','&ugrave;','&uacute;','&ucirc;','&uuml;','&yacute;','&thorn;','&szlig;','&agrave;','&aacute;','&acirc;','&atilde;','&auml;','&aring;','&aelig;','&ccedil;','&egrave;','&eacute;','&ecirc;','&euml;','&igrave;','&iacute;','&icirc;','&iuml;','&eth;','&ntilde;','&ograve;','&oacute;','&ocirc;','&otilde;','&ouml;','&divide;','&oslash;','&ugrave;','&uacute;','&ucirc;','&uuml;','&yacute;','&thorn;','&yuml;','&quot;','&amp;','&lt;','&gt;','&oelig;','&oelig;','&scaron;','&scaron;','&yuml;','&circ;','&tilde;','&ensp;','&emsp;','&thinsp;','&zwnj;','&zwj;','&lrm;','&rlm;','&ndash;','&mdash;','&lsquo;','&rsquo;','&sbquo;','&ldquo;','&rdquo;','&bdquo;','&dagger;','&dagger;','&permil;','&lsaquo;','&rsaquo;','&euro;','&fnof;','&alpha;','&beta;','&gamma;','&delta;','&epsilon;','&zeta;','&eta;','&theta;','&iota;','&kappa;','&lambda;','&mu;','&nu;','&xi;','&omicron;','&pi;','&rho;','&sigma;','&tau;','&upsilon;','&phi;','&chi;','&psi;','&omega;','&alpha;','&beta;','&gamma;','&delta;','&epsilon;','&zeta;','&eta;','&theta;','&iota;','&kappa;','&lambda;','&mu;','&nu;','&xi;','&omicron;','&pi;','&rho;','&sigmaf;','&sigma;','&tau;','&upsilon;','&phi;','&chi;','&psi;','&omega;','&thetasym;','&upsih;','&piv;','&bull;','&hellip;','&prime;','&prime;','&oline;','&frasl;','&weierp;','&image;','&real;','&trade;','&alefsym;','&larr;','&uarr;','&rarr;','&darr;','&harr;','&crarr;','&larr;','&uarr;','&rarr;','&darr;','&harr;','&forall;','&part;','&exist;','&empty;','&nabla;','&isin;','&notin;','&ni;','&prod;','&sum;','&minus;','&lowast;','&radic;','&prop;','&infin;','&ang;','&and;','&or;','&cap;','&cup;','&int;','&there4;','&sim;','&cong;','&asymp;','&ne;','&equiv;','&le;','&ge;','&sub;','&sup;','&nsub;','&sube;','&supe;','&oplus;','&otimes;','&perp;','&sdot;','&lceil;','&rceil;','&lfloor;','&rfloor;','&lang;','&rang;','&loz;','&spades;','&clubs;','&hearts;','&diams;');
			var arr2 = new Array('&#160;','&#161;','&#162;','&#163;','&#164;','&#165;','&#166;','&#167;','&#168;','&#169;','&#170;','&#171;','&#172;','&#173;','&#174;','&#175;','&#176;','&#177;','&#178;','&#179;','&#180;','&#181;','&#182;','&#183;','&#184;','&#185;','&#186;','&#187;','&#188;','&#189;','&#190;','&#191;','&#192;','&#193;','&#194;','&#195;','&#196;','&#197;','&#198;','&#199;','&#200;','&#201;','&#202;','&#203;','&#204;','&#205;','&#206;','&#207;','&#208;','&#209;','&#210;','&#211;','&#212;','&#213;','&#214;','&#215;','&#216;','&#217;','&#218;','&#219;','&#220;','&#221;','&#222;','&#223;','&#224;','&#225;','&#226;','&#227;','&#228;','&#229;','&#230;','&#231;','&#232;','&#233;','&#234;','&#235;','&#236;','&#237;','&#238;','&#239;','&#240;','&#241;','&#242;','&#243;','&#244;','&#245;','&#246;','&#247;','&#248;','&#249;','&#250;','&#251;','&#252;','&#253;','&#254;','&#255;','&#34;','&#38;','&#60;','&#62;','&#338;','&#339;','&#352;','&#353;','&#376;','&#710;','&#732;','&#8194;','&#8195;','&#8201;','&#8204;','&#8205;','&#8206;','&#8207;','&#8211;','&#8212;','&#8216;','&#8217;','&#8218;','&#8220;','&#8221;','&#8222;','&#8224;','&#8225;','&#8240;','&#8249;','&#8250;','&#8364;','&#402;','&#913;','&#914;','&#915;','&#916;','&#917;','&#918;','&#919;','&#920;','&#921;','&#922;','&#923;','&#924;','&#925;','&#926;','&#927;','&#928;','&#929;','&#931;','&#932;','&#933;','&#934;','&#935;','&#936;','&#937;','&#945;','&#946;','&#947;','&#948;','&#949;','&#950;','&#951;','&#952;','&#953;','&#954;','&#955;','&#956;','&#957;','&#958;','&#959;','&#960;','&#961;','&#962;','&#963;','&#964;','&#965;','&#966;','&#967;','&#968;','&#969;','&#977;','&#978;','&#982;','&#8226;','&#8230;','&#8242;','&#8243;','&#8254;','&#8260;','&#8472;','&#8465;','&#8476;','&#8482;','&#8501;','&#8592;','&#8593;','&#8594;','&#8595;','&#8596;','&#8629;','&#8656;','&#8657;','&#8658;','&#8659;','&#8660;','&#8704;','&#8706;','&#8707;','&#8709;','&#8711;','&#8712;','&#8713;','&#8715;','&#8719;','&#8721;','&#8722;','&#8727;','&#8730;','&#8733;','&#8734;','&#8736;','&#8743;','&#8744;','&#8745;','&#8746;','&#8747;','&#8756;','&#8764;','&#8773;','&#8776;','&#8800;','&#8801;','&#8804;','&#8805;','&#8834;','&#8835;','&#8836;','&#8838;','&#8839;','&#8853;','&#8855;','&#8869;','&#8901;','&#8968;','&#8969;','&#8970;','&#8971;','&#9001;','&#9002;','&#9674;','&#9824;','&#9827;','&#9829;','&#9830;');
			return this.swapArrayVals(s,arr1,arr2);
		},	

		// Convert Numerical entities into HTML entities
		NumericalToHTML : function(s){
			var arr1 = new Array('&#160;','&#161;','&#162;','&#163;','&#164;','&#165;','&#166;','&#167;','&#168;','&#169;','&#170;','&#171;','&#172;','&#173;','&#174;','&#175;','&#176;','&#177;','&#178;','&#179;','&#180;','&#181;','&#182;','&#183;','&#184;','&#185;','&#186;','&#187;','&#188;','&#189;','&#190;','&#191;','&#192;','&#193;','&#194;','&#195;','&#196;','&#197;','&#198;','&#199;','&#200;','&#201;','&#202;','&#203;','&#204;','&#205;','&#206;','&#207;','&#208;','&#209;','&#210;','&#211;','&#212;','&#213;','&#214;','&#215;','&#216;','&#217;','&#218;','&#219;','&#220;','&#221;','&#222;','&#223;','&#224;','&#225;','&#226;','&#227;','&#228;','&#229;','&#230;','&#231;','&#232;','&#233;','&#234;','&#235;','&#236;','&#237;','&#238;','&#239;','&#240;','&#241;','&#242;','&#243;','&#244;','&#245;','&#246;','&#247;','&#248;','&#249;','&#250;','&#251;','&#252;','&#253;','&#254;','&#255;','&#34;','&#38;','&#60;','&#62;','&#338;','&#339;','&#352;','&#353;','&#376;','&#710;','&#732;','&#8194;','&#8195;','&#8201;','&#8204;','&#8205;','&#8206;','&#8207;','&#8211;','&#8212;','&#8216;','&#8217;','&#8218;','&#8220;','&#8221;','&#8222;','&#8224;','&#8225;','&#8240;','&#8249;','&#8250;','&#8364;','&#402;','&#913;','&#914;','&#915;','&#916;','&#917;','&#918;','&#919;','&#920;','&#921;','&#922;','&#923;','&#924;','&#925;','&#926;','&#927;','&#928;','&#929;','&#931;','&#932;','&#933;','&#934;','&#935;','&#936;','&#937;','&#945;','&#946;','&#947;','&#948;','&#949;','&#950;','&#951;','&#952;','&#953;','&#954;','&#955;','&#956;','&#957;','&#958;','&#959;','&#960;','&#961;','&#962;','&#963;','&#964;','&#965;','&#966;','&#967;','&#968;','&#969;','&#977;','&#978;','&#982;','&#8226;','&#8230;','&#8242;','&#8243;','&#8254;','&#8260;','&#8472;','&#8465;','&#8476;','&#8482;','&#8501;','&#8592;','&#8593;','&#8594;','&#8595;','&#8596;','&#8629;','&#8656;','&#8657;','&#8658;','&#8659;','&#8660;','&#8704;','&#8706;','&#8707;','&#8709;','&#8711;','&#8712;','&#8713;','&#8715;','&#8719;','&#8721;','&#8722;','&#8727;','&#8730;','&#8733;','&#8734;','&#8736;','&#8743;','&#8744;','&#8745;','&#8746;','&#8747;','&#8756;','&#8764;','&#8773;','&#8776;','&#8800;','&#8801;','&#8804;','&#8805;','&#8834;','&#8835;','&#8836;','&#8838;','&#8839;','&#8853;','&#8855;','&#8869;','&#8901;','&#8968;','&#8969;','&#8970;','&#8971;','&#9001;','&#9002;','&#9674;','&#9824;','&#9827;','&#9829;','&#9830;');
			var arr2 = new Array('&nbsp;','&iexcl;','&cent;','&pound;','&curren;','&yen;','&brvbar;','&sect;','&uml;','&copy;','&ordf;','&laquo;','&not;','&shy;','&reg;','&macr;','&deg;','&plusmn;','&sup2;','&sup3;','&acute;','&micro;','&para;','&middot;','&cedil;','&sup1;','&ordm;','&raquo;','&frac14;','&frac12;','&frac34;','&iquest;','&agrave;','&aacute;','&acirc;','&atilde;','&auml;','&aring;','&aelig;','&ccedil;','&egrave;','&eacute;','&ecirc;','&euml;','&igrave;','&iacute;','&icirc;','&iuml;','&eth;','&ntilde;','&ograve;','&oacute;','&ocirc;','&otilde;','&ouml;','&times;','&oslash;','&ugrave;','&uacute;','&ucirc;','&uuml;','&yacute;','&thorn;','&szlig;','&agrave;','&aacute;','&acirc;','&atilde;','&auml;','&aring;','&aelig;','&ccedil;','&egrave;','&eacute;','&ecirc;','&euml;','&igrave;','&iacute;','&icirc;','&iuml;','&eth;','&ntilde;','&ograve;','&oacute;','&ocirc;','&otilde;','&ouml;','&divide;','&oslash;','&ugrave;','&uacute;','&ucirc;','&uuml;','&yacute;','&thorn;','&yuml;','&quot;','&amp;','&lt;','&gt;','&oelig;','&oelig;','&scaron;','&scaron;','&yuml;','&circ;','&tilde;','&ensp;','&emsp;','&thinsp;','&zwnj;','&zwj;','&lrm;','&rlm;','&ndash;','&mdash;','&lsquo;','&rsquo;','&sbquo;','&ldquo;','&rdquo;','&bdquo;','&dagger;','&dagger;','&permil;','&lsaquo;','&rsaquo;','&euro;','&fnof;','&alpha;','&beta;','&gamma;','&delta;','&epsilon;','&zeta;','&eta;','&theta;','&iota;','&kappa;','&lambda;','&mu;','&nu;','&xi;','&omicron;','&pi;','&rho;','&sigma;','&tau;','&upsilon;','&phi;','&chi;','&psi;','&omega;','&alpha;','&beta;','&gamma;','&delta;','&epsilon;','&zeta;','&eta;','&theta;','&iota;','&kappa;','&lambda;','&mu;','&nu;','&xi;','&omicron;','&pi;','&rho;','&sigmaf;','&sigma;','&tau;','&upsilon;','&phi;','&chi;','&psi;','&omega;','&thetasym;','&upsih;','&piv;','&bull;','&hellip;','&prime;','&prime;','&oline;','&frasl;','&weierp;','&image;','&real;','&trade;','&alefsym;','&larr;','&uarr;','&rarr;','&darr;','&harr;','&crarr;','&larr;','&uarr;','&rarr;','&darr;','&harr;','&forall;','&part;','&exist;','&empty;','&nabla;','&isin;','&notin;','&ni;','&prod;','&sum;','&minus;','&lowast;','&radic;','&prop;','&infin;','&ang;','&and;','&or;','&cap;','&cup;','&int;','&there4;','&sim;','&cong;','&asymp;','&ne;','&equiv;','&le;','&ge;','&sub;','&sup;','&nsub;','&sube;','&supe;','&oplus;','&otimes;','&perp;','&sdot;','&lceil;','&rceil;','&lfloor;','&rfloor;','&lang;','&rang;','&loz;','&spades;','&clubs;','&hearts;','&diams;');
			return this.swapArrayVals(s,arr1,arr2);
		},

		// Numerically encodes all unicode characters
		numEncode : function(s){
			
			if(this.isEmpty(s)) return "";

			var e = "";
			for (var i = 0; i < s.length; i++)
			{
				var c = s.charAt(i);
				if (c < " " || c > "~")
				{
					c = "&#" + c.charCodeAt() + ";";
				}
				e += c;
			}
			return e;
		},
		
		// HTML Decode numerical and HTML entities back to original values
		htmlDecode : function(s){

			var c,m,d = s;
			
			if(this.isEmpty(d)) return "";

			// convert HTML entites back to numerical entites first
			d = this.HTML2Numerical(d);
			
			// look for numerical entities &#34;
			arr=d.match(/&#[0-9]{1,5};/g);
			
			// if no matches found in string then skip
			if(arr!=null){
				for(var x=0;x<arr.length;x++){
					m = arr[x];
					c = m.substring(2,m.length-1); //get numeric part which is refernce to unicode character
					// if its a valid number we can decode
					if(c >= -32768 && c <= 65535){
						// decode every single match within string
						d = d.replace(m, String.fromCharCode(c));
					}else{
						d = d.replace(m, ""); //invalid so replace with nada
					}
				}			
			}

			return d;
		},		

		// encode an input string into either numerical or HTML entities
		htmlEncode : function(s,dbl){
				
			if(this.isEmpty(s)) return "";

			// do we allow double encoding? E.g will &amp; be turned into &amp;amp;
			dbl = dbl | false; //default to prevent double encoding
			
			// if allowing double encoding we do ampersands first
			if(dbl){
				if(this.EncodeType=="numerical"){
					s = s.replace(/&/g, "&#38;");
				}else{
					s = s.replace(/&/g, "&amp;");
				}
			}

			// convert the xss chars to numerical entities ' " < >
			s = this.XSSEncode(s,false);
			
			if(this.EncodeType=="numerical" || !dbl){
				// Now call function that will convert any HTML entities to numerical codes
				s = this.HTML2Numerical(s);
			}

			// Now encode all chars above 127 e.g unicode
			s = this.numEncode(s);

			// now we know anything that needs to be encoded has been converted to numerical entities we
			// can encode any ampersands & that are not part of encoded entities
			// to handle the fact that I need to do a negative check and handle multiple ampersands &&&
			// I am going to use a placeholder

			// if we don't want double encoded entities we ignore the & in existing entities
			if(!dbl){
				s = s.replace(/&#/g,"##AMPHASH##");
			
				if(this.EncodeType=="numerical"){
					s = s.replace(/&/g, "&#38;");
				}else{
					s = s.replace(/&/g, "&amp;");
				}

				s = s.replace(/##AMPHASH##/g,"&#");
			}
			
			// replace any malformed entities
			s = s.replace(/&#\d*([^\d;]|$)/g, "$1");

			if(!dbl){
				// safety check to correct any double encoded &amp;
				s = this.correctEncoding(s);
			}

			// now do we need to convert our numerical encoded string into entities
			if(this.EncodeType=="entity"){
				s = this.NumericalToHTML(s);
			}

			return s;					
		},

		// Encodes the basic 4 characters used to malform HTML in XSS hacks
		XSSEncode : function(s,en){
			if(!this.isEmpty(s)){
				en = en || true;
				// do we convert to numerical or html entity?
				if(en){
					s = s.replace(/\'/g,"&#39;"); //no HTML equivalent as &apos is not cross browser supported
					s = s.replace(/\"/g,"&quot;");
					s = s.replace(/</g,"&lt;");
					s = s.replace(/>/g,"&gt;");
				}else{
					s = s.replace(/\'/g,"&#39;"); //no HTML equivalent as &apos is not cross browser supported
					s = s.replace(/\"/g,"&#34;");
					s = s.replace(/</g,"&#60;");
					s = s.replace(/>/g,"&#62;");
				}
				return s;
			}else{
				return "";
			}
		},		

		hasEncoded : function(s){
			if(/&#[0-9]{1,5};/g.test(s)){
				return true;
			}else if(/&[A-Z]{2,6};/gi.test(s)){
				return true;
			}else{
				return false;
			}
		},

		// will remove any unicode characters
		stripUnicode : function(s){
			return s.replace(/[^\x20-\x7E]/g,"");
			
		},

		// corrects any double encoded entities e.g &amp;amp;
		correctEncoding : function(s){
			//return s.replace(/(&amp;)(amp;)+/,"$1");
			if(s){
				s = s.replace(/(&amp;)(#\d{3,6};)/gi,"&$2");
				s = s.replace(/(&amp;)([a-z]{2,6})(;)/gi,"&$2;");
			}
			return s;
		},

		// Function to loop through an array swaping each item with the value from another array e.g swap HTML entities with Numericals
		swapArrayVals : function(s,arr1,arr2){
			if(this.isEmpty(s)) return "";

			if(arr1 && arr2){
				//ShowDebug("in swapArrayVals arr1.length = " + arr1.length + " arr2.length = " + arr2.length)
				// array lengths must match
				if(arr1.length == arr2.length){
					for(var x=0,i=arr1.length;x<i;x++){
						s = s.replace(arr1[x],arr2[x]); //swap arr1 item with matching item from arr2	
					}
				}
			}
			return s;
		},

		getEmailAddress : function(strMailbox, strFQDN){
			return strMailbox +'@'+ strFQDN;
		},


		// foreach function will loop through a node list or array and call a supplied function
		// for each item passing in the the element. A function can be supplied instead of a nodelist
		// to generate the nodelist e.g a call to G or GC (get elements by class/tag/id)
		foreach : function(list, callback, args){

			var obj;

			ShowDebug("in foreach list = " + list + " - " + callback + " - " + args);

			// if typeof list is a function then run that to generate node list
			if(typeof(list) == "function"){
				ShowDebug("list is function to pass to create object/array");
				list = list.call();
			}

			/*ShowDebug("check object properties")
			
			ShowDebug("obj.length = " + list.length)
			ShowDebug("obj is function = " + this.isFunction(list))
			ShowDebug("obj is string = " + this.isString(list))
			ShowDebug("obj is not window = " + (list!==window))

			ShowDebug("check status of this should be Strictly!");
			ShowDebug("this = "+ this);
			ShowDebug("this.Version = " + this.Version);
			ShowDebug("this.Name = " + this.Name);

			if(window === this){
				ShowDebug("this IS SAME AS WINDOW")
			}else{
				ShowDebug("this IS NOT SAME AS WINDOW");
			}
			if(typeof(window) === typeof(this)){
				ShowDebug("TYPEOF this IS SAME AS WINDOW")
			}else{
				ShowDebug("TYPEOF this IS NOT SAME AS WINDOW");
			}*/

			// two loops one for array like objects the other for hash objects
			if(this.isArrayLike(list)){
				ShowDebug("IS ARRAY LIKE!")

				if(args){
					ShowDebug("args - CALL");
					for(var x=0,l=list.length;x<l;x++){
						ShowDebug("typeof list[x] = " + typeof(list[x]) + " - " + (list[x]===window)?"list[x] IS SAME AS WINDOW":"list[x] IS NOT SAME AS WINDOW");
						callback.apply(list[x],args);
					}
				}else{
					ShowDebug("no args - CALL");
					for(var x=0,l=list.length;x<l;x++){					
						
						obj = list[x];
						
					/*	ShowDebug("1 obj= " + obj);						
						ShowDebug("2 typeof obj = " + typeof(obj));	
						ShowDebug("3 is DOM obj = " + S.isDOMobj(obj));

						if(window === obj){
							ShowDebug("obj IS SAME AS WINDOW")
						}else{
							ShowDebug("obj IS NOT SAME AS WINDOW");
						}
						if(typeof(window) === typeof(obj)){
							ShowDebug("TYPEOF obj IS SAME AS WINDOW")
						}else{
							ShowDebug("TYPEOF obj IS NOT SAME AS WINDOW");
						}
						*/
						callback.call(obj,args);
					}
				}
			}else{
				ShowDebug("IS NOT ARRAY LIKE");
				if(args){
					ShowDebug("args - CALL");
					for(var x in list){
						/*ShowDebug("1 list[x] = " + list[x]);
						ShowDebug("2 typeof list[x] = " + typeof(list[x]))
						ShowDebug("3 is list[x] same as window==this - " + (list[x]===window)?"list[x] IS SAME AS WINDOW":"list[x] IS NOT SAME AS WINDOW");
						*/
						callback.apply(list[x],args);
					}
				}else{
					ShowDebug("no args - CALL");
					for(var x in list){
						obj = list[x];
						
						/*ShowDebug("1 obj= " + obj);						
						ShowDebug("2 typeof obj = " + typeof(obj))	
						

						if(window === obj){
							ShowDebug("obj IS SAME AS WINDOW")
						}else{
							ShowDebug("obj IS NOT SAME AS WINDOW");
						}
						if(typeof(window) === typeof(obj)){
							ShowDebug("TYPEOF obj IS SAME AS WINDOW")
						}else{
							ShowDebug("TYPEOF obj IS NOT SAME AS WINDOW");
						}
						*/
						callback.call(obj,obj);
					}
				}
			}
			return;

		},


		// test functions for outtputing object attributes and HTML values

		enumObj : function(obj){
			ShowDebug("IN enumObj");
			for(var x in obj){
				ShowDebug("obj["+x+"] = " + obj[x]);
			}
		},

		testHTML : function(el){
			ShowDebug("IN testHTML el = " + el + " - " + typeof(el));
			if(el && el.nodeType){
				ShowDebug("el = " + el.tagName + " - id = " + el.id + " - nodeType = " + el.nodeType + " - nodeName = " + el.nodeName);
				var k,c = el.childNodes;
				for(var i=0;i<c.length;i++){
					k = c[i];
					ShowDebug("k.nodeName = " + k.nodeName + " - id = " + k.id + " - tagName = " + k.tagName + " - className = " + k.className + " - style.display = " + k.style.display + " - visibility = " + k.style.visibility);
					ShowDebug("k.innerHTML = " + k.innerHTML);
				}           
			}
		},

		Trim : function(str){
			if(this.isEmpty(str)) return "";
			var x;
			x = this.LTrim(this.RTrim(str));
			return x;		
		},
		
		LTrim : function(v){
			return v.replace(/[\s\xA0]+$/,"");
		},

		RTrim : function(v){
			return v.replace(/^[\s\xA0]+/,"");
		},
		
		kill : function(obj){
	
			if(obj){
				try{
					obj = null;
				}catch(e){}
				try{
					delete obj;					
				}catch(e){}			
			}
			return obj;
		},

		createCookie : function(name,value,days) {
			if (days) {
				var date = new Date();
				date.setTime(date.getTime()+(days*24*60*60*1000));
				var expires = "; expires="+date.toGMTString();
			}
			else var expires = "";
			_d.cookie = name+"="+escape(value)+expires+"; path=/";
		},

		readCookie : function(name) {
			var nameEQ = name + "=";
			var ca = _d.cookie.split(';');
			for(var i=0;i < ca.length;i++) {
				var c = ca[i];
				while (c.charAt(0)==' ') c = c.substring(1,c.length);
				if (c.indexOf(nameEQ) == 0) return unescape(c.substring(nameEQ.length,c.length));
			}
			return null;
		},

		// creates an activeX object by testing progIds passed in, returns either an object or the progId that matched
		CreateObject : function(ax,m){

			//ShowDebug("IN CreateObject length of classIDs = " + ax.length + " " + m);

			if(!_w.ActiveXObject) return;

			var o,id="",f=false,er;
			if(ax){
				for(var x=0;x<ax.length && !f;x++){
					try{
						id=ax[x];
						//ShowDebug("try for id = " + id);
						o = new ActiveXObject(id);
						f=true;
					}catch(ex){
						//ShowDebug("error = " + ex.toString());
						er=ex;
					}
				}
			}
			ShowDebug("did we get an object f = " + f + " o = " + o + " - " + typeof(o))

			if(!f){
				if(typeof(window.console)!="undefined"){
					console.error("An error occurred trying to create an ActiveX object classid: " +id + "; Error: " + er + ";");
				}
			}
			if(m=="ID"){
				return id;
			}else{
				return o;
			}		
		},

		// create an XMLHTTP object for AJAX requests
		XMLHttpRequest : function(){
			
			var self = this;
			var xmlHTTP;

			// IE versions should support this object and we'd rather use it as its inbuilt with no "request for ActiveX object use msg to user"
			if(typeof XMLHttpRequest != 'undefined'){
				try{
					xmlHTTP = new XMLHttpRequest();
					return xmlHTTP;
				}catch(e){}
			}

			// set up progIDs in order of most likely to work
			var XML_ACTIVE_X_IDENTS = ["MSXML2.XMLHTTP.6.0","MSXML2.XMLHTTP.5.0", "MSXML2.XMLHTTP.4.0", "MSXML2.XMLHTTP.3.0",
									  "MSXML2.XMLHTTP", "MICROSOFT.XMLHTTP.1.0", "MICROSOFT.XMLHTTP.1", "MICROSOFT.XMLHTTP" ];

			// try for activeX
			xmlHTTP = self.CreateObject(XML_ACTIVE_X_IDENTS,"OBJECT");

			if(self.isObject(xmlHTTP)){
				return xmlHTTP;
			}

			// try for ICE
			if(_w.createRequest) {
				try {
					xmlHTTP = _w.createRequest();
					return xmlHTTP;
				} catch (e) {}
			}

			return xmlHTTP;
		}
	

	}

	D = Strictly.Debugger = {
		
		counter : 0,

		cache : [],

		debug : false, // do we debug or not?

		logTo : "",

		cached : false,

		ready: false,

		debugInterval: null,

		ForceCustomDebug : true, // force all debug to my own custom DIV log screen instead of using browser console or Firebug/lite

		ForceFirebugLite : false, // force browsers apart from Firefox to use Firebug-lite instead of their own console unless ForceCustomDebug is also on then it will use that


		// sm used as a way of debugging my debugger always outtputing msg to console

		setupCustomLog : function (){
			//alert("IN SetupCustomLog");
			// set up custom logger as long as we have access to the body
			var b = PageLoader.BodyLoaded;
			if(!b){
				//sm("Body not ready to add custom logger so quit")
				return false;
			}
			//alert("Body ready so add custom logger")
			var log = document.createElement("div");
			log.setAttribute("id","logwindow");			
			var styles = {visibility:"visible",display:"block",zIndex:"2147483647",position:"relative",backgroundColor:"#fff",border:"1px solid",overflow:"auto",width:"98%",left:"0",bottom:"0",height:"200px",padding:"5px",textAlign:"left" };
			S.setStyles(log,styles);
			S.getBody().appendChild(log);	
			//sm("append to body")
			var r = G('logwindow');
			if(!r){ 
				S.Debugger.cached = true; 
				//alert("no window yet");
				return false;
			}else{
				//sm("this.cached = " +S.Debugger.cached);
				//alert("got win");
				return true;
			}
		},

		ShowDebug : function(msg){
			//sm("IN ShowDebug msg = " + msg);
			if(!S.Debugger.debug)return;
			S.Debugger.counter++;
			var logMsg = S.Debugger.counter.toString()+": "+msg
			if(!S.Debugger.CheckLogger()){
				//sm("Add msg to cache at pos " + S.Debugger.counter + " length of cache = " + S.Debugger.cache.length)
				S.Debugger.cache.push(logMsg); //store in cache until console is loaded
				S.Debugger.cached=true;
				//check every second until bug is loaded
				//sm("interval = " + S.Debugger.debugInterval);
				if(S.Debugger.debugInterval==null){
					S.Debugger.debugInterval = setInterval(function(){
						//sm("call ConsoleReady for every second");
						S.Debugger.ConsoleReady();
						},1000);
				}
			}else{
				if(S.Debugger.cached){
					//sm("clear the cache of " + S.Debugger.cache.length + " messages");
					S.Debugger.ClearCache()
				};				
				S.Debugger.Log(logMsg);
			}
		},

		CheckLogger: function(){
			//sm("in CheckLogger this.ready = " +S.Debugger.ready);
			if(S.Debugger.ready){
				//sm("ready so return true");
				return true;
			}else{
				//sm("else do we want custom = " + S.Debugger.ForceCustomDebug);
				// if we want to use my own div logger check for that
				if(S.Debugger.ForceCustomDebug){
					//sm("custom log")
					if(G('logwindow')){
						//sm("logwindow exists")
						S.Debugger.logTo = "logwindow"; // might have been added to DOM already							
						S.Debugger.ready = true;
					}else{ 
						//sm("not ready yet")
						// custom logger not ready so try to create it
						S.Debugger.ready = S.Debugger.setupCustomLog();
						if(S.Debugger.ready){
							S.Debugger.logTo = "logwindow";							
						}
					}
				}else{
					// check for console or firebug-lite if wanting to use that for non FF browsers instead of own console
					if(S.Browser.name != "Firefox" && this.ForceFirebugLite){
						if((typeof(firebug)!="undefined") && firebug.env && firebug.env.init ){
							//sm("found firebug-lite console")
							S.Debugger.logTo = "firebug-lite";
							S.Debugger.ready = true;
						}else{
							S.Debugger.ready = false;
						}
					}else{
						//sm("any type of console");
						// any type of console
						S.Debugger.ready = (typeof(_w.console)!="undefined");
						if(S.Debugger.ready){
							S.Debugger.logTo = "console";
						}
					}
				}
			}
			//sm("return this.ready = " + S.Debugger.ready);
			return S.Debugger.ready; //never ever going to let you go baby
		},


		ConsoleReady: function(){		
			//sm("in consoleReady");
			if(S.Debugger.CheckLogger()){
				//sm("CheckLogger() is ok clearCache!!")
				S.Debugger.ClearCache();
				clearInterval(S.Debugger.debugInterval);
				S.Debugger.debugInterval=null;			
			}
		},

		ClearCache: function(){		
			//sm("clear cache")
			if(S.Debugger.cache.length>0){
				for(var c=0;c<S.Debugger.cache.length;c++){
					S.Debugger.Log(S.Debugger.cache[c]); //add all cached messages to debug console
				}
				S.Debugger.cache.length=0;
				S.Debugger.cached=false;
			}
			//sm("cleared all cached messages")
		},

		Log : function(m){
			//sm("in Log logTo = " + S.Debugger.logTo + " msg = " + m);
			// get log window
			if(S.Debugger.logTo === "logwindow"){
				//sm("Log to logwindow");
				var s=document.createElement("span");
				s.innerHTML = S.XSSEncode(m) + "<br />";
				//sm("s.innerHTML = " + s.innerHTML);
				var el=G("logwindow"); //use custom logger
				el.appendChild(s);
				//sm("appended to my DIV");
			}else if(S.Debugger.logTo == "console"){
				//sm("Log to console");
				console.log(m);
			}else if(S.Debugger.logTo == "firebug-lite"){
				//sm("Log to firebug-lite console")
				firebug.d.console.cmd.log(m);
			}
			//sm("logged to " + S.Debugger.logTo);
			return true;
		}	
		
	}

	ShowDebug = function(m){ S.Debugger.ShowDebug(m); }


	B = Strictly.Browser = {
		userAgent:_n.userAgent,
		platform:_n.platform,
		name:null,
		version:0,
		gecko:false,  //moz based rendering engine firefox,firebird
		khtml:false,  //konqueror rendering engine	
		webkit:false, //Safari,OmniWeb,Chrome
		webkitversion:0, //version of webkit as some sniffing is required
		opera:false, //Opera rendering engine is presto but no1 will remember that so use opera
		ie:false, //trident renering engine used by IE
		ieDocMode:5, //the document rendering engine mode, in IE8 this can be changed on the fly
		windows:false,
		mac:false,
		linux: false,
		xml:false,
		xmlDOM: (document.implementation.hasFeature && document.implementation && document.implementation.createDocument)!==undefined?true:false,
		jscript:false,
		javascript:false,
		flashEnabled:false,//if use has flash available
		flashVersion:"0", //If user has flash installed it will have the max.min version number as a string 
		cssGradeA:null, //if browser supports grade A sex n violence CSS
		cssEnhanced:false, //whether the enchance function has been run (if cssGradeA=true) which toggles classes
		boxModel:false, //subset of cssEnhanced which tells us whether browser supports the box model width=width+padding+margin
		styleFloat:"cssFloat",
		opacity:false,
		anchorsEnabled: false,
		regexpEnabled: false,
		cookieEnabled: false,
		imagesEnabled: false,
		formsEnabled: false,
		linksEnabled: false,
		framesEnabled: false,
		javaEnabled: false,
		AJAXEnabled: false,
		spoof:null,
		bot:null,
		widgeEditor:false,
		dom:_d.all?(_d.getElementById?2:1):(_d.getElementById?4:(_d.layers?3:0)), //set the dom type for browser (0=none,1=old IE,2=new IE,3=old NN browsers,4 modern moz)
		w3cDOM: typeof _d.getElementById != "undefined" && typeof _d.getElementsByTagName != "undefined" && typeof _d.createElement != "undefined", //check to see if browser is wc3 DOM enabled
		BrowserName: function(){  //Basic Browser sniffer uses name/agent and not object as IE may decide to support addEventListener instead of attachEvent etc
				ShowDebug("IN browserName")
				var a=this.userAgent;		
				if(this.name===null){ //do basic spoof testing (not accurate) obviously ppl can override functions but ppl do not tend to that for the event handlers so I will use those
					 ShowDebug("check for window opera = " + _w.opera + " and in agent = " + a + " is opera = " + (/Opera/i.test(a)))
					 if(/^\s*$/.test(a)){
						this.name = "Blank Agent";
						this.spoof = true;
					 }else if(/Opera/i.test(a) || _w.opera){					
						this.name = "Opera";
						this.opera = true;
						if(!(_w.attachEvent&&_w.addEventListener)){
							this.spoof = true; //opera supports both event models
						}else if(_w.opera && !(/Opera/i.test(a))){
							this.spoof = true; //we know its opera but no mention in agent
						}					
					 }else if(/WebKit/i.test(a) || /Apple/i.test(a)){
						this.webkit = true;
						if(/Chrome/i.test(a)){
							this.name = "Chrome";
						}else if(/Apple.*Mobile.*Safari/i.test(a)){
							this.name = "Mobile Safari";
						}else{
							this.name = "Safari";
						}
					 }else if(/msie/i.test(a) && (!_w.opera)){
						this.name = "Internet Explorer";
						this.ie = true;
						if(!_w.attachEvent || _w.addEventListener){ this.spoof = true; }
						else if(!_w.ActiveXObject || !this.jscript){ this.spoof = true; }
						if(!this.spoof){
							// find out in IE the document compatibility mode ie quirks, ie7, ie8
							this.ieDocMode = (_d.documentMode) ? _d.documentMode : (_d.compatMode && _d.compatMode=="CSS1Compat") ? 7 : 5;//default to quirks mode IE5						   
						}
					 }else if(/Firefox/i.test(a)||_n.vendor=="Firefox"){
						this.name = "Firefox";
						this.gecko = true;
					 }else if(/Firebird/i.test(a)||_n.vendor=="Firebird"){
						this.name =  "Firebird";
						this.gecko = true;
					 }else if(/konqueror/i.test(a) || /KHTML/i.test(a)){
						this.name = "Konqueror";
						this.khtml = true;
					 }else{
						this.name = _n.appName;
						// look for gecko engine
						if(_n.product&&_n.product.toLowerCase()=="gecko"&&a.indexOf('gecko')!=-1){
							this.gecko = true;
						}
					 }
					 this.version = (a.match( /.+(?:ox|rv|ion|ra|ie|me)[\/: ]([\d.]+)/i ) || [])[1];
			
					 if(this.webkit){
						this.webkitversion = (a.match(/AppleWebKit\/(\d+)/)[1]);
					 }


					 //do more spoof checks
					 if(!this.spoof && (this.gecko || this.khtml||this.webkit)){
						if(_w.attachEvent || !_w.addEventListener){ this.spoof = true;}
						else if(_w.ActiveXObject || this.jscript){ this.spoof = true;}
					 }
					 if(!this.spoof&&(this.khtml||this.webkit)){
						if(_d.all) this.spoof=true; //FF actually returns an object for this	
					 }				
				}
				ShowDebug("spoof = " + this.spoof);
				return this.name;
			},
		isSpoof: function(){ //detect whether user is trying to spoof the browser by switching useragent not 100% accurate so do not rely
				if(this.spoof===null){
					if(/(?:spoof|spoofer|fake|ripper)/i.test(this.userAgent)){
						this.spoof = true;
					}else if(/[a-z1-9]{20,}/i.test(this.userAgent)){
						if(!this.name||this.name.length==0){
							this.name = "Fake Agent";
						}
						this.spoof = true;
					}else{
						this.spoof = false;
					}
				}
				return this.spoof;
			},
		
		ScriptTest: function(){
				/*@cc_on				
					@if (@_jscript)
						this.jscript = true;
					@else */
						this.javascript = true;  /*
					@end
				@*/
			},
		OperatingSystemTest: function(){
				var p=this.platform.toLowerCase();			
				/*@cc_on
					@if (@_win32)
						this.windows = true;
					@elif (@_win16)
						this.windows = true;
					@elif (@_win64)
						this.windows = true;
					@elif (@_mac)
						this.mac = true;
					@elif (@_alpha)
						this.linux = true;
					@else */
						this.windows = p ? /win/i.test(p) : /win/.test(this.userAgent),
						this.mac = p ? /mac/i.test(p) : /mac/.test(this.userAgent),
						this.linux = p ? /linux/i.test(p) : /linux/i.test(this.userAgent);  /*
					@end
				@*/
			},
		SniffFlash: function(){			
				var a=[0,0],p=_n.plugins;
				if(p&&typeof p["Shockwave Flash"]=="object"){
					var b=p["Shockwave Flash"].description;
					if(typeof b!="undefined"){
						b=b.replace(/^.*\s+(\S+\s+\S+$)/,"$1");
						var c=parseInt(b.replace(/^(.*)\..*$/,"$1"),10);
						var d=/r/.test(b)?parseInt(b.replace(/^.*r(.*)$/,"$1"),10):0;
						a=[c,d]
					}
				}else if(_w.ActiveXObject) {
					var m=10;
					if(S.FlashMaxCurVersion&&S.FlashMaxCurVersion>9){
						m=S.FlashMaxCurVersion+1; //add 1 incase someone forgot to update when flash brought out latest version
					}
					for (var ii=m;ii>=4;ii--){			
						try {
							var f=eval("new ActiveXObject('ShockwaveFlash.ShockwaveFlash."+ii+"');");						
						}catch(e){}
					}
					if(typeof(f)=="object"){
						if(ii==6){
							f.AllowScriptAccess = "always"; //GetVariable("$version") crashes for versions 6.0.22 through 6.0.29,
						}
						try{
							var b=f.GetVariable("$version");
							if(typeof(b)!="undefined"){
								b=b.replace(/^\S+\s+(.*)$/,"$1").split(",");
								a=[parseInt(b[0],10),parseInt(b[2],10)]
							}
						}catch(e){
							if(ii>4){
								a=[ii,0];
							}
						}
					}		
				}
				if(a[0]==0&&a[1]==0){
					this.flashEnabled=false;	
				}else{	
					this.flashEnabled=true;
					this.flashVersion=a[0].toString()+'.'+a[1].toString();
				}
				return;
			},
		BrowserTest: function(){
				this.anchorsEnabled = (_d.anchors) ? "true":"false";
				this.regexpEnabled = (_w.RegExp) ? "true":"false";
				_d.cookie = "cookies=true";
				this.cookieEnabled = (_d.cookie) ? "true" : "false";
				this.imagesEnabled = (_d.images) ? "true":"false";
				this.formsEnabled = (_d.forms) ? "true" : "false";
				this.linksEnabled = (_d.links) ? "true" : "false";
				this.framesEnabled = (_w.frames) ? "true" : "false";
				this.javaEnabled = (_n.javaEnabled());
				this.AJAXEnabled = S.isObject(S.XMLHttpRequest()) ? true : false; //will be set to true/false on first time an ajax request is made.
				var m = _d.getElementsByTagName("meta");			
				for (var i = 0; i < m.length; i++) {
					if (/content-type/i.test(m[i].getAttribute("http-equiv")) && /xml/i.test(m[i].getAttribute("content"))){
						this.xml=true;
						break;
					}
				}
				return;
			},
		CSSTest: function(){  //function to set the cssGradeA setting if not already set (may have called it specifically somewhere else)
				ShowDebug("IN CSSTest");
				if(this.cssGradeA===null){
					//check from cookie we set if cookies are enabled
					if(this.cookieEnabled){
						var ck = S.readCookie('enhanced');
						ShowDebug("Cookie val = " + ck);
						if(ck===true){
							ShowDebug("Cookie says enhanced already")
							this.cssGradeA=true; //set our flag so we know browser is CSS gradeA super cool
							ShowDebug("Do we run enhancement function to modify css = " + S.EnhanceCSSDoc);
							if(S.EnhanceCSSDoc){
								ShowDebug("Yes if not already been run has it? = " + this.cssEnhanced);
								if(!this.cssEnhanced){
									ShowDebug("RUN enhanceDocument()");
									this.enhanceDocument(); //call the enhance function if we decree it and not already done
								}
							}
							return true;
						}else if(ck===false){ //cookie says browser not enhanced
							ShowDebug("Cookie says not enhanced already so skip check")
							this.cssGradeA=false;//set flag so we know browser is not CSS gradeA its gradeB 
							return true;
						}else{ ShowDebug("cookie not set so run test now")}
					}
					// not cookie enabled or cookie not set so we need to check
				}	
				var fail = false;
				ShowDebug("check w3c DOM otherwise no point")
				if(this.w3cDOM){
					ShowDebug("DO CSS TEST")
					var newDiv = _d.createElement('div');
					newDiv.style.display = "none";
					//Nicked from JQuery so we check support not browser type
					newDiv.innerHTML = '<a href="/a" style="color:red;float:left;opacity:.5;">a</a>';
					_d.body.appendChild(newDiv);
					var a = newDiv.getElementsByTagName("a")[0];
					// (IE uses filter instead)
					this.opacity = a.style.opacity === "0.5";					
					// Verify style float existence
					// (IE uses styleFloat instead of cssFloat)
					this.styleFloat = (!!a.style.cssFloat) ? "cssFloat" : "styleFloat";
					 _d.body.removeChild(newDiv);
					// Check whether box model is supported
					ShowDebug("Check Box Model")
					var newDiv = _d.createElement('div');
					_d.body.appendChild(newDiv);
					newDiv.style.visibility = 'hidden';
					newDiv.style.padding = '10px';
					newDiv.style.width = '20px';				
					var divWidth = newDiv.offsetWidth;
						if(divWidth != 40) {_d.body.removeChild(newDiv); fail=true; ShowDebug("Failed on 1");}
					if(!fail){
						newDiv.style.position = 'absolute';
						newDiv.style.left = '10px';
						var leftVal = newDiv.offsetLeft;
						if(leftVal != 10) { _d.body.removeChild(newDiv); fail=true; ShowDebug("Failed on 2");}
					}
					//set boxModel flag, browser may fail rest of tests but still support box model
					if(!fail){this.boxModel = true;}
					ShowDebug("this.boxModel = " + this.boxModel)
					// The following tests are similar but unrelated to the previous
					// tapped from JQuery as well, starting to like it apart from a few bugs!		
					var innerDiv, checkDiv, table, td, rules, prop, bodyMarginTop = _d.body.style.marginTop;
					var newDiv2 = _d.createElement('div');
					// set up html we will test
					html = '<div style="position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;"><div></div></div><table style="position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;" cellpadding="0" cellspacing="0"><tr><td></td></tr></table>';
					rules = { position: 'absolute', top: 0, left: 0, margin: 0, border: 0, width: '1px', height: '1px', visibility: 'hidden' };
					for ( prop in rules ){ newDiv2.style[prop] = rules[prop];}
					newDiv2.innerHTML = html;
					_d.body.insertBefore(newDiv2, _d.body.firstChild);
					innerDiv = newDiv2.firstChild, checkDiv = innerDiv.firstChild, td = innerDiv.nextSibling.firstChild.firstChild;
					// Set some browser flags which are used when we calculate the position of elements within the DOM correctly
					this.doesNotAddBorder = (checkDiv.offsetTop !== 5);
					this.doesAddBorderForTableAndCells = (td.offsetTop === 5);
					innerDiv.style.overflow = 'hidden', innerDiv.style.position = 'relative';
					this.subtractsBorderForOverflowNotVisible = (checkDiv.offsetTop === -5);
					_d.body.style.marginTop = '1px';
					this.doesNotIncludeMarginInBodyOffset = (_d.body.offsetTop === 0);
					// reset body style to original settings
					_d.body.style.marginTop = bodyMarginTop;
					_d.body.removeChild(newDiv2); //clean up
					//ShowDebug("this.doesNotAddBorder = " + this.doesNotAddBorder)
					//ShowDebug("this.doesAddBorderForTableAndCells = " + this.doesAddBorderForTableAndCells)
					//ShowDebug("this.subtractsBorderForOverflowNotVisible = " + this.subtractsBorderForOverflowNotVisible)
					//ShowDebug("this.doesNotIncludeMarginInBodyOffset = " + this.doesNotIncludeMarginInBodyOffset)
					// Check float works correctly
					if(!fail){
						var newInnerDiv = _d.createElement('div');
						newInnerDiv.style.width = '5px';
						newInnerDiv.style.cssFloat = 'left';
						newInnerDiv.style.styleFloat = 'left';
						newDiv.appendChild(newInnerDiv);
						var secondInnerDiv = newInnerDiv.cloneNode(true); 
						newDiv.appendChild(secondInnerDiv);
						var newInnerDivTop = newInnerDiv.offsetTop;
						var secondInnerDivTop = secondInnerDiv.offsetTop;
						if(newInnerDivTop != secondInnerDivTop) { _d.body.removeChild(newDiv); fail=true; ShowDebug("Failed on 3");}
					}
					if(!fail){
						ShowDebug("Do Float Test on UL LI")
						newDiv.innerHTML = '<ul><li style="width: 5px; float: left;">test</li><li style="width: 5px; float: left;clear: left;">test</li></ul>';
						var top1 = newDiv.getElementsByTagName('li')[0].offsetTop;
						var top2 = newDiv.getElementsByTagName('li')[1].offsetTop;
						ShowDebug("top1 = " + top1 + " top2 = " + top2)
						if(top1 == top2){fail=true; ShowDebug("Failed on 4");}
					}
					if(!fail){
						newDiv.innerHTML = '<div style="height: 20px;"></div>';
						newDiv.style.padding = '0';
						newDiv.style.height = '10px';
						newDiv.style.overflow = 'auto';S
						var newDivHeight = newDiv.offsetHeight;
						if(newDivHeight != 10){_d.body.removeChild(newDiv); fail=true; ShowDebug("Failed on 5");}
					}
					if(!fail){
						newDiv.innerHTML = '<div style="line-height: 2; font-size: 10px;">Te<br />st</div>';
						newDiv.style.padding = '0';
						newDiv.style.height = 'auto';
						newDiv.style.overflow = '';
						var newDivHeight = newDiv.offsetHeight;
						if(newDivHeight > 40){_d.body.removeChild(newDiv); fail=true; ShowDebug("Failed on 6");}
					}
					if(!fail){
						if(_w.onresize == false){_d.body.removeChild(newDiv); fail=true; ShowDebug("Failed on 7");}
					}
					if(!fail){
						if(!_w.print){ _d.body.removeChild(newDiv); fail=true; ShowDebug("Failed on 8");}
					}
					if(!fail){
						if(_w.clientInformation && _w.opera){_d.body.removeChild(newDiv); fail=true; ShowDebug("Failed on 9");}
					}
					ShowDebug("Did test fail = " + fail);
					if(!fail){
						ShowDebug("Remove Test Div")
						_d.body.removeChild(newDiv);					
						if(S.EnhanceCSSDoc){
							ShowDebug("Yes if not already been run has it? = " + this.cssEnhanced);
							if(!this.cssEnhanced){
								ShowDebug("RUN enhanceDocument()");
								this.enhanceDocument(); //call the enhance function if we decree it and not already done
							}
						}					
						ShowDebug("Set cookie so next time no need to run check");
						S.createCookie('enhanced', 'true');//set cookie so next time we do not have to carry out this check				
						this.cssGradeA=true;
						ShowDebug("DONE")
						return true;
					}				
				}
				ShowDebug("CSS failed GradeA check");
				createCookie('enhanced', 'false');//set cookie so next time we do not have to carry out this check
				this.cssGradeA=false;
				ShowDebug("FAILED");
				return false;
			},
		
		// Modifies a document to put special classnames if browser supports enhanced or basic CSS use for Mobile devices or old browsers
		enhanceDocument : function(){
			ShowDebug("IN enhanceDocument");
			//add class to body "enhanced" for css scoping (makes sure it's not already there)
			if (!/\benhanced\b/.exec(document.body.className)){
				document.body.className += ' enhanced';
			}
			//function to enable enhanced stylesheets (enables alt stylesheet links with class name "enhanced)
			var allLinks = document.getElementsByTagName('link');
			for(i=0; i<allLinks.length; i++){
				ShowDebug("Look at class " + i + " - " + allLinks[i].id + " - " + allLinks[i].tagName + " - " + allLinks[i].className + " - " + allLinks[i].href);
				//enumObj(allLinks[i]);
				//if the link has a class of "basicNoCascade", disable it
				if (/\bbasicNoCascade\b/.exec(allLinks[i].className)){
					allLinks[i].disabled = true;
				}
				//if the link has a class of "enhanced", enable it
				if (/\benhanced\b/.exec(allLinks[i].className)){
					allLinks[i].disabled = true; //opera likes to have it toggled
					allLinks[i].disabled = false;
				}
			}
			ShowDebug("Set Browser.cssEnhanced=true");
			S.Browser.cssEnhanced=true; //let global obj know we have run this alread on page
			ShowDebug("RETURN")
		},

		GUITest: function(){ //test for CSS and Widgit Editor support on onload
				ShowDebug("IN GUI Test");
				this.CSSTest();
				//set up support for our widge editor 
				ShowDebug("w3cDOM = "+this.w3cDOM + " GradeA CSS = " + this.cssGradeA);
				if(this.w3cDOM){ //DOM 3 and Good CSS
					ShowDebug("Check for contenteditable = " + typeof(S.getBody().contentEditable))
					ShowDebug("Check for designMode = " + typeof(_d.designMode))
					if(typeof(S.getBody().contentEditable)!="undefined"||typeof(_d.designMode)!="undefined"){
						// Until I can fix 100% editor in Safari/Chrome/Opera don't allow WYSIWYG editing
						if(S.Browser.ie||S.Browser.gecko){
							this.widgeEditor = true;
						}
					}				
				}
				ShowDebug("widgeditor support = " + this.widgeEditor);
			},

		// Outputs all browser settings
		Settings: function(){
				var s="UserAgent: "+this.userAgent+"<br />",x=0;
				for(var p in this){
					if(typeof(this[p])!="function"&&p!="userAgent"){
						x++;
						s+=p+": "+this[p]+"<br />";						
					}
				}
				return s;
			}
	}
	
	
	// Strictly.js can be used with or without jquery but if its used without then the PageLoader and events files should be used as well
	// which will extend the Pageloader object created here by adding extra addEvent functions.
	P = PageLoader = {
		// Flags that tell us when parts of the page have loaded
		DOMLoaded : false,
		BodyLoaded : false,
		WindowLoaded : false,
		Body:[],
		WinLoadArr : [],
		DOMArr : [],		
		DOMTimer : null, //for browsers with no DOM ready support we may use a timer to check when it is ready
		
		AddWindowLoadEvent : function(fn,ignoreDupe){ //use this so all window onloads are fired in order they are added plus we fire my onafterload events afterwards
			ShowDebug("IN AddWindowLoadEvent = " + fn + ", " + ignoreDupe);
			if(typeof(fn)=="function"){
				//check not already been added
				if(!ignoreDupe&&S.inArray(this.WinLoadArr,fn)) { ShowDebug("Function already in array!!");return false; }
				if(this.WindowLoaded){  
					ShowDebug("Window already loaded so run function now!!!")
					fn(); //window already loaded so run now
				}else{
					ShowDebug("Add function to Window array at pos "+ this.WinLoadArr.length);
					this.WinLoadArr.push(fn); //add to array so all fire in order					
				}
			}
			return true;
		},	

		RunWindowLoaded : function(){
			ShowDebug("IN RunWindowLoaded this.WindowLoaded = "+this.WindowLoaded)
			if(this.WindowLoaded){
				ShowDebug("Window already loaded so return");
				return;
			}else{
				ShowDebug("Run any DOMLoad functions that were not run on DOMLoaded")
				//It may be that the DOM functions that should have run on DOM Ready failed so we ensure anything that hasn't run does
				var da=this.DOMArr;
				for (var i = 0; i < da.length; i++) {
					if(da&&S.isFunction(da)){
						ShowDebug("Fix Prev Problems By Running Function Loaded By DOMLoader = " + da[i].toString());
						try{
							da[i](); //if it fails again then tough luck
						}catch(e){};
					}
				}
				ShowDebug("Now run any functions in the WinLoadArr array = " + this.WinLoadArr.length +" functions to run");
				this.WindowLoaded = true;
				// make sure if an old DOM level 0 event has been added after any addWinLoadEvent function calls its still handled		
				for (var i = 0; i < this.WinLoadArr.length; i++) {
					if(S.isFunction(this.WinLoadArr[i])){
						ShowDebug("Run Function Loaded By WindowLoader = " + this.WinLoadArr[i].toString());
						this.WinLoadArr[i]();
					}
				}				
			}
			return true;
		},

		onBodyLoad : function(fn){
			if(S.isFunction(fn)){
				if(!this.Body[fn]){
					if(P.BodyLoaded || S.getBody()){
						fn.call();
						P.Body[fn]=true;
						P.BodyLoaded=true;
					}
				}else{
					setTimeout(function(){P.onBodyLoad(fn);},200);
				}
			}
		},

		AddDOMLoadEvent : function(fn){
			ShowDebug("add function = " + fn + " this.DOMLoaded = " + this.DOMLoaded);
			if (this.DOMLoaded) {
				fn();
			}else { 		
				this.DOMArr.push( fn ); 				
			}
			return true;
		},

		RunDOMLoadFunctions : function() {		
			//D.debug=true;
			ShowDebug("IN RunDOMLoadFunctions this.DOMLoaded = " + this.DOMLoaded)
			if (this.DOMLoaded) {
				return;
			}
			if (B.ie && B.windows) { // Test if we can really add elements to the DOM; we don't want to fire it too early
				var s = _d.createElement("span");
				ShowDebug("test DOM for IE");
				try { // Avoid a possible Operation Aborted error
					var t = S.getBody().appendChild(s);
					t.parentNode.removeChild(t);
				}
				catch (e) {
					//if we are not using a timer to poll for DOM readiness we set one up to ensure the DOM functions get run
					if(!this.DOMTimer){
						this.DOMTimer = setInterval(function(){ P.RunDOMLoadFunctions();},10);
					}
					return;
				}
			}
			ShowDebug("Set DOM Loaded = TRUE");
			this.BodyLoaded=true;
			this.DOMLoaded = true;
			if (this.DOMTimer) {
				clearInterval(this.DOMTimer);
				this.DOMTimer = null;
			}
			for (var i = 0; i < this.DOMArr.length; i++) {
				ShowDebug("Run Function Loaded By DOMLoader = " + this.DOMArr[i].toString());			
				this.DOMArr[i]();
				this.DOMArr[i] = S.kill( this.DOMArr[i] ); //clear ref as RunWindowLoaded function will run anything not run by DOM loaded due to failures
			}
			return true;
		},
		onDOMLoad : function(){  // this will call RunDOMLoadFunctions that will loop through the DOM array running any functions setup for it once the DOM is ready
			//D.debug=true;
			ShowDebug("IN onDOMLoad should only run once!!!!");
			//for spoofers or older browsers we have no idea of true object support so revert to an onload
			if(B.w3cDOM && !B.spoof){
								
				// if webkit < 525 OR opera < 9 use timer as they have no DOMContentLoaded support
				if((B.webkit&&B.webkitversion<525)||B.khtml||(B.opera&&B.version<9)&&_d.readyState!="undefined"){
					ShowDebug("create timer for old webkit khtml opera");
					P.DOMTimer = setInterval(function(){ if(/loaded|complete/.test(_d.readyState)){ P.RunDOMLoadFunctions(); }},10);
				}
				// DOM 2
				else if(_d.addEventListener){
					ShowDebug("Add DOMContentLoaded EventListener for RunDOMLoadFunctions");
					//_d.addEventListener("DOMContentLoaded", function(){PageLoader.RunDOMLoadFunctions();}, false);		
					addEvent(_d,"DOMContentLoaded",function(){
						removeEvent(_d,"DOMContentLoaded",arguments.callee); //remove straight away
						P.RunDOMLoadFunctions();}, false);	// run all DOM ready functions

				}
				// IE Event Model (try a couple of things)
				else if(_d.attachEvent){
					ShowDebug("Attach onReadyStateChangeEvent for RunDOMLoadFunctions");
					// This should fire before window.onload but might not
					addEvent(_d,"onreadystatechange",function(){
						//D.debug = true
						ShowDebug("IN onreadystatechange _d.readyState = " + _d.readyState);
						if ( _d.readyState === "complete" ) {	
							ShowDebug("OK - removeEvent and RunDOMLOadFunctions");
							removeEvent(_d,"onreadystatechange",arguments.callee); //remove straight away
							PageLoader.RunDOMLoadFunctions(); // run all DOM ready functions
						}},false);
					
					// Also try this hack by Diego Perini which will work if window is not an iframe and better than the defer method
					if ( _d.documentElement.doScroll && _w == _w.top ) (function(){
						if ( this.DOMLoaded ) return;

						try {
							// This will raise an error until DOM is ready
							_d.documentElement.doScroll("left");
						}catch(e) {
							setTimeout( arguments.callee, 0 );
							return;
						}
						ShowDebug("Try/Catch doScroll no error call RunDOMLoadFunctions");
						// once try doesn't raise an error it means DOM is ready
						PageLoader.RunDOMLoadFunctions(); 
					})();
				}
			}
			ShowDebug("add a windows load event in case it all goes tits up");
			// Even if this is set any of the above that work will set the DOMLoaded flag so that the call isn't run multiple times this way if anything fails the window.onload still runs
			this.AddWindowLoadEvent( function(){P.RunDOMLoadFunctions();} );
			ShowDebug("END of onDOMLoad");
			return true;
			//D.debug =false;
		}
	}
	


	S.Browser.ScriptTest();
	S.Browser.BrowserName();
	S.Browser.isSpoof();	
	S.Browser.OperatingSystemTest();

	
	
	CreateDocument = function(rootTag,nameSpace){

		ShowDebug("IN CreateDocument rootTag = " + rootTag + ", nameSpace = " + nameSpace);

		//variable for the created DOM Document
		var objDOM = null;
		
		//if this is a standards-compliant browser like Mozilla
		if(B.xmlDOM){
		
			ShowDebug("XMLDOM supported");

			//create the DOM Document the standards way
			objDOM = document.implementation.createDocument(nameSpace, rootTag, null);    			
			
			if(!window.XMLDocument){
				// correct any missing object
				if(typeof(Document)!="undefined") XMLDocument = Document;
			}
			
			// make sure a root node exists
			if(objDOM && (nameSpace || rootTag) && !objDOM.documentElement){
				objDOM.appendChild(oDoc.createElementNS(nameSpace, rootTag));
			}
			

		} else if (B.ie) {
		
			ShowDebug("IE")

			var ax = ["MSXML4.DOMDocument", "MSXML3.DOMDocument", "MSXML2.DOMDocument", "MSXML.DOMDocument", "Microsoft.XmlDom"];
			
			objDOM = S.CreateObject(ax,"OBJECT"); //create object

			if(objDOM){
				//if there is a root tag name, we need to preload the DOM
				
				ShowDebug("got ActiveX so create DOM");

				 if (rootTag){
					// create an artifical namespace prefix 
					// or reuse existing prefix if applicable
					var prefix = "";
					if(nameSpace){
						if(rootTag.indexOf(":") > 1){
							prefix = rootTag.substring(0, rootTag.indexOf(":"));
							rootTag = rootTag.substring(rootTag.indexOf(":")+1); 
						}else{
							prefix = "a" + S.getCounter();
						}
					}
					// use namespaces if a namespace URI exists
					if(nameSpace){
						objDOM.loadXML('<' + prefix+':'+rootTag + " xmlns:" + prefix + "=\"" + nameSpace + "\"" + " />");
					} else {
						objDOM.loadXML('<' + sName + " />");
					}
				}
			}
		}
		
		//return the object
		return objDOM;
	}


	function SetupXML(){

		ShowDebug("IN SetupXML")

		// for standard compliant browsers add a loadXML method to mimic IE
		if(B.xmlDOM){

			ShowDebug("XMLDOM support create loadXML function");

			//add the loadXML() method to the Document class
			Document.prototype.loadXML = function(xml) {
				
				ShowDebug("IN loadXML = " + xml);

				//create a DOMParser
				var objDOMParser = new DOMParser();
				
				//create new document from string
				var objDoc = objDOMParser.parseFromString(xml, "text/xml");
				
				//make sure to remove all nodes from the document
				while (this.hasChildNodes()){
					this.removeChild(this.lastChild);
				}

				//add the nodes from the new document
				for (var i=0; i < objDoc.childNodes.length; i++) {
					
					//import the node
					var objImportedNode = this.importNode(objDoc.childNodes[i], true);
					
					//append the child to the current document
					this.appendChild(objImportedNode);
				
				}       
			}

			

			function _Node_getXML() {
				
				ShowDebug("IN _Node_getXML");

				//create a new XMLSerializer
				var objXMLSerializer = new XMLSerializer;
				
				//get the XML string
				var xml = objXMLSerializer.serializeToString(this);
				
				//return the XML string
				return xml;
			}

			//add the getter for the .xml attribute
			Node.prototype.__defineGetter__("xml", _Node_getXML);
		}

		

		// for browsers without a DOMParser object such as IE and old Safari create one
		if(!window.DOMParser){

			ShowDebug("NO Window.DOMParser object");

			if(B.webkit){ // handle old safari

				ShowDebug("WEBKIT")

				DOMParser = function(){};
				
				DOMParser.prototype.parseFromString = function(xml, contentType){
					var xmlhttp = S.XMLHttpRequest();
					xmlhttp.open("GET", "data:" + (contentType || "application/xml") +";charset=utf-8," + S.enc(xml), false);
					if (contentType && xmlhttp.overrideMimeType) {
						xmlhttp.overrideMimeType(contentType);
					 }
					xmlhttp.send(null);
					return xmlhttp.responseXML;
				};
			}else if(typeof(CreateDocument)=="function" && CreateDocument(null, "dummy").xml){

				DOMParser = function(){};
				DOMParser.prototype.parseFromString = function(xml, contentType){
					var doc = CreateDocument();
					doc.loadXML(xml);
					return doc;
				};
			}
		}

		ShowDebug("finished");
	}

	// if html string is passed in for doc then create a document object
	// with that html and use that to search for the element
	getDoc = function(doc){
		if(S.isString(doc)){
			if(/<[^>]+?>/.test(doc)){
				//ShowDebug("yes html create new document");
				var dochtml = doc;
				
				doc = DOMParser.parseFromString(xml,"text/xml")
				
				//ShowDebug("typeof(dochtml) =" + typeof(dochtml))
				//ShowDebug("childNodes = " + doc.childNodes.length);	
				
			}
		}

		return doc || document;
	}


	// create some short cuts
	//G = function(el,doc){return S.getEl(el,doc);}
	GC = function(c,n,t){return getElementsByClassName(c,n,t)}

	// SUPER G!!
	// Returns in no particular order
	// Element by ID (xml or html)
	// JQuery element for normal DOM manip
	// If an XHTML/XML node is passed in for the element then the raw HTML/XML as a string e.g innerHTML
	// If a string of XHTML is passed in for the node then a document will be created and used as the context.
	// If a string of XHTML is passed in for the element then a DIV is created from that and a node list returned
	// If a selector string is passed in for the element then a node list will be returned e.g
	// .text will return all elements with class=text in document/node
	// P.text will return all paragraphs with class=text in document/node
	// #myElem.text will return all elements with class=text within a node with the id=myElem
	// if <SPAN> or <P> is passed in then an array of all elements of that node type are returned
	// CHILD, CHILDREN, PARENT will return the firstChild, all children or parent of node passed in
	G = function(el,node,tag){	

		//ShowDebug("IN G el = " +el + " node = " + node + " tag = " + tag);
		
		// return either current document or a newly created XML document if an HTML string has been passed in
		// for the node value
		doc = getDoc(node);
		
		if(el){
			if(S.isString(el)){
				// if an html string turn into an element array

				//sm("el = string is it html?")

				// this is wrong as it will match <P> and we want children so at least one closing tag <P>werwe</P>
				// do a match with open and close tag
				if(/<[^>]+?>/.test(el)){
				//	sm("IS HTML create nodes from DIV");
					var div = (node||document).createElement("div");
					div.innerHTML = el;
	
					//sm("nodes = " + el.length);
					el = div.childNodes;					
				}else{
					
					//sm("NOT HTML get element");
					// test for selectors e.g P.error which we can call getElementsByClass with to return an array of nodes
					// or #myEl.text which would be all elements with a class of text inside the element with an id of myEl

					//match = /^(\|#)?(\w\+). ., /.exec(el);

		//			ShowDebug("call getEl el = "+ el + " node = "+ node);
					el = S.getEl(el,node);
				}
			// for jQuery objects return the element (first one from a node list)
			}else if(el.jquery){
				// convert into an element
				el = el.get(0);
			// otherwise return the innerHTML
			}else if(S.isHTML(el)){
				el = el.innerHTML;
			}else if(S.isXML(el)){
				el = el.xml;
			}
		}else{
			el = node || document;  
		}

		return el;
	}

	Strictly.Element = function(el){

		//ShowDebug("new element el = " +el);

		this.html = function(el){
						if(S.isXML(el)){
							return el.xml;
						}else if(el.jquery){
							return el.html();
						}else{
							return el.innerHTML;
						}
					}

		//ShowDebug("return el = " + el)
		return el;
	}


	// will set our markers using JQuery if possible
	if(typeof jQuery=='function'){
	//if(1==2){
		
		// Create some wrapper functions making use of JQuery
		DOM = addDOMLoadEvent = function(f){ if(B.w3cDOM){$(_d).ready(f); }else{W(f);}}
		W = addWinLoadEvent = function(f){ $(_w).load(f); }
		
		addEvent = function(obj,type,fn){
			$(obj).bind(type,fn);
		}

		removeEvent = function(obj,type,fn){
			$(obj).unbind(type,fn);
		}

		DOM(function(){
			PageLoader.BodyLoaded = true;
			PageLoader.DOMLoaded = true;
			//D.debug = true;
			SetupXML();
		})

		W(function(){
			PageLoader.WindowLoaded = true;
		})
	}else{
		// No JQuery available so use window onloads

		DOM = addDOMLoadEvent = function(f){ ShowDebug("IN DOM - call P.AddDOMLoadEvent");P.AddDOMLoadEvent(f); } // use the page loader to add DOM ready events
		W = addWinLoadEvent = function(f){ P.AddWindowLoadEvent(f); }
		
		addEvent = function( obj, type, fn, cp ) 
		{ 			
			if(obj){
				if(obj.addEventListener){
					cp = cp || false;
					obj.addEventListener( type, fn, cp ); 
				}else if ( obj.attachEvent ) { 			
					obj[type+fn] = function(){fn.call(obj,window.event);}
					obj.attachEvent( 'on'+type, obj[type+fn] );
					/*var ev = type+fn;
					obj['e'+ev] = fn; 
					obj[ev] = function(){obj['e'+ev]( window.event );} 
					obj.attachEvent( 'on'+type, obj[ev] ); */
				}else{
					var ev='on'+type;
					var oldevent = obj[ev];
					if (typeof oldevent != 'function'){			
						obj[ev]=fn;
					}else{			
						obj[ev] = function(){ oldevent();fn();}
					}
				}	
			}
		}

		removeEvent = function( obj, type, fn ) { 
			if(obj){  
				if(obj.removeEventListener){
					obj.removeEventListener( type, fn, false ); 
				}else if(obj.detachEvent){
					ShowDebug("detachEvent on on"+type+" " + obj.id + " - " + obj.tagName);
					try{
						obj.detachEvent( 'on'+type, obj[type+fn] ); 						
						ShowDebug("now set to null")
						obj[type+fn] = null; 
						//obj['e'+type+fn]=null;
						ShowDebug("detachedEvent on " + obj.id + " - " + obj.tagName);
					}catch(e){}
				}else{
					var exfunc = obj["on"+type];		
					if(exfunc==fn){		
						obj["on"+type]=null;
					}
				}
			}
		} 

		//set up a DOMReady event to run any functions added with non JQuery version of addDOMLoadEvent once
		//the DOM has loaded
		P.onDOMLoad(); 
		
		//set up a window onload function
		var obj, evType = (_w.attachEvent) ? "on"+evType : evType;

		if(_w.addEventListener){
			obj = _w ; //gecko, safari, konqueror, standards
		}else if(_d.addEventListener){
			obj = _d //opera 7
		}else{
			obj = _w // IE
		}

		// if old skool inline event exists for window.onload = blah then remove and add to beginning of page loader array
		if(obj[evType]){
			inlineFunc = obj[evType];
			obj[evType] = null;

			if(P.WinLoadArr.length>0){
				P.WinLoadArr.unshift(inlineFunc); //put inline function at beginning of array of functions
			}else{
				P.WinLoadArr[0] = inlineFunc;
			}
		}

		// make sure we have one window.onload event that runs all functions
		addEvent(obj,"load", function(){PageLoader.RunWindowLoaded();} );
		
	}

	// Call a function once DOMS ready to test browser setup and GUI
	DOM(function(){
		S.Browser.BrowserTest();			
		S.Browser.SniffFlash();
		S.Browser.GUITest();
		//D.debug = true;
		SetupXML();
	})


	sm = function(m){ console.log(m) }


}())

