//
// create the GOOP Object
//
var GOOP = {
	version:.7,
	dom:false, // is the DOM ready?
	load:false // has the window loaded
};


//
// initator, called automatically when the DOM is ready
//
GOOP.ondom = function() {
	GOOP.dom = true;
	GOOP.extend(document.body,["events","dimensions"]);
};

//
// window onload, called automatically when the window has loaded
//
GOOP.onload = function() {
	GOOP.load = true;
	Reflect(window);
}


//
// extends the element(s) attaching the GOOP methods
//
GOOP.extend = function(element,methods) {
	
	// they didn't want it to be extended
	if(methods === false) return element;
	
	// find out what methods to attach
	methods = methods || ["styles","events","dimensions","effects"];
	if(methods.indexOf("basic") == -1) 
		methods.unshift("basic");
	
	// array of elements
	if(Object.prototype.toString.apply(element) === "[object Array]") {
		
		var l = element.length, i;
		for(i = 0; i < l; i++)
			GOOP.extend(element[i],methods);
		
	// individual element
	} else {
		
		var l = methods.length, i;
		for(i = 0; i < l; i++) {
			if(!element["goop_" + methods[i]]) {
				for(var m in GOOP[methods[i]])
					element[m] = GOOP[methods[i]][m];
				element["goop_" + methods[i]] = true;
			}
		}
		
	}
	
	return element;
};


//
// basic, or most commonly used from the other extended types
//
GOOP.basic = {
	
	//
	// get elements
	// thank you simon willision (http://simonwillison.net/2003/Mar/25/getElementsBySelector/)
	//
	getElements:function(search,methods) {
		
		var search = search.split(" ");
		var l = search.length, i, s;
		var context = [this];
		
		for(i = 0; i < l; i++) {
			
			s = search[i];
			
			// ids
			if(s.indexOf("#") > -1) {
				var el = $(s.split("#")[1],false);
				if(!el) return [];
				context = [el];
				continue;
			}
			
			// classes
			if(s.indexOf(".") > -1) {
				var b = s.split("."), t = b[0] || "*", c = b[1], f = [], j, el, k;
				for(j = 0; j < context.length; j++) {
					el = context[j].getElementsByTagName(t.toUpperCase());
					for(k = 0; k < el.length; k++) 
						f.push(el[k]);
				}
				context = [];
				for(j = 0; j < f.length; j++) {
					if(f[j].className && f[j].className.match(new RegExp('(^|\\s)' + c + '(?:\\s|$)')) != null) 
						context.push(f[j]);
				}
				continue;
			}
			
			// code to deal with attribute selectors
			if(s.match(/^(\w*)\[(\w+)([=~\|\^\$\*]?)=?"?([^\]"]*)"?\]$/)) {
				var t = RegExp.$1 || "*", an = RegExp.$2, ao = RegExp.$3, av = RegExp.$4, f = [], j, el, k;
				for(j = 0; j < context.length; j++) {
					el = context[j].getElementsByTagName(t.toUpperCase());
					for(k = 0; k < el.length; k++) f.push(el[k]);
				}
				if(Browser.name == "Explorer" && an.toLowerCase() == "class") an = "className"; // for IE bug
				var ftn; // this function will be used to filter the elements
				switch(ao) {
					case "=": ftn = function(e) { return (e.getAttribute(an) == av); }; break; // equality
					case "~": ftn = function(e) { return (e.getAttribute(an).match(new RegExp("\\b" + av + "\\b"))); }; break; // match one of the space seperated words
					case "|": ftn = function(e) { return (e.getAttribute(an).match(new RegExp("^" + av + "-?"))); }; break; // match start with value followed by options hyphen
					case "^": ftn = function(e) { return (e.getAttribute(an).indexOf(av) == 0); }; break; // match starts with
					case "$": ftn = function(e) { return (e.getAttribute(an).lastIndexOf(av) == e.getAttribute(an).length - av.length); }; break; // match ends with value - fails with warning in Opera 7
					case "*": ftn = function(e) { return (e.getAttribute(an).indexOf(av) > -1); }; break; // match ends with value
					default: ftn = function(e) { return e.getAttribute(an); }; // just test for existence of attribute
				}
				context = [];
				for(j = 0; j < f.length; j++) {
					if(!f[j].getAttribute(an)) continue;
					if(ftn(f[j])) context.push(f[j]);
				}
				continue;
			}
			
			// if we made it here, its just a tag name
			var f = [], j, el, k;
			for(j = 0; j < context.length; j++) {
				el = context[j].getElementsByTagName(s.toUpperCase());
				for(k = 0; k < el.length; k++) 
					f.push(el[k]);
			}
			context = f;
			
		}
		
		return (context.length > 0 ? GOOP.extend(context,methods) : null);
		
	},

	getElement:function(search,methods) {
		var elements = this.getElements(search,methods);
		return (elements != null ? elements[0] : null);
	},


	//
	// set and get properties
	//
	set:function(attr,value) {
		
		if(typeof attr != "string") {
			for(var i in attr)
				this.set(i,attr[i]);
			return;
		}

		if(attr == "html") {
			this.innerHTML = value;
		} else if(attr == "class") {
			this.className = value;
		} else if(attr == "id") {
			this.id = value;
		} else if(attr == "text") {
			if(this.innerText) 
				this.innerText = value;
			else 
				this.textContent = value;
		} else {
			(this.hasOwnProperty && this.hasOwnProperty(attr)) ? this[attr] = value : this.setAttribute(attr,'' + value);
		}

		return this;

	},

	get:function(attr) {

		if(attr == "html") {
			return this.innerHTML;
		} else if(attr == "class") {
			return this.className || '';
		} else if(attr == "id") {
			return this.id || '';
		} else if(attr == "text") {
			if(this.innerText) 
				return this.innerText;
			else 
				return this.textContent;
		} else {
			return (this.hasOwnProperty && this.hasOwnProperty(attr)) ? this[attr] : this.getAttribute(attr);
		}

	},
				
	hasClass:function(name) {
		return (this.get("class").match(new RegExp('(^|\\s)' + name + '(?:\\s|$)')) != null ? true : false);
	},

	addClass:function(name) {
		if(!this.hasClass(name)) 
			this.set("class",(this.get("class") + " " + name).trim());
		return this;
	},

	removeClass:function(name) {
		this.set("class",this.get("class").replace(new RegExp('(^|\\s)' + name + '(?:\\s|$)'), '$1'));
		return this;
	},
	
	
	//
	// inserters - replace, adopt, grab, inject, wraps, and destroy
	// huge thanks to MooTools
	//
	inserters:function(where,context,element) {
		if(where == "after") {
			if(!element.parentNode) return;
			var next = element.nextSibling;
			(next) ? element.parentNode.insertBefore(context,next) : element.parentNode.appendChild(context);
		} else if(where == "before") {
			if(element.parentNode) element.parentNode.insertBefore(context,element);
		} else if(where == "bottom") {
			element.appendChild(context);
		} else if(where == "top") {
			var first = element.firstChild;
			(first) ? element.insertBefore(context,first) : element.appendChild(context);
		}
	},
	
	replaces:function(element) {
		element.parentNode.replaceChild(this,element);
		return this;
	},

	adopt:function(element) {
		if(element[0]) {
			var l = element.length, i;
			for(i = 0; i < l; i++)
				this.adopt(element[i]);
		} else {
			this.appendChild(element);
		}
		return this;
	},
	
	grab:function(element,where) {
		this.inserters((where || "bottom"),element,this);
		return this;
	},
	
	inject:function(element,where) {
		this.inserters((where || "bottom"),this,element);
		return this;
	},
	
	wraps:function(element,where) {
		if(element[0]) {
			var l = element.length, i;
			for(i = 0; i < l; i++) 
				this.wraps(element[i],where);
		} else {
			this.replaces(element).grab(element,where);
		}
		return this;
	},

	destroy:function() {
		return this.parentNode.removeChild(this);
	},
	
	empty:function() {
		while(this.hasChildNodes()) 
			this.removeChild(this.firstChild);
		return this;
	},
	
	
	//
	// set and get misc properties and values in storage
	// thank you MooTools
	//
	_set:function(property,value) {
		this.storage = this.storage || [];
		
		if(typeof property != "string") {
			for(var v in property)
				this._set(v,property[v]);
			return;
		}
		
		this.storage[property] = value;
		return this;
	},
	
	_get:function(property) {
		if(!this.storage) return false;
		if(this.storage[property] == 0 || this.storage[property] == "0") return 0;
		return this.storage[property] || false;
	}
	
};



