/*

 * ADOBE SYSTEMS INCORPORATED

 * Copyright 2007 Adobe Systems Incorporated

 * All Rights Reserved

 * 

 * NOTICE:  Adobe permits you to use, modify, and distribute this file in accordance with the 

 * terms of the Adobe license agreement accompanying it. If you have received this file from a 

 * source other than Adobe, then your use, modification, or distribution of it requires the prior 

 * written permission of Adobe.

 */



// Copyright 2001-2005 Interakt Online. All rights reserved.

var is = new BrowserCheck();



if (typeof utility == 'undefined') utility = {};

/*

utility = {

	'math': {},

	'string': {}, 

	'js': {}, 

	'debug': {}, 

	'url': {},

	'dom': {},

	'window': {}, 

	'cookie': {}, 

	'date': {}, 

	'req': {}, 

	'xml': {}

};

*/



Object_weave_safe(utility, {math: {}});



utility.math.intbgr2hexrgb = function(a) {

	d2h = utility.math.dec2hex;

	pad = utility.math.zeroPad;

	// on mozilla will report rgb(a, b, c) - so the following is not good

	return "#" + pad(d2h(a % 256), 2) + pad(d2h((a / 256) % 256), 2) + pad(d2h((a / 65536) % 256), 2);

}



utility.math.mozcolor2rgb = function(color) {

	return color;

}



utility.math.dec2hex = function(x) {

	return Number(parseInt(x)).toString(16);

}



utility.math.hex2dec = function(x) {

	return parseInt(x, 16);

}



utility.math.zeroPad = function (str, length) {

	if (!str) str = "";

	str = str.toString();

	while (str.length < length) {

		str = "0" + str;

	}

	return str;

}

utility.math.rgb2hexcolor = function(color) {

	var arr = [];

	if (arr = color.match(/^rgb\(([0-9]+),\s*([0-9]+),\s*([0-9]+)\)/i)) {

		var ret = '';

		for (var i = 1; i < 4; i++) {

			var tmp = utility.math.dec2hex(arr[i]);

			while (tmp.length < 2) {

				tmp = "0" + tmp;

			}

			ret += tmp;

		}

		return "#" + ret;

	} else {

		return color;

	}

}



Object_weave_safe(utility, {js: {}});



utility.js.build = function(fun1, fun2) {

	var me = function() {

		if (fun2) { fun2(); }

		if (fun1) { fun1(); }

	}

	return me;

}

utility.js.empty_func = function() {};



Object_weave_safe(utility, {debug: {}});



utility.debug.dump = function (obj, sep) {

	if (sep == undefined) {

		sep = '';

	}

	tm = "";

	if (typeof (obj) == "object") {

		for (var i in obj) {

			tm += sep + i + ":{\n" + utility.debug.dump(obj[i], sep + '  ') + "}\n";

		}

		return tm;

	}

	if (typeof (obj) == "function") return sep + typeof (obj) + "\n";

	return sep + obj + "\n";

}

function al(obj, rx) {

	alert(utility.debug.dumpone(obj, rx));

}



utility.debug.dumpone = function (obj, rx, sep) {

	if (rx == undefined) {

		rx = new RegExp("", "");

	}

	if (sep == undefined) {

		sep = '';

	}

	tm = "";

	if (typeof (obj) == "object" && obj!=null) {

		if (typeof(obj.push) != "undefined" && obj.push.toString().indexOf("[native code]")>0) {

			tm = sep + "Array[" + obj.length + "]\n";

		} else {

			for (i in obj) {

				if (i.toUpperCase() == i) {

					continue;

				}

				if (!rx.test(i)) {

					continue;

				}

				try {

					if (typeof obj[i] != 'function') {

						tm += sep + i + ":{" + obj[i] + "}\n";

					} else {

						//tm += sep + i + ":{\n js function }\n";

					}

				} catch(err){

					tm += sep + i + ":ERROR{" + err.message + "}\n";

				}

			}

		}

		return tm;

	}

	if (typeof (obj) == "function") return sep + typeof (obj) + "\n";

	return sep + obj + "\n";

}



utility.debug.breakpoint = function(evalFunc, msg, initialExprStr) { 

	if (evalFunc == null) 

		evalFunc = function(e){return eval(e)};

    if (msg == null)

        msg = "";

    var result = initialExprStr || "1+2";

    while (true) {

        var expr = prompt("BREAKPOINT: " + msg + "\nEnter an expression to evaluate, or Cancel to continue.", result); 

        if (expr == null || expr == "")

            return;

        try {

            result = evalFunc(expr);

        } catch (e) {

            result = e;

        }

    }

}



Object_weave_safe(utility, {string: {}});



utility.string.htmlspecialchars = function(str) {

	Array_each([	['>', '&gt;'],

		['<', '&lt;'],

		['\xA0', '&nbsp;'],

		['"', '&quot;']

	], function(repl, idx) {

		str = str.replace(new RegExp('['+repl[0]+']', "g"), repl[1]);

	});

	return str;

}



utility.string.getInnerText = function(str) {

	if (typeof getInnerText_tmpDiv == 'undefined') {

		getInnerText_tmpDiv = document.createElement('div');

	}

	var oldstr = str;

	try {

		getInnerText_tmpDiv.innerHTML = str;

		if (is.safari) {

			str = getInnerText_tmpDiv.innerHTML;

			getInnerText_tmpDiv.innerHTML = "";

		} else {

			str = getInnerText_tmpDiv.innerText;

			getInnerText_tmpDiv.innerHTML = "";

		}

	} catch(e) { return oldstr; } 

	if ( typeof str == 'undefined') {

		return oldstr;

	}

	return str;

}



