/**
 * $Id: ngcore.js 5331 2007-06-12 23:08:16Z michael $
 *
 * Javascript Library v0.1
 *
 * Copyright Noggin <info@noggin.com.au> 2003,2004
 *
 * Last Updated: 12/Sep/2004
 *      Depends: Javascript >= 1.2
 *
 * @author Travers Carter <tcarter@noggin.com.au>
 *
 * Changelog:
 *   12/Sep/2004 TC: Initial version
 *
 * TODO
 * -----------------
 * - Date.parse2() - Context sensitive date parser
 * - Date.fullYear()
 * - Number.format()
 * - Number.parse()
 */

var __G = new Object(); // Engine globals
var N=null, T=true, F=false;

function NG() {}

NG.rev = '$Id: ngcore.js 5331 2007-06-12 23:08:16Z michael $';

// Core functions
function isFunc(x) {
	if (typeof x == 'function') return T;
	if (!isObj(x)) return F;
	if (String(x.constructor) == String(Function)) return T;
	try { return (String(x).search(/^\s*function [a-zA-Z]+\(\) \{\s+\[native code\]\s+\}\s*$/) != -1); } catch (err) { }
	return F;
}
function isDef(x) { return x != 'undefined'; }
function isObj(x) { return typeof x == 'object' && !isNull(x); }
function isArr(x) { return isObj(x) && String(x.constructor) == String(Array); }
function isStr(x) { return typeof x == 'string'; }
function isNum(x) { return typeof x == 'number'; }
function isInt(x) { return typeof x == 'number' && Math.floor(x) == x; }
function isA(x,c) { return isObj(x) && x.constructor == c; }
function isIntVal(x) { return isInt(x) || (isStr(x) && x.search(/^[\-\+]?[0-9]+$/) != -1); }
function isRegex(x) { return (x && isFunc(x.test)) || (isObj(x) && x.constructor == RegExp); }
function isNull(x) { return x === N; }
function isId(x) { return isIntVal(x) && x>=1; }
function ifnull() { var a=arguments; for (var i=0; i<a.length; i++) if (a[i] !== N) return a[i]; return N; }
function ifnot() { var a=arguments; for (var i=0; i<a.length; i++) if (a[i]) return a[i]; return N; }

NG.dump = function (x) {
	var p=[],m=[],i,s='--------',n=15,c=0,f=0;s+=s;
	var r = (arguments.length > 1) ? arguments[1] : N;
	if (r && !isRegex(r)) r = new RegExp(r);
	for (i in x) {
		if (r && !r.test(i)) continue;
		try { if (isFunc(x[i])) m.push(i); else p.push('.'+i+' = '+x[i]); }
		catch (e) { p.push('.'+i+' = *EXCEPTION* '); }
	}
	if (r) f='matching /'+r.source+'/ ';
	for (i=0; (i+n)<p.length; i+=n) if (!confirm(s+'[ Properties '+f+(i+1)+' to '+(i+n)+' of '+p.length+' ]'+s+'\n'+p.slice(i,i+n).join('\n')+'\n...')) throw('NG.dump cancelled');
	if (!confirm(s+'[ Properties '+f+(i+1)+' to '+(p.length)+' of '+p.length+' ]'+s+'\n'+p.slice(i,i+n).join('\n')+'\n'+s+'[ Methods '+f+']'+s+'\n'+m.join(', '))) throw('NG.dump cancelled');
}

//--------------- Forwards compatibility / Browser bugfixes ------------------------


// Browser Bugfix - Gecko 64bit, TODO: Test Math.exp() & Math.log() on a broken Gecko
if (Math.pow(2,2) == 0) {
	Math.pow = function (b,p) {
		if (p == 0) return 1;
		var pi = Math.floor(Math.abs(p))
		var pf = Math.abs(p)-pi;
		var r = 1;
		for (var i=0; i<pi; i++) r*=b; // Integer component
		if (pf != 0 && b != 1) r *= Math.exp(Math.log(b)*pf); // Fractional component
		if (p < 0) r = 1/r; // Reciprocal if pow -ve
		return r;
	}
}

