if ( ! Function.prototype.bind ) {
	Function.prototype.bind = function( object ) {
		var __method = this;
		return function() {
			__method.apply( object, arguments );
		};
	};
}

function clone(obj) {
	if (typeof(obj) == 'object') {
		if (obj == null) return null;
		else if (obj instanceof Array) var ret = new Array();
		else var ret = new Object();

		for (var i in obj) {
			switch (typeof(obj[i])) {	
			case 'object':	ret[i] = clone(obj[i]); break;
			//case 'string': case 'number': case 'boolean': case 'function':
			default:		ret[i] = obj[i]; break;
			}
		}
		return ret;
	} else return obj;
}

function extend(original, extension) {
	var ret = clone(original);
	for(var i in extension) ret[i] = extension[i];
	return ret;
}

if (!window.htmlspecialchars) htmlspecialchars = function(input) {
	return input.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
};

if (!window.attachEvent) window.attachEvent = function(e,f) {
	if (window.addEventListener) window.addEventListener(e.substring(2), f, false);
	else window.setTimeout(f, 500);
}

function obj2url(obj) {
	var arr = [];
	for(var i in obj) {
		arr.push(encodeURIComponent(i) + '=' + encodeURIComponent(obj[i]));
	}
	return arr.join('&');
}
function isEmpty(o) {
	var i, v;
	var tO = typeOf(o);
	if (tO === 'object' || tO === 'array') for (i in o) {
		v = o[i];
		if (v !== undefined && typeOf(v) !== 'function') return false;
	}
	return true;
}
function typeOf(value) {
    var s = typeof value;
    if (s === 'object') {
        if (value) {
            if (typeof value.length === 'number' &&
                    !(value.propertyIsEnumerable('length')) &&
                    typeof value.splice === 'function') {
                s = 'array';
            }
        } else {
            s = 'null';
        }
    }
    return s;
}

// this is modified from the prototype library
if (!window.$) {
	var $ = function(element) {
		if (arguments.length > 1) {
			for (var i = 0, elements = [], length = arguments.length; i < length; i++) elements.push($(arguments[i]));
			return elements;
		}
		if (typeof element == 'string') element = document.getElementById(element);
		return element;
	}
}
// this is lifted from the prototype library
var Try = {
	these: function() {
		var returnValue;

		for (var i = 0; i < arguments.length; i++) {
			var lambda = arguments[i];
			try {
				returnValue = lambda();
				break;
			} catch (e) {}
		}

		return returnValue;
	}
}

function ajax_show_busy(indicator) {
	var busy = document.getElementById(indicator);
	if (!busy) {
		var body = document.getElementsByTagName('body')[0];
		if (!body) return;
		busy = document.createElement('div');
		busy.id = 'ajax_busy';
		busy.innerHTML = 'Updating...';
		body.appendChild(busy);
	}
	busy.style.visibility = 'visible';
	busy.className = 'active';
}
function ajax_hide_busy(indicator) {
	var busy = document.getElementById(indicator);
	if (busy) {
		busy.style.visibility = 'hidden';
		busy.className = 'inactive';
	}
}


function ajax_new_xhr() {
	return Try.these(
		function() {return new ActiveXObject('Msxml2.XMLHTTP')},
		function() {return new ActiveXObject('Microsoft.XMLHTTP')},
		function() {return new XMLHttpRequest()}
	) || false;
}

function ajax_handle(xhr, handler) {
	return Try.these(
		function() { xhr.onreadystatechange=handler; return true; },
		function() { xhr.onload=handler; xhr.onerror=handler; return true; }
	) || false;
}

function GetXmlHttpObject(handler) { 
	var xhr = ajax_new_xhr();
	if (!xhr || !ajax_handle(xhr, handler)) {
		alert ("Parts of this page will not work in this browser.");
		return;
	} else return xhr;
} 

var xmlHttp;

var hideAjaxStatus;
function Ask(url, options) {
	this.xhr = ajax_new_xhr();
	if (!this.xhr) {
		alert ("Parts of this page will not work in this browser.");
		return;
	}
	if (options && options.handler) {
		this.async = true;
		this.action = options.handler;
		if (!ajax_handle(this.xhr, this.respond.bind(this))) {
			alert ("Parts of this page will not work in this browser.");
			return;
		}
	} else this.async = false;
	if (options && options.indicator) this.indicator = options.indicator;
	else this.indicator = 'ajax_busy';
	this.busy = true;
	if (!hideAjaxStatus) ajax_show_busy(this.indicator);
	if (options && options.postdata) {
		this.xhr.open('POST', url, this.async);
		this.xhr.setRequestHeader('Content-Type', (options.enctype? options.enctype : 'application/x-www-form-urlencoded'));
		this.xhr.send(options.postdata);
	} else {
		this.xhr.open('GET', url, this.async);
		this.xhr.send(null);
	}
}
Ask.prototype.respond = function() {
	if (this.xhr.readyState==4 || this.xhr.readyState=='complete') {
		this.action(this.xhr);
		this.busy = false;
		if (!hideAjaxStatus) ajax_hide_busy(this.indicator);
	}
};

// execute JS in a certain node
var bSaf = (navigator.userAgent.indexOf('Safari') != -1);
var bOpera = (navigator.userAgent.indexOf('Opera') != -1);
var bMoz = (navigator.appName == 'Netscape');
function execJS(node, debug) {
	var st = node.getElementsByTagName('SCRIPT');
	var strExec;
	for(var i=0;i<st.length; i++) {     
		if (bSaf) strExec = st[i].innerHTML;
		else if (bOpera) strExec = st[i].text;
		else if (bMoz) strExec = st[i].textContent;
		else strExec = st[i].text;
		try {
			eval(strExec.split("<!--").join("").split("-->").join(""));
		} catch(e) {
			if (debug) alert(e);
		}
	}
}
