// $Id: site.js,v 1.6 2010-05-10 17:52:51 cmanley Exp $


// Determines if given argument is an array.
function isArray(o) {
	return (typeof(o) == 'object') && (String(o.constructor) == String(Array));
}


// xGetElementById, Copyright 2001-2007 Michael Foster (Cross-Browser.com)
// Part of X, a Cross-Browser Javascript Library, Distributed under the terms of the GNU LGPL
function xGetElementById(e) {
	if(typeof(e)=='string') {
		if(document.getElementById) e=document.getElementById(e);
		else if(document.all) e=document.all[e];
		else e=null;
	}
	return e;
}


// xGetElementsByTagName r5, Copyright 2002-2007 Michael Foster (Cross-Browser.com)
// Part of X, a Cross-Browser Javascript Library, Distributed under the terms of the GNU LGPL
function xGetElementsByTagName(t,p) {
	var list = null;
	t = t || '*';
	p = xGetElementById(p) || document;
	if (typeof p.getElementsByTagName != 'undefined') { // DOM1
		list = p.getElementsByTagName(t);
		if (t=='*' && (!list || !list.length)) list = p.all; // IE5 '*' bug
	}
	else { // IE4 object model
		if (t=='*') list = p.all;
		else if (p.all && p.all.tags) list = p.all.tags(t);
	}
	return list || [];
}


// xGetElementsByClassName(sClsName, oParentEle, sTagName, fnCallback) r5, Copyright 2002-2007 Michael Foster (Cross-Browser.com)
// Part of X, a Cross-Browser Javascript Library, Distributed under the terms of the GNU LGPL
function xGetElementsByClassName(c,p,t,f) {
	var r = new Array();
	var re = new RegExp("(^|\\s)"+c+"(\\s|$)");
	//var e = p.getElementsByTagName(t);
	var e = xGetElementsByTagName(t,p); // See xml comments.
	for (var i = 0; i < e.length; ++i) {
		if (re.test(e[i].className)) {
			r[r.length] = e[i];
			if (f) f(e[i]);
		}
	}
	return r;
}


// xAddEventListener, Copyright 2001-2007 Michael Foster (Cross-Browser.com)
// Part of X, a Cross-Browser Javascript Library, Distributed under the terms of the GNU LGPL
// http://cross-browser.com/x/lib/view.php?sym=xAddEventListener
// Modified by Craig Manley to accept arrays of event names.
// Modified by Craig Manley to support stacked on* events in old browsers.
function xAddEventListener(e,eT,eL,cap) {
	if ((typeof(eT) == 'object') && (eT.constructor.toString().indexOf('function Array()') != -1)) {
		for (var i=0; i<eT.length; i++) {
			xAddEventListener(e,eT[i],eL,cap);
		}
	}
	else {
		if(!(e=xGetElementById(e)))return;
		eT=eT.toLowerCase();
		if(e.addEventListener)e.addEventListener(eT,eL,cap||false);
		else if(e.attachEvent)e.attachEvent('on'+eT,eL);
		//else e['on'+eT]=eL;
		else {
			if (e['on'+eT]) {
				var f = e['on'+eT];
				e['on'+eT] = function() {
					f();
					eL();
				}
			}
			else {
				e['on'+eT]=eL;
			}
		}
	}
}


// xCamelize r1, Copyright 2007 Michael Foster (Cross-Browser.com)
// Part of X, a Cross-Browser Javascript Library, Distributed under the terms of the GNU LGPL
function xCamelize(cssPropStr) {
	var i, c, a = cssPropStr.split('-');
	var s = a[0];
	for (i=1; i<a.length; ++i) {
		c = a[i].charAt(0);
		s += a[i].replace(c, c.toUpperCase());
	}
	return s;
}