// 
// styles
// thank you MooTools
//
GOOP.styles = {
	
	setStyle:function(style,value) {

		if(style == "opacity") {
			if(!this.currentStyle || !this.currentStyle.hasLayout) this.style.zoom = 1;
			this.style.opacity = value * .01;
			this.style.filter = "alpha(opacity=" + value + ")";
			value = (value < 0 ? 0 : (value > 100 ? 100 : value)); // can't be > 100 || < 0
			this._set("opacity",value.toInt()); // stored for reference
		} else if(style == "float") {
			if(Browser.name == "Explorer") 
				this.style.styleFloat = value;
			else 
				this.style.cssFloat = value;
		} else {
			this.style[style.camelCase()] = value + (typeof value == "number" && style.camelCase() != "zIndex" ? "px" : '');
		}

		return this;
	},

	setStyles:function(styles) {
		for(var s in styles) 
			this.setStyle(s,styles[s]);
		return this;
	},

	getStyle:function(style) {

		if(style == "opacity") {
			if(this._get("opacity") === 0) return 0;
			if(Browser.name == "Explorer") 
				return this._get("opacity") || this.currentStyle[style.camelCase()] || this.style.filter;
			else 
				return this._get("opacity") || document.defaultView.getComputedStyle(this,'').getPropertyValue(style) || this.style.opacity;
		} else if(style == "float") {
			if(Browser.name == "Explorer") 
				return this.style.styleFloat;
			else
				return this.style.cssFloat;
		} else {
			if(Browser.name == "Explorer")
				return this.style[style.camelCase()] || this.currentStyle[style.camelCase()];
			else
				return this.style[style.camelCase()] || document.defaultView.getComputedStyle(this,'').getPropertyValue(style);
		}

	},
	
	getStyles:function(styles) {
		var returned = {}, i;
		for(i = 0; i < styles.length; i++)
			returned[styles[i]] = this.getStyle(styles[i]);
		return returned;
	}
	
};


// 
// events to attach to elements
//
GOOP.events = {
	
	addEvent:function(type,ftn) {
		if(this.addEventListener) {
			
			// HUGE thanks to "incoherent babble" at http://blog.stchur.com/2007/03/15/mouseenter-and-mouseleave-events-for-firefox-and-other-non-ie-browsers/
			
			if(type.match(/mouseenter|mouseleave/i))
				this.addEventListener((type.match(/mouseenter/i) ? "mouseover" : "mouseout"),this._mouseEvent(ftn),false);
			else
				this.addEventListener(type,ftn,false);
			
		} else if(this.attachEvent) {
			var p = this;
			this._set("event_" + type, function() { return ftn.apply(p,[window.event]); });
			this.attachEvent("on" + type,this._get("event_" + type));
		} else {
			this["on" + type] = ftn;
		}
		return this;
	},

	addEvents:function(events) {
		for(var e in events)
			this.addEvent(e,events[e]);
		return this;
	},

	removeEvent:function(type,ftn) {
		if(this.removeEventListener) {
			this.removeEventListener(type,ftn,false);
		} else if(this.detachEvent) {
			this.detachEvent("on" + type,this._get("event_" + type));
		} else {
			this["on" + type] = null;
		}
		return this;			
	},

	removeEvents:function(events) {
		for(var e in events)
			this.removeEvent(e,events[e]);
		return this;
	},

	doEvent:function(type) {
		if(document.createEvent) {
			var e = document.createEvent("HTMLEvents");
			e.initEvent(type,true,true);
			this.dispatchEvent(e);
		} else if(document.createEventObject) {
			this._set("event_" + type,null);
			this.fireEvent("on" + type,document.createEventObject());
		} else {
			this["on" + type]();
		}
		return this;
	},

	doEvents:function(events) {
		for(var i = 0; i < events.length; i++)
			this.doEvent(events[i]);
		return this;
	},
	
	// used if mouseenter and mouseleave events are being used
	_mouseEvent:function(ftn) {
		return function(e) {
			if(this === e.relatedTarget || this._childOf(e.relatedTarget)) return;
			ftn.call(this,e);
		}
	},
	
	_childOf:function(target) {
		if(this === target) return false;
		while(target && target !== this)
			target = target.parentNode;
		return target === this;
	}
	
};


//
// dimensions
// thanks MooTools
// 
GOOP.dimensions = {
	
	getSize:function() {
		return {width:this.offsetWidth, height:this.offsetHeight};
	},

	getScroll:function() {
		var tag = this.tagName.toLowerCase();
		if(tag.indexOf("body") > -1 || tag.indexOf("html") > -1)
			return {left:(window.pageYOffset || document.body.scrollLeft || document.documentElement.scrollLeft), top:(window.pageYOffset || document.body.scrollTop || document.documentElement.scrollTop)};
		else
			return {left:this.scrollLeft, top:this.scrollTop};
	},

	getPosition:function() {
		var s = this.getScroll(), l = this.offsetLeft, t = this.offsetTop, p = this.offsetParent;
		while(p != null) {
			l += p.offsetLeft;
			t += p.offsetTop;
			p = p.offsetParent;
		}
		return {left:l + s.left, top:t + s.top};
	},

	getCoordinates:function() {
		var s = this.getSize(), p = this.getPosition();
		return {left:p.left, top:p.top, width:s.width, height:s.height, right:p.left + s.width, bottom:p.top + s.height};
	},
	
	// thank you - http://snippets.dzone.com/posts/show/913
	hitTest:function(el) {
		var a = this.getCoordinates(), b = $(el,["dimensions"]).getCoordinates();
		return ((a.left == b.left || (a.left > b.left ? a.left <= b.right : b.left <= a.right)) && (a.top == b.top || (a.top > b.top ? a.top <= b.bottom : b.top <= a.bottom)));
	}
	
};


// 
// effects
// thank you MooTools
//
GOOP.effects = {
	
	fade:function(action,options) {

		options = options || {};
		action = action || "out";
	
		if(action == "in") {
			if(!this.getStyle("opacity")) 
				this.setStyle("opacity",0); 
		} else if(action == "out") {
			if(!this.getStyle("opacity")) 
				this.setStyle("opacity",100); 
		}

		this.tween("opacity",(action == "in" ? 0 : (options.opacity || 100)),(action == "out" ? 0 : (options.opacity || 100)),options);
	
		return this;
	
	},

	hide:function(options) {
		options = options || {};
		options.direction = options.direction || "top";
		options.duration = 1;
		this.slide("out",options);
		return this;
	},
	
	show:function(options) {
		options = options || {};
		options.direction = options.direction || "top";
		options.duration = 1;
		this.slide("in",options);
		return this;
	},

	toggle:function(options) {
	
		options = options || {};
		options.direction = options.direction || "top";
	
		var pos = this.getStyle("margin-" + options.direction);
		this.slide((pos == '' || pos.toInt() >= 0 ? "out" : "in"),options);
	
		return this;
	
	},

	slide:function(action,options) {
	
		options = options || {};
		options.direction = options.direction || "top";
		action = (action || "out");
	
		// make a parent div to wrap it in
		var p = GOOP.extend(this.parentNode,[]);
		if(p.tagName != "DIV" || !p.hasClass("slide")) {
			new Element("div",{
				"class":"slide",
				"setStyles":{
					"margin":0,
					"padding":0,
					"overflow":"hidden"
				}
			}).wraps(this);
		}
	
		// get current position
		var pos = this.getStyle("margin-" + options.direction);
		if(pos == '') {
			this.setStyle("margin-" + options.direction,0);
			pos = 0;
		}
	
		// check if we should slide
		if(pos.toInt() <= 0 && action == "in")
			this.tween("margin-" + options.direction,pos.toInt(),0,options);
		else if(pos.toInt() >= 0 && action == "out")
			this.tween("margin-" + options.direction,0,-this.getSize()[(options.direction == "top" || options.direction == "bottom" ? "height" : "width")],options);
	
		return this;
	
	},

	morph:function(styles,options) {
		options = options || {};
		for(var i in styles)
			this.tween(i,styles[i][0],styles[i][1],options);
		return this;
	},

	tween:function(style,from,to,options) {

		options = options || {};
		
		var p = this; // acts as parent
		p.started = options.start || function() {}; // function to execute at the start
		p.completed = options.complete || function() {}; // function to execute once completed
		var interval = Math.ceil(1000 / (options.fps || 50));
		var tf = Math.ceil((options.duration || 500) / interval);
		
		// for color, background-color, and border-color - the transition is a bit different
		if(style == "color" || style == "background-color" || style == "border-color") {
			var brgb = Color.toRGB(from), ergb = Color.toRGB(to);
			var step = [(ergb[0] - brgb[0]) / tf, (ergb[1] - brgb[1]) / tf, (ergb[2] - brgb[2]) / tf, 0];
		} else {
			var step = (to.toInt() - from.toInt()) / tf;
		}
	
		// make a tweentimer array
		if(!this.tweentimer) this.tweentimer = [];
	
		// execute at start
		this.started();
	
		// firstly, stop the timer of that tweened style so we don't leak memory, then set the style
		this.stopTween(style).setStyle(style,from).tweentimer[style] = $interval(interval,function() {
			
			var flag = false;
			
			// for color, background-color, and border-color
			if(style == "color" || style == "background-color" || style == "border-color") {
				
				brgb[0] += step[0], brgb[1] += step[1], brgb[2] += step[2];
				
				p.setStyle(style,Color.toHEX(brgb));
				
				// are we done with the colors?
				if((brgb[0] + step[0]) >= ergb[0] && (brgb[1] + step[1]) >= ergb[1] && (brgb[2] + step[2]) >= ergb[2] && !flag) {
					if(step[3] == 2) flag = true;
					step[3] = 1;
				} else if((brgb[0] + step[0]) <= ergb[0] && (brgb[1] + step[1]) <= ergb[1] && (brgb[2] + step[2]) <= ergb[2] && !flag) {
					if(step[3] == 1) flag = true;
					step[3] = 2;
				}
				
				if(flag) {
					p.setStyle(style,to);
					p.stopTween(style);
				}
				
			} else {
				
				// get position
				var pos = p.getStyle(style).toFloat();
				
				// move it
				if(step > 0 && (pos + step) < to) {
					p.setStyle(style,pos + step);
				} else if(step < 0 && (pos + step) > to) {
					p.setStyle(style,pos + step);
				} else {
					p.setStyle(style,to);
					p.stopTween(style);
					flag = true;
				}
				
			}
			
			// done moving
			if(flag) {
				if(!p.anyTweens())
					p.completed(); // we do this so in the complete function we can use "this" or the passed variable/object
			}
			
		});
	
		return this;
	
	},

	stopTween:function(style) {
		if(!this.tweentimer) return;
		$clear(this.tweentimer[style]);
		this.tweentimer[style] = -1;
		return this;
	},

	stopTweens:function(styles) {
		var i;
		if(styles == "all") {
			for(i in this.tweentimer) 
				this.stopTween(i);
		} else {
			for(i = 0; i < styles.length; i++)
				this.stopTween(styles[i]);
		}
		return this;
	},

	anyTweens:function() {
		if(!this.tweentimer) return false;
		var flag = false;
		for(var i in this.tweentimer)
			flag = (this.tweentimer[i] > -1 ? true : flag);
		return flag;
	}
	
};