utility.string.sprintf = function() {

	if (!arguments || arguments.length < 1 || !RegExp) {

		return;

	}

	var str = arguments[0];

	var oldstr = arguments[0];

	var re = /([^%]*)%('.|0|\x20)?(-)?(\d+)?(\.\d+)?(%|b|c|d|u|f|o|s|x|X)(.*)/;

	var a = b = [], numSubstitutions = 0, numMatches = 0;

	while (a = re.exec(str)) {

		var leftpart = a[1], pPad = a[2], pJustify = a[3], pMinLength = a[4];

		var pPrecision = a[5], pType = a[6], rightPart = a[7];

		numMatches++;



		if (pType == '%') {

			subst = '%';

		} else {

			numSubstitutions++;

			if (numSubstitutions >= arguments.length) {

				return oldstr;

			}

			var param = arguments[numSubstitutions];

			var subst = param;



			if (pType == 'c') subst = String.fromCharCode(parseInt(param));

			else if (pType == 'd') subst = parseInt(param) ? parseInt(param) : 0;

			else if (pType == 's') subst = param;

		}

		str = leftpart + subst + rightPart;

	}

	return str;

}



Object_weave_safe(utility, {dom: {}});



utility.dom.setUnselectable = function(el) {

	if (is.ie) {

		for(var i=0; i<el.all.length; i++){

			if(el.all[i].tagName != "INPUT" && el.all[i].tagName != "TEXTAREA"){

				var oldCurr = utility.dom.getStyleProperty(el.all[i], "cursor");

				el.all[i].unselectable = "On";

				if(oldCurr == "auto"){

					el.all[i].style.cursor = "default";

				}

			} else if(el.all[i].type == "text" || el.all[i].tagName == "TEXTAREA"){

				el.all[i].style.cursor = "text";

			}

		}

	} else {

		var allChilds = utility.dom.getElementsByTagName(el,'*');

		Array_each(allChilds, function(child){

			var oldCurr = utility.dom.getStyleProperty(child, "cursor");

			var isHtmlEl = (child.nodeType == 1)? true: false;

			if(/*isHtmlEl*/true){

				var isInput   = ((child.nodeName.toLowerCase()=="input") && 

				                 (child.getAttribute('type') && child.getAttribute('type').toLowerCase()=='text') ||

				                 (child.getAttribute('type') && child.getAttribute('type').toLowerCase()=='password'))? true: false;

				var isTxtArea = (child.nodeName.toLowerCase()=="textarea")? true: false;

				if(!isInput && !isTxtArea ){

					if(oldCurr == "auto"){

						child.style.cursor = "default";

					}

					var hasHTMLChilds = utility.dom.getElementsByTagName(child, '*').length? true: false;

					if(!hasHTMLChilds){

						child.style.MozUserSelect = 'none';

					}

				} else{

					child.style.cursor = "text !important";

				}

			};

		});

	}

};



/**

 * utility.dom.getPixels

 * 	returns the value of a CSS property as Int, converting medium to 2

 * @param {DOMElement} m - elements

 * @param {String} s - 

 */

utility.dom.getPixels = function (m, s) {

	var v = utility.dom.getStyleProperty(m, s);

	if (v == "medium") {

		v = 2;

	} else {

		v = parseInt(v, 10);

	}

	v = isNaN(v)?0:v;

	return v;

};





/**

 * utility.dom.getBorderBox

 * 	returns a border box object (x,y,width,height) which perfectly covers the el element and its borders

 * 	the x, y are absolute coordinates measured from from the window viewport

 * 	use the box as the second parameter in utility.dom.setBorderBox

 * @param {DOMElement or String} el - 

 * @param {DOMDocument,optional} doc - 

 */

utility.dom.getBorderBox = function (el, doc) {

	doc = doc || document;

	if (typeof(el) == 'string') {

		el = doc.getElementById(el);

	}



	if (!el) {

		return false;

	}



	if (el.parentNode === null || utility.dom.getStyleProperty(el, 'display') == 'none') {

		//element must be visible to have a box

		return false;

	}



	var ret = {x:0, y:0, width:0, height:0};

	var parent = null;

	var box;



	if (el.getBoundingClientRect) { // IE

		box = el.getBoundingClientRect();

		var scrollTop = doc.documentElement.scrollTop || doc.body.scrollTop;

		var scrollLeft = doc.documentElement.scrollLeft || doc.body.scrollLeft;

		ret.x = box.left + scrollLeft;

		ret.y = box.top + scrollTop;

		ret.width = box.right - box.left;

		ret.height = box.bottom - box.top;

	} else if (doc.getBoxObjectFor) { // gecko

		box = doc.getBoxObjectFor(el);

		ret.x = box.x;

		ret.y = box.y;

		ret.width = box.width;

		ret.height = box.height;

		var btw = utility.dom.getPixels(el, "border-top-width");

		var blw = utility.dom.getPixels(el, "border-left-width");

		ret.x -= blw;

		ret.y -= btw;

	} else { // safari/opera

		ret.x = el.offsetLeft;

		ret.y = el.offsetTop;

		ret.width = el.offsetWidth;

		ret.height = el.offsetHeight;

		parent = el.offsetParent;

		if (parent != el) {

			while (parent) {

				ret.x += parent.offsetLeft;

				ret.y += parent.offsetTop;

				parent = parent.offsetParent;

			}

		}

		var blw = utility.dom.getPixels(el, "border-left-width");

		var btw = utility.dom.getPixels(el, "border-top-width");

		ret.x -= blw;

		ret.y -= btw;

		// opera & (safari absolute) incorrectly account for body offsetTop

		var ua = navigator.userAgent.toLowerCase();

		if (is.opera || is.safari && utility.dom.getStyleProperty(el, 'position') == 'absolute') {

			ret.y -= doc.body.offsetTop;

		}

	}

	if (el.parentNode) {

			parent = el.parentNode;

	} else {

		parent = null;

	}

	while (parent && parent.tagName != 'BODY' && parent.tagName != 'HTML') {

		ret.x -= parent.scrollLeft;

		ret.y -= parent.scrollTop;

		if (parent.parentNode) {

			parent = parent.parentNode;

		}	else {

			parent = null;

		}

	}

	return ret;

};



/**

 * utility.dom.setBorderBox

 * 	puts the element el to the location specified by box

 * @param {DOMElement} el - the element to be placed

 * @param {Object} box - hash containing the x and y coordinates where to put el

 *

 */

utility.dom.setBorderBox = function (el, box) {

	var pos = utility.dom.getBorderBox(el, el.ownerDocument);

	if (pos === false) {

		return false;

	}



	var delta = {

		x:utility.dom.getPixels(el, 'left'),

	 	y:utility.dom.getPixels(el, 'top')

	};



	var new_pos = {x:0, y:0};

	if (box.x !== null) {

		new_pos.x = box.x - pos.x + delta.x;

	}

	if (box.y !== null) {

		new_pos.y = box.y - pos.y + delta.y;

	}



	if (box.x !== null) {

		el.style.left = new_pos.x + 'px';

	}

	if (box.y !== null) {

		el.style.top = new_pos.y + 'px';

	}

	return true;

};



/**

 * utility.dom.bringIntoView

 * 	set the position of the source element so it is completely visible in the window

 * @param {DOMElemenet} source - the element to be 

 */

utility.dom.bringIntoView = function (source) {

	var box = utility.dom.getBorderBox(source, source.ownerDocument);

	if (box === false) {

		return false;

	}



	var current = {

		x:utility.dom.getPixels(source, 'left'),

	 	y:utility.dom.getPixels(source, 'top')

	};



	var delta = {x:0, y:0};

	var offset_fix = {x:0, y:0};

	var strictm = source.ownerDocument.compatMode == "CSS1Compat";

	var doc = (is.ie && strictm || is.mozilla)?source.ownerDocument.documentElement:source.ownerDocument.body;



 	offset_fix.x = utility.dom.getPixels(doc, 'border-left-width');

 	offset_fix.y = utility.dom.getPixels(doc, 'border-top-width');



	var st = doc.scrollTop;

	var ch = doc.clientHeight;

	var t = box.y + (is.ie?-offset_fix.y:offset_fix.y);

	var b = box.y + box.height + (is.ie?-offset_fix.y:offset_fix.y);



	if ( b - st > ch) {

		delta.y = ch - (b - st);

		if (t + delta.y < st) {

			delta.y = st-t;

		}

	} else if (t < st) {

		delta.y = st - t;

	}



	if (delta.y != 0) {

		source.style.top = (current.y + delta.y) + 'px';

	}

	

	var sl = doc.scrollLeft;

	var cw = doc.clientWidth;

	var l = box.x + (is.ie?-offset_fix.x:offset_fix.x);

	var r = box.x + box.width + (is.ie?-offset_fix.x:offset_fix.x);



	if ( r - sl > cw) {

		delta.x = cw - (r - sl);

		if (l + delta.x < sl) {

			delta.x = sl-l;

		}

	} else if (l < sl) {

		delta.x = sl - l;

	}



	if (delta.x != 0) {

		source.style.left = (current.x + delta.x) + 'px';

	}

};



/**

 * utility.dom.putElementAt

 * 	place an element over another element, at a specified special location (corner over corner)

 * @param {DOMElement} source 

 * @param {DOMElement} target 

 * @param {String} relative - string specifiing the position of source relative to target [0-4]{2}

 * 	'03' - means put source corner 0 over target corner 3, ie:dropdown menu opens below opener button

 * 	0-NW, 1-NE, 2-SE, 3-SW, 4-N (top-center), 5-E (middle-right), 6-S, 7-W, 8-center :)

 * @param {Object} offset - optional, offset.x and offset.y specifies additional amount 

 * @param {Object} biv - optional, offset.x and offset.y specifies additional amount 

 */



utility.dom.putElementAt = function (source, target, relative, offset, biv) {

	offset = util_defaultValue(offset, {x:0, y:0});

	biv = util_defaultValue(biv, true);

	var si = parseInt(relative.charAt(0), 10);

	var ti = parseInt(relative.charAt(1), 10);



	var source_box = utility.dom.getBorderBox(source, source.ownerDocument);

	var target_box = utility.dom.getBorderBox(target, target.ownerDocument);



	var sx = ['0', '-source_box.width', '-source_box.width', '0','-source_box.width/2', '-source_box.width','-source_box.width/2', '0','-source_box.width/2'];

	var tx = ['target_box.x', 'target_box.x+target_box.width', 'target_box.x+target_box.width', 'target_box.x', 'target_box.x+target_box.width/2', 'target_box.x+target_box.width', 'target_box.x+target_box.width/2', 'target_box.x', 'target_box.x+target_box.width/2'];



	var sy = ['0', '0', '-source_box.height', '-source_box.height', '0', '-source_box.height/2', '-source_box.height', '-source_box.height/2', '-source_box.height/2'];

	var ty = ['target_box.y', 'target_box.y', 'target_box.y+target_box.height', 'target_box.y+target_box.height', 'target_box.y', 'target_box.y+target_box.height/2', 'target_box.y+target_box.height', 'target_box.y+target_box.height/2', 'target_box.y+target_box.height/2'];



	var box = {x:0, y:0};

	box.x = eval(sx[si] + ' + ' + tx[ti]) + offset.x;

	box.y = eval(sy[si] + ' + ' + ty[ti]) + offset.y;



	utility.dom.setBorderBox(source, box);

	if (biv) {

		utility.dom.bringIntoView(source);

	}

	return true;

};





utility.dom.put = function(el, left, top) {

	el.style.left = left + 'px';

	el.style.top = top + 'px';

}



utility.dom.resize = function(el, width, height) {

	el.style.width = width + 'px';

	el.style.height = height + 'px';

}



utility.dom.focusElem =function(elem) {

	var d;

	d = this.getElem(elem);

	if (!d) return;

	if (d.focus) d.focus();

}



utility.dom.hideElem = function(elem) {

	this.setCssProperty(elem, "display", "none");

}



utility.dom.showElem = function(elem, force) {

	var tag_display = {

		table: 'table',

		tr: 'table-row',

		td: 'table-cell'

	}

	elem = utility.dom.getElem(elem);

	var tn = elem.tagName.toLowerCase();

	var t;

	if (!force) {

		if (typeof tag_display[tn] != 'undefined') {

			t = tag_display[tn];

		} else {

			t = "block";

		}

	} else {

		t = 'force';

	}

	try {

		this.setCssProperty(elem, "display", t);

	} catch(e) {

		// default to block if first try doesn't work

		// this happens on explorer when trying to set table-row and friends

		this.setCssProperty(elem, "display", "block");

	}

}



// because we can't find out on the first call the real state, we assume the element is hidden

utility.dom.toggleElem = function(elem, force) {

	elem = utility.dom.getElem(elem);

	try {

		if (!elem.style.display || elem.style.display == 'none') {

			utility.dom.showElem(elem, force);

		} else {

			utility.dom.hideElem(elem);

		}

	} catch(e) { }

}



// select the option that has the given value

utility.dom.selectOption = function(sel, val) {

	var i;

	if (!sel) return;

	for (i=0; i<sel.options.length; i++) {

		sel.options[i].removeAttribute('selected');

	}

	for (i=0; i<sel.options.length; i++) {

		if (sel.options[i].value == val) {

			sel.options[i].setAttribute('selected','selected');

			sel.options[i].selected = true;

			return;

		} else {

			sel.options[i].removeAttribute('selected');

		}

	}

}



// get value of the selected option

utility.dom.getSelected = function(sel) {

	return sel.options[sel.selectedIndex].value;

}







utility.dom.getPositionRelativeTo00 = function(x, y, w, h) {

	var bw, bh, sw, sh, d;

	if (is.mozilla) {

		bw = document.width;

		bh = document.height;

		sw = window.pageXOffset;

		sh = window.pageYOffset;

	} else {

		var strictm = document.compatMode == "CSS1Compat";

	

		d = strictm?document.documentElement:document.body;

		bw = d.offsetWidth - 20;

		bh = d.offsetHeight;

		sw = d.scrollLeft;

		sh = d.scrollTop;

	}

	if (x + w > bw + sw) {

		x = bw + sw - w;

	}

	if (y + h > bh + sh) {

		y = bh + sh - h;

	}

	if (x < 0) x = 0;

	if (y < 0) y = 0;

	return { x: x, y: y };

}

utility.dom.setCssProperty = function(elem, name, value) {

	var d;

	// sanity

	if (!elem || !name || !value) return;

	d = this.getElem(elem);

	if (!d) return;

	d.style[name] = value;

}



utility.dom.getElem = function(elem) {

	var d;

	if (typeof(elem) == "string") {

		d = document.getElementById(elem);

	} else {

		d = elem;

	}

	return d;

}



// return 

utility.dom.getClassNames = function(o) {

	o = utility.dom.getElem(o);

	if (!o) return false;

	var className = typeof(o.className) == 'undefined'?'':o.className;

	var cn = String_trim(String_normalize_space(className));

	if (cn == '') {

		return [];

	}

	return cn.split(" ");

}



utility.dom.classNameAdd = function(obj, toadd) {

	var cls = utility.dom.getClassNames(obj);

	if (typeof toadd == 'string') {

		toadd = toadd.split(',');

	}

	Array_each(toadd, function(item, i){

		if (Array_indexOf(cls, item) == -1) {

			Array_push(cls, item);

		}

	});

	cls = String_trim(cls.join(' '));

	var className = typeof(obj.className) == 'undefined'?'':obj.className;

	if (String_trim(className) != cls) {

		obj.className = cls;

	}

}



utility.dom.classNameRemove = function(obj, toremove) {

	var cls = utility.dom.getClassNames(obj);

	var result = [];

	/* can't use ruby.js and all those nice things yet 

	 * since ie5 doesn't have .hasOwnProperty

	cls = cls.reject(function(item, i) {

		return (item == str);

	});

	*/

	if (typeof toremove == 'string') {

		toremove = toremove.split(',');

	}

	Array_each(cls, function(item, i){

		if (Array_indexOf(toremove, item) == -1) {

			Array_push(result, item);

		}

	});

	

	cls = String_trim(result.join(' '));

	var className = typeof(obj.className) == 'undefined'?'':obj.className;

	if (String_trim(className) != cls) {

		obj.className = cls;

	}

}



utility.dom.insertAfter = function(newElement, targetElement) {

	var sibling = targetElement.nextSibling

	var parent = targetElement.parentNode;

	if (sibling == null) {

		var toret = parent.appendChild(newElement);

	} else {

		var toret = parent.insertBefore(newElement, sibling);

	}

	return toret;

}



utility.dom.getPreviousSiblingByTagName = function(t, siblingName, allowSameTag) {

	if ((t.nodeName.toLowerCase()==siblingName.toLowerCase()) && !allowSameTag) {

		return t;

	}



	while (t.previousSibling

			&& t.previousSibling.nodeName.toLowerCase() != siblingName.toLowerCase()

			) {

		t = t.previousSibling;

	}



	if (t.previousSibling && t.previousSibling.nodeName.toLowerCase() == siblingName.toLowerCase()) {

		return t.previousSibling;

	} else {

		return null;

	}

}



utility.dom.getNextSiblingByTagName = function(t, siblingName, allowSameTag) {

	if ((t.nodeName.toLowerCase()==siblingName.toLowerCase()) && !allowSameTag) {

		return t;

	}



	while (t.nextSibling

			&& t.nextSibling.nodeName.toLowerCase() != siblingName.toLowerCase()

			) {

		t = t.nextSibling;

	}



	if (t.nextSibling && t.nextSibling.nodeName.toLowerCase() == siblingName.toLowerCase()) {

		return t.nextSibling;

	} else {

		return null;

	}

}





utility.dom.getParentByTagName = function(t, parentName) {

	if (t.nodeName.toLowerCase() == parentName.toLowerCase()) {

		return t;

	}



	while (t.parentNode

			&& t.parentNode.nodeName.toLowerCase() != parentName.toLowerCase()

			&& t.parentNode.nodeName != 'BODY') {

		t = t.parentNode;

	}



	if (t.parentNode && t.parentNode.nodeName.toLowerCase() == parentName.toLowerCase()) {

		return t.parentNode;

	} else {

		return null;

	}

}



// should refactor this to take the tagname as a list or array of tagnames

// TODO : parameter order

utility.dom.getElementsByTagName = function(o, sTagName) {

	var el;

	if (typeof o == 'undefined') {

		o = document;

	} else {

		o = utility.dom.getElem(o);

	}



	if (sTagName == '*' || typeof sTagName == 'undefined') {

		el = utility.dom.getAllChildren(o);

	} else {

		el = o.getElementsByTagName(sTagName.toLowerCase());

	}

	return el;

}



// actually, this should be a front for a more generic method that gets elements filtered by an attribute

// or, we should try to use more of ruby.js to make this things easier to do (include Enumerable)

utility.dom.getElementsByClassName = function(o, sClassName, sTagName) {

	var elements = [];

	Array_each(utility.dom.getElementsByTagName(o, sTagName), function(elem, i) {

		if (Array_indexOf(utility.dom.getClassNames(elem), sClassName) != -1) { 

			Array_push(elements, elem);

		}

	});

	return elements;

}



utility.dom.getElementById = function(o, sId, sTagName) {

	var elements = [];

	Array_each(utility.dom.getElementsByTagName(o, sTagName), function(elem, i) {

		if (typeof elem.id != "undefined" && elem.id != null && elem.id.toString() == sId) { 

			Array_push(elements, elem);

		}

	});

	return elements;

}



utility.dom.getElementsByProps = function(start, props_hash) {

	var unfiltered, toret = [];

	if (typeof(start) == 'undefined') {

		start = document;

	} else {

		start = utility.dom.getElem(o);

	}

	if (o.all) {

		unfiltered = o.all;

	} else {

		unfiltered = o.getElementsByTagName('*');

	}

	//unfiltered.each = Array.prototype.each;

	Array_each(unfiltered, function(item) {

		var cond = true;

		for (i in props_hash) {

			try {

				var value = item[i];

			} catch(e) { value = null; }

			cond = cond && (value == props_hash[i]);

		}

		if (cond) {

			Array_push(toret, item);

		}

	});

	return toret;

}



// get all children of elem that have the "tag" tagName

utility.dom.getChildrenByTagName = function(elem, tag) {

	var result = [];

	var x;

	if (typeof(tag) == 'undefined') tag = '*';

	tag = tag.toLowerCase();

	if (!elem.childNodes) return result;

	for (var i=0; i<elem.childNodes.length; i++) {

		x = elem.childNodes[i];

		try {

			if (

				(typeof(x) != 'undefined' && 

				typeof(x.tagName) != 'undefined' && 

				x.tagName.toLowerCase() == tag) || tag == '*'

				

			) {

				Array_push(result, x);

			}

		} catch(e) { 

			// nick the error 

		}

	}

	return result;

}



// get all children of elem that have the class "sClassName"

// sTagName is optional, defaults to *

utility.dom.getChildrenByClassName = function(elem, sClassName, sTagName) {

	var result = [];

	result = Array_each(utility.dom.getChildrenByTagName(sTagName), function(elem, i) {

		if (Array_indexOf(utility.dom.getClassNames(item), sClassName) != -1) { 

			Array_push(result, elem);

		}

	});

}



utility.dom.getAllChildren = function(e) {

	// Returns all children of element. Workaround required for IE5/Windows. Ugh.

	return e.all ? e.all : e.getElementsByTagName('*');

}



utility.dom.getElementsBySelector = function(selector, startfrom) {

	if (typeof startfrom == 'undefined') {

		startfrom = document;

	}



	if (!document.getElementsByTagName) {

		return [];

	}

	// Split selector in to tokens

	var tokens = selector.split(' ');

	var currentContext = new Array(startfrom);

	for (var i = 0; i < tokens.length; i++) {

		token = tokens[i].replace(/^\s+/,'').replace(/\s+$/,'');

		if (token.indexOf('#') > -1) {

			// Token is an ID selector

			var bits = token.split('#');

			var tagName = bits[0];

			var id = bits[1];

			var element = document.getElementById(id);

			if (element && tagName && element.nodeName.toLowerCase() != tagName) {

				// tag with that ID not found, return false

				return [];

			}

			// Set currentContext to contain just this element

			currentContext = new Array(element);

			continue; // Skip to next token

		}

		if (token.indexOf('.') > -1) {

			// Token contains a class selector

			var bits = token.split('.');

			var tagName = bits[0];

			var className = bits[1];

			if (!tagName) {

				tagName = '*';

			}

			// Get elements matching tag, filter them for class selector

			var found = new Array;

			var foundCount = 0;

			for (var h = 0; h < currentContext.length; h++) {

				var elements;

				if (tagName == '*') {

					elements = utility.dom.getAllChildren(currentContext[h]);

				} else {

					elements = currentContext[h].getElementsByTagName(tagName);

				}

				for (var j = 0; j < elements.length; j++) {

				  found[foundCount++] = elements[j];

				}

			}

			currentContext = new Array;

			var currentContextIndex = 0;

			for (var k = 0; k < found.length; k++) {

				var cclassName = typeof(found[k].className) == 'undefined'?'':found[k].className;

				if (cclassName && cclassName.match(new RegExp('\\b'+className+'\\b'))) {

				  currentContext[currentContextIndex++] = found[k];

				}

			}

			continue; // Skip to next token

		}

		// Code to deal with attribute selectors

		if (token.match(/^(\w*)\[(\w+)([=~\|\^\$\*]?)=?"?([^\]"]*)"?\]$/)) {

			var tagName = RegExp.$1;

			var attrName = RegExp.$2;

			var attrOperator = RegExp.$3;

			var attrValue = RegExp.$4;

			if (!tagName) {

				tagName = '*';

			}

			// Grab all of the tagName elements within current context

			var found = new Array;

			var foundCount = 0;

			for (var h = 0; h < currentContext.length; h++) {

				var elements;

				if (tagName == '*') {

					elements = utility.dom.getAllChildren(currentContext[h]);

				} else {

					elements = currentContext[h].getElementsByTagName(tagName);

				}

				for (var j = 0; j < elements.length; j++) {

					found[foundCount++] = elements[j];

				}

			}

			currentContext = new Array;

			var currentContextIndex = 0;

			var checkFunction; // This function will be used to filter the elements

			switch (attrOperator) {

				case '=': // Equality

					checkFunction = function(e) { try {return (e.getAttribute(attrName).toString() == attrValue);} catch(ex) { } };

				break;

				case '~': // Match one of space seperated words 

					checkFunction = function(e) { try {return (e.getAttribute(attrName).toString().match(new RegExp(attrValue)));} catch(ex) { return false; }  };

				break;

				case '|': // Match start with value followed by optional hyphen

					checkFunction = function(e) { return (e.getAttribute(attrName).toString().match(new RegExp('^'+attrValue+'-?'))); };

				break;

				case '^': // Match starts with value

					checkFunction = function(e) { return (e.getAttribute(attrName).toString().indexOf(attrValue) == 0); };

				break;

				case '$': // Match ends with value - fails with "Warning" in Opera 7

					checkFunction = function(e) { return (e.getAttribute(attrName).toString().lastIndexOf(attrValue) == e.getAttribute(attrName).length - attrValue.length); };

				break;

				case '*': // Match ends with value

					checkFunction = function(e) { return (e.getAttribute(attrName).toString().indexOf(attrValue) > -1); };

				break;

				default :

					// Just test for existence of attribute

					checkFunction = function(e) { return e.getAttribute(attrName); };

			}

			currentContext = new Array;

			var currentContextIndex = 0;

			for (var k = 0; k < found.length; k++) {

				if (checkFunction(found[k])) {

					currentContext[currentContextIndex++] = found[k];

				}

			}

			//alert('Attribute Selector: '+tagName+' '+attrName+' '+attrOperator+' '+attrValue);

			continue; // Skip to next token

		}

		// If we get here, token is JUST an element (not a class or ID selector)

		tagName = token;

		var found = new Array;

		var foundCount = 0;

		for (var h = 0; h < currentContext.length; h++) {

			if (currentContext[h] != null) {

				var elements = currentContext[h].getElementsByTagName(tagName);

				for (var j = 0; j < elements.length; j++) {

					found[foundCount++] = elements[j];

				}

			}

		}

		currentContext = found;

	}

	return currentContext;

}



utility.dom.createForm = function(options, inputs, doc) {

	if (typeof options == 'undefined') options = {};

	if (typeof inputs == 'undefined') inputs = [];

	if (typeof doc == 'undefined') doc = document;



	var default_options = {

		name: '', 

		id: '', 

		action: '',

		method: 'POST', // form method

		target: ''

	}



	options = Object_weave_safe(options, default_options);



	var frm = utility.dom.createElement( "FORM", {

		name: options.name, 

		id: options.id, 

		action: options.action, 

		method: options.method, 

		style: "display: none"

	});



	Array_each(inputs, function(input, i) {

		frm.appendChild(utility.dom.createElement('INPUT', {

			'type': 'hidden', 

			'id': input[0], 

			'name': input[0], 

			'value': input[1]

		}));

	});



	frm = doc.body.appendChild(frm);

	frm.target = options.target;

	return frm;

}



utility.dom.createIframe = function(options, doc) {

	if (typeof options == 'undefined') options = {};

	if (typeof doc == 'undefined') doc = document;



	var default_options = {

		name: '', 

		id: '', 

		src: options.src

	}



	options = Object_weave_safe(options, default_options);



	if (is.mozilla) {

		var ifr = utility.dom.createElement('iframe', {

			'id': options.id, 

			'name': options.name, 

			'style': 'display: none;'

		});

		ifr.src = options.src;

		ifr = doc.body.appendChild(ifr);

		ifr.name = options.name;

		ifr.id = options.id;

	} else if (is.ie) {

		var str = '<iframe name="'+options.name+'" src="' + options.src + '" id="'+options.id+'" style="display: none;"></iframe>';

		var dv = doc.createElement('div');

		doc.body.appendChild(dv);

		dv.innerHTML = str;

	}

	var ifr = doc.getElementById(options.id);

	return ifr;

}



utility.dom.addIframeLoad = function(ifr, functor) {

	if (is.mozilla) {

		ifr.onload = function() {

			functor();

		}

	} else {

		ifr.onreadystatechange = function() {

			if (ifr.readyState == 'complete') {

				functor();

			}

		}

	}

}



utility.dom.removeIframeLoad = function(ifr) {

	if (is.ie) { ifr.onreadystatechange = function() { }; }

	if (is.mozilla) {ifr.onload = function() { }; }

}



utility.dom.buildUrl = function() {

}



utility.dom.stripAttributes = function(el, additional_arr) {

	var cearElementProps = [

		'onload', 'data', 'onmouseover', 'onmouseout', 'onmousedown', 

		'onmouseup', 'ondblclick', 'onclick', 'onselectstart', 

		'oncontextmenu', 'onkeydown',   'onkeypress', 'onkeyup',

		'onblur', 'onfocus', 'onbeforedeactivate', 'onchange'];

	if (typeof el == 'undefined' || el == null) {

		return true;

	}

	for (var c = cearElementProps.length; c--; ) {

		el[cearElementProps[c]] = null;

	}

	if (typeof additional_arr != 'undefined') {

		for (var c = additional_arr.length; c--; ) {

			el[additional_arr[c]] = null;

		}

	}

}

// use attachEvent for ie

utility.dom.attachEvent2 = function(where, type, what, when) {

	utility.dom.attachEvent_base(where, type, what, when, 1);

}

// use on. for ie

utility.dom.attachEvent = function(where, type, what, when) {

	utility.dom.attachEvent_base(where, type, what, when, 0);

}



// don't use attachEvent for ie since we can't get 

// to the element where the handler is added from the handler

utility.dom.attachEvent_base = function(where, type, what, when, add_first) {

	if (typeof(when) == 'undefined') when = 1;

	var doNotAdd = type.match(/unload$/i);

	var real_type = type.match(/^on/) ? type : 'on' + type ;

	var logical_type = type.replace(/^on/, '');



	if (typeof where.__eventHandlers == 'undefined') {

		where.__eventHandlers = {};

	}

	var place = null;

	if (typeof where.__eventHandlers[logical_type] == 'undefined') {

		where.__eventHandlers[logical_type] = [];

		place = where.__eventHandlers[logical_type];



		var raiseEvent = function(e) {

			if (!e && window.event) {

				e = window.event;

			}

			for (var i=0;i < where.__eventHandlers[logical_type].length; i++) {

				var f = where.__eventHandlers[logical_type][i];

				if (typeof f == 'function') {

					f.apply(where, [e]);

					f = null;

				}

			}

		}



		/*

		var oldHandler = function() { };

		if (where[real_type] != null && 

			typeof where[real_type] != "undefined") {

			oldHandler = where[real_type];

			place[place.length] = oldHandler;

			oldHandler = null;

		}

		where[real_type] = null;

		*/

		if (where.addEventListener) {

			where.addEventListener(logical_type, raiseEvent, false);

		}

		else if (where.attachEvent) {

			where.attachEvent("on" + logical_type, raiseEvent);

		}

		else {

			where["on" + logical_type] = raiseEvent;

		}

		if ( (! (is.ie && is.mac)) && !doNotAdd) {

			EventCache.add(where, logical_type, raiseEvent, 1);

		}

	} else {

		place = where.__eventHandlers[logical_type];

	}





	for (var i=0;i<place.length;i++) {

		if (place[i] == what) {

			return;

		}

		try {

			 if (place[i] && what && place[i].toString() == what.toString()) {

			 	return;

			 }

		} catch(err) { }

	}

	place[place.length] = what;



	// add the event

}



var EventCache = function(){

	var listEvents = [];

	

	return {

		listEvents : listEvents,

	

		add : function(node, sEventName, fHandler, bCapture){

			Array_push(listEvents, arguments);

		},

	

		flush : function(){

			var i, item;

			for(i = listEvents.length - 1; i >= 0; i = i - 1){

				item = listEvents[i];

				if(!item) {

					continue;

				}

				if(item[0].removeEventListener){

					item[0].removeEventListener(item[1], item[2], item[3]);

				};

				

				/* From this point on we need the event names to be prefixed with 'on" */

				var logical_type = '';

				if(item[1].substring(0, 2) != "on") {

					logical_type = item[1];

					item[1] = "on" + item[1];

				} else {

					logical_type = item[1].substring(2, event_name_without_on.length);

				};

				//delete from __eventHandlers

				if (typeof item[0].__eventHandlers != 'undefined' && typeof item[0].__eventHandlers[logical_type] != 'undefined') {

					item[0].__eventHandlers[logical_type] = null;

				}

				if(item[0].detachEvent){

					item[0].detachEvent(item[1], item[2]);

				};

				

				item[0][item[1]] = null;

			};

			listEvents = null;

		}

	};

}();





utility.dom.getStyleProperty = function(el, property) {

	try{

		var value = el.style[property];

	}catch(e) {

		return "";

	}

	if (!value) {

		if (el.ownerDocument.defaultView && 

			typeof (el.ownerDocument.defaultView.getComputedStyle) == "function") { 

			// moz, opera

			value = el.ownerDocument.defaultView.getComputedStyle(el, "").getPropertyValue(property);

		} else if (el.currentStyle) {

			// IE

			var m = property.split(/-/);

			if (m.length>0) {

				property = m[0];

				for(var i=1;i<m.length;i++) {

					property += m[i].charAt(0).toUpperCase() + m[i].substring(1);

				}

			}

			value = el.currentStyle[property];

		} else if (el.style) {

			value = el.style[property];

		}

	}



	return value;

}



utility.dom.getLink = function(link) {

	if (!is.ie) {

		href = link.getAttribute('href');

	} else {

		if (!is.mac) {

			href = link.outerHTML.toString().replace(/.*href="([^"]*)".*/, "$1");

		} else {

			href = link.getAttribute('href');

		}

	}

	return href;

}