// xGetComputedStyle r7, Copyright 2002-2007 Michael Foster (Cross-Browser.com)
// Part of X, a Cross-Browser Javascript Library, Distributed under the terms of the GNU LGPL
function xGetComputedStyle(e, p, i) {
	if(!(e=xGetElementById(e))) return null;
	var s, v = 'undefined', dv = document.defaultView;
	if(dv && dv.getComputedStyle){
		s = dv.getComputedStyle(e,'');
		if (s) v = s.getPropertyValue(p);
	}
	else if(e.currentStyle) {
		v = e.currentStyle[xCamelize(p)];
	}
	else return null;
	return i ? (parseInt(v) || 0) : v;
}


// xDef r1, Copyright 2001-2007 Michael Foster (Cross-Browser.com)
// Part of X, a Cross-Browser Javascript Library, Distributed under the terms of the GNU LGPL
function xDef() {
	for(var i=0; i<arguments.length; ++i){if(typeof(arguments[i])=='undefined') return false;}
	return true;
}


// xStr r1, Copyright 2001-2007 Michael Foster (Cross-Browser.com)
// Part of X, a Cross-Browser Javascript Library, Distributed under the terms of the GNU LGPL
function xStr(s) {
	for(var i=0; i<arguments.length; ++i){if(typeof(arguments[i])!='string') return false;}
	return true;
}


// xNum r2, Copyright 2001-2007 Michael Foster (Cross-Browser.com)
// Part of X, a Cross-Browser Javascript Library, Distributed under the terms of the GNU LGPL
function xNum() {
	for(var i=0; i<arguments.length; ++i){if(isNaN(arguments[i]) || typeof(arguments[i])!='number') return false;}
	return true;
}


// xLeft r2, Copyright 2001-2007 Michael Foster (Cross-Browser.com)
// Part of X, a Cross-Browser Javascript Library, Distributed under the terms of the GNU LGPL
function xLeft(e, iX) {
	if(!(e=xGetElementById(e))) return 0;
	var css=xDef(e.style);
	if (css && xStr(e.style.left)) {
		if(xNum(iX)) e.style.left=iX+'px';
		else {
			iX=parseInt(e.style.left);
			if(isNaN(iX)) iX=xGetComputedStyle(e,'left',1);
			if(isNaN(iX)) iX=0;
		}
	}
	else if(css && xDef(e.style.pixelLeft)) {
		if(xNum(iX)) e.style.pixelLeft=iX;
		else iX=e.style.pixelLeft;
	}
	return iX;
}


// xTop r2, Copyright 2001-2007 Michael Foster (Cross-Browser.com)
// Part of X, a Cross-Browser Javascript Library, Distributed under the terms of the GNU LGPL
function xTop(e, iY) {
	if(!(e=xGetElementById(e))) return 0;
	var css=xDef(e.style);
	if(css && xStr(e.style.top)) {
		if(xNum(iY)) e.style.top=iY+'px';
		else {
			iY=parseInt(e.style.top);
			if(isNaN(iY)) iY=xGetComputedStyle(e,'top',1);
			if(isNaN(iY)) iY=0;
		}
	}
	else if(css && xDef(e.style.pixelTop)) {
		if(xNum(iY)) e.style.pixelTop=iY;
		else iY=e.style.pixelTop;
	}
	return iY;
}


// xWidth r6, Copyright 2001-2007 Michael Foster (Cross-Browser.com)
// Part of X, a Cross-Browser Javascript Library, Distributed under the terms of the GNU LGPL
function xWidth(e,w) {
	if(!(e=xGetElementById(e))) return 0;
	if (xNum(w)) {
		if (w<0) w = 0;
		else w=Math.round(w);
	}
	else w=-1;
	var css=xDef(e.style);
	if (e == document || e.tagName.toLowerCase() == 'html' || e.tagName.toLowerCase() == 'body') {
		w = xClientWidth();
	}
	else if(css && xDef(e.offsetWidth) && xStr(e.style.width)) {
		if(w>=0) {
			var pl=0,pr=0,bl=0,br=0;
			if (document.compatMode=='CSS1Compat') {
				var gcs = xGetComputedStyle;
				pl=gcs(e,'padding-left',1);
				if (pl !== null) {
					pr=gcs(e,'padding-right',1);
					bl=gcs(e,'border-left-width',1);
					br=gcs(e,'border-right-width',1);
				}
				// Should we try this as a last resort?
				// At this point getComputedStyle and currentStyle do not exist.
				else if(xDef(e.offsetWidth,e.style.width)){
					e.style.width=w+'px';
					pl=e.offsetWidth-w;
				}
			}
			w-=(pl+pr+bl+br);
			if(isNaN(w)||w<0) return;
			else e.style.width=w+'px';
		}
		w=e.offsetWidth;
	}
	else if(css && xDef(e.style.pixelWidth)) {
		if(w>=0) e.style.pixelWidth=w;
		w=e.style.pixelWidth;
	}
	return w;
}


