function addLoadEvent(func) {
	var oldonload = window.onload;
	if (typeof window.onload != "function") {
		window.onload = func;
	}
	else {
		window.onload = function() {
			if (oldonload) { oldonload(); }
			func();
		}
	}
}

function buildElement(data) {
	if (isNode(data)) { return data; } // already a dom element
	if (typeof data == "string" || typeof data == "number") {
		return document.createTextNode(new String(data));
	}
	var tagName = data[0];
	var className, id;
	if (tagName.include(".")) {
		tagName = tagName.split(".");
		className = tagName[1];
		tagName = tagName[0];
	}
	else if (tagName.include("#")) {
		tagName = tagName.split("#");
		id = tagName[1];
		tagName = tagName[0];
	}
	var node = Element.extend(document.createElement(tagName));
	if (className) { node.className = className; }
	if (id) { node.id = id; }
	if (data[1]) {
		var attr = data[1];
		for (var i in attr) {
			if (i.startsWith("style.")) {
				node.style[i.substr(6)] = attr[i];
			}
			if (i.startsWith("store.")) {
				node.store(i.substr(6), attr[i]);
			}
			else {
				node[i] = attr[i];
			}
		}
		if (tagName.toLowerCase() == "a" && !node.href) { node.href = "#"; }
		for (var i = 2; i < data.length; i++) {
			if (data[i]) { node.appendChild(buildElement(data[i])); }
		}
	}
	return node;
}
function buildTable() {
	var table = buildElement(["table"]);
	for (var i = 0; i < arguments.length; i++) {
		var row = buildElement(["tr"]);
		for (var j = 0; j < arguments[i].length; j++) {
			row.appendChild(buildElement( ["td", {}, arguments[i][j]] ));
		}
		table.appendChild(row);
	}
	return table;
}

function getMouseCoords(e) {
	if (!e) { e = window.event; }
	if (e.pageX || e.pageY) {
		return [e.pageX, e.pageY];
	}
	if (e.clientX || e.clientY) {
		return [e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft,
		        e.clientY + document.body.scrollTop + document.documentElement.scrollTop];
	}
}

function isArray(obj) {
	return Object.prototype.toString.apply(obj) == "[object Array]";
}

function isNode(obj) { return Boolean(obj && obj.nodeType == 1); }

function now() { return (new Date()).getTime(); }

function log(msg) { try { window.console.log(msg); } catch (e) {} }

function toSet(list) {
	var result = {};
	for (var i = 0; i < list.length; i++) { result[list[i]] = true; }
	return result;
}

if (Object.extend) {
	/*Object.extend(Date.prototype, {
		strftime: function(format) {
			var day = this.getUTCDay(), month = this.getUTCMonth();
			var hours = this.getUTCHours(), minutes = this.getUTCMinutes();
			function pad(num) { return num.toPaddedString(2); };
			return format.gsub(/\%([aAbBcdDHiImMpSTwyY])/, function(part) {
				switch(part[1]) {
					case 'a': return $w("Sun Mon Tue Wed Thu Fri Sat")[day]; break;
					case 'A': return $w("Sunday Monday Tuesday Wednesday Thursday Friday Saturday")[day]; break;
					case 'b': return $w("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec")[month]; break;
					case 'B': return $w("January February March April May June July August September October November December")[month]; break;
					case 'c': return this.toString(); break;
					case 'd': return this.getUTCDate(); break;
					case 'D': return pad(this.getUTCDate()); break;
					case 'H': return pad(hours); break;
					case 'i': return (hours === 12 || hours === 0) ? 12 : (hours + 12) % 12; break;
					case 'I': return pad((hours === 12 || hours === 0) ? 12 : (hours + 12) % 12); break;
					case 'm': return pad(month + 1); break;
					case 'M': return pad(minutes); break;
					case 'p': return hours > 11 ? 'PM' : 'AM'; break;
					case 'S': return pad(this.getUTCSeconds()); break;
					case 'T': return pad(hours) + ":" + pad(minutes) + ":" + pad(this.getUTCSeconds()); break;
					case 'w': return day; break;
					case 'y': return pad(this.getUTCFullYear() % 100); break;
					case 'Y': return this.getUTCFullYear().toString(); break;
				}}.bind(this));
		}
	});*/
	Object.extend(Date.prototype, {
		strftime: function(format) {
			var day = this.getDay(), month = this.getMonth();
			var hours = this.getHours(), minutes = this.getMinutes();
			function pad(num) { return num.toPaddedString(2); };
			return format.gsub(/\%([aAbBcdDHIklmMpSTwyY])/, function(part) {
				switch(part[1]) {
					case 'a': return $w("Sun Mon Tue Wed Thu Fri Sat")[day];
					case 'A': return $w("Sunday Monday Tuesday Wednesday Thursday Friday Saturday")[day];
					case 'b': return $w("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec")[month];
					case 'B': return $w("January February March April May June July August September October November December")[month];
					case 'c': return this.toString();
					case 'd': return this.getDate();
					case 'D': return pad(this.getDate());
					case 'H': return pad(hours);
					case 'I': return pad((hours + 11) % 12 + 1);
					case 'k': return hours;
					case 'l': return (hours + 11) % 12 + 1;
					case 'm': return pad(month + 1);
					case 'M': return pad(minutes);
					case 'p': return hours > 11 ? 'PM' : 'AM';
					case 'S': return pad(this.getSeconds());
					case 'T': return pad(hours) + ":" + pad(minutes) + ":" + pad(this.getSeconds());
					case 'w': return day;
					case 'y': return pad(this.getFullYear() % 100);
					case 'Y': return this.getFullYear();
				}}.bind(this));
		}
	});

}

/*
function formatLoc(num) {
	var str = new String(Math.round(1000000 * num));
	while (str.length < 7) { str = "0" + str; }
	return str.substring(0, str.length - 6) + "." + str.substring(str.length - 6);
}

function getValue(node) {
	if (node.tagName.toLowerCase() == "input") { return node.value; }
	return node.innerHTML;
}
function setValue(node, value) {
	if (node.tagName.toLowerCase() == "input") { node.value = value; }
	else { node.innerHTML = value; }
}
*/
