/* ripped from http://www.onlinetools.org/articles/unobtrusivejavascript/cssjsseparation.html */
/* 31-10-2005 13:59 replaced with tino's code, see below */
/*
	a
		defines the action you want the function to perform.
	o
		the object in question.
	c1
		the name of the first class
	c2
		the name of the second class

	Possible actions are:

	swap
		replaces class c1 with class c2 in object o.
	add
		adds class c1 to the object o.
	remove
		removes class c1 from the object o.
	check
		test if class c1 is already applied to object o and returns true or false
	toggle
		test if class c1 is already applied to object o and remove if so, otherwise add class c1
*/
function jscss(a,o,c1,c2)
{
	switch (a)
	{
		case 'add':
			jscss.addClass(o, c1);
			break;
		case 'remove':
			jscss.removeClass(o, c1, c2);
			break;
		case 'check':
			return jscss.hasClass(o, c1);
			break;
		case 'checkParents':
			do
			{
				if (jscss.hasClass(o, c1))
					return true;

				if(o.tagName.toLowerCase() == 'body')
					return false;
			}
			while(o = o.parentNode);
			return false;
			break;
		case 'toggle':
			var operation = 'add';

			if(jscss('check', o, c1))
				operation = 'remove';

			jscss(operation, o, c1, c2);
			break;
		case 'swap':
			jscss.replaceClass(o, c2, c1);
			break;
		case 'get':
			return jscss.getClassList(o);
			break;
	}
	return null;
};

/* taken from http://therealcrisp.xs4all.nl/meuk/classdealer.js */
/* author: Tino Zijdel, 2005 */
jscss.addClass = function (element, classname)
{
	var classes = jscss.getClassList(element);
	if (classes.indexOf(classname) == -1)
	{
		classes[classes.length] = classname;
	}

	jscss.setClassList(element, classes);
};

jscss.removeClass = function (element, classname)
{
	var classes = jscss.getClassList(element), index;
	if ((index = classes.indexOf(classname)) > -1)
	{
		delete classes[index];
	}

	jscss.setClassList(element, classes);
};

jscss.replaceClass = function (element, oldclass, newclass)
{
	var classes = jscss.getClassList(element), index;
	if ((index = classes.indexOf(oldclass)) > -1 && classes.indexOf(newclass) == -1)
	{
		classes[index] = newclass;
	}

	jscss.setClassList(element, classes);
};

jscss.getClassList = function (element)
{
	if (element.className)
		return element.className.split(/\s+/);
	return [];
};

jscss.setClassList = function (element, classes)
{
	element.className = classes.join(' ');
};

jscss.hasClass = function (element, classname)
{
	var wantedClasses = new Array();
	if (classname.indexOf(' ') > -1)
	{
		wantedClasses = classname.split(/\s+/);
	} else {
		wantedClasses[0] = classname;
	}

	var classes = jscss.getClassList(element);

	for (var i = 0; i < wantedClasses.length; i++)
	{
		if (classes.indexOf(wantedClasses[i]) == -1)
		{
			return false;
		}
	}

	return true;
};

if (!Array.prototype.indexOf)
{
	Array.prototype.indexOf = function(searchElement, fromIndex)
	{
		var l = this.length, i = 0;
		if (fromIndex)
		{
			i = fromIndex;
			if (i < 0)
			{
				i += l;
				if (i < 0)
					i = 0;
			}
		}

		while (i < l)
		{
			if (this[i] === searchElement)
				return i;
			i++;
		}

		return -1;
	};
}

if (!Array.prototype.lastIndexOf)
{
	Array.prototype.lastIndexOf = function(searchElement, fromIndex)
	{
		var i = this.length;
		if (!fromIndex) fromIndex = 0;
		else if (fromIndex < 1)
		{
			fromIndex += i;
			if (fromIndex < 0) fromIndex = 0;
		}

		while (i-- > fromIndex)
		{
			if (this[i] === searchElement) return i;
		}

		return -1;
	};
}