// xHeight r6, Copyright 2001-2007 Michael Foster (Cross-Browser.com)
// Part of X, a Cross-Browser Javascript Library, Distributed under the terms of the GNU LGPL
function xHeight(e,h) {
	if(!(e=xGetElementById(e))) return 0;
	if (xNum(h)) {
		if (h<0) h = 0;
		else h=Math.round(h);
	}
	else h=-1;
	var css=xDef(e.style);
	if (e == document || e.tagName.toLowerCase() == 'html' || e.tagName.toLowerCase() == 'body') {
		h = xClientHeight();
	}
	else if(css && xDef(e.offsetHeight) && xStr(e.style.height)) {
		if(h>=0) {
			var pt=0,pb=0,bt=0,bb=0;
			if (document.compatMode=='CSS1Compat') {
				var gcs = xGetComputedStyle;
				pt=gcs(e,'padding-top',1);
				if (pt !== null) {
					pb=gcs(e,'padding-bottom',1);
					bt=gcs(e,'border-top-width',1);
					bb=gcs(e,'border-bottom-width',1);
				}
				// Should we try this as a last resort?
				// At this point getComputedStyle and currentStyle do not exist.
				else if(xDef(e.offsetHeight,e.style.height)){
					e.style.height=h+'px';
					pt=e.offsetHeight-h;
				}
			}
			h-=(pt+pb+bt+bb);
			if(isNaN(h)||h<0) return;
			else e.style.height=h+'px';
		}
		h=e.offsetHeight;
	}
	else if(css && xDef(e.style.pixelHeight)) {
		if(h>=0) e.style.pixelHeight=h;
		h=e.style.pixelHeight;
	}
	return h;
}


// xPageX r2, Copyright 2001-2007 Michael Foster (Cross-Browser.com)
// Part of X, a Cross-Browser Javascript Library, Distributed under the terms of the GNU LGPL
function xPageX(e) {
	var x = 0;
	e = xGetElementById(e);
	while (e) {
		if (xDef(e.offsetLeft)) x += e.offsetLeft;
		e = xDef(e.offsetParent) ? e.offsetParent : null;
	}
	return x;
}


// xPageY r4, Copyright 2001-2007 Michael Foster (Cross-Browser.com)
// Part of X, a Cross-Browser Javascript Library, Distributed under the terms of the GNU LGPL
function xPageY(e) {
	var y = 0;
	e = xGetElementById(e);
	while (e) {
		if (xDef(e.offsetTop)) y += e.offsetTop;
		e = xDef(e.offsetParent) ? e.offsetParent : null;
	}
	return y;
}


// xDocSize r1, Copyright 2007 Michael Foster (Cross-Browser.com)
// Part of X, a Cross-Browser Javascript Library, Distributed under the terms of the GNU LGPL
function xDocSize() {
	var b=document.body, e=document.documentElement;
	var esw=0, eow=0, bsw=0, bow=0, esh=0, eoh=0, bsh=0, boh=0;
	if (e) {
		esw = e.scrollWidth;
		eow = e.offsetWidth;
		esh = e.scrollHeight;
		eoh = e.offsetHeight;
	}
	if (b) {
		bsw = b.scrollWidth;
		bow = b.offsetWidth;
		bsh = b.scrollHeight;
		boh = b.offsetHeight;
	}
	// alert('compatMode: ' + document.compatMode + '\n\ndocumentElement.scrollHeight: ' + esh + '\ndocumentElement.offsetHeight: ' + eoh + '\nbody.scrollHeight: ' + bsh + '\nbody.offsetHeight: ' + boh + '\n\ndocumentElement.scrollWidth: ' + esw + '\ndocumentElement.offsetWidth: ' + eow + '\nbody.scrollWidth: ' + bsw + '\nbody.offsetWidth: ' + bow);
	return {w:Math.max(esw,eow,bsw,bow),h:Math.max(esh,eoh,bsh,boh)};
}