utility.dom.getDisplay = function(el) {

	return utility.dom.getStyleProperty(el, 'display');

}



utility.dom.getVisibility = function(el) {

	return utility.dom.getStyleProperty(el, 'visibility');

}

var first_getAbsolutePos_caller_element = null;

utility.dom.getAbsolutePos = function(el) {

	var scrollleft = 0, scrolltop = 0, tn = el.tagName.toUpperCase();

	if (utility.dom.getAbsolutePos.caller!=utility.dom.getAbsolutePos) {

		//do not substract the scrollLeft of the target element if you want to find it's left...

		first_getAbsolutePos_caller_element = el;

	}

	if (Array_indexOf(['BODY', 'HTML'], tn) == -1 && first_getAbsolutePos_caller_element!=el) { // ?

		if (el.scrollLeft) {

			scrollleft = el.scrollLeft;

		}



		if (el.scrollTop) {

			scrolltop = el.scrollTop;

		}

	}



	var r = { x: el.offsetLeft - scrollleft, y: el.offsetTop - scrolltop };



	if (el.offsetParent && tn != 'BODY') {

		var tmp = utility.dom.getAbsolutePos(el.offsetParent);

		r.x += tmp.x;

		r.y += tmp.y;

	}



	return r;

}



/**

*	FF : stopping the onsubmit event seems to alter the event.type (accessing the property after stopping the event raise an error)

*/