// 
// global functions
//
function $(id,methods) {
	
	var el, i;
	
	if(typeof id == "string") {
		
		el = document.getElementById(id) || null;
		
		// for ie only, becareful of the 'name' and 'id'
		if(Browser.name == "Explorer" && el != null) {
			if(el.id != id) {
				for(i = 0; i < document.all[id].length; i++) {
					if(document.all[id][i].id == id)
						el = document.all[id][i];
				}
			}
		} 
		
		if(el != null) 
			GOOP.extend(el,methods);
			
	} else if(typeof id == "object") {
		el = GOOP.extend(id,methods);
	}
	
	return el;
}

function $$(search,methods) {
	return document.body.getElements(search,methods);
}

function $time() {
	return (new Date).getTime();
}

function $rand(n1,n2,w) {
	if(!w)
		return Math.ceil(n2 * Math.random()) + n1;
	else 
		return (n2 * Math.random()) + n1;
}

function $focus(form,name) {
	
	if(!form) 
		form = document.forms[0];
	else 
		form = document.forms[form];
	
	if(!form) return;
	
	if(name) {
		if(form[name]) 
			form[name].focus();
	} else {
		for(var i in form) {
			if(!form[i]) continue;
			if(!form[i].type) continue;
			if(form[i].type.toLowerCase() == "text" || form[i].type.toLowerCase() == "textarea") {
				form[i].focus();
				break;
			}
		}
	}
	
}

function $timeout(mil,ftn) {
	return setTimeout(ftn,mil);
}
function $interval(mil,ftn) {
	return setInterval(ftn,mil);
}
function $clear(t) {
	clearTimeout(t);
	clearInterval(t);
}

function jump2field(el,to,form) {
	
	// find form if not passed
	if(form) {
		form = document.forms[form];
	} else {
		form = el.parentNode;
		while(form.tagName != "FORM") form = form.parentNode;
	}
	
	// never found, and size is not set
	if(!form && (!el.size || !el.maxLength)) return;
	
	// jump to field if we meet the length
	if(el.value.length == (el.maxLength > -1 ? el.maxLength : el.size)) 
		if(form[to]) 
			form[to].focus();
}


// huge thanks to supersleight
var fixPNG = {
	
	path:"transparent.gif",
	active:true,
	_class:[],
	_id:[],
	
	init:function(element,mode) {		
		element = element || document;
		if(Browser.name != "Explorer") return;
		if(Browser.version > 6) return;
			
		var i, j, el, flag;
		
		for(i = element.all.length - 1, el = null; el = element.all[i]; i--) {
			
			flag = false;
			
			// ignores
			for(j = 0; j < this._class.length; j++) {
				if(el.className.match(new RegExp('(^|\\s)' + this._class[j] + '(?:\\s|$)')) != null) flag = true;
			}
			for(j = 0; j < this._id.length; j++) {
				if(el.id == this._id[j]) flag = true;
			}
			if(flag) continue;
			
			// backgrounds
			if(el.currentStyle.backgroundImage.match(/\.png/i) != null) 
				fixPNG.bg_fix(el,mode);

			// images
			if(el.tagName.toLowerCase() == "img" && el.src.match(/\.png/i) != null) 
				fixPNG.el_fix(el,mode);

			// apply position to active elements
			if(this.active && (el.tagName.toLowerCase() == "a" || el.tagName.toLowerCase() == "input") && el.style.position === '') 
				el.style.position = "relative";
			
		}
	},
	
	bg_fix:function(element,mode) {
		var bg = element.currentStyle.backgroundImage;
		var src = bg.substring(5,bg.length-2); // strips the src from inside: url("path/to/file.png")
		if(element.currentStyle.backgroundRepeat == "no-repeat") mode = mode || "crop";
		element.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + src + "'), sizingMethod='" + (mode || "scale") + "')"; 
		element.style.backgroundImage = "url(" + this.path + ")";
	},
	
	el_fix:function(element,mode) {
		var src = element.src;
		element.style.width = element.width + "px";
		element.style.height = element.height + "px";
		element.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + src + "',sizingMethod='" + (mode || "scale") + "')";
		element.src = this.path;
	}
	
};


//
// creates an element and gets extended by GOOP
//
function Element(tag,options,methods) {
	
	options = options || {};
	
	var el = document.createElement(tag.toUpperCase());
	GOOP.extend(el,methods);
	
	for(var op in options) {
		if(typeof op == "string") {
			if(typeof el[op] == "function") 
				el[op](options[op]);
			else 
				el.set(op,options[op]); 
		} else if(typeof op == "object") {
			el[op](options[op]);
		}
	}

	return el;
	
};


//
// swf
// thank you MooTools
//
function SWF(path,options) {

	options = options || {};
	options = {
		id:options.id || "swf_" + $time(),
		container:options.container || null,
		width:options.width || 1,
		height:options.height || 1,
		flashVars:options.flashVars || '',
		properties:options.properties || {},
		params:options.params || {
			quality:"high",
			allowScriptAccess:"always",
			wMode:"transparent"
		}
	};
	
	options.properties.id = options.id;			
	options.properties.width = options.width;
	options.properties.height = options.height;
	options.params.flashVars = options.flashVars;
	
	if(Browser.name == "Explorer") {
		options.properties.classid = "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000";
		options.params.movie = path;
	} else {
		options.properties.type = "application/x-shockwave-flash";
		options.properties.data = path;
	}

	var swf = "<object", p;
	for(p in options.properties) swf += " " + p + "=\"" + options.properties[p] + "\""; 
	swf += " />";

	for(p in options.params) swf += "<param name=\"" + p + "\" value=\"" + options.params[p] + "\" />";
	swf += "</object>";
	
	// write it inside of a new div
	$(options.container).adopt(new Element("div",{},[]).set("html",swf));
	
};


//
// event, makes the event crossbrowser
// HUGE thanks to MooTools
//
function Event(e,w) {
	
	w = w || window;
	
	if(e.type.match(/key/i)) {
		var code = e.which || e.keyCode;
	} else if(e.type.match(/(click|mouse|menu)/i)) {
		var page = {
			x:(e.pageX) ? e.pageX : e.clientX + document.body.getScroll().left,
			y:(e.pageY) ? e.pageY : e.clientY + document.body.getScroll().top
		};
		var client = {
			x:(e.pageX) ? e.pageX - w.pageXOffset : e.clientX,
			y:(e.pageY) ? e.pageY - w.pageYOffset : e.clientY
		}
		if(e.type.match(/dommousescroll|mousewheel/i)) {
			var wheel = (e.wheelDelta) ? el.wheelDelta / 120 : -(e.detail || 0) / 3;
		}
		var rightClick = (e.which == 3) || (e.button == 2);
	}
	
	return {
		event:e,
		type:e.type,
		wheel:wheel,
		page:page,
		client:client,
		rightClick:rightClick,
		code:code
	}
	
}


// 
// DOM ready, automatically is called
//
var DOM = {
	count:10,
	ftns:[],
	ready:function(ftn) {
		this.ftns.push(ftn);
	},
	init:function() {
		var l = this.ftns.length, i;
		for(i = 0; i < l; i++)
			(this.ftns.shift())();
	}
};
(function() {

	// now lets check if its ready
	// if it reaches the </body> tag, it should be ready... we also have a counter to check several times just in case
	var timer = 1000;
	var setInt = $interval(10,function() {
		if(document.getElementsByTagName("HTML")[0].innerHTML.toLowerCase().lastIndexOf("</body>") > -1) {
			if(DOM.count == 0) {
				$clear(setInt);
				DOM.init();
			} else {
				DOM.count--;
			}
		} else {
			timer--;
			if(timer == 0)
				$clear(setInt);
		}
	});
	
})();