// xClientHeight r5, Copyright 2001-2007 Michael Foster (Cross-Browser.com)
// Part of X, a Cross-Browser Javascript Library, Distributed under the terms of the GNU LGPL
// Patched to work with Opera 9.50 by Craig Manley 2008-06-16
function xClientHeight() {
	var v=0,d=document,w=window;
	if((!d.compatMode || d.compatMode == 'CSS1Compat') && !(w.opera && (!w.opera.version || parseFloat(w.opera.version()) < 9.5)) && d.documentElement && d.documentElement.clientHeight)
		{v=d.documentElement.clientHeight;}
	else if(d.body && d.body.clientHeight)
		{v=d.body.clientHeight;}
	else if(xDef(w.innerWidth,w.innerHeight,d.width)) {
		v=w.innerHeight;
		if(d.width>w.innerWidth) v-=16;
	}
	return v;
}


// xClientWidth r5, Copyright 2001-2007 Michael Foster (Cross-Browser.com)
// Part of X, a Cross-Browser Javascript Library, Distributed under the terms of the GNU LGPL
function xClientWidth() {
	var v=0,d=document,w=window;
	if((!d.compatMode || d.compatMode == 'CSS1Compat') && !w.opera && d.documentElement && d.documentElement.clientWidth)
		{v=d.documentElement.clientWidth;}
	else if(d.body && d.body.clientWidth)
		{v=d.body.clientWidth;}
	else if(xDef(w.innerWidth,w.innerHeight,d.height)) {
		v=w.innerWidth;
		if(d.height>w.innerHeight) v-=16;
	}
	return v;
}


// xSmartLoad r1, Copyright 2007 Chris Nelson, based on xSmartLoadScript by Brendan Richards
// Part of X, a Cross-Browser Javascript Library, Distributed under the terms of the GNU LGPL
function xSmartLoad(what, url) {
	var loadedBefore = false;
	var s;
	for (var i=0; i<xSmartLoad.list.length; i++) {
		if (xSmartLoad.list[i].url == url) {
			loadedBefore = true;
			s = xSmartLoad.list[i].node;
			break;
		}
	}
	if (document.createElement && document.getElementsByTagName && !loadedBefore) {
		s = document.createElement(what);
		var h = document.getElementsByTagName('head');
		if (s && h.length) {
			switch (what.toUpperCase()) {
			case 'SCRIPT':
				s.src = url;
				break;
			case 'LINK':
				s.rel = 'stylesheet';
				s.type = 'text/css';
				s.href = url;
				break;
			default:
				s = null;
				break;
			}
			h[0].appendChild(s);
			xSmartLoad.list[xSmartLoad.list.length] = {url:url, node:s};
		}
	}
	return s;
}
xSmartLoad.list = []; // static property of xSmartLoad