utility.dom.setEventVars = function(e) {

	var targ; var relTarg; var posx=0; var posy=0;

	if (!e){

		e = window.event;

	}

	if (!e){

		return {'e':null,'relTarg':null,'targ':null,'posx':0,'posy':0,'leftclick':false,'middleclick':false,'rightclick':false,'type':''};

	}

	if(e.relatedTarget) {

		relTarg = e.relatedTarget;

	} else if(e.fromElement) {

		relTarg = e.fromElement;

	}



	if(e.target) { 

		targ = e.target;

	} else if(e.srcElement) { 

		targ = e.srcElement;

	}



	var st = utility.dom.getPageScroll();

	if (e.pageX || e.pageY) {

		posx = e.pageX;

		posy = e.pageY;

	} else if (e.clientX || e.clientY) {

		posx = e.clientX + st.x;

		posy = e.clientY + st.y;

	}



	if (window.event) {

		var leftclick = (e.button == 1);

		var middleclick = (e.button == 4);

		var rightclick = (e.button == 2);

	} else {

		var leftclick = (e.button == 0);

		var middleclick = (e.button == 1);

		var rightclick = (e.button == 2 || e.button == 0 && is.mac && e.ctrlKey);

	}



	var o = {

		'e':e,'relTarg':relTarg,'targ':targ,'posx':posx,'posy':posy,'leftclick':leftclick,'middleclick':middleclick,'rightclick':rightclick

	}

	try {

		o.type = e.type;

	} catch (err) {

		o.type = '';

	}

	return o;

}



utility.dom.stopEvent = function(e) {

	if (typeof is == 'undefined') {

		is = new BrowserCheck();

	}

	if (typeof e != "undefined" && e!=null) {

		if(is.ie) {

			e.cancelBubble = true;

		} 

		if (e.stopPropagation) {

			e.stopPropagation();

		}



		if(is.ie) {

			e.returnValue = false;

		}

		if (e.preventDefault) {

			e.preventDefault();

		}

	}

	return false;

}



utility.dom.toggleSpecialTags = function(el, exclude, mode, documentObject, boxRecipient) {

	//var t1 = new Date();

	var hide_tags = ['select'];

	if (mode==1) {

		var boxObject = utility.dom.getBox(el);

	}

	for (var i = 0; i < hide_tags.length; i++) {

		var _document = null;

		if( documentObject && documentObject.nodeType && (documentObject.nodeType==9) ) {

			_document = documentObject;

			utility.dom.toggleSpecialTags._saved_DOC = documentObject;

		} else if ( documentObject && utility.dom.toggleSpecialTags._saved_DOC &&

		           utility.dom.toggleSpecialTags._saved_DOC.nodeType &&

		           (utility.dom.toggleSpecialTags._saved_DOC.nodeType==9) ) {

			_document = utility.dom.toggleSpecialTags._saved_DOC;

		} else {

			_document = document;	

		};

		var arr = _document.getElementsByTagName(hide_tags[i]);

		for (var j = 0; j < arr.length; j++) {

			if (exclude == arr[j]) {

				continue;

			}

			if (mode == 1) {

				var cVisibility = utility.dom.getVisibility(arr[j]);

				var cDisplay = utility.dom.getDisplay(arr[j]);

				if (cDisplay=="none" || cVisibility=="hidden") {

					continue;

				}

				var boxSelect =	utility.dom.getBox(arr[j]);

				if(boxRecipient){

					var parentBox = utility.dom.getBox(boxRecipient);

					boxSelect.x += parentBox.x;

					boxSelect.y += parentBox.y;

				}

				var overlap = utility.dom.boxOverlap(boxObject, boxSelect);

				if (overlap) {

					if(documentObject && boxRecipient){

						if(!arr[j].oldPosition){

							var cPosition = utility.dom.getStyleProperty(arr[j], "position");

							arr[j].oldPosition = cPosition;

							}

						if(!arr[j].oldLeft){

							var cLeft = utility.dom.getStyleProperty(arr[j], "left");

							arr[j].oldLeft = cLeft;

							}

						arr[j].style.position = "relative";

						arr[j].style.left = "-1000px";

					}

					else {

						if(!arr[j].oldvisibility) {

							arr[j].oldvisibility = cVisibility;

						}

						arr[j].style.visibility = 'hidden';					

					}

				}

			} else {

				if(documentObject && boxRecipient){

					if(arr[j].oldPosition){

						arr[j].style.position = arr[j].oldPosition;

						arr[j].removeAttribute("oldPosition");

						}

					if(arr[j].oldLeft){

						arr[j].style.left = arr[j].oldLeft;

						arr[j].removeAttribute("oldLeft");

						}

				}

				else {

					if (arr[j].oldvisibility) {

						arr[j].style.visibility = arr[j].oldvisibility;

					}				

				}

			}

		}

	}

}