if (!isFunc(Array.prototype.splice)) {
	Array.prototype.splice = function (at, del) {
		var al = arguments.length-2, d = al-del, nl = this.length+d;
		var rm = this.slice(at, at+del);
		if (d <= 0) {
			for (i=at; i-at<al; i++) this[i] = arguments[i-at+2];
			if (d < 0) {
				for (i++; i <= nl; i++) this[i+d] = this[i];
			}
		} else {
			for (i=nl-1; i >= at+al; i--) this[i] = this[i-d];
			for (i=0; i<al; i++) this[at+i] = arguments[i+2];
		}
		this.length = nl;
		return rm;
	};
}
if (!isFunc(Array.prototype.pop)) { Array.prototype.pop = function () { return (this.splice(this.length-1, 1))[0]; } }
if (!isFunc(Array.prototype.push)) { Array.prototype.push = function () { this.splice(this.length, 0, arguments); return this.length; }}
if (!isFunc(Array.prototype.shift)) { Array.prototype.shift = function () { return (this.splice(0, 1))[0]; }}
if (!isFunc(Array.prototype.unshift)) { Array.prototype.unshift = function () { this.splice(0, 0, arguments); return this.length; }}
if (!isFunc(Array.prototype.search)) {
	if (isFunc(Array.prototype.indexOf)) Array.prototype.search = Array.prototype.indexOf;
	else Array.prototype.search = function (e) { for (var i=0; i<this.length; i++) if (this[i] === e) return i; return -1; }
}

if (!isFunc(Number.prototype.toFixed)) {
	Number.prototype.toFixed = function (l) {
		if (isNaN(this) || !isFinite(this) || Math.abs(this) > 1e+21) return this.toString();
		if (!isIntVal(l) || l == 0) return (((this < 0) ? -1 : 1) * Math.round(Math.abs(this))).toString();
		if (l < 0 || l > 20) return NaN; // throw RangeError
		var s=(this<0 ? '-':'');
		var v=Math.abs(this), i=Math.floor(v), d=String(Math.round((v-i)*Math.pow(10,l)));
		d = '0'.repeat(l-d.length+1)+d;
		d = d.insert('.', d.length-l);
		i += parseInt(d);
		d = d.substr(d.indexOf('.')+1);
		return s + i+'.'+d;
	}
}
if (!isFunc(Number.prototype.toPrecision)) {
	Number.prototype.toPrecision = function (p) {
		if (isNaN(this) || !isFinite(this) || !isIntVal(p)) return this.toString();
		var e = this == 0 ? 1 : Math.floor(Math.log(Math.abs(this))/Math.LN10);
		var il = Math.round(Math.abs(this)).toString().length;
		if (e <= -7 || il > p) {
			return this.toExponential(p-1);
		} else {
			return this.toFixed(Math.max(0,-e)+p-(Math.floor(Math.abs(this)).toString().length));
		}
	}
}
if (!isFunc(Number.prototype.toExponential)) {
	Number.prototype.toExponential = function (l) {
		if (isNaN(this) || !isFinite(this)) return this.toString();
		var e = this == 0 ? 1 : Math.floor(Math.log(Math.abs(this))/Math.LN10);
		var n = (e <= 0) ? (this*Math.pow(10,Math.min(-e, 150))*Math.pow(10,Math.max(0,-e-150))) : (this/Math.pow(10,Math.min(e,150))/Math.pow(10,Math.max(0,e-150)));
		return (isIntVal(l) ? n.toFixed(l) : n.toString()) + 'e' + (e >= 0 ? '+' : '') + ((this == 0) ? '0' : e);
	}
}

if (!isFunc(Function.prototype.apply)) {
	Function.prototype.apply = function (o,a) {
		var r,n='__NGapply'; o[n]=this;
		switch (a.length) {
			case 0: r = o[n](); break;
			case 1: r = o[n](a[0]); break;
			case 2: r = o[n](a[0],a[1]); break;
			case 3: r = o[n](a[0],a[1],a[2]); break;
			case 4: r = o[n](a[0],a[1],a[2],a[3]); break;
			default:
				var e='r=o[n](a[0]';
				for (var i=0; i<a.length; i++) e+=',a['+i+']';
				eval(e+');');
		}
		delete o[n];
		return r;
	}
}
if (!isFunc(Function.prototype.call)) { Function.prototype.call = function (o) { return this.apply(o,arguments.slice(1)); }}