// xOpacity r1, Copyright 2006-2007 Michael Foster (Cross-Browser.com)
// Part of X, a Cross-Browser Javascript Library, Distributed under the terms of the GNU LGPL
function xOpacity(e, o) {
	var set = xDef(o);
	//	if (set && o == 1) o = .9999; // FF1.0.2 but not needed in 1.5
	if(!(e=xGetElementById(e))) return 2; // error
	if (xStr(e.style.opacity)) { // CSS3
		if (set) e.style.opacity = o + '';
		else o = parseFloat(e.style.opacity);
	}
	else if (xStr(e.style.filter)) { // IE5.5+
		if (set) e.style.filter = 'alpha(opacity=' + (100 * o) + ')';
		else if (e.filters && e.filters.alpha) { o = e.filters.alpha.opacity / 100; }
	}
	else if (xStr(e.style.MozOpacity)) { // Gecko before CSS3 support
		if (set) e.style.MozOpacity = o + '';
		else o = parseFloat(e.style.MozOpacity);
	}
	else if (xStr(e.style.KhtmlOpacity)) { // Konquerer and Safari
		if (set) e.style.KhtmlOpacity = o + '';
		else o = parseFloat(e.style.KhtmlOpacity);
	}
	return isNaN(o) ? 1 : o; // if NaN, should this return an error instead of 1?
}


// xAniOpacity r1, Copyright 2006-2007 Michael Foster (Cross-Browser.com)
// Part of X, a Cross-Browser Javascript Library, Distributed under the terms of the GNU LGPL
function xAniOpacity(e, o, t, a, oe) {
	if (!(e=xGetElementById(e))) return;
	var o0 = xOpacity(e); // start value
	var dx = o - o0; // displacement
	var fq = 1 / t; // frequency
	if (a) fq *= (Math.PI / 2);
	var t0 = new Date().getTime(); // start time
	var tmr = setInterval(
		function() {
			var et = new Date().getTime() - t0; // elapsed time
			if (et < t) {
				var f = et * fq; // constant velocity
				if (a == 1) f = Math.sin(f); // sine acceleration
				else if (a == 2) f = 1 - Math.cos(f); // cosine acceleration
				f = Math.abs(f);
				xOpacity(e, f * dx + o0); // instantaneous value
			}
			else {
				clearInterval(tmr);
				xOpacity(e, o); // target value
				if (typeof oe == 'function') oe(); // 'onEnd' handler
				else if (typeof oe == 'string') eval(oe);
			}
		}, 10 // timer resolution
	);
}


// xHasClass r3, Copyright 2005-2007 Daniel Frechette - modified by Mike Foster
// Part of X, a Cross-Browser Javascript Library, Distributed under the terms of the GNU LGPL
function xHasClass(e, c) {
	e = xGetElementById(e);
	if (!e || e.className=='') return false;
	var re = new RegExp("(^|\\s)"+c+"(\\s|$)");
	return re.test(e.className);
}


// xAddClass r3, Copyright 2005-2007 Daniel Frechette - modified by Mike Foster
// Part of X, a Cross-Browser Javascript Library, Distributed under the terms of the GNU LGPL
function xAddClass(e, c) {
	if ((e=xGetElementById(e))!=null) {
		var s = '';
		if (e.className.length && e.className.charAt(e.className.length - 1) != ' ') {
			s = ' ';
		}
		if (!xHasClass(e, c)) {
			e.className += s + c;
			return true;
		}
	}
	return false;
}


// xRemoveClass r3, Copyright 2005-2007 Daniel Frechette - modified by Mike Foster
// Part of X, a Cross-Browser Javascript Library, Distributed under the terms of the GNU LGPL
function xRemoveClass(e, c) {
	if(!(e=xGetElementById(e))) return false;
	e.className = e.className.replace(new RegExp("(^|\\s)"+c+"(\\s|$)",'g'),
		function(str, p1, p2) { return (p1 == ' ' && p2 == ' ') ? ' ' : ''; }
	);
	return true;
}


// xDisplay r3, Copyright 2003-2007 Michael Foster (Cross-Browser.com)
// Part of X, a Cross-Browser Javascript Library, Distributed under the terms of the GNU LGPL
function xDisplay(e,s) {
	if ((e=xGetElementById(e)) && e.style && xDef(e.style.display)) {
		if (xStr(s)) {
			try { e.style.display = s; }
			catch (ex) { e.style.display = ''; } // Will this make IE use a default value appropriate for the element?
		}
		return e.style.display;
	}
	return null;
}