utility.dom.boxOverlap = function(b1, b2) {

	//boxes do not overlap when b1:

	//is in the left of b2

	//or in the right of b2

	//or above b2

	//or below b2



	if( (b1.x+b1.width) < b2.x || b1.x > (b2.x+b2.width) ||

		(b1.y+b1.height) < b2.y || b1.y > (b2.y+b2.height) || false) {

		return false;

	}

	return true;

}



utility.dom.getBox = function(el) {

	var box = { 

		"x": 0, "y": 0, 

		"width": 0, "height": 0, 

		"scrollTop": 0, "scrollLeft": 0 

	};

	var strictm = el.ownerDocument.compatMode == "CSS1Compat";

	if (el.ownerDocument.getBoxObjectFor) {

		var rect = el.ownerDocument.getBoxObjectFor(el);

		box.x = rect.x - el.parentNode.scrollLeft;

		box.y = rect.y - el.parentNode.scrollTop;

		box.width = rect.width;

		box.height = rect.height;

		box.scrollLeft = (strictm?el.ownerDocument.documentElement:el.ownerDocument.body).scrollLeft;

		box.scrollTop = (strictm?el.ownerDocument.documentElement:el.ownerDocument.body).scrollTop;

	} else if (el.getBoundingClientRect) {

		var rect = el.getBoundingClientRect();

		box.x = rect.left;

		box.y = rect.top;

		box.width = rect.right - rect.left;

		box.height = rect.bottom - rect.top;

		box.scrollLeft = 0; //el.document.body.scrollLeft;

		box.scrollTop = 0;  //el.document.body.scrollTop;

	} else {

		var tmp = utility.dom.getAbsolutePos(el);

		box.x = tmp.x - el.parentNode.scrollLeft;

		box.y = tmp.y - el.parentNode.scrollTop;

		box.width = parsetInt(utility.dom.getStyleProperty(el, 'width'), 10);

		box.height = parsetInt(utility.dom.getStyleProperty(el, 'height'), 10);

		box.scrollLeft = el.ownerDocument.body.scrollLeft;

		box.scrollTop = el.ownerDocument.body.scrollTop;

	}

	return box;

}



utility.dom.getBBox = function(el) {

	var box = { 

		"x": 0, "y": 0, 

		"width": 0, "height": 0, 

		"scrollTop": 0, "scrollLeft": 0 

	};

	var strictm = el.ownerDocument.compatMode == "CSS1Compat";

	if (el.ownerDocument.getBoxObjectFor) {

		var doc = strictm?el.ownerDocument.documentElement:document;

		var bt = parseInt(utility.dom.getStyleProperty(el, "border-top-width"));

		var bl = parseInt(utility.dom.getStyleProperty(el, "border-left-width"));

		var br = parseInt(utility.dom.getStyleProperty(el, "border-right-width"));

		var bb = parseInt(utility.dom.getStyleProperty(el, "border-bottom-width"));



		var rect = el.ownerDocument.getBoxObjectFor(el);

		var sl = 0;

		var st = 0;

		while(el.parentNode) {

			if (el.scrollTop) {

				st += el.scrollTop;

			}

			if (el.scrollLeft) {

				sl += el.scrollLeft;

			}

			el = el.parentNode;

		}

		box.scrollLeft = sl;

		box.scrollTop = st;

		box.x = rect.x - bl - sl;

		box.y = rect.y - bt - st;

		box.width = rect.width;

		box.height = rect.height;

	} else if (el.getBoundingClientRect) {

//	var ss = '';

//	var zel = el;

//	var b = null;

//	while(zel) {

//		b = zel.getBoundingClientRect()

//		ss += zel.tagName+"\t" + b.top + "\t" + zel.scrollTop + "\r\n";

//		zel = zel.offsetParent;

//	}

//	al(ss);

		var pel = strictm?el.ownerDocument.documentElement:document.body;//el.offsetParent;

		var bt = parseInt(utility.dom.getStyleProperty(el, "border-top-width")) || 0;

//		var br = parseInt(utility.dom.getStyleProperty(el, "border-right-width")) || 0;

//		var bb = parseInt(utility.dom.getStyleProperty(el, "border-bottom-width")) || 0;

		var bl = parseInt(utility.dom.getStyleProperty(el, "border-left-width")) || 0;



//		var pbt = parseInt(utility.dom.getStyleProperty(pel, "border-top-width")) || 0;

//		var pbr = parseInt(utility.dom.getStyleProperty(pel, "border-right-width")) || 0;

//		var pbb = parseInt(utility.dom.getStyleProperty(pel, "border-bottom-width")) || 0;

//		var pbl = parseInt(utility.dom.getStyleProperty(pel, "border-left-width")) || 0;



		var rect = el.getBoundingClientRect();

		//al(rect);

		box.x = rect.left - bl;

		box.y = rect.top - bt;

//		box.y = rect.top - pbt;

//		box.x = rect.left - pbl;

		box.width = rect.right - rect.left;

		box.height = rect.bottom - rect.top;

		box.scrollLeft = 0; //el.document.body.scrollLeft;

		box.scrollTop = 0;  //el.document.body.scrollTop;

	} else {

		var pel = el.ownerDocument.documentElement;//el.offsetParent;

		var mt = parseInt(utility.dom.getStyleProperty(pel, "margin-top"));

		var ml = parseInt(utility.dom.getStyleProperty(pel, "margin-left"));

		var bt = parseInt(utility.dom.getStyleProperty(pel, "border-top-width"));

		var bl = parseInt(utility.dom.getStyleProperty(pel, "border-left-width"));

		var pt = parseInt(utility.dom.getStyleProperty(pel, "padding-top"));

		var pl = parseInt(utility.dom.getStyleProperty(pel, "padding-left"));



		pel = el.offsetParent;

		var mt2 = parseInt(utility.dom.getStyleProperty(pel, "margin-top"));

		var ml2 = parseInt(utility.dom.getStyleProperty(pel, "margin-left"));

		var bt2 = 0;//parseInt(utility.dom.getStyleProperty(pel, "border-top-width"));

		var bl2 = 0;//parseInt(utility.dom.getStyleProperty(pel, "border-left-width"));

		var pt2 = 0;//parseInt(utility.dom.getStyleProperty(pel, "padding-top"));

		var pl2 = 0;//parseInt(utility.dom.getStyleProperty(pel, "padding-left"));



		var tmp = utility.dom.getAbsolutePos(el);

		box.x = tmp.x;

		box.y = tmp.y;

		box.width = parseInt(utility.dom.getStyleProperty(el, 'width'));

		box.height = parseInt(utility.dom.getStyleProperty(el, 'height'));

		box.scrollLeft = el.ownerDocument.body.scrollLeft;

		box.scrollTop = el.ownerDocument.body.scrollTop;

		if (is.opera) {

			box.x -= (ml + bl + pl + ml2);

			box.y -= mt + bt + pt + mt2;

		}

	}

	return box;

}



// from quirksmode, fixed to properly differentiate between IE versions

utility.dom.getPageInnerSize = function() {

	var x, y;

	if (typeof self.innerHeight != "undefined") {

		x = self.innerWidth;

		y = self.innerHeight;

	} else if (typeof document.compatMode != 'undefined' && document.compatMode == 'CSS1Compat') {

		x = document.documentElement.clientWidth;

		y = document.documentElement.clientHeight;

	} else if (document.body) {

		x = document.body.clientWidth;

		y = document.body.clientHeight;

	}

	return {x: x, y: y};

}

// from quirksmode, fixed to properly differentiate between IE versions

utility.dom.getPageScroll = function() {

	var x, y;

	if (typeof self.pageYOffset != 'undefined') {

		x = self.pageXOffset;

		y = self.pageYOffset;

	} else if (typeof document.compatMode != 'undefined' && document.compatMode == 'CSS1Compat') {

		x = document.documentElement.scrollLeft;

		y = document.documentElement.scrollTop;

	}

	else if (document.body) {

		x = document.body.scrollLeft;

		y = document.body.scrollTop;

	}

	return {x: x, y: y};

}



utility.dom.createElement = function(type, attribs, wnd) {

	if (typeof is == 'undefined') {

		is = new BrowserCheck();

	}

	if (typeof wnd != 'undefined') {

		var elem = wnd.document.createElement( type );

	} else {

		var elem = document.createElement( type );

	}

	if ( typeof attribs != 'undefined' ) {

		for (var i in attribs) {

			switch ( true ) {

				case ( i == 'text' )  : 

					elem.appendChild( document.createTextNode( attribs[i] ) ); 

					break;

				case ( i == 'class' ) : 

					elem.className = attribs[i]; 

					break;

				case ( i == 'id' ) : 

					elem.id = attribs[i]; 

					break;

				case ( i == 'type' ) : 

					if (type.toLowerCase()=="input" && is.ie && is.mac) {

						//IE MAC cant set the type

						var tspn = document.createElement("SPAN");

						document.body.appendChild(tspn);

						tspn.style.display= "none";

						tspn.innerHTML = elem.outerHTML.replace(/<input/i, "<input type=\""+attribs[i]+"\"");

						elem = tspn.firstChild;

						document.body.removeChild(tspn);

					} else if (type.toLowerCase()=="input" && is.mac && is.safari) {

						elem.setAttribute('type', attribs[i]);

					} else {

						elem.type = attribs[i]; 

					}

					break;

				case ( i == 'style' ) : 

					elem.style.cssText = attribs[i]; 

					break;

				default : 

					try{

						elem.setAttribute(i, attribs[i] );

						elem[i] = attribs[i];

					}catch(e) {}

			}

		}

	}

	if (attribs['value']) {

		elem.value = attribs['value'];

	}

	return elem;	

};





utility.dom.getImports = function(s) {

	//var ss = document.styleSheets;

	try {

		if (is.ie) {

			return s.imports;

		} else {

			var toret = [];

			for (var i = 0; i < s.cssRules.length; i++) {

				if (is.safari) {

					if (typeof s.cssRules[i].href != 'undefined') {

						Array_push(toret, s.cssRules[i].styleSheet);

					}

				} else {

					if (s.cssRules[i].toString().match('CSSImportRule')) {

						Array_push(toret, s.cssRules[i].styleSheet);

					}

				}

			}

			return toret;

		}

	} catch(e) { return []; }

}



utility.dom.getRuleBySelector = function(s, rx) {

	try {

		var koll = [];

		if (is.ie) {

			koll = s.rules;

		} else {

			koll = s.cssRules;

		}

		var toret = [];

		for (var i = 0; i < koll.length; i++) {

			var rule = koll[i];

			if (rule.selectorText.toString().match(rx)) {

				Array_push(toret, rule);

			}

		}

		return toret;

	} catch(e) { return []; }

}



utility.dom.createStyleSheet = function(doc, path) {

	if (is.ie) {

		return doc.createStyleSheet(path);

	} else if (is.mozilla) {

	  // load the xml

		var theHeadNode = doc.getElementsByTagName("head")[0];



		var theStyleNode = doc.createElement('style');

		theStyleNode.type ="text/css"

		theStyleNode.rules = new Array();



		theHeadNode.appendChild(theStyleNode);



		if (path != "") {

			var xmlHttp = new XMLHttpRequest();

			try {

				xmlHttp.open("GET", path, false);

				xmlHttp.send(null);

			}

			catch (e) {

				alert('Cannot load a stylesheet from a server other than the current server.\r\nThe current server is "'+doc.location.hostname+'".\r\nThe requested stylesheet URL is "'+path+'".');

				return null;

			}



			if(xmlHttp.status==404){

				prompt('Stylesheet was not found:', path);

				return null;

			}

			var theTextNode = doc.createTextNode(xmlHttp.responseText);

			theStyleNode.appendChild(theTextNode);



			var re = /\s*\{([^\}]*)\}\s*/;

			nameList = xmlHttp.responseText.split (re);

			for(var i=0; i<nameList.length; i=i+2) {

				var rul = new Object();

				rul.selectorText = nameList[i];

				rul.cssText = nameList[i+1]

				theStyleNode.rules.push(rul);

			}



		} else {

			var theTextNode = doc.createTextNode('u');

			theStyleNode.appendChild(theTextNode);

		}

		return theStyleNode;

	}

}