//
// simple ajax
// thank you XHConn
//
function Ajax(options) {
	
	options = options || {};
	if(!options.url) return;
	
	url = options.url;
	options.start = options.start || function() {};
	options.complete = options.complete || function() {};
	options.method = (options.method || "post").toUpperCase();
	
	// set up xmlttp
	var xmlhttp;
	try { xmlhttp = new ActiveXObject("Msxml2.XMLHTTP"); }
	catch(e) { 
		try { xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); }
		catch(e) { 
			try { xmlhttp = new XMLHttpRequest(); } 
			catch(e) { xmlhttp = false; }
		}
	}
	
	// make functions to act as prototype
	function stop() {
		xmlhttp.abort();
	}
	
	function send(query) {
		
		if(!xmlhttp) return;
		
		stop();
		
		options.start();
		
		xmlhttp.onreadystatechange = function() {
			if(xmlhttp.readyState == 4 && xmlhttp.status == 200)
				options.complete(xmlhttp.responseText.trim());
		}
		
		// autmatically put a cache kill in, if cache is false
		var url = options.url + "?" + (options.cache === true ? '' : "c=" + $time() + "&") + (query || '');
		
		// was it a get or post
		if(options.method == "GET") {
			xmlhttp.open("GET",url,true);
			xmlhttp.send(null);
		} else {
			var q = url.indexOf("?");
			xmlhttp.open("POST",url.substring(0,q),true);
			xmlhttp.setRequestHeader("Method","POST " + url.substring(0,q) + " HTTP/1.1");
			xmlhttp.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
			xmlhttp.send(url.substring(q+1));
		}
		
	}
	
	// store them as prototypes
	this.stop = stop;
	this.send = send;	
	
};


//
// cookies
// thank you Dhryn and quirksmode
//
var Cookie = {
	set:function(name,value,days) {
		var date = new Date();
		date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
		var expires = "; expires=" + date.toGMTString();
		document.cookie = name + "=" + value + expires + "; path=/";
	},
	get:function(name) {
		var ca = document.cookie.split(";"), i, c;
		for(i = 0; i < ca.length; i++) {
			c = ca[i];
			while(c.charAt(0) == ' ') 
				c = c.substring(1,c.length);
			if(c.indexOf(name + "=") == 0) 
				return c.substring((name + "=").length,c.length); 
		}
		return false;
	},
	unset:function(name) {
		this.set(name,'',-1);
	}
};


