function MyEvent(rawEvent) {
	this.ie = typeof(rawEvent.target)=="undefined";
	///This will come back to bite me. I needed codeChar/plainChar for
	///moz, because the value it returns in keycode will be
	///the same for the UP key and for '&' (for example).
	///To use it, then if (and only if) I'm looking for a code char,
	///check codeChar. Similarly, iff I'm looking for a plain char,
	///check plainChar. (IOW, don't check 'not plainChar' when looking for a codeChar)
	///because that will break IE. In IE, there's no possibility of overlap
	///in keycodes, so it doesn't matter.
	this.plainChar = true;
	this.codeChar = true;
	if (!this.ie) {
		this.target = (rawEvent.target.tagName ? rawEvent.target : rawEvent.target.parentNode);
		this.mouseButton = rawEvent.button+1;
		this.relatedTarget = rawEvent.relatedTarget;
		this.rawEvent = rawEvent;
		this.stopPropagation = function () { this.rawEvent.stopPropagation(); }
		this.preventDefault = function () { this.rawEvent.preventDefault(); }
		// preventBubble deprecated, try to remove all refs
		this.preventBubble = function () { this.rawEvent.stopPropagation(); }
		this.offsetX = function() { return this.left - getElLeft(this.target); }
		this.offsetY = function() { return this.top - getElTop(this.target); }
		this.left = parseInt(rawEvent.pageX);
		this.top = parseInt(rawEvent.pageY);
		if (rawEvent.keyCode) {
			this.keyCode = rawEvent.keyCode;
			switch (this.keyCode) {
				case 109: this.keyCode = 45; break;
				case 188: this.keyCode = 44; break;
				case 190: this.keyCode = 46; break;
				case 191: this.keyCode = 47; break;
				case 192: this.keyCode = 96; break;
				case 219: this.keyCode = 91; break;
				case 220: this.keyCode = 92; break;
				case 221: this.keyCode = 93; break;
				case 222: this.keyCode = 39; break;
			}
			this.plainChar = false;
		}
		else {
			this.keyCode = rawEvent.which;
			this.codeChar = false;
		}
	}
	else {
		this.srcElement = rawEvent.srcElement;
		this.target = rawEvent.srcElement;
		this.mouseButton = rawEvent.button;
		this.relatedTarget = rawEvent.toElement;
		this.rawEvent = rawEvent;
		this.stopPropagation = function () { this.rawEvent.cancelBubble = true; }
		this.preventDefault = function () { this.rawEvent.returnValue = false; }
		// preventBubble deprecated
		this.preventBubble = function () { this.rawEvent.cancelBubble = true; }
		this.offsetX = function() { return this.rawEvent.offsetX; }
		this.offsetY = function() { return this.rawEvent.offsetY; }
		this.keyCode = rawEvent.keyCode;
		if (this.keyCode && (rawEvent.type == "keydown" || rawEvent.type == "keyup")) {
			switch (this.keyCode) {
				case 109: this.keyCode = 45; break;
				case 188: this.keyCode = 44; break;
				case 190: this.keyCode = 46; break;
				case 191: this.keyCode = 47; break;
				case 192: this.keyCode = 96; break;
				case 220: this.keyCode = 92; break;
				case 222: this.keyCode = 39; break;
			}
		}
		var sl, st;
		if (document.documentElement) {
			sl = document.documentElement.scrollLeft;
			st = document.documentElement.scrollTop;
		}
		else {
			sl = document.body.scrollLeft;
			st = document.body.scrollTop;
		}
		this.left = sl+rawEvent.clientX;
		this.top = st+rawEvent.clientY;
		//this.left = rawEvent.offsetX;
		//this.top = rawEvent.offsetY;
	}
	this.clientX = rawEvent.clientX;
	this.clientY = rawEvent.clientY;
	this.ctrlKey = rawEvent.ctrlKey;
	this.shiftKey = rawEvent.shiftKey;
	this.altKey = rawEvent.altKey;
	this.adjusted = true;
}

function getEventObject(rawEvent) {
	if (typeof(rawEvent)=="undefined") {
		rawEvent = window.event;
	}
	if (rawEvent.adjusted) { return rawEvent; }
	if (!rawEvent) { rawEvent = window.event; }
	var evt = new MyEvent(rawEvent);
	return evt;
}

var geo = getEventObject;

function setElEvent(el, eventName, eventStr) {
	eval("function x(){"+eventStr+"}");
	el.setAttribute('on'+eventName, eventStr);
	el["on"+eventName] = x;
}

/***
el: either id of element as string, or element itself
name: string name of event, without 'on' prefix
funcName: string name of function
bubble: (bool) whether event bubbles up
*/
function setEventListener(el, eventName, funcName, bubble) {
	if (typeof(el)=="string") {
		el = document.getElementById(el);
	}
	if (el.addEventListener) {
		el.addEventListener(eventName, eval(funcName), bubble);
	}
	else {
		str = "el.on"+eventName+" = function () { evt = getEventObject(event);\n";
		str += funcName+ "(evt);\n";
		if (!bubble) {
			str += "event.cancelBubble = true;\n";
		}
		str += "return "+(!bubble)+";\n";
		str += "}";
		eval(str);
	}
}

function setEventObjectListener(el, eventName, objName, funcName, bubble) {
	var mglName = objName+"__"+funcName;
	eval(mglName +' = function(evt) { \
		'+objName+'.'+funcName+'(evt); \
	}');
	setEventListener(el, eventName, mglName, bubble);
}


if (typeof(onloads)=="undefined") {
	onloads = [];
}

function onloadAll(event) {
	event = geo(event);
	for (var i=0; i<onloads.length; i++) {
		onloads[i](event);
	}
}

function addEvent(obj, type, fn) {
	if (obj.addEventListener) {
		obj.addEventListener(type, fn, false);
	}
	else if (obj.attachEvent) {
		obj.attachEvent("on"+type, fn);
	}
}

function removeEvent(obj, type, fn) {
	if (obj.removeEventListener) {
		obj.removeEventListener(type, fn, false);
	}
	else if (obj.detachEvent) {
		obj.detachEvent("on"+type, fn);
	}
}