Object_weave_safe(utility, {date: {}});



$UNI_DATETIME_MASK_SEPARATORS = ['-', '/', '[', ']', '(', ')', '*', '+', '.', '\s', ':'];

$UNI_DATETIME_MASK_REGEXP = '[';

for(var zi=0;zi<$UNI_DATETIME_MASK_SEPARATORS.length; zi++) {

	$UNI_DATETIME_MASK_REGEXP += "\\"+$UNI_DATETIME_MASK_SEPARATORS[zi]+'|';

}

$UNI_DATETIME_MASK_REGEXP += ']';

$UNI_DATETIME_MASK_REGEXP = new RegExp($UNI_DATETIME_MASK_REGEXP,"g");



utility.date.date2regexp = function(txt) {

	txt = txt.replace(/[\/\-\.]/g, 'DATESEPARATOR');

	txt = txt.replace(/([-\/\[\]\(\)\*\+\.\:])/g, '\\$1');

	txt = txt.replace(/DATESEPARATOR/g, '[\\/\\-\\.]');

	txt = txt.replace(/(\\s)/g, '\s');

	txt = txt.replace(/yyyy/gi, '([0-9]{1,4})');

	txt = txt.replace(/yy/gi, '([0-9]{1,4})');

	txt = txt.replace(/y/gi, '([0-9]{1,4})');



	txt = txt.replace(/mm/g, '([0-9]{1,2})');

	txt = txt.replace(/m/g, '([0-9]{1,2})');



	txt = txt.replace(/dd/g, '([0-9]{1,2})');

	txt = txt.replace(/d/g, '([0-9]{1,2})');



	txt = txt.replace(/HH/g, '([0-9]{1,2})*');

	txt = txt.replace(/H/g, '([0-9]{1,2})*');



	txt = txt.replace(/hh/g, '([0-9]{1,2})*');

	txt = txt.replace(/h/g, '([0-9]{1,2})*');



	txt = txt.replace(/ii/g, '([0-9]{1,2})*');

	txt = txt.replace(/i/g, '([0-9]{1,2})*');



	txt = txt.replace(/ss/g, '([0-9]{1,2})*');

	txt = txt.replace(/s/g, '([0-9]{1,2})*');



	txt = txt.replace(/tt/g, '(AM|PM|am|pm|A|P|a|p)*');

	txt = txt.replace(/t/g, '(AM|PM|am|pm|A|P|a|p)*');



	txt = txt.replace(/ /g, ' *');

	txt = txt.replace(/:/g, ':*');



	var re = new RegExp('^' + txt + '$');

	return re;

}



utility.date.parse_date = function(arr, dateMask) {

	var vYear = vMonth = vDay = null;

	var vHour = vHour12h = vHour24H = vMinutes = vSeconds = vTimeMarker1C = vTimeMarker2C = null;



	var groups = dateMask.split($UNI_DATETIME_MASK_REGEXP);

	var groupIdx = 0;



	var vTimeMarkerUpdate = 0;

	

	for (var i = 0; i< groups.length; i++) {

		var currentGroupMask = groups[i];

		groupIdx++;

		var groupValue = arr[groupIdx];



		if (Array_indexOf('HH,H,ii,i,ss,s'.split(','), currentGroupMask) >= 0) {

			if (groupValue == '' || typeof groupValue == 'undefined') {

				groupValue = '0';

			}

		}

		if (Array_indexOf('hh,h'.split(','), currentGroupMask) >= 0) {

			var tmpValue = parseInt(groupValue, 10);

			if (groupValue == '' || typeof groupValue == 'undefined') {

				groupValue = '12';

			} else if (tmpValue > 12 && tmpValue < 24) {

				var index = (Array_indexOf(groups, 't') >= 0 ? Array_indexOf(groups, 't')+1 : Array_indexOf(groups, 'tt')+1);

				if (arr[index] == '') {

					groupValue = tmpValue - 12;

					vTimeMarkerUpdate = 1;

				}

			}

		}

		if (Array_indexOf('tt,t'.split(','), currentGroupMask) >= 0) {

			if (groupValue == '') {

				groupValue = [['A', 'AM'], ['P', 'PM']][vTimeMarkerUpdate][currentGroupMask.length - 1];

			}

		}



		switch(currentGroupMask) {

		case 'yyyy':

		case 'YYYY':

			vYear = parseInt(groupValue, 10);

			break;

		case 'yy': 

		case 'YY': 

		case 'y':

			vYear = parseInt(groupValue, 10);

			if (vYear < 1000) {

				if (vYear < 10) {

					vYear = 2000 + vYear;

				} else {

					if (vYear < 70) {

						vYear = 2000 + vYear;

					} else {

						vYear = 1900 + vYear;

					}

				}

			}

			break;

		case 'mm':

		case 'm':

			vMonth = parseInt(groupValue, 10);

			//vMonth;

			break;

		case 'dd': 

		case 'd':

			vDay = parseInt(groupValue, 10);

			break;

		case 'HH': 

		case 'H':

			vHour24H = parseInt(groupValue, 10);

			break;

		case 'hh': 

		case 'h':

			vHour12h = parseInt(groupValue, 10);

			break;

		case 'ii':

		case 'i':

			vMinutes = parseInt(groupValue, 10);

			break;

		case 'ss':

		case 's':

			vSeconds = parseInt(groupValue, 10);

			break;

		case 't':

			vTimeMarker1C = groupValue;

			break;

		case 'tt':

			vTimeMarker2C = groupValue;

			break;

		}

	}





	vYear = vYear == null?1900:vYear;

	vMonth = vMonth == null?0:vMonth;

	vDay = vDay == null?1:vDay;



	vMinutes = vMinutes == null?0:vMinutes;

	vSeconds = vSeconds == null?0:vSeconds;

	var vHourOffset = 0;



	if (vHour12h != null) {

		if (vHour12h >= 1 && vHour12h <= 12) {

			vHour = vHour12h;

			if ((vTimeMarker1C || vTimeMarker2C || "").charAt(0)=="P") {

				if (vHour12h < 12) {

					vHour = vHour12h + 12;

				}

			} else {

				if (vHour12h == 12) {

					vHour = 0;

				}

			}

			//must add 12 to hour if time is PM

			//also, must add 12 if vHour12h in 12h format is greater than 11, which is invalid

			//vHourOffset = ( (vTimeMarker1C || vTimeMarker2C || "").charAt(0)=="P" || vHour12h>11)?12:0;

			//vHour = vHour12h + vHourOffset;

		} else {

			vHour = -1000;

		}

	} else if(vHour24H != null) {

		vHour = vHour24H;

	} else {

		vHour = 0;

	}



	var o = {

		'year': vYear, 

		'month': vMonth, 

		'day': vDay,

		'hour': vHour, 

		'minutes': vMinutes, 

		'seconds': vSeconds

	};



	if (dateMask.indexOf('y') < 0

		&& dateMask.indexOf('m') < 0 

		&& dateMask.indexOf('d') < 0 ) {

		o['year'] = '1900';

		o['month'] = '1';

		o['day'] = 1;

	}

	return o;

}



Object_weave_safe(utility, {window: {}});



utility.window.openWindow = function(target, url, width, height) {

	var wndHandler;

	var left = (screen.width - width) / 2;

	var top = (screen.height - height) / 2;

	var winargs = "width=" + width + ",height=" + height + ",resizable=No,scrollbars=No,status=Yes,modal=yes,dependent=yes,dialog=yes,left=" + left + ",top=" + top;



	wndHandler = window.open(url, target, winargs);

	if (wndHandler) {

		utility.window.reference = wndHandler;

		var ctrlModalBlocker = document.getElementById('modalBlocker');

		if (!ctrlModalBlocker) {

			var ctrlModalBlocker = utility.dom.createElement("DIV", {

				'id'      : 'modalBlocker',

				'style'   : 'display: block'

			});

			var pos = utility.dom.getPageInnerSize();

			ctrlModalBlocker.style.zIndex = 999;

			ctrlModalBlocker.style.width = (pos.x) + 'px';

			ctrlModalBlocker.style.height = (pos.y) + 'px';

			prepfixieinsertnodescrollup();

			ctrlModalBlocker = document.body.insertBefore(ctrlModalBlocker, document.body.firstChild);

			utility.dom.attachEvent(ctrlModalBlocker, 'onmousedown', function() {

				return utility.window.focusmodal();

			});

			utility.dom.attachEvent(ctrlModalBlocker, 'ondblclick', function() {

				return utility.window.focusmodal();

			});

			utility.dom.attachEvent(ctrlModalBlocker, is.ie?'onbeforeactivate':'onfocus', function() {

				return utility.window.focusmodal();

			});

			utility.dom.attachEvent(is.mozilla?window.document.body:window, is.ie?'onbeforeactivate':'focus', function() {

				return utility.window.focusmodal();

			});

			fixieinsertnodescrollup();

		} else {

			ctrlModalBlocker.style.display = 'block';

		}

		wndHandler.focus();

	}



	if (!wndHandler) {

		alert(translate('Cannot open dialog. Please allow site popups.'));

	}



	return wndHandler;

};

function prepfixieinsertnodescrollup() {

	//IE will scrollup inside all iframes after a DOM node insert

	if (is.ie && typeof(ktmls)!="undefined") {

		prepfixieinsertnodescrollup.scrolls = [];

		for (var i=0;i<ktmls.length; i++) {

			if (ktmls[i].destroyed) {

				continue;

			}

			prepfixieinsertnodescrollup.scrolls[i] = ktmls[i].edit.body.scrollTop;

		}

	}

}

function fixieinsertnodescrollup() {

	//it doesn't work without an timeout (IE needs some 

	window.setTimeout("fixieinsertnodescrollup_late()", 1);

};



function fixieinsertnodescrollup_late() {

	if (is.ie && typeof(ktmls)!="undefined") {

		for (var i=ktmls.length-1;i>=0; i--) {

			if (ktmls[i].destroyed) {

				continue;

			}

			ktmls[i].edit.body.scrollTop = prepfixieinsertnodescrollup.scrolls[i];

		}

	}

};



utility.window.focusmodal = function() {

	if (utility.window.reference && !utility.window.reference.closed) {

		utility.window.reference.focus();

		return;

	}

	utility.window.hideModalBlocker();

};



utility.window.hideModalBlocker = function (wnd) {

	if (!wnd) {

		wnd = window;

	}

	utility.window.reference = null;

	if (wnd.closed) {

		return;

	}

	var ctrlModalBlocker = wnd.document.getElementById('modalBlocker');

	if (ctrlModalBlocker) {

		ctrlModalBlocker.style.display = 'none';

	}

};



utility.window.close = function() {

	window.close();

};



utility.popup = {};

utility.popup.stiva = [];

//one may need the keyboard events while having the popup open

//so instruct utility.popup to not block keyboard while popup is open