//
// color
// thank you leigeber and linuxtopia
//
var Color = {
	toRGB:function(c) {
		c = c.replace(/\#/,'').toString().toLowerCase();
		if(c.length == 3) 
			c = c.charAt(0) + c.charAt(0) + c.charAt(1) + c.charAt(1) + c.charAt(2) + c.charAt(2);
		return [ c.substring(0,2).toInt(16), c.substring(2,4).toInt(16), c.substring(4,6).toInt(16) ];
	},
	toHEX:function(c) {
		return this._findHEX(c[0]) + this._findHEX(c[1]) + this._findHEX(c[2]);
	},
	_findHEX:function(c) {
		if(c == undefined || c == null) return "00";
		c = c.toInt();
		if(c == 0 || isNaN(c)) return "00";
		c = Math.max(0,c);
		c = Math.min(c,255);
		c = Math.round(c);
		return "0123456789ABCDEF".charAt((c - c % 16) / 16) + "0123456789ABCDEF".charAt(c % 16);
	}
};


// 
// JSON encode and decode
// thank you - http://www.openjs.com/scripts/data/json_encode.php (their example doesn't work, had to alter it a bit)
//
var JSON = {
	toString:function(obj) {
		var parts = [], flag = (Object.prototype.toString.apply(obj) === "[object Array]"), key, value, str;

		for(key in obj) {
			value = obj[key];
			if(typeof value == "function") continue;
			if(typeof value == "object") {
				parts.push('"' + key + '":' + JSON.encode(value));
			} else {
				str = '';
				if(!flag) str += '"' + key + '":'

				if(typeof value == "number") str += value;
				else if(typeof value == false) str += "false";
				else if(typeof value == true) str += "true";
				else str += '"' + value + '"';

				parts.push(str);
			}
		}

		return (flag ? "[" + parts.join(",") + "]" : "{" + parts.join(",") + "}");
	},
	toObject:function(str) {
		return eval("(" + str + ")");
	}
}


//
// Browser detection 
// thank you quirksmode
//
var Browser = {
	init:function() {
		this.name = this.searchString(this.dataBrowser) || "Unknown";
		this.version = this.searchVersion(navigator.userAgent) || this.searchVersion(navigator.appVersion) || "Unknown";
		this.platform = this.searchString(this.dataOS) || "Unknown";
	},
	searchString:function(data) {
		var l = data.length, i, dataString, dataProp;
		for(i = 0; i < l; i++) {
			dataString = data[i].string;
			dataProp = data[i].prop;
			this.versionSearchString = data[i].versionSearch || data[i].identity;
			if(dataString) {
				if(dataString.indexOf(data[i].subString) != -1)
					return data[i].identity;
			} else if(dataProp) {
				return data[i].identity;
			}
		}
	},
	searchVersion:function(dataString) {
		var index = dataString.indexOf(this.versionSearchString);
		if (index == -1) return;
		return dataString.substring(index + this.versionSearchString.length + 1).toFloat();
	},
	dataBrowser:[
		{
			string:navigator.userAgent,
			subString:"Chrome",
			identity:"Chrome"
		},
		{ 	string:navigator.userAgent,
			subString:"OmniWeb",
			versionSearch:"OmniWeb/",
			identity:"OmniWeb"
		},
		{
			string:navigator.vendor,
			subString:"Apple",
			identity:"Safari",
			versionSearch:"Version"
		},
		{
			prop:window.opera,
			identity:"Opera"
		},
		{
			string:navigator.vendor,
			subString:"iCab",
			identity:"iCab"
		},
		{
			string:navigator.vendor,
			subString: "KDE",
			identity: "Konqueror"
		},
		{
			string: navigator.userAgent,
			subString: "Firefox",
			identity: "Firefox"
		},
		{
			string: navigator.vendor,
			subString:"Camino",
			identity:"Camino"
		},
		{
			string:navigator.userAgent,
			subString:"Netscape",
			identity:"Netscape"
		},
		{
			string:navigator.userAgent,
			subString:"MSIE",
			identity:"Explorer",
			versionSearch:"MSIE"
		},
		{
			string:navigator.userAgent,
			subString:"Gecko",
			identity:"Mozilla",
			versionSearch:"rv"
		},
		{
			string:navigator.userAgent,
			subString:"Mozilla",
			identity:"Netscape",
			versionSearch:"Mozilla"
		}
	],
	dataOS:[
		{
			string:navigator.platform,
			subString:"Win",
			identity:"Windows"
		},
		{
			string:navigator.platform,
			subString:"Mac",
			identity:"Mac"
		},
		{
			string:navigator.platform,
			subString:"Linux",
			identity:"Linux"
		}
	]

};
	

//
// accordion effect
// thank you leigeber
//
function Accordion(id,options) {
	
	options = options || {};
	
	// set variables
	var element = $(id);	
	var headers = element.getElements(options.header || "dt");
	var sliders = element.getElements(options.slider || "dd");
	
	// set sliders
	sliders.each(function(el) {
		el.setStyles({
			"height":0,
			"display":"none",
			"overflow":"hidden"
		});
	});
	
	// set headers
	headers.each(function(el) {
		el.addEvent("click",slide);
	});
	
	function slide() {
		var i, el;
		for(i = 0; i < headers.length; i++) {
			
			el = sliders[i].stopTweens("all");

			if(headers[i] == this && el.getStyle("display") == "none") {
				el.setStyle("display",'');
				moving(el,true);
			} else if(el.getStyle("display") == '' || el.getStyle("display") == "block") {
				moving(el,false);
			}
			
		}	
	}
	
	function moving(el,flag) {
		
		// two tricks to get the current maxium height of the element, we do this because FF and IE do it different 
		var i, h = 0;
		
		// first way, find out which element inside the slider element has the tallest height - for ff
		el.getElements("*",false).each(function(e) {
			if(e.offsetHeight > h) h = e.offsetHeight;
		})
		
		// second way, change the overflow - for ie
		el.setStyle("overflow","visible");
		if(el.getSize().height > h) h = el.getSize().height;
		el.setStyle("overflow","hidden");
		
		// some default value - 20 is fine
		h = h || 20;
		
		if(flag) {
			el.morph({
				"height":[0,h],
				"opacity":[0,100]
			},{ 
				duration:300 
			});
		} else if(!flag) {
			el.morph({
				"height":[h,0],
				"opacity":[100,0]
			},{
				duration:300,
				complete:function() {
					this.setStyle("display","none");
				}
			});
		}
	}
	
	// these functions act as prototypes
	function move(n) {
		headers[n].doEvent("click");
	}
	
	// automatically show
	if(options.open > -1) move(options.open)
	
	// store for reference
	this.move = move;
	
};


//
// tips
// thanks for reference leigeber
//
function Tip(id,options) {
	
	options = options || {};
	var element = $(id);
	
	// create the tip div
	var tip = new Element("div",{
		"class":"tip" + (options._class ? " tip_" + options._class : ''),
		"html":(options.title ? "<strong>" + options.title + "</strong>" : '') + (options.message ? "<p>" + options.message + "</p>" : ''),
		"setStyles":{
			"opacity":0,
			"display":"none",
			"position":"absolute",
			"z-index":99
		}
	}).inject(document.body,"top");
	
	// add events
	element.addEvents({
		"mouseover":show,
		"mouseout":hide,
		"mousemove":follow
	});
	
	// show the tip
	function show() {
		tip.setStyle("display","block").fade("in",{
			opacity:options.opacity || 85
		});
	}
	
	// hide the tip
	function hide() {
		tip.fade("out",{
			complete:function() {
				this.setStyle("display","none");
			}
		});
	}
	
	// follow the cursor
	function follow(e) {

		// get position
		var top = (e.pageY ? e.pageY : e.clientY + document.body.getScroll().top) - tip.getSize().height - 15;
		var left = (e.pageX ? e.pageX : e.clientX + document.body.getScroll().left) + 15;

		// fix position so it doesn't go off the page :)
		if(top < 0) 
			top = (e.pageY ? e.pageY : e.clientY) + 15;
		if((left + tip.getSize().width) > document.body.getSize().width) 
			left = (e.pageX ? e.pageX : e.clientX) - tip.getSize().width - 15;

		// set position, finally
		tip.setStyles({
			"top":top,
			"left":left
		});
		
	}
	
}


// 
// growl effect
// thanks for reference digitarald and Growl
//
var Growl = {
	
	growls:[],
	
	smoke:function(options) {
		
		options = options || {};
		
		// make an id for it; variable for height
		var id = "smoke_" + $time(), h = 0;
		
		// set the height
		this.growls.each(function(el) {
			h += el.getSize().height;
		});
		
		// set up html for the smoke
		var html = '';
		html += (options.close ? "<div class=\"close\" style=\"display:none;\" onclick=\"Growl.close('" + id + "');\"></div>" : '');
		html += (options.image ? "<div class=\"image\"><img src=\"" + options.image + "\" /></div>" : '');
		html += "<div class=\"message\"><strong>" + (options.title || '') + "</strong><p>" + (options.message || '') + "</p></div>";
		html += "<div style=\"clear:both;\"></div>";
		
		// create the element and effects and put it in array
		this.growls.push(new Element("div",{
			"id":id,
			"class":"smoke" + (options._class ? " smoke_" + options._class : ''),
			"html":html,
			"setStyles":{
				"opacity":0,
				"position":"absolute",
				"z-index":99,
				"top":document.body.getScroll().top + h,
				"right":0
			}
		}).addEvents({
			mouseover:function() {
				var c = this.getElement("div.close");
				if(c) c.setStyle("display","block");
			},
			mouseout:function() {
				var c = this.getElement("div.close");
				if(c) c.setStyle("display","none");
			}
		})._set("duration",options.duration || 2000)._set("growl_opacity",options.opacity || 100));
		
		this.add("smoke");
		
	},
	
	bezel:function(options) {
		
		options = options || {};
		
		// set up html for the bezel
		var html = '';
		html += (options.image ? "<img src=\"" + options.image + "\" /><br />" : '');
		html += "<div class=\"message\"><strong>" + (options.title || '') + "</strong><p>" + (options.message || '') + "</p></div>";
		
		// create the element and effects and put it in array
		this.growls.push(new Element("div",{
			"class":"bezel" + (options._class ? " bezel_" + options._class : ''),
			"html":html,
			"setStyles":{
				"opacity":0,
				"position":"absolute",
				"z-index":99,
				"height":options.height || "auto",
				"top":document.body.getScroll().top + 300,
				"left":"50%"
			}
		})._set("duration",options.duration || 2000)._set("growl_opacity",options.opacity || 100));
		
		this.add("bezel");
		
	},
	
	mv:function(options) {
		
		options = options || {};
		
		// set up html for the mv
		var html = '';
		html += (options.image ? "<div class=\"image\"><img src=\"" + options.image + "\" /></div>" : '');
		html += "<div class=\"message\"><strong>" + (options.title || '') + "</strong><p>" + (options.message || '') + "</p></div>";
		html += "<div style=\"clear:both;\"></div>";
		
		// create the element and effects and put it in array
		this.growls.push(new Element("div",{
			"class":"mv" + (options._class ? " mv_" + options._class : ''),
			"html":html,
			"setStyles":{
				"opacity":options.opacity || 100,
				"position":"absolute",
				"z-index":99,
				"width":"100%",
				"top":0,
				"left":0
			}
		})._set("duration",options.duration || 2000));
		
		this.add("mv");
		
	},
	
	doScroll:function() {
		var h = 0, m = 0;
		Growl.growls.each(function(el,i) {
			m = el.getStyle("margin");
			h += (i > 0 ? el.getSize().height + (m != '' ? m.toInt() : 0) : 0);
			el.setStyle((el.hasClass("bezel") ? "margin-" : '') + "top",document.body.getScroll().top + h);
		});
	},
	
	addScroll:function() {
		window.addEvent("scroll",this.doScroll);
	},
	
	removeScroll:function() {
		if(this.growls.length > 0) this.growls.shift().destroy();
		else window.removeEvent("scroll",this.doScroll);
	},
	
	add:function(what) {
		
		// add scroll event
		if(this.growls.length == 0) return;
		else if(this.growls.length == 1) this.addScroll();
		
		// acts as parent; get the first element, then put it back
		var p = this, el = this.growls.pop();
		this.growls.push(el);
		
		// only smoke can have more than one at a time
		if(what == "bezel") {
			if($$("div.bezel") != null) return;
		} else if(what == "mv") {
			if($$("div.mv") != null) return;
		}
		
		// place in body at the top
		el.inject(document.body,"top");
	
		if(what == "mv") {
			
			el.setStyle("visibility","hidden").hide({
				complete:function() {
					el.setStyle("visibility","visible").slide("in",{
						complete:function() {
							$timeout(el._get("duration"),function() {
								el.slide("out",{
									complete:function() {
										p.removeScroll();
										p.add(what);
									}
								});
							});
						}
					});
				}
			});
			
		} else {
			
			el.fade("in",{
				opacity:el._get("growl_opacity"),
				complete:function() {
					$timeout(el._get("duration"),function() {
						el.fade("out",{
							opacity:el._get("growl_opacity"),
							complete:function() {
								p.removeScroll();
								if(what == "bezel")	p.add(what);
							}
						});
					});
				}
			});
			
			// makes it centered
			if(what == "bezel")	el.setStyle("margin-left",-(el.getSize().width / 2));
			
		}
		
	},
	
	close:function(id) {
		var p = this;
		this.growls.each(function(el,i) {
			if(el.get("id") == id) {
				el.fade("out",{
					complete:function() {
						p.growls.splice(i,1);
						this.destroy();
					}
				});
			}
		});
	}
	
};


// 
// Table Sorter
// HUGE THANKS to leigeber - this is completely rewritten from his famous TINY Table to fit with GOOP... no credit here
//
function TableSorter(id,options) {
	
	options = options || {};
	
	var element = $(id);
	var thead = element.getElement("thead",[]), tbody = element.getElement("tbody",[]);
	var rows = tbody.getElements("tr",["styles"]), rows_length = rows.length;
	var cells = [], col = -1, order, pp = options.perpage || 20, pages_max = 1, pages_current = 1, i, el;
	
	// set up thead cells
	for(i = 0; i < thead.getElement("tr").cells.length; i++) {
		el = $(thead.getElement("tr").cells[i],["events","dimensions"]);
		if(!el.hasClass("nosort")) 
			el.addEvent("click",sort);
	};
	
	// make the cell array with objects
	for(i = 0; i < rows_length; i++) cells[i] = {};
	
	// start and complete functions
	element.started = options.start || function() {};
	element.completed = options.complete || function() {};
	
	// auto sort
	if(options.sort > -1) {
		thead.getElement("tr").cells[options.sort].doEvent("click");
	} else {
		if(options.paginate)
			perpage(pp);
	}
	
	// search ability?
	if(options.search) {
		
		var tr = new Element("tr",{"class":"tablesorter_search"},[]);
		tr.inject(thead);

		for(i = 0; i < thead.getElement("tr",false).cells.length; i++) {
			el = new Element("td",{"class":"tablesorter_search"},[]);
			if(options.search.indexOf(i) > -1) {
				new Element("input",{
					"type":"text",
					"setStyles":{
						"width":thead.getElement("tr",false).cells[i].getSize().width
					},
					"addEvents":{
						"keyup":search
					}
				}).inject(el);
			}
			el.inject(tr);
		}
	}
	
	// sort the table
	function sort() {

		element.started();
		
		var tr = tbody.getElement("tr.tablesorter_noresults");
		if(tr) tr.destroy();
		
		// remove all header class names
		for(i = 0; i < thead.getElements("tr",false)[options.search ? 1 : 0].cells.length; i++) {
			thead.getElements("tr",false)[options.search ? 1 : 0].cells[i].removeClass("asc").removeClass("desc");
		}
		
		if(col == this.cellIndex) {
			cells.reverse();
			order = (order == "asc") ? "desc" : "asc";
			this.set("class",order);
		} else {
			col = this.cellIndex;
			rows.each(function(el,i) {
				var v = el.setStyle("display",'').cells[col];
				while(v.hasChildNodes()) v = v.firstChild;
				cells[i].v = (v.nodeValue || '').toLowerCase();
				cells[i].n = i;
			});
			cells.sort(compare);
			if(options.order) {
				order = options.order;
				options.order = -1;
				if(order == "desc") cells.reverse();
			} else {
				order = "asc";
			}
			this.set("class",order);
		}
		
		// create a new tbody and replace the old
		var tb = new Element("tbody",{},[]);
		cells.each(function(el,i) {
			tb.adopt(rows[el.n].set("class", i % 2 ? "even" : "odd"));
		});
		tb.replaces(tbody);
		tbody = tb;
		
		// show the current page we are on
		if(options.paginate) perpage(pp);
		
		element.completed();
				
	}
	
	// comapre values
	function compare(f,c) {
		var g,h; f = g = f.v, c = h = c.v;
        var i = f.replace(/(\$|\,)/g, '').toFloat(), n = c.replace(/(\$|\,)/g, '').toFloat();
        if(!isNaN(i) && !isNaN(n)) g = i, h = n;
		i = Date.parse(f), n = Date.parse(c);
		if(!isNaN(i) && !isNaN(n)) g = i, h = n;
        return g > h ? 1 : (g < h ? -1 : 0);
    }

	function search() {
		
		var p = this, v, f, c = 0, w = 1, tr = tbody.getElement("tr.tablesorter_noresults");
		
		if(this.value == '') {
			if(tr) tr.destroy();
			perpage(pp);
		} else {

			// find the cell value we are looking in
			tbody.getElements("tr",["styles"]).each(function(el) {
				if(!el.hasClass("tablesorter_noresults")) {
				
					v = el.cells[p.parentNode.cellIndex];
					while(v.hasChildNodes()) v = v.firstChild;
					v = (v.nodeValue || '').toLowerCase();
				
					f = 0;
					if(v.indexOf(p.value) > -1 && c < pp) f = 1, c++;
				
					el.setStyle("display",f ? '' : "none");
					if(f) w++, el.set("class",w % 2 ? "even" : "odd");
					
				}
			});
			
			// no found results
			if(c > 0) {
				if(tr) tr.destroy();
			} else {
				if(tr) return;
				tr = new Element("tr",{"class":"tablesorter_noresults"},[]);
				new Element("td",{
					"colspan":thead.getElement("tr").cells.length,
					"align":"center",
					"html":"No Results"
				}).inject(tr.inject(tbody));
			}
			
		}
		
	}

	// make functions, then save them to act as prototypes
	function move(d,f) {
		var s = d == 1 ? (f ? pages_max : pages_current + 1) : (f ? 1 : pages_current - 1);
		if(s > pages_max || s <= 0) return;
		pages_current = s;
		page((s - 1) * pp);
		if(options._ids[0]) 
			$(options._ids[0]).set("html",pages_current);
	}
	
	function perpage(n) {
		pp = n.toInt();
		pages_max = Math.ceil(rows_length / pp);
		move(-1,true); // show the beginning
		if(options._ids[1]) 
			$(options._ids[1]).set("html",pages_max);
	}
	
	function page(n) {
		var m = n + pp;
		tbody.getElements("tr",["styles"]).each(function(el,i) {
			el.setStyle("display",i >= n && i < m ? '' : "none").set("class",i % 2 ? options.even || "even" : options.odd || "odd");
		});
	}
	
	// acts as prototypes
	this.move = move;
	this.perpage = perpage;
	this.page = page;
	
};


// 
// tab slider
// thank you for the idea creative pony and panic
//
function SlideTabs(id,options) {
	
	options = options || {};
	options.slide = (options.slide == undefined ? true : options.slide);
	
	var element = $(id);
	var tabs = element.getElements(options.tabs || "li.tab");
	var pans = element.getElements(options.pans || "div.pan");
	var count = tabs.length;
	var current_pan_index;

	// get width, include the padding if any
	var pans_width = options.width || pans[0].getSize().width;
	pans_width = (options.wholebody ? document.body.getSize().width : pans_width);
	var wrapper_width = pans_width * count;
	
	
	// set the header tab index and click event
	tabs.each(function(el,i) {
		el._set("slidetab_index",i);
		el.addEvent("click",slide);
	});
	
	// set the width for the pans
	pans.each(function(el) {
		el.setStyles({
			"width":pans_width,
			"float":"left"
		});
	});
	
	// make a container
	var container = new Element("div",{
		"id":"slidetab_container",
		"setStyles":{
			"overflow":"hidden",
			"width":pans_width
		}
	});
	
	// now make a wrapper
	var wrapper = new Element("div",{
		"id":"slidetab_wrapper",
		"setStyles":{
			"margin-left":0,
			"width":wrapper_width
		}
	});
	
	// put the pans in the wrapper, then the wrapper in the container
	wrapper.wraps(pans);
	container.wraps(wrapper);

	// adjust the onreize for the window, if we sent the option to do so... this is only necessary if it strecths the whole window
	if(options.wholebody) {
		window.addEvent("resize",fixpans);
		window.doEvent("resize");
	}
	
	// auto show?
	if(options.show > -1) {
		var h = options.slide;
		options.slide = false;
		tabs[options.show].doEvent("click");
		options.slide = h;
	} else {
		tabs[0].doEvent("click");
	}
	
	// slide the wrapper
	function slide() {
		
		// change the class
		var p = this;
		tabs.each(function(el) {
			if(el == p) 
				el.addClass("current");
			else 
				el.removeClass("current");
		});
		
		var next = -(this._get("slidetab_index") * pans_width);
		current_pan_index = this._get("slidetab_index");
		
		if(options.slide) {
			
			var current = wrapper.getStyle("margin-left").toInt();
		
			wrapper.tween("margin-left",current,next,{
				duration:750
			});
			
		} else {
			wrapper.setStyle("margin-left",next);
		}
		
	}
	
	// fix the pans when resize
	function fixpans() {
		
		// get new width
		pans_width = document.body.getSize().width;
		wrapper_width = pans_width * count;
		
		// reset the width for the pans
		pans.each(function(el) {
			el.setStyles({
				"width":pans_width,
				"float":"left"
			});
		});		
		
		// adjust the wrapper and container width
		container.setStyle("width",pans_width)
		wrapper.setStyle("width",wrapper_width);
		wrapper.setStyle("margin-left",-(current_pan_index * pans_width));
		
	}
	
};


//
// autocomplete
//
function AutoComplete(id,options) {
	
	options = options || {};
	if(!options.path) return;
	
	options.limit = options.limit || 20;
	
	var element = $(id);
	var list = [], selected = -1;
	var ajax = new Ajax({
		url:options.path,
		complete:didSearch
	});
	
	// make the ul tag
	var ul = new Element("ul",{
		"class":"autocomplete",
		"setStyles":{
			"display":"none",
			"position":"absolute",
			"z-index":99
		}
	}).inject(document.body,"top");
	
	// add event to element
	element.addEvents({
		"keyup":doSearch,
		"blur":hideSearch
	});
	
	function hideSearch() {
		$timeout(500,function() {
			ul.setStyle("display","none");
		});
	}
	
	function doSearch(e) {
		
		// move the list 
		ul.setStyles({
			"top":element.getPosition().top + element.getSize().height,
			"left":element.getPosition().left
		});
		
		// determine what key was pressed
		switch(new Event(e).code) {
			case 37: // left arrow
				return;
			case 39: // right arrow
				return;
			case 38: // up arrow
				selected = selected > 0 ? selected - 1 : 0;
				showSelected();
				break;
			case 40: // down arrow
				selected = selected < list.length - 1 ? selected + 1 : list.length - 1;
				showSelected();
				break;
			case 13: // enter
				if(list[selected])
					list[selected].doEvent("click");
				break;
			case 27: // escape
				ul.setStyle("display","none");
				break;
			default:
				list = [], selected = -1;
				ajax.send("value=" + this.value);
				break;
		}
		
	}
	
	function didSearch(html) {
		
		// empty all children inside of ul
		ul.empty();
		
		var results = JSON.toObject(html), c = 0, i;
		
		for(i in results) {

			list[c++] = new Element("li",{
				"html":i,
				"setStyles":{
					cursor:"pointer"
				},
				"addEvents":{
					click:function() {
						window.location.href = this._get("autocomplete_click");
					},
					mouseover:function() { 
						selected = this._get("autocomplete_c");
						showSelected();
					}
				}
			},["styles","events"])._set("autocomplete_c",c - 1)._set("autocomplete_click",results[i]).inject(ul);
			
			// limit
			if(c >= options.limit) break;
			
		}
		
		ul.setStyle("display",(c == 0 ? "none" : ''));
	
	}
	
	function showSelected() {
		list.each(function(el,i) {
			if(selected == i)
				el.addClass("over");
			else 
				el.removeClass("over");
		});
	}
	
}


//
// Validate
// idea from leigeber
//
var Validate = {
	
	move:true, // true to move window to error, false otherwise
	goaway:true, // do you want the validate warning to go away?
	offset_x:10,
	offset_y:5,
	duration:2500, // how long before it fades out
	
	// legal characers only
	legal:function(input,msg) {
		var value, filter, flag;
		value = (typeof input == "object" ? input.value : input).trim();
		filter = /\W/;
		flag = (value != '' ? !filter.test(value) : false);
		if(!flag && typeof input == "object") this.alert(input,msg || "Invalid Characters");
		return flag;
	},

	// validate email - sample@sample.com
	email:function(input,msg) {
		var value, filter, flag;
		value = (typeof input == "object" ? input.value : input).trim();
		filter = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;
		flag = filter.test(value);
		if(!flag && typeof input == "object") this.alert(input,msg || "Invalid Email");
		return flag;
	},
	
	// phone - (123) 456-7890
	phone:function(input,msg) {
		var value, filter, flag;
		value = (typeof input == "object" ? input.value : input).trim();
		filter = /^\([1-9]\d{2}\)\s?\d{3}\-\d{4}$/;
		flag = filter.test(value);
		if(!flag && typeof input == "object") this.alert(input,msg || "Invalid Phone");
		return flag;
	},
	
	// number
	number:function(input,msg) {
		var value, filter, flag;
		value = (typeof input == "object" ? input.value : input).trim();
		filter = /(^-?\d\d*\.\d*$)|(^-?\d\d*$)|(^-?\.\d\d*$)/;
		flag = filter.test(value);
		if(!flag && typeof input == "object") this.alert(input,msg || "Invalid Number");
		return flag;
	},
	
	// letters only
	letters:function(input,msg) {
		var value, filter, flag;
		value = (typeof input == "object" ? input.value : input).trim();
		filter = /^[a-zA-Z]+$/;
		flag = filter.test(value);
		if(!flag && typeof input == "object") this.alert(input,msg || "Characters Only");
		return flag;
	},
	
	// zip - 12345 or 12345-1234
	zip:function(input,msg) {
		var value, filter, flag;
		value = (typeof input == "object" ? input.value : input).trim();
		filter = /\d{5}(-\d{4})?/;
		flag = filter.test(value);
		if(!flag && typeof input == "object") this.alert(input,msg || "Invalid Zip");
		return flag;
	},
	
	// date - MM/DD/YYYY
	date:function(input,msg) {
		var value, filter, flag;
		value = (typeof input == "object" ? input.value : input).trim();
		filter = /^([1-9]|0[1-9]|1[012])\D([1-9]|0[1-9]|[12][0-9]|3[01])\D(19[0-9][0-9]|20[0-9][0-9])$/;
		flag = filter.test(value);
		if(!flag && typeof input == "object") this.alert(input,msg || "Invalid Date");
		return flag;
	},
	
	// url - http://www.sample.com or www.sample.com
	url:function(input,msg) {
		var value, filter, flag;
		value = (typeof input == "object" ? input.value : input).trim();
		filter = /(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/;
		flag = filter.test(value);
		if(!flag && typeof input == "object") this.alert(input,msg || "Invalid URL");
		return flag;
	},
	
	// extension - default: jpeg, jpg, gif, png, swf ... pass an array to match your own
	ext:function(input,msg,ex) {
		var value, flag;
		ex = ex || ["jpeg","jpg","gif","png","swf"];
		value = (typeof input == "object" ? input.value : input).trim();
		value = value.substring(value.lastIndexOf(".") + 1).toLowerCase();
		flag = false;
		ex.each(function(e) {
			if(e == value) flag = true;
		});
		if(!flag && typeof input == "object") this.alert(input,msg || "Invalid Extension Type");
		return flag;
	},
	
	// determines if the input field is empty
	empty:function(input,msg) {
		var value, flag, i;
		if(typeof input == "object") {
			if(input.tagName == "SELECT") {
				value = input.options[input.selectedIndex].value.trim();
			} else if(input.tagName == "INPUT" || input.tagName == "TEXTAREA") {
				value = input.value.trim();
			} else if(input[0] && input.tagName == undefined) {
				value = ''; // lets assume its not checked
				for(i = 0; i < input.length; i++) {
					if(input[i].checked) value = "checked"; // value is now set to something
				}
				input = input[0]; // for the error message, if any
			}
		} else {
			value = input.trim();
		}
		flag = value != '';
		if(!flag && typeof input == "object") this.alert(input,msg || "Can not be empty");
		return !flag;
	},
	
	// alerts the warning
	alert:function(element,msg) {
		
		if(!element || !msg || typeof element != "object") return;
		
		// acts as parent
		var p = this;
		
		// extend the element first, then we can get the dimensions
		GOOP.extend(element,["dimensions"]);
		var pos = element.getCoordinates();
		
		// wrapper
		new Element("div", {
			"html":msg,
			"class":"validate",
			"setStyles":{
				"position":"absolute",
				"z-index":99,
				"opacity":0,
				"top":pos.top - this.offset_y,
				"left":pos.left + pos.width + this.offset_x
			}
		}).inject(document.body,"top").fade("in",{
			complete:function() {
				if(!p.goaway) return;
				var el = this;
				$timeout(p.duration,function() {
					el.fade("out",{
						complete:function() {
							this.destroy();
						}
					});
				});
			}
		});
		
		// move to element
		if(this.move) window.scrollTo(pos.left, pos.top);
		
	}
	
};


//
// date picker
// reference from jszen.blogspot.com
//
var DatePicker = {
	
	element:null,
	
	//
	picked:function(year,month,day) {
		if(this.element == null || !year || !month || !day) return;
		month++;
		this.element.value = year + "-" + (month < 10 ? "0" : '') + month + "-" + (day < 10 ? "0" : '') + day;
		this.close();
	},
	
	// 
	changeDate:function(y,m) {
		if(m < 0) y - 1, m = 11;
		if(m > 11) y + 1, m = 0;
		this.close();
		this.open(this.element,{year:y,month:m});
	},

	// open the datepicker
	open:function(element,options) {

		this.element = element || this.element;
		if(!this.element) return;
		if($("datepicker") != null) return;
		
		options = options || {};
		
		var date = new Date();
		var month = (options.month != undefined ? options.month : date.getMonth());
		var year = (options.year != undefined ? options.year : date.getFullYear());
		
		var days = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
		var months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
		var days_in_month = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];

		var first_day = new Date(year, month, 1);
		var start_day = first_day.getDay();
		var month_length = days_in_month[month];
		if(month == 1) {
			if((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)
				month_length++;
		}

		// 
		var html = '';
		html += "<table class=\"datepicker\">";

		// close
		html += "<tr><td align=\"right\" colspan=\"7\"><a href=\"javascript:DatePicker.close();\" class=\"close\">Close</a></td></tr>";

		// month and year
		html += "<tr><th colspan=\"7\">" + months[month] + " " + year + "</th></tr>";
		
		// options
		html += "<tr class=\"datepicker_options\">";
		html += "<td align=\"center\"><a href=\"javascript:DatePicker.changeDate(" + (year - 1) + "," + month + ");\"><<</a></td>";
		html += "<td align=\"center\"><a href=\"javascript:DatePicker.changeDate(" + year + "," + (month - 1) + ");\"><</a></td>";
		html += "<td align=\"center\" colspan=\"3\"><a href=\"javascript:DatePicker.changeDate(" + date.getFullYear() + "," + date.getMonth() + ");\">Today</a></td>";
		html += "<td align=\"center\"><a href=\"javascript:DatePicker.changeDate(" + year + "," + (month + 1) + ");\">></a></td>";
		html += "<td align=\"center\"><a href=\"javascript:DatePicker.changeDate(" + (year + 1) + "," + month + ");\">>></a></td>";
		html += "</tr>";

		// days of week
		html += "<tr class=\"datepicker_header\">";
		for(var i = 0; i < 7; i++)
			html += "<td>" + days[i] + "</td>";
		html += "</tr>";

		// days of month
		var day = 1, i, j;
		html += "<tr>";
		for(i = 0; i < 9; i++) {
			for(j = 0; j < 7; j++) {
				html += "<td class=\"day\" onclick=\"DatePicker.picked(" + year + "," + month + "," + day + ");\">";
				if(day <= month_length && (i > 0 || j >= start_day)) {
					
					if(year == date.getFullYear() && month == date.getMonth() && day == date.getDate()) html += "<strong>" + day + "</strong>";
					else html += day;

					day++;
				}
				html += "</td>";
			}
			if(day > month_length) break;
			else html += "</tr><tr>";
		}

		// done
		html += "</tr></table>";

		// extend the element, then we can get the dimensions
		GOOP.extend(this.element,["dimensions"]);
		var pos = this.element.getCoordinates();

		// wrapper
		new Element("div",{
			"html":html,
			"id":"datepicker",
			"setStyles":{
				"position":"absolute",
				"z-index":99,
				"top":pos.top,
				"left":pos.left + pos.width + 10
			}
		}).inject(document.body,"top");
		
	},
	
	// closes the datepicker
	close:function() {
		var dp = $("datepicker");
		if(dp != null) dp.destroy();
	}
	
};

//
// rounder - makes a rounded
// thank you Steven Wittens
//
function Rounder(id,options) {
	
	options = options || {};
	options.bg = options.bg || "000000";
	options.fg = options.fg || "eeeeee";
	options.radius = options.radius || 8;
	options.size = options.size || 1;
	
	var element = $(id);
	
	// get html and erase it
	var html = element.get("html");
	element.set("html",'');
	
	// round the element
	if(options.top === true || options.top == undefined) _round(element,options,"top");
	rounder_content(element,options);
	if(options.bottom === true || options.bottom == undefined) _round(element,options,"bottom");
	
	// put the html back in it, and fix the orginial element 
	element.setStyles({
		"border":"none",
		"background-color":"transparent"
	}).getElement("div.rounder_content").set("html",html);

	function sqr(n) {
		return n * n;
	}

	function _round(el,options,where) {
		
		var div = new Element("div",{},[]);
		
		var begin = (where == "top" ? 1 : options.radius);
		var end = (where == "top" ? options.radius : 1);
		var increment = (where == "top" ? 1 : -1);
		
		for(var i = begin; (where == "top" ? i <= end : i >= end); i+=increment) {
			
			var arc = -(Math.sqrt(1 - sqr(1 - i / options.radius)) * options.radius);
			
			div.adopt(new Element("div", {
				setStyles:{
					"margin":"0px " + (arc + options.radius) + "px",
					"padding":0,
					"height":(i == end ? Math.ceil(options.size / 2) : 1),
					"background-color":"#" + (i == 1 ? options.bg : options.fg),
					"border-left":options.size + "px solid #" + options.bg,
					"border-right":options.size + "px solid #" + options.bg
				}
			}));
			
		}
		
		div.inject(el,where);
	}
	
	function rounder_content(el,options) {
		
		el.adopt(new Element("div",{
			"class":"rounder_content",
			"setStyles":{
				"background-color":(options.fg != "transparent" ? "#" : '') + options.fg,
				"border-top":(options.top === false ? options.size + "px solid #" + options.bg : "none"),
				"border-right":options.size + "px solid #" + options.bg,
				"border-bottom":(options.bottom === false ? options.size + "px solid #" + options.bg : "none"),
				"border-left":options.size + "px solid #" + options.bg
			}
		}));
		
	}
	
};


//
// drag and drop
// thank you Luke Breuer - http://luke.breuer.com/tutorial/javascript-drag-and-drop-tutorial.aspx
//
function DragDrop(id,options) {
	
	options = options || {};
	options.revert = (options.revert === false ? false : true);
	options.x = (options.x === false ? false : true);
	options.y = (options.y === false ? false : true);
	options.disable = (options.disable === false ? false : true);
	
	var element = $(id);
	var handle = (options.handle ? element.getElement(options.handle) : null);
	
	// can't be a static element
	element.setStyle("position","relative");
	
	// add the functions
	element.started = options.start || function() {};
	element.moved = options.move || function() {};
	element.completed = options.complete || function() {};

	// some variables
	var sx = 0, sy = 0, ox = 0, oy = 0, z = element.getStyle("z-index"), target = null, drag = false;

	document.body.addEvent("mousedown", mousedown);
	document.body.addEvent("mouseup", mouseup);
	
	// if strict, disable the text selection
	if(options.disable) {
		var t = (handle ? handle : element);
		t.onselectstart = function() { return false; }
		t.onmousedown = function() { return false; }
		t.ondragstart = function() { return false; }
	}
	
	function mousedown(e) {
		
		target = $((e.target ? e.target : e.srcElement));
		
		// not the element we want to move
		if((target !== handle && handle != null) || (target !== element && handle == null)) return;
		
		// check the click
		if(e.button == 1 && window.event != null || e.button == 0) {

			// dragging
			drag = true;

			// grab the mouse position
			e = new Event(e);
			sx = e.page.x;
			sy = e.page.y;
			
			// grab the clicked elements position
			ox = element.getStyle("left").toInt();
			oy = element.getStyle("top").toInt();
			ox = (isNaN(ox) ? 0 : ox);
			oy = (isNaN(oy) ? 0 : oy);
			
			// bring to the front, and start the function
			element.setStyle("z-index",99).started();
			
			// add event
			document.body.addEvent("mousemove", mousemove);
			
		}
	}
	
	function mousemove(e) {
		
		e = new Event(e);
		var x = ox + e.page.x - sx, y = oy + e.page.y - sy;
		
		// move the element, execute the function
		element.setStyles({
			"left":(options.x ? x : ''),
			"top":(options.y ? y : '')
		}).moved();
				
	}
	
	function mouseup() {
		
		// stop moving the element
		if(!drag) return;
		drag = false;
		
		// remove the event
		document.body.removeEvent("mousemove",mousemove);
		
		// completed
		element.completed();
		
		// do this at end
		if(!options.revert) {
			element.setStyles({
				"top":0,
				"left":0,
				"z-index":z
			});
		} else {
			element.setStyle("z-index",z);
		}
		
	}
	
}


//
// reflect
// reflections on images - big thanks to reflection.js 2.0 - http://cow.neondragon.net/stuff/reflection/
//
function Reflect(id,options) {
	
	options = options || {};
	options.height = options.height || .5;
	options.opacity = (options.opacity || 50) * .01;
	
	// to save an errors
	if(!GOOP.dom || !GOOP.load) {
		recheck(50);
		return;
	}
	
	var element = (this == window || id == window ? $$("img.reflect") : $(id));
	if(element == null) return;
	
	if(Object.prototype.toString.apply(element) === "[object Array]") {
		element.each(function(el) {
			add(el);
		});
	} else {
		add(element);
	}
	
	// add the reflection
	function add(el) {
		
		// remove old reflection first
		remove(el);
		
		if(!el.tagName) {
			recheck(50);
			return;
		}
		
		var h = el.getSize().height, w = el.getSize().width;
		var rh = Math.floor(h * options.height);
		var dh = Math.floor(h * (1 + options.height));
		
		if(Browser.name == "Explorer") {
			
			// fix hyberlinks
			if(el.parentNode.tagName == "A")
				var a = new Element("a",{"href":el.parentNode.href},[]);
			else
				var d = new Element("div",{},[]);
			
			var reflection = new Element("img",{
				"src":el.get("src"),
				"setStyles":{
					"width":w,
					"height":h,
					"display":"block",
					"margin-bottom":-(h - rh),
					"filter":"flipv progid:DXImageTransform.Microsoft.Alpha(opacity=" + (options.opacity * 100) + ", style=1, finishOpacity=0, startx=0, starty=0, finishx=0, finishy=" + (options.height * 100) + ")"
				}
			});
			
			reflection.inject((a || d).wraps(el));
			
		} else {
			
			var canvas = new Element("canvas",{
				"class":el.get("class"),
				"width":w,
				"height":h * .5
			});

			if(!canvas.getContext) return;
			
			var context = canvas.getContext("2d");
			context.save();
			context.translate(0,h-1);
			context.scale(1,-1);
			context.drawImage(el, 0, 0, w, h);
			context.restore();
			context.globalCompositeOperation = "destination-out";
			
			var gradient = context.createLinearGradient(0, 0, 0, rh);
			gradient.addColorStop(1, "rgba(255, 255, 255, 1.0)");
			gradient.addColorStop(0, "rgba(255, 255, 255, " + (1 - options.opacity) + ")");
			
			context.fillStyle = gradient;
			context.rect(0, 0, w, rh * 2);
			context.fill();

			canvas.inject(new Element("div",{
				"setStyles":{
					"width":w
				}
			},["styles"]).wraps(el.setStyle("vertical-align","bottom")));
			
		}
		
	}
	
	function remove(el) {
		if(!el.hasClass("reflect")) return;
		var p = GOOP.extend(el.parentNode,[]), c = p.getElement("canvas");
		if(c) {
			c.destroy();
			el.replaces(p);
		}
	}
	
	function recheck(m) {
		$timeout(m, function() { Reflect(window); });
	}
	
}



//
// extended prototypes
// thank you MooTools
//

// array
Array.prototype.each = function(ftn) {
	var l = this.length, i;
	for(i = 0; i < l; i++)
		ftn(this[i],i);
	return this;
}
Array.prototype.indexOf = function(search) {
	var l = this.length, i;
	for(i = 0; i < l; i++)
		if(this[i] == search) 
			return i;
	return -1;
}
Array.prototype.shuffle = function() {
	var l = this.length, i;
	for(i = 0; i < l; i++)
		this.push(this.splice(Math.floor(Math.random()*l),1));
	return this;
}

// numbers and string
Number.prototype.toInt = String.prototype.toInt = function(radix) {
	return parseInt(this, radix || 10);
}
Number.prototype.toFloat = String.prototype.toFloat = function() {
	return parseFloat(this);
}
String.prototype.trim = function() {
	return this.replace(/^\s+|\s+$/g, '');
}
String.prototype.camelCase = function() {
	return this.replace(/-\D/g, function(match) {
		return match.charAt(1).toUpperCase();
	});
}


//
GOOP.extend(window,["events"]);
Browser.init();
DOM.ready(GOOP.ondom);
window.addEvent("load",GOOP.onload);