// xVisibility r1, Copyright 2003-2007 Michael Foster (Cross-Browser.com)
// Part of X, a Cross-Browser Javascript Library, Distributed under the terms of the GNU LGPL
function xVisibility(e, bShow) {
	if(!(e=xGetElementById(e))) return null;
	if(e.style && xDef(e.style.visibility)) {
		if (xDef(bShow)) e.style.visibility = bShow ? 'visible' : 'hidden';
		return e.style.visibility;
	}
	return null;
}



// Extend some core classes.
if (!String.prototype.toHtml) {
	String.prototype.toHtml = function() {
		return this.replace(/[&<>]/g, function(c) { if (c == '&') return '&amp;'; if (c == '<') return '&lt;'; if (c == '>') return '&gt;'; });
	}
}
if (!String.prototype.trim) {
	String.prototype.trim = function() {
		return this.replace(/(^\s+|\s$)/g, '');
	}
}
if (!String.prototype.nl2br) {
	String.prototype.nl2br = function() {
		return this.replace(/\r?\n/g, '<br/>');
	}
}
if (!Date.prototype.getUnixTime) {
	Date.prototype.getUnixTime = function() {
		return Math.floor(this.valueOf() / 1000);
	}
}
String.prototype.zf = function(l) { return '0'.string(l - this.length) + this; }
String.prototype.string = function(l) { var s = '', i = 0; while (i++ < l) { s += this; } return s; }
Number.prototype.zf = function(l) { return this.toString().zf(l); }
Date.prototype.format = function(f) {
	if (!this.valueOf()) {
		return ' ';
	}
	var d = this;
	return f.replace(/(yyyy|mm|dd|hh|nn|ss)/gi,
		function($1) {
			switch ($1.toLowerCase()) {
				case 'yyyy': return d.getFullYear();
				//case 'mmmm': return gsMonthNames[d.getMonth()];
				//case 'mmm':  return gsMonthNames[d.getMonth()].substr(0,3);
				case 'mm':   return (d.getMonth() + 1).zf(2);
				//case 'dddd': return gsDayNames[d.getDay()];
				//case 'ddd':  return gsDayNames[d.getDay()].substr(0, 3);
				case 'dd':   return d.getDate().zf(2);
				case 'hh':   return ((h = d.getHours() % 12) ? h : 12).zf(2);
				case 'nn':   return d.getMinutes().zf(2);
				case 'ss':   return d.getSeconds().zf(2);
			}
		}
	);
}
Date.prototype.isWeekDay = function() {
	var d = this.getDay();
	return (d != 0) && (d != 6);
}


// http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:map
if (!Array.prototype.map) {
	Array.prototype.map = function(fun /*, thisp*/) {
		var len = this.length;
		if (typeof fun != "function") {
			throw new TypeError();
		}
		var res = new Array(len);
		var thisp = arguments[1];
		for (var i = 0; i < len; i++) {
			if (i in this) {
				res[i] = fun.call(thisp, this[i], i, this);
			}
		}
		return res;
	};
}

if (!Array.prototype.grep) {
	Array.prototype.grep = function(fun /*, thisp*/) {
		var len = this.length;
		if (typeof fun != "function") { // TODO: add support for RegExp too.
			throw new TypeError();
		}
		var res = new Array();
		var thisp = arguments[1];
		for (var i = 0; i < len; i++) {
			if (i in this) {
				if (fun.call(thisp, this[i])) {
					res.push(this[i]);
				}
			}
		}
		return res;
	};
}

// http://www.schuerig.de/michael/javascript/
if (!Array.prototype.equals) {
	Array.prototype.equals = function(other) {
		if (!other) {
			return false;
		}
		var len = this.length;
		if (len != other.length) {
			return false;
		}
		for (var i = 0; i < len; i++) {
			if (this[i] != other[i]) {
				return false;
			}
		}
		return true;
	};
}