//but then he must treat the ESC key himself

utility.popup.makeModal = function(clickCallBack, elementOnTop, stopEvents) {

	if(typeof(stopEvents) == "undefined") {

		stopEvents = true;

	}

	utility.popup.stiva.push({'element' : elementOnTop, 'callback': clickCallBack, 'stopEvents':stopEvents});

};



utility.popup.removeModal = function(e) {

	if (utility.popup.stiva.length == 0) {

		return;

	}

	if (utility.popup.force || e) {

		var tmp = utility.popup.stiva[utility.popup.stiva.length-1];

		if (e) {

			var o = utility.dom.setEventVars(e);

			var clickedElement = o.targ;

			while (clickedElement) {

				if (tmp.element && clickedElement == tmp.element) {

					break;

				}

				if (clickedElement.mi && clickedElement.mi['action_event'] != 'mousedown') {

					//must not close the open context menu if mousedown on an open submenu

					//modals should be closed inside the close menu function call

					break;

				}

				clickedElement = clickedElement.parentNode;

			}

			if (clickedElement) {

				// the user clicked on the elementOnTop

				return;

			}

		}

		if (tmp.callback) {

			tmp.callback();

		}

		utility.popup.stiva.pop();

		utility.popup.removeModal(e);

	}

	utility.dom.toggleSpecialTags(null, false, 0, true, true);

};



utility.popup.escapeModal = function(e) {

	if (utility.popup.stiva.length > 0) {

		if (!utility.popup.stiva[utility.popup.stiva.length-1].stopEvents) {

			return true;

		}

		var o = utility.dom.setEventVars(e);

		if (e.keyCode == 27) {

			utility.popup.force = true;

			utility.popup.removeModal(o.e);

			utility.popup.force = false;

		}

		if (is.ie && !o.e.ctrlKey) {

			try{o.e.keyCode = 90909090;}catch(e){};

		}

		utility.dom.stopEvent(o.e);

		return false;

	}

	return true;

}



utility.window.blockInterface = function(cursor, el, customId) {

	if (typeof(cursor) == "undefined") {

		cursor = "wait";

	}

	var ctrlInterfaceBlocker = utility.dom.createElement('div', {});

	ctrlInterfaceBlocker.className = 'interfaceBlocker';

	ctrlInterfaceBlocker.id = customId || 'interfaceBlocker';

	prepfixieinsertnodescrollup();

	ctrlInterfaceBlocker = document.body.appendChild(ctrlInterfaceBlocker);

	fixieinsertnodescrollup();

	ctrlInterfaceBlocker.style.cursor = cursor;

	var pos;

	if(!el)	{

		pos = utility.dom.getPageInnerSize();

		ctrlInterfaceBlocker.style.width = pos.x + 'px';

		ctrlInterfaceBlocker.style.height = pos.y + 'px';

	}

	else{

		pos = utility.dom.getBox(el);

		ctrlInterfaceBlocker.style.top = pos.y + 'px';

		ctrlInterfaceBlocker.style.left = pos.x + 'px';

		ctrlInterfaceBlocker.style.width = pos.width + 'px';

		ctrlInterfaceBlocker.style.height = pos.height + 'px';

	}

};



utility.window.unblockInterface = function() {

	var ctrlInterfaceBlocker = document.getElementById('interfaceBlocker');

	if (ctrlInterfaceBlocker) {

		document.body.removeChild(ctrlInterfaceBlocker);

	}

};



utility.window.setModal = function(set_unselectable) {

	if (typeof set_unselectable == "undefined") {

		set_unselectable = true;

	}

	window.isloading = false;

	window.focus();

	if (!window.dialogArguments) {

		window.onbeforeunload = function() {

			if (!window.opener.closed) {

				utility.window.hideModalBlocker(window.opener);

			}

		}

		if (set_unselectable) {

			utility.dom.setUnselectable(window.document.body);

		}

	} else {

		window.opener = dialogArguments;

	}

	if (!window.opener) {

		document.body.innerHTML = "<center>Invalid context! No opener.</center>" + '<div style="display:none !important">' + document.body.innerHTML + '</div>';

		return;

	}

	if (window.opener.topOpener) {

		window.topOpener = window.opener.topOpener;

	} else {

		window.topOpener = window.opener;

	}

	utility.dom.attachEvent(is.ie?window.document.body:window, 'keydown', function(e) {

		var ret = utility.popup.escapeModal(e);

		if (ret && e.keyCode == 27) {

			utility.window.close();

		}

	});

	utility.dom.attachEvent2(window.document.body, 'mousedown', utility.popup.removeModal);

};



Object_weave_safe(utility, {cookie: {}});



utility.cookie.set = function(name, value, lifespan, access_path) {

	var cookietext = name + "=" + escape(value);

	if (lifespan != null) {

		var date = new Date();

		date.setTime(date.getTime() + (1000*60*60*24*lifespan));

		cookietext += "; expires=" + date.toGMTString();

	}

	if (access_path != null) {

		cookietext += "; path=" + access_path;

	}

	document.cookie = cookietext;

	return null;

}



utility.cookie.get = function(name) {

	var nameeq = name + "=";

	var ca = document.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;

}



utility.cookie.del = function(name, path) {

	utility.cookie.set(name, "", -1, path);

}



// simple UID generator

UIDGenerator = function(name) {

	if (typeof(name) == 'undefined') {

		name = 'iaktuid_' + Math.random().toString().substring(2, 6) + '_';

	}

	this.name = name;

	this.counter = 1;

}

UIDGenerator.prototype.generate = function(detail) {

	if (typeof(detail) == 'undefined') {

		detail = '';

	}

	return (this.name + detail + this.counter++ + '_');

}



ObjectStorage = function (name) {

	this.storage = {};

	this.gen = new UIDGenerator(name + "_reference_by_id_");

}