//-------------- New functionality for native objects  --------------------
Array.prototype.unset = function (i) { if (isInt(i) && i >= 0 && i < this.length) this.splice(i,1); }
Array.prototype.map = function (f) { for (var i=0; i<this.length; i++) this[i] = f(this[i]); }

NG.cloneObj = function (o) { var r = new o.constructor(); for (var i in o) r[i] = o[i]; return r; }

String.prototype.repeat = function (n) {var s=''; for (var i=0; i<n; i++) s += this; return s;}
String.prototype.normalize_nl = function (nl) { var s = this.replace(/\r\n/g, '\n').replace(/\r/g, '\n'); return (nl != '\n' ? s.replace(/\n/g, nl) : s); }
String.prototype.nl2unix = function () { return this.normalize_nl('\n'); }
String.prototype.nl2dos = function () { return this.normalize_nl('\r\n'); }
String.prototype.nl2mac = function () { return this.normalize_nl('\r'); }
String.prototype.span = function (s) { for (var i=0; i<this.length && s.indexOf(this.charAt(i)) != -1; i++); return i; }
String.prototype.insert = function (v,p) { return this.substr(0,p)+v+this.substr(p); }
String.prototype.rev = function () { var s=''; for (var i=this.length-1; i>=0; i--) s+=this.charAt(i); return s; }

String.prototype.toHex = function () {
	var r = '';
	for (var h,i = 0; i < this.length; i++) { h = this.charCodeAt(i).toString(16).toUpperCase(); r += (h.length == 1 ? '0' : '')+h; }
	return r;
}

String.prototype.fromHex = function () {
	var r = '';
	for (var i = 0; i < this.length; i+=2) { r += String.fromCharCode(parseInt(this.substr(i,2), 16)); }
	return r;
}

Number.prototype.ordinal = function (show) {
	if (!isDef(typeof show)) show = T;
	var n = Math.abs(this);
	return (show ? this : '') + ['th','st','nd','rd','th'][Math.min(n%100-n%10==10 ? 0 : n%10, 4)];
}


//------------------ NG scoped functions --------------------

NG.round = function (v,d) { if (arguments.length < 2) d = 0; return new Number(v).toFixed(d); }

NG.point = function (x,y) {
	this.x = parseInt(x);
	this.y = parseInt(y);
}

NG.getPagePos = function (node, offsetParent) {
	if (arguments.length == 1) offsetParent = null;
	if (offsetParent && node != offsetParent) {
		var p = new NG.point(0-node.scrollLeft, 0-node.scrollTop);
	} else {
		var p = new NG.point(node.offsetLeft-node.scrollLeft, node.offsetTop-node.scrollTop);
		offsetParent = null;
	}
	var r,t;
	if (node.parentNode && node.parentNode.nodeType == 1) {
		t = NG.getPagePos(node.parentNode, (offsetParent ? offsetParent : node.offsetParent));
		p.x += t.x;
		p.y += t.y;
	} else if (node.tagName == 'BODY' && isDef(typeof node.leftMargin) && NG.ua.is('MACIE')) {
		p.x += parseInt((r = node.currentStyle.marginLeft.match(/([0-9]+)px/)) ? r[1] : node.leftMargin);
		p.y += parseInt((r = node.currentStyle.marginTop.match(/([0-9]+)px/)) ? r[1] : node.topMargin);
	}
	if (NG.ua.isEng('MSIE', '6.0', '=') && node.currentStyle.styleFloat != 'none') p.y -= node.offsetTop;
	return p;
}

NG.include = function (uri, force) {
	if (!isObj(__G['includes'])) __G['includes'] = new Object();
	if (!force && isDef(typeof __G['includes'][uri])) return F;
	__G['includes'][uri] = T;
	document.writeln('<scr'+'ipt type="text/javascript" language="Javascript1.2" src="'+uri+'"></scr'+'ipt>');
	return T;
}

NG.imgPreload = function (url) { new Image().src = url; }

NG.rollover = function(img,altSrc,preload) {
	if (!isDef(typeof img.onmouseout) || isNull(img.onmouseout)) {
		img.altSrc = altSrc;
		img.origSrc = img.src;
		if (preload) NG.imgPreload(img.altSrc);
		img.onmouseout = function out() { this.src = this.origSrc; }
	}
	img.src = img.altSrc;
}