if (!Array.getUnique)
{
	Array.prototype.getUnique = function()
	{
		var new_array = [];

		for (var i=0; i < this.length; i++)
			if (new_array.indexOf(this[i]) == -1)
				new_array.push(this[i]);

		return new_array;
	}
}

/* todo: optimize passing of variables to DOMQuery.cssToXPath */
function DOMQuery(selector, contextNode, ns)
{
	if(typeof contextNode == "undefined")
	{
		contextNode = DOMQuery.prototype.scope;
	}

	if(!DOMQuery.hasXPath)
	{
		if(typeof Element != 'undefined' && typeof Element.getElementsBySelector != 'undefined')
		{
			this.resultType = 'getElementsBySelector';

			/* prototype's highest point where getElementsBySelector is to be found is... */
			if(contextNode == document)
				contextNode = document.documentElement;

			try
			{
				this.result = $(contextNode).getElementsBySelector.apply($(contextNode), selector.split(',') );
			}
			catch(e)
			{
				this.result = [];
				this.length = 0;
				throw e;
			}
			this.length = this.result.length;
		}
		else if(typeof cssQuery != 'undefined')
		{
			this.resultType = 'cssQuery';
			this.result = cssQuery(selector, contextNode);
			this.length = this.result.length;
		}
		else if(typeof jQuery != 'undefined')
		{
			this.resultType = 'jQuery';
			this.result = jQuery(selector, contextNode);
			this.length = this.result.size();
		}

	}
	else
	{
		try
		{
			var owner = '';
			if(typeof contextNode.contentType != 'undefined')
				owner = contextNode.contentType;
			else if (contextNode.ownerDocument != null && typeof contextNode.ownerDocument.contentType != 'undefined')
				owner = contextNode.ownerDocument.contentType;
			else
				owner = 'text/html';

			var namespace = ns ? ns : (['application/xml', 'application/xhtml+xml', 'text/xml'].indexOf(owner) > -1) ? 'html:' : '';

			/* namespace = 'html:'; */

			var xpath = this.cssToXPath(selector, contextNode, namespace);

			this.result = document.evaluate(xpath, contextNode, this.NSResolver, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);

			this.length = this.result.snapshotLength;
			this.resultType = 'XPath';
		}
		catch(e)
		{
			if (showAlertOnXpathError)
				alert('XPath error:'+selector+'\n'+xpath+'\n'+e);
		}
	}
};

	DOMQuery.prototype.get = function (index)
	{
		switch(this.resultType)
		{
			case 'XPath':
				return this.result.snapshotItem(index);
			case 'cssQuery':
			case 'getElementsBySelector':
				return this.result[index];
			case 'jQuery':
				return this.result.get(index);
			default:
				throw new Error("Unknown resultType: "+this.resultType);
		}
	};

	DOMQuery.prototype.scope = document;

	DOMQuery.prototype.NSResolver = function (prefix)
	{
		if(prefix == 'html')
		{
			return 'http://www.w3.org/1999/xhtml';
		}
		else
		{
			 //this shouldn't ever happen
			return null;
		}
	};

	DOMQuery.hasXPath = (document.evaluate && document.implementation.hasFeature('xpath','3.0'));

	/* static / across all instances */
	DOMQuery.cachedXPaths = [ {}, {} ];

	/*if(typeof globalStorage != 'undefined' && typeof globalStorage['www.office.parse.nl'].cachedXPaths != 'undefined')
	{
		DOMQuery.cachedXPaths = globalStorage['www.office.parse.nl'].cachedXPaths.parseJSON();
	}

	DOMQuery.storeCachedXPaths = function()
	{
		if(typeof globalStorage != 'undefined')
			globalStorage['www.office.parse.nl'].cachedXPaths = DOMQuery.cachedXPaths.toJSONString();
	};*/

	/* tnx to http://www.joehewitt.com/ */
	DOMQuery.prototype.cssToXPath = function (rule, contextNode, namespace)
	{
		var namespaceSpecified = false;
		if(namespace == 'undefined')
			namespace = '';
		if(namespace != "")
			namespaceSpecified = true;

		var xpath = DOMQuery.cachedXPaths[ namespaceSpecified ? 0 : 1 ][rule];

		if(typeof xpath == 'string')
		{
			return xpath;
		}

		var _rule = rule;

		var regElement = /^([#.]?)([a-z0-9\\*_-]*)((\|)([a-z0-9\\*_-]*))?/i;
		var regAttr1 = /^\[([^\]]*)\]/i;
		var regAttr2 = /^\[\s*([^\^\$~*=\s]+)\s*([\^\$~*]?=)\s*(["]?)([^"]+)\3\s*\]/i;
		var regPseudo = /^:([a-z-]+)(\((["]?)([^)]+)\3\))?/i;
		var regCombinator = /^(\s*[>+\s])?/i;
		var regComma = /^\s*,/i;

		var index = 1;
		var parts = [".//", "*"], subparts = [], collection = [];
		var lastRule = null;
		var limit = false;

		while (rule.length && rule != lastRule)
		{
			lastRule = rule;

			// Trim leading whitespace
			rule = rule.replace(/^\s*|\s*$/g,"");
			if (!rule.length)
				break;

			subparts = [];

			// Match the element identifier
			var m = regElement.exec(rule);
			if (m)
			{
				if (!m[1])
				{
					if (m[5])
						parts[index] = namespace + m[5];
					else
						parts[index] = namespace + m[2];
				}
				else if (m[1] == '#')
				{
					subparts.push("@id='" + m[2] + "'");
				}
				else if (m[1] == '.')
					subparts.push("contains(concat(' ', @class, ' '),' " + m[2] + " ')");

				rule = rule.substr(m[0].length);
			}

			// Match attribute selectors
			m = regAttr2.exec(rule);
			if (m)
			{
				switch(m[2])
				{
					case '*=': /* contains */
						subparts.push("contains(@" + m[1] + ", \"" + m[4] + "\")");
					break;
					case '~=': /* contains in space-separated value */
						subparts.push("contains(concat(' ', @" + m[1] + ", ' '), \" " + m[4] + " \")");
					break;
					case '|=': /* its value either being exactly "val" or beginning with "val" immediately followed by "-"  */
						subparts.push("@" + m[1] + " = \"" + m[4] + "\") or starts-with(concat(@" + m[1] + ", '-'), \"" + m[4] + "\"))");
					break;
					case '$=': /* ends with */
						/* not supported: http://developer.mozilla.org/en/docs/XPath:Functions*/
						/*subparts.push("ends-with(\""+m[4]+"\", @"+m[1]+")");*/
						subparts.push("substring(@" + m[1] + ", string-length(@" + m[1] + ") - " + (m[4].length - 1) + ") = \"" + m[4] + "\"");
					break;
					case '^=': /* starts with */
						subparts.push("starts-with(@"+m[1]+", \""+m[4]+"\")");
					break;
					default:
						subparts.push("@" + m[1] + "=\"" + m[4] + "\"");
					break;
				}

				rule = rule.substr(m[0].length);
			}
			else
			{
				m = regAttr1.exec(rule);
				if (m)
				{
					subparts.push("@" + m[1] + "");
					rule = rule.substr(m[0].length);
				}
			}

			m = regPseudo.exec(rule);
			while (m)
			{
				rule = rule.substr(m[0].length);
				/* position() == 5 of pos[5] ? */
				/* check msdn! */
				switch(m[1])
				{
					case 'first-child':
						subparts.push("position() = 1");
					break;
					case 'last-child':
						subparts.push("last()");
					break;
					case 'only-child':
						subparts.push("position() = 1");
						subparts.push("last()");
					break;
					case 'enabled':
					case 'disabled':
					case 'checked':
						subparts.push("@" + m[1] + " != \"\"");
					break;
					case 'empty':
						subparts.push("count(.) = 0");
					break;
					case 'lang':
						subparts.push("@lang=\""+m[4]+"\"");
					break;
					case 'contains':
						subparts.push("contains(text(), \""+m[4]+"\")");
					break;
					/* http://www.w3.org/TR/css3-selectors/#nth-child-pseudo */
					case 'nth-child':

						/* let op: tagname kan ook iets zijn als 'html div bla:nth-child(2n+1)', dus 'parent' klopt niet!!!! */
						/*position is dan ook tov div, niet bla's parent */

						switch(m[4])
						{
							/* special / frequently used cases */
							case 'odd':
							case '2n+1':
								subparts.push("position() mod 2 > 0");
								break;
							case 'even':
							case '2n':
							case '2n+0':
								subparts.push("position() mod 2 = 0");
								break;
							/* If both a and b are equal to zero, the pseudo-class represents no element in the document tree. .*/
							case '0n+0':
								subparts.push("false()");
								break;
							default:
								var found;
								/* When a=0, no repeating is used, so for example :nth-child(0n+5) matches only the fifth child. */
								if(found = m[4].match(/^(0n\+)?([0-9]+)$/))
								{
									subparts.push("position() = " + found[2]);
								}
								/* When a=1, the number may be omitted from the rule. */
								else if(found = m[4].match(/^(^|1)n$/))
								{
									;
								}
								/* If b=0, then every ath element is picked. In such a case, the b part may be omitted. */
								else if(found = m[4].match(/^([0-9]+)n(\+0|$)$/))
								{
									subparts.push("position() mod " + found[1] + " = 0");
								}
								/* The value a can be negative  */
								else if(found = m[4].match(/^-n\+([0-9]+)$/))
								{
									subparts.push("position() <= " + found[1]);
								}
								/* this matches the bth child of an element after all the children have been split into groups of a elements each. */
								else if(found = m[4].match(/^([0-9]+)n([+-])([0-9]+)$/))
								{
									subparts.push("position() = floor(length(../TAGNAME)/" + found[1] + ") * " + found[1] + " " + found[2] + " " + found[3] );
								}
								else
								{
									/*throw new Error("unsupported nth-child selector: "+ m[4];)*/
								}
						}
					break;

					case 'target':
						/* should read current anchor and find matching element */
					case 'hover':
					case 'root':
						/* unsupported atm http://www.quirksmode.org/css/root.html */
					default:
						throw new Error("unsupported pseudo class: "+ m[1]);
					break;
				}

				m = regPseudo.exec(rule);
			}

			if(subparts.length > 0)
			{
				parts.push('[' + subparts.join(" and ") + ']');
			}

			// Match combinators
			m = regCombinator.exec(rule);
			if (m && m[0].length)
			{
	            if(limit)
	         {
	             parts.push(limit);
	             limit = false;
	            }

				if (m[0].indexOf(">") != -1)
				{
					parts.push("/");
				}
				else if (m[0].indexOf("+") != -1)
				{
					parts.push("/following-sibling::");
					// following-sibling selects all following siblings, we need only the first next sibling
					limit = '[1]';
				}
				else
				{
					parts.push("//");
				}

				index = parts.length;
				parts.push("*");
				rule = rule.substr(m[0].length);
			}

			m = regComma.exec(rule);
			if (m)
			{
				if(limit)
				{
					parts.push(limit);
					limit = false;
				}

				collection.push( parts.join("") );

				parts = [".//", "*"];

				index = parts.length-1;
				rule = rule.substr(m[0].length);
			}
		}

	    if(limit)
			parts.push(limit);

		collection.push( parts.join("") );

		xpath = collection.join(" | ");

		DOMQuery.cachedXPaths[ namespaceSpecified ? 0 : 1 ][_rule] = xpath;

		/*DOMQuery.storeCachedXPaths();*/

		return xpath;
	};

function getTargets(targets, defaultDOMQuery)
{
	if(targets)
	{
		if(typeof targets == 'string')
			return new DOMQuery(targets);
		else
			return targets;
	}
	else
	{
		if(typeof defaultDOMQuery == 'string')
			return new DOMQuery(defaultDOMQuery);
		else
			return defaultDOMQuery;
	}

	return new DOMQuery('');
};

function addClassToTargets(query, classname)
{
	var items = new DOMQuery(query);

	for(var i=0, item; (item=items.get(i)); i++)
	{
		jscss('add', item, classname, '');
	}
};

function addEventToTargets(targets, type, handler, defaultDOMQuery)
{
	var elements = getTargets(targets, defaultDOMQuery), el;

	for(var i=0;(el=elements.get(i));i++)
	{
		addEvent(el, type, handler);
	}

	return elements;
};

// written by Dean Edwards, 2005
// with input from Tino Zijdel - crisp@xs4all.nl
// http://dean.edwards.name/weblog/2005/10/add-event/
function addEvent(element, type, handler)
{
	if (element.addEventListener) {
		element.addEventListener(type, handler, arguments.callee.eventListenerUseCapture);
	}
	else
	{
		if (!handler.$$guid) handler.$$guid = addEvent.guid++;
		if (!element.events) element.events = {};
		var handlers = element.events[type];
		if (!handlers)
		{
			handlers = element.events[type] = {};
			if (element['on' + type]) handlers[0] = element['on' + type];
			element['on' + type] = handleEvent;
		}

		handlers[handler.$$guid] = handler;
	}
}
addEvent.guid = 1;
addEvent.eventListenerUseCapture = false;

function removeEvent(element, type, handler)
{
	if (element.removeEventListener)
		element.removeEventListener(type, handler, false);
	else if (element.events && element.events[type] && handler.$$guid)
		delete element.events[type][handler.$$guid];
};

function handleEvent(event)
{
	event = event || fixEvent(window.event);
	var returnValue = true;
	var handlers = this.events[event.type];

	for (var i in handlers)
	{
		if (!Object.prototype[i])
		{
			this.$$handler = handlers[i];
			if (this.$$handler(event) === false) returnValue = false;
		}
	}

	if (this.$$handler) this.$$handler = null;

	return returnValue;
};

function fixEvent(event)
{
	event.preventDefault = fixEvent.preventDefault;
	event.stopPropagation = fixEvent.stopPropagation;
	return event;
}

fixEvent.preventDefault = function()
{
	this.returnValue = false;
};

fixEvent.stopPropagation = function()
{
	this.cancelBubble = true;
};

// This little snippet fixes the problem that the onload attribute on the body-element will overwrite
// previous attached events on the window object for the onload event
if (!window.addEventListener)
{
	document.onreadystatechange = function()
	{
		if (window.onload && window.onload != handleEvent)
		{
			addEvent(window, 'load', window.onload);
			window.onload = handleEvent;
		}
	};
};

function getObj(ev, ob)
{
	if(!ob)
	{
		var targ;
		if (!ev) ev = window.event;

		if (ev.target) targ = ev.target;
		else if (ev.srcElement) targ = ev.srcElement;

		if (targ && targ.nodeType == 3) // defeat Safari bug
			targ = targ.parentNode;

		return targ;
	}
	else
	{
		return ob;
	}
};

function loadScript(url, prependBoardUrl)
{
	if(prependBoardUrl)
		url = board_template_url + url;

	var e = createDOMNode('script', {"type" : 'text/javascript', "src" : url}, []);

	document.getElementsByTagName("head")[0].appendChild(e);
};

function currentStyle(element, property)
{
	return parseInt(window.getComputedStyle ? window.getComputedStyle(element,'').getPropertyValue(property) : element.currentStyle.getAttribute(property));
};

function empty()
{
	if(this && this.value == this.defaultValue )
	{
		this.value = '';
	}
};

function unhtmlspecialchars(str)
{
	str = str.replace(/&amp;/gi, '&');
	str = str.replace(/&lt;/gi, '<');
	str = str.replace(/&gt;/gi, '>');
	return str;
};

/* tnx crisp */
function htmlspecialchars(input)
{
	input = input.replace(/&/g,'&amp;');
	input = input.replace(/>/g,'&gt;');
	input = input.replace(/</g,'&lt;');
	input = input.replace(/"/g,'&quot;');

	/* " < fix syntax highlighting */

	return input;
};

function getCookie(sName)
{
	var aCookie = document.cookie.split('; '), i = aCookie.length, aCrumb;
	while (i--)
	{
		aCrumb = aCookie[i].split('=');
		if (sName == aCrumb[0])
			return typeof aCrumb[1] != 'undefined'? unescape(aCrumb[1]) : null;
	}

	return null;
}

/*
 * Find the next sibling node (skipping text nodes) or a sibling with a specific tag name
 */
function getSiblingNode(startpoint, direction, tagName)
{
	var o = startpoint, tagEmpty = (tagName == undefined || tagName.length == 0);

	if (tagName != undefined)
		tagName = tagName.toLowerCase();

	do
	{
		if (direction == 'previous')
		{
			o = o.previousSibling;
		}
		else if ( direction == "next" )
		{
			o = o.nextSibling;
		}
		else if ( direction == "up" )
		{
			o = o.parentNode;
		}

		if ( o && o.nodeType == 1)
		{
			if (tagEmpty || o.tagName.toLowerCase() == tagName )
				return o;
		}

	} while (o);

	return null;
}

/*
example syntax:

var test = createDOMNode( 'div', {"class" : 'waa', "event" : ['click', _func] },
			[
				createDOMNode( 'span', {"class" : 'woei'},
				[
					'snotbeuken'
				]),
				'waa',
				123
			]);
creates:
text = <div class="waa"><span class="woei">snotbeuken>waa123</div>
*/
function createDOMNode(tagname, options, children)
{
	var option, child, me;

	if(isIE && typeof options['type'] == 'string' && (options['type'] == 'radio' || options['type'] == 'submit'))
	{
		/* IE doesn't like dynamically generated [s]radiobuttons[/] anything, so we have to set 'name' manually */
		me = document.createElement(
				'<input' +
				' type="'+options['type'] + '"' +
				' name="' + options['name'] + '"' +
				 (typeof options['checked'] != 'undefined' ? ' checked' : '') +
				'>'
			);
	}
	else if(tagname != null)
	{
		me = document.createElement(tagname);
	}
	else
	{
		me = document.createDocumentFragment();
	}

	for(option in options)
	{
		if(!options.hasOwnProperty(option))
			continue;

		if(option == 'event')
		{
			addEvent(me, options[option][0], options[option][1]);
		}
		else
		{
			if (option == 'class')
			{
				me.setAttribute('className', options[option]);
			}
			else if (option == 'style' && me.style.setAttribute)
			{
				me.style.setAttribute('cssText', options[option]);
				continue;
			}

			me.setAttribute(option, options[option]);
		}
	}

	for(var i = 0; (child=children[i]); i++)
	{
		if( ["string", "number"].indexOf(typeof child) > -1 )
		{
			child = document.createTextNode(child);
		}
		me.appendChild(child);
	}

	return me;
};

function setCookie(sName, sValue)
{
	document.cookie = sName + '=' + escape(sValue) + '; expires=Fri, 31 Dec 2099 23:59:59 GMT; path=/';
}

// transparantPNG - Based on http://www.schillmania.com/projects/png/ but very much completely rewritten
// Apply a filter in IE to make png's (both images and background-images) transparant
function transparantPNG(targets)
{
	if (!isIE || !isWin || !isNotIE7)
		return;

	// Here you can decide which elements to search for png's (you can use * but that will be very slow)
	var elements = getTargets(targets, '.transparantPNG');
	var imagesource;

	for (var i=0, object; (object=elements.get(i)); i++)
	{
		if (object.getAttribute('src'))
		{
			imagesource = object.getAttribute('src');
			object.src = board_template_url + 'img/layout/iefix/transparantPNG.gif';
		}
		else if (object.currentStyle.backgroundImage.toString() && object.currentStyle.backgroundImage.toString() != "none")
		{
			var cssBackground = object.currentStyle.backgroundImage.toString();
			var j = cssBackground.indexOf('url("')+5;
			imagesource = cssBackground.substr(j,cssBackground.length-j-2);
			object.style.backgroundImage = 'none';
		}
		else
		{
			return false;
		}

		object.style.writingMode = 'lr-tb';
		object.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+imagesource+"',sizingMethod='image')";

		object.style.border = '0';
	}
}

var texts = new Array();
function getText(a, b, c)
{
	if(typeof texts[a] == 'undefined' || typeof texts[a][b] == 'undefined' || !texts[a][b] )
		return '[text not found: '+a+'::'+b+']';

	if ( c )
		return texts[a][b].replace('%s',c);
	else
		return texts[a][b];
}

// Dean Edwards/Matthias Miller/John Resig
/* http://dean.edwards.name/weblog/2006/06/again/ */
function init()
{
	// quit if this function has already been called
	if (arguments.callee.done)
		return;

	// flag this function so we don't do the same thing twice
	arguments.callee.done = true;

	// kill the timer
	if (_timer)
		clearInterval(_timer);

	_init(events);
};

function rand ( n )
{
	return ( Math.floor ( Math.random ( ) * n + 1 ) );
}

var timings = [];
var eventTiming = false;

if (typeof showAlertOnXpathError == "undefined")
	var showAlertOnXpathError = false;

var isIE, isNotIE7, isGecko, isWebKit, isWin;

function _init(events, scope)
{
	if(!document.body)
		return;

	var time1, time2, funcname;
	var funcPattern = /function ([a-zA-Z]+)/, total = 0, duration = 0;

	if(!arguments.callee.initalInit)
	{
		isIE = navigator.userAgent.indexOf('MSIE') != -1 && navigator.userAgent.indexOf('Opera') == -1;
		isNotIE7 = isIE && navigator.userAgent.indexOf('MSIE 7.0') == -1;
		isGecko = navigator.userAgent.indexOf('Gecko') != -1;
		isWebKit = navigator.userAgent.indexOf('WebKit') != -1;
		isWin = navigator.userAgent.indexOf('Windows') != -1;
		jscss('add', document.body, 'javascript', '');

		arguments.callee.initalInit = true;
	}

	if(scope)
	{
		var previousScope = DOMQuery.prototype.scope;
		DOMQuery.prototype.scope = scope;
	}

	for(var i=0; i<events.length; i++)
	{
		try
		{
			if(eventTiming)
			{
				funcname = events[i].toString().match(funcPattern)[1];
				timings[i] = funcname + ' ???';
				time1 = new Date().getTime();
			}

			if(typeof events[i] == 'function')
				events[i]();
			else if(typeof events[i] == 'object')
				events[i][0].apply(window, events[i][1]);

			if(eventTiming)
			{
				time2 = new Date().getTime();
				duration = (time2 - time1);
				total += duration;

				for(j=(funcname.length + duration.toString().length); j<50; j++)
					funcname += ' ';

				timings[i] = funcname + duration + ' ms\n';
			}
		}
		catch (e)
		{
			/* we don't need to pass the scope again */
			arguments.callee( events.slice(i + 1) );
			if(scope)
			{
				DOMQuery.prototype.scope = previousScope;
			}
			throw e;
		}
	}

	if(scope)
	{
		DOMQuery.prototype.scope = previousScope;
	}

	if(eventTiming)
		document.body.appendChild(createDOMNode('pre', {}, timings));

/*	window.status = 'xpath: ' + DOMQuery.hasXPath + ' - total JS events: '+total+'ms' ; */

}

/* for Mozilla/Opera9 */
if (document.addEventListener)
{
	document.addEventListener("DOMContentLoaded", init, false);
}

/* for Internet Explorer */
/*@cc_on @*/
/*@if (@_win32)
	document.write("<script id=__ie_onload defer src=//:><\/script>");
	var script = document.getElementById("__ie_onload");
	script.onreadystatechange = function()
	{
		if (this.readyState != "complete")
			return;

		if(typeof initReadyStateDetectionCallback != 'function' || initReadyStateDetectionCallback())
		{
			init();
			return;
		}

		var _timer = setInterval(function()
		{
			if(initReadyStateDetectionCallback())
			{
				init(); // call the onload handler
			}
		}, 10);
	};
/*@end @*/

/* for Safari */
if (/WebKit/i.test(navigator.userAgent))
{ // sniff
	var _timer = setInterval(function()
	{
		if (/loaded|complete/.test(document.readyState))
		{
			init(); // call the onload handler
		}
	}, 10);
};

/* for other browsers */
window.onload = init;