ObjectStorage.prototype.add = ObjectStorage.prototype.storeObject = function (obj) {

	var type = obj.constructor.toString().match(/^\s*function\s*([^\s\(]*)\s*\(/i);

	if (!type) {

		type = "unknown_contructor";

	} else {

		type = type[1];

	}

	var newId = this.gen.generate(type);

	obj.id = newId;

	this.storage[newId] = obj;

}



ObjectStorage.prototype.get = ObjectStorage.prototype.getObject = function (id) {

	return this.storage[id];

}



ObjectStorage.prototype.deleteObject = function (id) {

	delete this.storage[id];

}



ObjectStorage.prototype.dispose = function () {

	this.storage = null;

}



QueryString = function(str) {

	if (typeof str == 'undefined') {

		var str = window.location.search.toString();

	}

	this.keys = new Array();

	this.values = new Array();

	var query = str;

	if (str.indexOf('?') == 0) {

		query = str.substring(1);

	}

	query = query.replace(/&amp;/g, '&');

	var pairs = query.split("&");



	for (var i = 0; i < pairs.length; i++) {

		var pos = pairs[i].indexOf('=');



		if (pos >= 0) {

			var argname = pairs[i].substring(0, pos);

			var value = pairs[i].substring(pos + 1);

			this.keys[this.keys.length] = argname;

			this.values[this.values.length] = value;

		}

	}

}



QueryString.prototype.find = function(key) {

	var value = null;

	for (var i = 0; i < this.keys.length; i++) {

		if (this.keys[i] == key) {

			value = this.values[i];

			break;

		}

	}

	return value;

}



KT_Tooltips = {

	cname: 'kt_add_tooltips', 

	worked: [], 

	cancel:false,

	gen: new UIDGenerator(), 

	show: function (id, x, y) {

		var div = document.getElementById(id);

		if (!div) {

			return;

		}

		//show it somewhere out of sight, so it gets a box

		div.style.left = '-1000px';

		div.style.top = '-1000px';

		div.style.display = 'block';

		var pos = utility.dom.getBBox(div);



		var pos2 = utility.dom.getPositionRelativeTo00(x, y, pos.width + 2, pos.height + 2);



		div.style.left = pos2.x + 'px';

		div.style.top = pos2.y + 'px';

		//KT_Tooltips.set_timeout(id, "hide", 3250);

	}, 

	hide: function (id) {

		var div = document.getElementById(id);

		if (!div) {

			return;

		}

		div.style.display = 'none';

	}, 

	clear_timeout: function(id, mode) {

		var to = id + mode + "timeout";

		if (typeof window[to] != 'undefined') {

			clearTimeout(window[to]);

		}

	}, 

	clear_showtimeout: function(id) {

		KT_Tooltips.clear_timeout(id, 'show');

	}, 

	clear_hidetimeout: function(id) {

		KT_Tooltips.clear_timeout(id, 'hide');

	}, 

	set_timeout: function(id, mode, time) {

		var params_str = '', params_arr = [];

		if (arguments.length > 3) {

			for (var i = 3; i < arguments.length; i++) {

				Array_push(params_arr, arguments[i]);

			}

		}

		params_str = params_arr.join(', ');

		if (params_str != '') {

			params_str = ', ' + params_str;

		}

		var str = "KT_Tooltips." + mode + "('" + id + "'"+ params_str+")";

		var to = id + mode + "timeout";

		window[to] = setTimeout(str, time);

	}, 

	set_showtimeout: function(id, vars) {

		KT_Tooltips.set_timeout(id, "show", 1000, vars.x, vars.y);

	}, 

	set_hidetimeout: function(id) {

		KT_Tooltips.set_timeout(id, "hide", 250);

	}, 

	attach_single: function(link) {

		if (is.ie || is.safari) {

			return;

		}

		var title = link.title;

		var mytip = null;

		if (link.getAttribute('divid')) {

			mytip = document.getElementById(link.getAttribute('divid'));

			if (mytip) {

				document.body.removeChild(mytip);

			}

			link.removeAttribute('divid');

		}

		if (/[\r\n]/.test(title)) {

			var divid = KT_Tooltips.gen.generate("tooltip");

			var div = utility.dom.createElement("div", {

				'class': 'tooltip_div', 

				'id': divid

			});

			div.innerHTML = link.getAttribute("title").toString().replace(/\r\n/g, "<br />").replace(/[\r|\n]/g, "<br />");

			link.divid = divid;

			div = document.body.appendChild(div);

			link.removeAttribute("title");

			link.setAttribute("divid", divid);

			if (!mytip) {//attach events only once

				utility.dom.attachEvent(link, 'mouseover', function(e) {		

					var id = link.getAttribute("divid");

					var pos = utility.dom.getBBox(link);

					var vars = utility.dom.setEventVars(e);

					KT_Tooltips.clear_hidetimeout(id);

					var obj = {x: pos.x + Math.round(pos.width / 2), y: pos.y + Math.round(pos.height / 2) + 10};

					KT_Tooltips.set_showtimeout(id, obj);

					utility.dom.stopEvent(e);

				});

				utility.dom.attachEvent(link, 'mouseout', function(e) {

					var id = link.getAttribute("divid");

					KT_Tooltips.clear_showtimeout(id);

					KT_Tooltips.set_hidetimeout(id);

					utility.dom.stopEvent(e);

				});

			}

		}

	}, 

	attach: function () {

		KT_Tooltips.worked = [];

		if (is.ie || is.safari) {

			return;

		}

		Array_each(utility.dom.getElementsByClassName(document.body, KT_Tooltips.cname), function(el) {

			Array_each(el.getElementsByTagName('a'), KT_Tooltips.attach_single);

		}) 

	}

};

utility.dom.attachEvent(window, 'load', KT_Tooltips.attach);



/*

 * class XmlHttp

*/

//MsXML on Mozilla

function getDomDocumentPrefix() {

	if (getDomDocumentPrefix.prefix) return getDomDocumentPrefix.prefix;

	var prefixes = ["MSXML2", "Microsoft", "MSXML", "MSXML3"];

	var o;



	for (var i = 0; i < prefixes.length; i++) {

		try {

			o = new ActiveXObject(prefixes[i] + ".DomDocument");

			return getDomDocumentPrefix.prefix = prefixes[i];

		} catch (ex) { }

	}

	throw new Error("Could not find an installed XML parser");

}

function getXmlHttpPrefix() {

	if (getXmlHttpPrefix.prefix) return getXmlHttpPrefix.prefix;



	var prefixes = ["MSXML2", "Microsoft", "MSXML", "MSXML3"];

	var o;



	for (var i = 0; i < prefixes.length; i++) {

		try {

			// try to create the objects

			o = new ActiveXObject(prefixes[i] + ".XmlHttp");

			return getXmlHttpPrefix.prefix = prefixes[i];

		} catch (ex) { }

	}



	throw new Error("Could not find an installed XML parser");

}



// XmlHttp factory

function XmlHttp() { }

XmlHttp.create = function() {

	try {

		if (window.XMLHttpRequest) {

			var req = new XMLHttpRequest();

			if (req.readyState == null) {

				req.readyState = 1;

				req.addEventListener("load", 

					function() {

						req.readyState = 4;

						if (typeof req.onreadystatechange == "function") 

							req.onreadystatechange();

					}, false);

			}

			return req;

		}

		if (window.ActiveXObject) {

			var ax = new ActiveXObject(getXmlHttpPrefix() + ".XmlHttp");

			return ax;

		}

	} catch (ex) { }



	// fell through

	throw new Error("Your browser does not support XmlHttp objects");

}

XmlHttp.post = function(rpc, url, postStr) {

	try {

		rpc.open("POST", url, false);

		rpc.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

		rpc.send(postStr);

	} catch(e) {

		return false;

	}

	return rpc;

}

XmlHttp.get = function(rpc, url, getStr) {

	try {

		rpc.open("GET", getStr, false);

		rpc.send(null);

	} catch(e) {

		return false;

	}

	return rpc;

}



// XmlDocument factory

function XmlDocument() {}



XmlDocument.create = function () {

	try {

		// DOM2

		if (document.implementation && document.implementation.createDocument) {

			var doc = document.implementation.createDocument("", "", null);

			

			// some versions of Moz do not support the readyState property

			// and the onreadystate event so we patch it!

			if (doc.readyState == null) {

				doc.readyState = 1;

				doc.addEventListener("load", function () {

					doc.readyState = 4;

					if (typeof doc.onreadystatechange == "function")

						doc.onreadystatechange();

				}, false);

			}

			

			return doc;

		}

		if (window.ActiveXObject)

			return new ActiveXObject(getDomDocumentPrefix() + ".DomDocument");

	}

	catch (ex) {}

	throw new Error("Your browser does not support XmlDocument objects");

};



// Create the loadXML method and xml getter for Mozilla

if (window.DOMParser &&

	window.XMLSerializer &&

	window.Node && Node.prototype && Node.prototype.__defineGetter__) {



	// XMLDocument did not extend the Document interface in some versions

	// of Mozilla. Extend both!

	//XMLDocument.prototype.loadXML = 

	Document.prototype.loadXML = function (s) {

		

		// parse the string to a new doc	

		var doc2 = (new DOMParser()).parseFromString(s, "text/xml");

		

		// remove all initial children

		while (this.hasChildNodes())

			this.removeChild(this.lastChild);

			

		// insert and import nodes

		var ret = false;

		for (var i = 0; i < doc2.childNodes.length; i++) {

			this.appendChild(this.importNode(doc2.childNodes[i], true));

			ret = true;

		}

		return ret;

	};

	

	

	/*

	 * xml getter

	 *

	 * This serializes the DOM tree to an XML String

	 *

	 * Usage: var sXml = oNode.xml

	 *

	 */

	// XMLDocument did not extend the Document interface in some versions

	// of Mozilla. Extend both!

	/*

	XMLDocument.prototype.__defineGetter__("xml", function () {

		return (new XMLSerializer()).serializeToString(this);

	});

	*/

/*@cc_on @*/

/*@if (@_jscript_version >= 3)

	//hide the next block of code from the IE compiler ;)

@else @*/

	var documentProto = Document.prototype;

	var documentGrandProto = documentProto.__proto__ = {

		__proto__: documentProto.__proto__

	};

	

	if (documentGrandProto) {

		documentGrandProto.__defineGetter__('xml',

			function () { return (new XMLSerializer()).serializeToString(this); }

		);

	}



	var elementProto = Element.prototype;

	var elementGrandProto = elementProto.__proto__ = {

		__proto__: elementProto.__proto__

	};

	if (elementGrandProto) {

		elementGrandProto.__defineGetter__('text',

			function () { return this.textContent; }

		);

		elementGrandProto.__defineGetter__('innerText',

			function () { return this.textContent; }

		);

		elementGrandProto.__defineSetter__('innerText',

			function (new_value) { 

				var tn = this.ownerDocument.createTextNode(new_value);

				this.innerHTML = "";

				this.appendChild(tn);

			}

		);

	}



/*@end @*/

}



function evaluateXPath(aNode, aExpr) {

	var found = [];

	if (is.mozilla) {

		if (typeof evaluateXPath.xpe == "undefined") {

			evaluateXPath.xpe = new XPathEvaluator();

		}

		//var nsResolver = xpe.createNSResolver(aNode.ownerDocument == null ? aNode.documentElement : aNode.ownerDocument.documentElement);

		//var result = xpe.evaluate(aExpr, aNode, nsResolver, XPathResult.ANY_TYPE, null);

		var result = evaluateXPath.xpe.evaluate(aExpr, aNode, null, XPathResult.ANY_TYPE, null);

		while (res = result.iterateNext()) {

			found.push(res);

		}

	} else if (is.ie) {

		var result = aNode.selectNodes(aExpr);

		for(var i=0; i<result.length; i++) {

			found.push(result[i]);

		}

	}

	if (found.length == 0) {

		found = false;

	}

	return found;

};



function BrowserCheck() {

	var b = navigator.appName.toString();

	var up = navigator.platform.toString();

	var ua = navigator.userAgent.toString();



	this.mozilla = this.ie = this.opera = r = false;

	var re_opera = /Opera.([0-9\.]*)/i;

	var re_msie = /MSIE.([0-9\.]*)/i;

	var re_gecko = /gecko/i;

	var re_safari = /safari\/([\d\.]*)/i;

	

	if (ua.match(re_opera)) {

		r = ua.match(re_opera);

		this.opera = true;

		this.version = parseFloat(r[1]);

	} else if (ua.match(re_msie)) {

		r = ua.match(re_msie);

		this.ie = true;

		this.version = parseFloat(r[1]);

	} else if (ua.match(re_safari)) {

		this.mozilla = true;

		this.safari = true;

		this.version = 1.4;

	} else if (ua.match(re_gecko)) {

		var re_gecko_version = /rv:\s*([0-9\.]+)/i;

		r = ua.match(re_gecko_version);

		this.mozilla = true;

		this.version = parseFloat(r[1]);

	}

	this.windows = this.mac = this.linux = false;



	this.Platform = ua.match(/windows/i) ? "windows" :

					(ua.match(/linux/i) ? "linux" :

					(ua.match(/mac/i) ? "mac" :

					ua.match(/unix/i)? "unix" : "unknown"));

	this[this.Platform] = true;

	this.v = this.version;

	this.valid = this.ie && this.v >= 6 || this.mozilla && this.v >= 1.4;

	if (this.safari && this.mac && this.mozilla) {

		this.mozilla = false;

	}

};



function sortFormHandlers(arr) {

	for(var i=0; i<arr.length; i++) {

		var fh1 = arr[i];

		for(var j=i+1;j<arr.length;j++) {

			var fh2 = arr[j];

			if (fh2[0]<fh1[0]) {

				var tmp = fh1;

				arr[i] = fh2;

				arr[j] = tmp;

			}

		}

	}

};



function GLOBAL_registerFormSubmitEventHandler(function_name, priority) {

	var frms = document.getElementsByTagName('form');

	for (var i = 0; i < frms.length; i++) {

		var frm = frms[i];

		if (typeof frm.onsubmit != 'undefined' && frm.onsubmit != null) {

			var form_handlers = frm.form_handlers;

			if (form_handlers) {

				form_handlers[form_handlers.length] = [priority, function_name];

				sortFormHandlers(form_handlers);

			} else {

				//user defined onsubmit handler

				frm.__kt_onsubmit = frm.onsubmit;

				frm.onsubmit = new Function('e', 'if (!KT_formSubmittalHandler(e)) return false;');

				form_handlers = [];

				form_handlers[form_handlers.length] = [priority, function_name];

			}

			frm.form_handlers = form_handlers;

		} else {

			frm.onsubmit = new Function('e', 'return KT_formSubmittalHandler(e);');

			var form_handlers = [];

			form_handlers[form_handlers.length] = [priority, function_name];

			frm.form_handlers = form_handlers;

		}

	}

};





/**

* Fix the KT_formSubmittalHandler from utility.js

*	FF : stopping the onsubmit event seems to alter the event.type (accessing the property after stopping the event raise an error)

*	IE : if the call to KT_formSubmittalHandler is not triggered by a submit, there's no way to find the FORM to handle; setEventVars(e) returns some other event

*/

var fire_starter = null;

var global_form_submit_lock = false;

function KT_formSubmittalHandler(e) {

	var frm = null;

	var o = utility.dom.setEventVars(e);

	if (!o.e) {

		return true;

	}

	try {

		if (global_form_submit_lock) {

			utility.dom.stopEvent(o.e);

			return false;

		}

		frm = o.targ;

		if (!frm) {

			return true;

		}

		if (!frm.tagName) {

			return true;

		}

		if (frm.tagName.toLowerCase()!="form") {

			frm = frm.form;

		}

	} catch(err) { }



	if(!frm){

		frm = fire_starter;

	}

	if (!frm) {

		return true;

	}



	if (typeof(UNI_disableButtons) != 'undefined') {

		UNI_disableButtons(frm, /.*/, true);

	}



	var ret = true;

	var form_handlers = frm.form_handlers;

	if (form_handlers) {

		for(var i=0; i<form_handlers.length; i++) {

			var fun = form_handlers[i];

			eval("ret = " + fun[1] + "(o.e);");

			//alert("KT_formSubmittalHandler ret = "+fun[1]+"(o.e);, the result is: " + ret);

			if (!ret) {

				break;

			}

		}

	}

	if (is.ie && is.mac && typeof(UNI_disableButtons) != 'undefined') {

		UNI_disableButtons(frm, /.*/, false);

	}



	if (!ret) {

		try {

			utility.dom.stopEvent(o.e);

		} catch(err) { }

		//the form submit lock does not enable the buttons

		if (!global_form_submit_lock && typeof(UNI_disableButtons) != 'undefined') {

			UNI_disableButtons(frm,/.*/,false);

		}

		return false;

	} else {

		if (frm.__kt_onsubmit) {

			var ret = frm.__kt_onsubmit(o.e);

			if (typeof(ret) == 'undefined' || ret) {

				return true;

			} else {

				return false;

			}

		}

		return true;

	}

};



utility.dom.attachEvent(window, 'unload', EventCache.flush);