NG.attachRollovers = function(preload) {
	if (arguments.length == 0) preload = true;
	var i,s,imgs = document.getElementsByTagName('IMG');
	function over() { NG.rollover(this,this.getAttribute('altsrc')); }
	for (i = 0; i < imgs.length; i++) {
		s = imgs[i].getAttribute('altsrc');
		if (isStr(s) && s != '') {
			if (preload) NG.imgPreload(s);
			imgs[i].onmouseover = over;
		}
	}
}

function userAgent() {
	this.App = N;
	this.AppVer = [];
	this.Engine = N;
	this.EngineVer = [];
	this.OS = N;
	this.OSRel = N;
	this.OSVer = [];
	this.Arch = N;

	var n = navigator;
	var p = n.userAgent.indexOf('(');
	var a = n.userAgent.substr(p, n.userAgent.length-p);
	p = n.userAgent.substr(0, p);

	if ((r = a.match(/ Opera ([.0-9]+)/)) || (r = p.match(/^Opera\/([0-9.]+) /))) {
		this.App = 'Opera';
		this.AppVer = r[1].split('.');
		this.Engine = 'OPERA';
		this.EngineVer = r[1].split('.');
	} else if (a.indexOf('(KHTML, like Gecko)') != -1 || (r = a.match(/ KHTML\/([\.0-9]+) \(like Gecko\)/))) {
		this.Engine = 'KHTML';
		this.EngineVer = r ? r[1].split('.') : N;
		if ((r = a.match(/ Konqueror\/([\.0-9]+); /))) {
			this.App = 'Konqueror';
			this.AppVer = r[1].split('.');
		} else if ((r = a.match(/ Safari\/([\.0-9]+)( |$)/))) {
			this.App = 'Safari';
			this.AppVer = r[1].split('.');
			if (isNull(this.EngineVer)) this.EngineVer = this.AppVer;
		}
	} else if (n.product && n.product == 'Gecko') {
		this.Engine = 'GECKO';
		this.EngineVer = n.productSub;
		if (r = a.match(/ Netscape\/([6-9](\.[0-9]+)?)( |$)/)) {
			this.App = 'Netscape';
			this.AppVer = r[1].split('.');
		} else if ((r = a.match(/ (SeaMonkey|Firefox|Camino|Netscape6)\/([0-9]+(\.([0-9]|b|rc|a|p)+)*)( |$)/))) {
			this.App = r[1].replace(/6$/,'');
			this.AppVer = r[2].split('.');
		} else if ((r = a.match(/[;\(] rv:([\.0-9]+)[ \)]/))) {
			this.App = 'Mozilla';
			this.AppVer = r[1].split('.');
		} else if (n.vendor && n.vendor.length > 0) {
			this.App = n.vendor;
			this.AppVer = n.vendorSub.split('.');
		}
	} else if ((r = a.match(/[;\(] ?MSIE ([\.0-9]+)[;\)]/))) {
		if (a.search('Mac') != -1) { // Check for Mac
			this.Engine = 'MACIE';
		} else {
			this.Engine = 'MSIE';
		}
		this.EngineVer = r[1].split('.');
		// Netscape 8 can use the MSIE engine
		if (r = a.match(/ Netscape\/([6-9](\.[0-9]+)?)( |$)/)) {
			this.App = 'Netscape'; this.AppVer = r[1].split('.');
		} else {
			this.App = n.appName; this.AppVer = this.EngineVer;
		}
	} else if ((r = n.userAgent.match(/^Mozilla\/([\.0-9]+)/)) && r[1] < 5) {
		this.Engine = 'NS4';
		this.EngineVer = r[1];
		this.App = 'Netscape';
		this.AppVer = r[1];
	}

	p = n.platform ? n.platform : N;
	if (p && p.search(/^Linux.*/) != -1) {
		this.OS='Unix';
		this.OSRel='Linux';
		if (p.search(/^Linux i[0-9]86/) != -1 || a.search(/Linux i[0-9]86;/) != -1) {
			this.Arch = 'x86';
		}
	} else if (p == 'Win32') {
		this.OS='Win';
		if (n.oscpu && (r = n.oscpu.match(/^Win(dows)? ?(95|98|NT)?( ?[0-9]+\.[0-9]+)?/))) {
			this.OSRel = r[2];
			this.OSVer = r[3] ? r[3].split('.') : '';
		} else if ((r = n.appVersion.match(/(\(|; ?)Win(dows)? ?(95|98|NT)?( ?[0-9]+\.[0-9]+)?/))) {
			this.OSRel = r[3];
			this.OSVer = r[4] ? r[4].split('.') : '';
		}
		// May be dangerous assumption, NT on Alpha, x86_64
		this.Arch = n.cpuClass ? n.cpuClass : 'x86';
	} else if (p && (r = p.match(/^Mac(PPC|Intel)$/))) {
		this.OS = 'MacOS';
		this.Arch = (r[1] == 'Intel' ? 'x86' : 'PPC');
		if (p.search(/ Mac OS X /)) {
			this.OSRel = 'X';
			this.OSVer = [10];
		}
	} else if (p && (r = p.match(/^(SunOS) (.*)/))) {
		this.OS = r[1];
		this.Arch = r[2];
	}
}


NG.ua = function () {}

NG.ua.get = function () {
	if (!isObj(__G['userAgent'])) __G['userAgent'] = new userAgent();
	return __G['userAgent'];
}


NG.ua.cmp = function (v1, cmp, v2) {
	if (!isArr(v1)) v1 = String(v1).split('.');
	if (!isArr(v2)) v2 = String(v2).split('.');

	v1.map(parseInt);
	v2.map(parseInt);

	var cl = Math.min(v1.length,v2.length);

	for (var i=0; i<cl; i++) {
		switch (cmp) {
			case '>':
			case '>=':
				if (v1[i] > v2[i]) return T;
				if (v1[i] < v2[i]) return F;
				break;
			case '==':
			case '=':
				if (v1[i] != v2[i]) return F;
				break;
			case '<':
			case '<=':
				if (v1[i] > v2[i]) return F;
				if (v1[i] < v2[i]) return T;
				break;
			case '!=':
				if (v1[i] != v2[i]) return T;
				break;
		}
	}
	switch (cmp) {
		case '>=': if (v1.length == v2.length) return T;
		case '>': return (v1.length > v2.length);
		case '=':
		case '==': return (v1.length == v2.length);
		case '<=': if (v1.length == v2.length) return T;
		case '<': return (v1.length < v2.length);
		case '!=': return (v1.length != v2.length);
	}
}

NG.ua.isCmp = function (want, have) { return isRegex(want) ? want.test(have) : have == want; }

NG.ua.isEng = function (eng, engVer, cmp) {
	var a = arguments, ua = NG.ua.get();
	if (a.length < 3) cmp = '=';
	if (a.length > 0 && !isNull(eng) && ua.Engine != eng) return F;
	if (a.length > 1 && !isNull(engVer) && !NG.ua.cmp(ua.EngineVer, cmp, engVer)) return F;
	return T;
}

NG.ua.isApp = function (app, appVer, cmp) {
	var a = arguments, ua = NG.ua.get();
	if (a.length < 3) cmp = '=';
	if (a.length > 0 && !isNull(app) && !NG.ua.isCmp(app, ua.App)) return F;
	if (a.length > 1 && !isNull(appVer) && !NG.ua.cmp(ua.AppVer, cmp, appVer)) return F;
	return T;
}

NG.ua.isOS = function (os, osRel, osVer, arch, cmp) {
	var a = arguments, ua = NG.ua.get();
	if (a.length < 5) cmp = '=';
	if (a.length > 0 && !isNull(os) && ua.OS != os) return F;
	if (a.length > 1 && !isNull(osRel) && ua.OSRel != osRel) return F;
	if (a.length > 2 && !isNull(osVer) && !NG.ua.cmp(ua.osVer, cmp, osVer)) return F;
	if (a.length > 3 && !isNull(arch) && ua.Arch != arch) return F;
	return T;
}

NG.ua.is = function (eng, engVer, app, appVer, cmp) { return (NG.ua.isEng(eng,engVer,cmp) && NG.ua.isApp(app,appVer,cmp)); }

NG.ua.hasPlugin = function (name, ver) {
	//TODO Implement this
}

NG.popup = function () {
	NG.popup.open.apply(NG.popup, arguments);
	return false;
}

NG.popup.open = function (a) {
	if (!isDef(typeof a)) a = '/blank.php';
	if (!isStr(a)) a = a.href;
	if (!isObj(__G['popup'])) __G['popup'] = new Object();
	var g=arguments,s='',i,d,w,o=(g.length > 1 && isObj(g[g.length-1]) ? NG.cloneObj(g[g.length-1]) : new Object());
	if (g.length >= 2 && isInt(g[1])) o.width = g[1];
	if (g.length >= 3 && isInt(g[2])) o.height = g[2];
	d = {'width':600,'height':400,'toolbars':'no','scrollbars':'yes','resizable':'yes'};
	for (i in d) if (!isDef(typeof o[i])) o[i] = d[i];
	if (isDef(typeof o.position)) {
		switch (o.position) {
			case 'windowcentre':
			case 'windowcenter':
				o.left = Math.max(0,Math.round((screen.width/2)-(o.width/2)));
				o.top = Math.max(0,Math.round((screen.height/2)-(o.height/2)));
				break;
		}
		delete o.position;
	}
	if (isDef(typeof o.modal) && !NG.popup.isClosed(__G['popup']['modalWindow'])) return null;
	if (isDef(typeof o.modal)) o.dependant = N;
	if (isDef(typeof o.name)) {
		w = o.name;
		delete o.name;
	} else {
		w = a.replace(/[^a-zA-Z0-9_]/g, '');
	}
	if (isDef(typeof o.arg)) {
		if (!isObj(__G['popup']['args'])) __G['popup']['args'] = new Object();
		__G['popup']['args'][w] = o.arg;
		delete o.arg;
	}
	for (i in o) {
		if (isStr(o[i]) || isInt(o[i])) s += (s == '' ? '' : ',')+i+'='+o[i];
		else if (isNull(o[i])) s += (s == '' ? '' : ',')+i;
	}
	i = window.open(a, w, s);
	try { i.focus(); } catch (e) { return null; }
	if (isDef(typeof o.modal)) {
		__G['popup']['modalWindow'] = i;
		NG.popup.focusModal.install(window.top);
	}
	if (isDef(typeof o.dependant) && (o.dependant === true || o.dependant === 'yes')) {
		if (!isObj(__G['popup']['dependantWindows'])) __G['popup']['dependantWindows'] = new Object();
		__G['popup']['dependantWindows'][w] = i;
		NG.addEventListener(window, 'unload', NG.popup.closeDependant);
	}
	return i;
}

NG.unpopup = function (reload) {
	if (NG.popup.hasOpener()) {
		if (arguments.length == 0 || reload) window.opener.location.reload();
		window.opener.focus();
	}
	window.close();
}

NG.popup.isClosed = function (win) { return (!isObj(win) || win.closed); }
NG.popup.hasOpener = function () { return !NG.popup.isClosed(window.opener); }

NG.popup.getArg = function () {
	var o = window.opener;
	if (isObj(o.__G) && isObj(o.__G['popup']) && isObj(o.__G['popup']['args']) && isDef(typeof o.__G['popup']['args'][window.name])) {
		return o.__G['popup']['args'][window.name];
	}
	return N;
}

NG.popup.focusModal = function (e) {
	if (isObj(__G['popup']) && !NG.popup.isClosed(__G['popup']['modalWindow'])) {
		__G['popup']['modalWindow'].focus();
		NG.stopPropagation(e);
		return false;
	} else {
		NG.popup.focusModal.uninstall(window.top);
	}
}

NG.popup.focusModal.install = function (win) {
	NG.addEventListener(win, 'focus', NG.popup.focusModal);
	for (var i = 0; i < win.frames.length; i++) NG.popup.focusModal.install(win.frames[i]);
}

NG.popup.focusModal.uninstall = function (win) {
	NG.removeEventListener(win, 'focus', NG.popup.focusModal);
	for (var i = 0; i < win.frames.length; i++) NG.popup.focusModal.uninstall(win.frames[i]);
}

NG.popup.closeDependant = function () {
	if (!isObj(__G['popup']) || !isObj(__G['popup']['dependantWindows'])) return;
	var d = __G['popup']['dependantWindows'];
	for (var w in d) if (!NG.popup.isClosed(d[w])) d[w].close();
}

NG.heightToContent = function () {
	window.resizeBy(0, document.body.clientHeight-document.documentElement.clientHeight);
}

NG.addEventListener = function (node, eventName, func) {
	 if ((eventName == 'mousewheel') && (NG.ua.isEng('GECKO'))) {
		return NG.addEventListener(node, 'DOMMouseScroll', func);
	} else if (isFunc(node.addEventListener) && (eventName != 'dblclick' || !NG.ua.is('KHTML'))) {
		return node.addEventListener(eventName, func, F);
	} else if (isFunc(node.attachEvent)) {
		return node.attachEvent('on'+eventName, NG._msieE._addReg(node, eventName, func));
	} else {
		if (!isObj(node.NGEventListener)) node.NGEventListener = new Object();
		if (!isArr(node.NGEventListener[eventName])) node.NGEventListener[eventName] = new Array();
		node.NGEventListener[eventName][node.NGEventListener[eventName].length] = func;
		node['on'+eventName] = function (e) {
			if (!e) e = window.event;
			for (var i = 0; i < this.NGEventListener[eventName].length; i++) {
				var f = this.NGEventListener[eventName][i];
				f.call(this, e);
			}
		}
	}
}

NG._msieE = {}
NG._msieE._reg = [];
NG._msieE._addReg = function (node, eventName, func) {
	var f = function (e) { if (!e) e = window.event; func.apply(node, [e]); };
	NG._msieE._reg.push({nf:node, eventName:eventName, origFunc:func, newFunc:f});
	return f;
}

NG._msieE._delReg = function (node, eventName, func) {
	var r = NG._msieE._reg;
	for (var i = r.length-1; i >= 0; i--) {
		try {
			if (r[i].eventName == eventName && r[i].nf == node && r[i].origFunc == func) {
				var f = r[i].newFunc;
				delete r[i];
				r.splice(i, 1);
				return f;
			}
		} catch (e) {}
	}
	return function () {}
}

NG.removeEventListener = function (node, eventName, func) {
	if (isFunc(node.removeEventListener) && (eventName != 'dblclick' || !NG.ua.is('KHTML'))) {
		return node.removeEventListener(eventName, func, F);
	} else if (isFunc(node.detachEvent)) {
		return node.detachEvent('on'+eventName, NG._msieE._delReg(node, eventName, func));
	} else {
		if (isObj(node.NGEventListener) && isArr(node.NGEventListener[eventName])) {
			for (var i = 0; i < node.NGEventListener[eventName].length; i++) {
				if (node.NGEventListener[eventName][i] == func) {
					delete node.NGEventListener[eventName][i];
					return;
				}
			}
		}
	}
}

NG.stopPropagation = function (e) {
	if (!isObj(e) && isObj(window.event)) e = window.event;
	if (isObj(e)) {
		if (isDef(typeof e.stopPropagation) && isFunc(e.stopPropagation)) {
			e.stopPropagation();
		} else if (isDef(typeof e.cancelBubble)) {
			e.cancelBubble = T;
		} else if (isDef(typeof e.originalEvent) && isObj(e.originalEvent)) {
			NG.stopPropagation(e.originalEvent);
		}
	}
}

NG.preventDefault = function (e) {
	if (!isObj(e) && isObj(window.event)) e = window.event;
	if (isObj(e)) {
		if (isDef(typeof e.preventDefault) && isFunc(e.preventDefault)) {
			e.preventDefault();
		} else if ('returnValue' in e) {
			e.returnValue = F;
		} else if (isDef(typeof e.originalEvent) && isObj(e.originalEvent)) {
			return NG.preventDefault(e.originalEvent);
		}
	}
	return false;
}

NG.applyCallable = function (func, args) {
	if (arguments.length < 2) args = [];
	else if (!isArr(args)) args = [args];
	if (isFunc(func)) {
		return func.apply(window,args);
	} else if (isStr(func)) {
		return eval(func);
	} else if (isArr(func) && func.length == 2 && isObj(func[0]) && isStr(func[1]) && isFunc(func[0][func[1]])) {
		return func[0][func[1]].apply(func[0],args);
	}
}

NG.hitch = function (obj,method){
	return function(){
		method.apply(obj,arguments);
	}
}

if (NG.ua.isEng('MSIE')) {
	try {
		document.execCommand("BackgroundImageCache", false, true);
	} catch(err) {}
}