// From http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:indexOf
if (!Array.prototype.indexOf) {
	Array.prototype.indexOf = function(elt /*, from*/) {
		var len = this.length;
		var from = Number(arguments[1]) || 0;
		from = (from < 0) ? Math.ceil(from) : Math.floor(from);
		if (from < 0)
			from += len;
		for (; from < len; from++) {
			if (from in this &&	this[from] === elt)
				return from;
		}
		return -1;
	};
}

// Based on http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:indexOf
if (!Array.prototype.indexOfNoCase) {
	Array.prototype.indexOfNoCase = function(elt /*, from*/) {
		var len = this.length;
		var from = Number(arguments[1]) || 0;
		if (typeof(elt) != 'string') {
			return this.indexOf(elt, from);
		}
		elt = elt.toLowerCase();
		from = (from < 0) ? Math.ceil(from) : Math.floor(from);
		if (from < 0) {
			from += len;
		}
		for (; from < len; from++) {
			if (!(from in this)) {
				continue;
			}
			var x = typeof(this[from]) == 'string' ? this[from].toLowerCase() : this[from];
			if (x == elt) {
				return from;
			}
		}
		return -1;
	};
}

// http://4umi.com/web/javascript/array.php#unique
// Array.unique( strict ) - Remove duplicate values
if (!Array.prototype.unique) {
	Array.prototype.unique = function(b) {
		var a = [], i, l = this.length;
		for (i=0; i<l; i++) {
			if (a.indexOf(this[i], 0, b) < 0) {
				a.push(this[i]);
			}
		}
		return a;
	}
};

if (!Array.prototype.uniqueNoCase) {
	Array.prototype.uniqueNoCase = function(b) {
		var a = [], i, l = this.length;
		for (i=0; i<l; i++) {
			if (a.indexOfNoCase(this[i], 0, b) < 0) {
				a.push(this[i]);
			}
		}
		return a;
	}
};

if (!Array.prototype.isUnique) {
	Array.prototype.isUnique = function() {
		return this.unique().equals(this);
	}
};

if (!Array.prototype.isUniqueNoCase) {
	Array.prototype.isUniqueNoCase = function() {
		var lc = function(s) { return typeof(s) == 'string' ? s.toLowerCase() : s; };
		var a = this.map(lc);
		var b = a.slice();
		return a.unique().length == b.length;
	}
};






// DOM functions.
function domNodeTextValue(n) {
	if (n.nodeType == 3) { // text node
		return n.nodeValue;
	}
	var result = '';
	if (n.hasChildNodes()) {
		var nodes = n.childNodes;
		for (var i = 0; i < nodes.length; i++) {
			result += domNodeTextValue(nodes[i]);
		}
	}
	return result;
}


function domGetFirstAncestorByTagName(e, tag) {
	tag = tag.toLowerCase();
	while (e.parentNode) {
		e = e.parentNode;
		if (e.nodeName && e.nodeName.toLowerCase() == tag) {
			return e;
		}
	}
	return null;
}


function domGetLabelFor(x /*, labels */) { // element or id
	var id = typeof(x) == 'string' ? x : x.id;
	if (id) {
		var label;
		var labels = arguments.length >= 2 ? arguments[1] : document.getElementsByTagName('label');
		for (var i = 0; (label = labels[i]); i++) {
			if (label.htmlFor == id) {
				return label;
			}
		}
	}
	return null;
}


function domGetLabelsFor(x /*, labels */) { // element or id
	var id = typeof(x) == 'string' ? x : x.id;
	var result = [];
	if (id) {
		var label;
		var labels = arguments.length >= 2 ? arguments[1] : document.getElementsByTagName('label');
		for (var i = 0; (label = labels[i]); i++) {
			if (label.htmlFor == id) {
				result.push(label);
			}
		}
	}
	return result;
}


// Adds an option to a Select element.
function selectAddOption(sel,text,value,selected) {
	var o = document.createElement('option');
	o.text = text;
	o.value = value;
	o.selected = selected;
	//o = new Option(text, value, false, selected);
	try {
		sel.add(o, null); // standards compliant; doesn't work in IE
	}
	catch(ex) {
		sel.add(o); // IE only
	}
}


// Removes all options from a Select element.
function selectRemoveAll(sel) {
	for (var i = sel.length - 1; i >= 0; i--) {
		sel.remove(i);
	}
	sel.selectedIndex = -1;
}


// See http://www.crockford.com/javascript/inheritance.html
Function.prototype.addMethod = function (name, func) {
	this.prototype[name] = func;
	return this;
}
Function.addMethod('extend', function (parent) {
	var d = {}, p = (this.prototype = new parent());
	this.addMethod('callSuper', function (name) {
		if (!(name in d)) {
			d[name] = 0;
		}
		var f, r, t = d[name], v = parent.prototype;
		if (t) {
			while (t) {
				v = v.constructor.prototype;
				t -= 1;
			}
			f = v[name];
		} else {
			f = p[name];
			if (f == this[name]) {
				f = v[name];
			}
		}
		d[name] += 1;
		r = f.apply(this, Array.prototype.slice.apply(arguments, [1]));
		d[name] -= 1;
		return r;
	});
	return this;
});


function objGetClass(o) {
	if (!(o && (typeof(o) == 'object') && o.constructor)) {
		return undefined;
	}
	var result = undefined;
	var ctr = o.constructor.toString();
	//alert(ctr);
	var matches = ctr.match(/^\s*function\s+(\w+)\(\)/); // /^\[class (\S+)\]$/
	if (matches && (matches.length == 2)) {
		result = matches[1];
	}
	/*
	function String() {
		[native code]
	}
	*/
	return result;
}


// Check if session cookie is present, if not then page was loaded from browser or google cache and is probably invalid.
xAddEventListener(this, 'load',
	function() {
		var name = 'pepernoot';
		if (CookieJar.contains('PHPSESSID') || CookieJar.contains(name)) {
			return;
		}
		CookieJar.store(name, 1);
		if (CookieJar.contains(name)) {
			if ((location.hostname.toLowerCase().indexOf('apotheekvoorzorg.') >= 0) && (location.pathname.indexOf('/user/') == 0)) {
				//location.reload(true);
				location.href = '/';
				return;
			}
		}
		else {
			/*
			if (!window.opera && /MSIE (\d+\.\d+)/.test(navigator.userAgent) && (RegExp.$1 < 7)) {
				// Don't show warning in old IE browsers because document.cookie sometimes incorrectly returns an empty string: http://support.microsoft.com/kb/820536
			}
			else {
			*/
				var e = document.getElementById('headerMsgText');
				if (e) {
					e.innerHTML += 'Helaas kunt u op dit moment niet inloggen doordat uw browser geen cookies aan heeft staan.';
					e.style.display = '';
				}
			//}
		}
	},
	false
);


// Inject query() method into the Location object.
location.query = function(/* key */) {
//location.query = function(/* key */) {
	var nvs = this.search ? this.search.substr(1).split('&') : [];
	var key = arguments.length ? arguments[0] : null;
	var o = {};
	for (var i=0; i < nvs.length; i++) {
		var j = nvs[i].indexOf('=');
		if (j > 0) {
			var n = nvs[i].substr(0,j);
			var v = j+1 < nvs[i].length ? nvs[i].substr(j+1) : '';
			if (n == key) {
				return v;
			}
			o[n] = v;
		}
	}
	if (key == null) {
		return o;
	}
	return null;
}


// Inject target attributes for a tags having rel="external".
xAddEventListener(this, 'load',
	function() {
		if (!document.getElementsByTagName) {
			return;
		}
		var anchors = document.getElementsByTagName('a');
		for (var i=0; i<anchors.length; i++) {
			var a = anchors[i];
			var relvalue = a.getAttribute('rel');
			if (a.getAttribute('href')) {
				var relvalue = a.getAttribute('rel');
				if (relvalue) {
					var re = /\bexternal\b/;
					if (re.test(relvalue)) {
						//a.target = '_blank';
						a.setAttribute('target', '_blank');
					}
				}
			}
		}
	},
	false
);

