var Class = {
	add: function (o, c) {
		var cn = o.className;
		var m = new RegExp("\\b" + c + "\\b", "i").exec(cn);
		if (!m) {
			o.className += (cn.length > 0 ? " " : "") + c;
		}
	},

	remove: function (o, c) {
		var cn = o.className;
		var m = new RegExp("\\b" + c + "\\b", "i").exec(cn);
		if (m) {
			o.className = (cn.replace(new RegExp(m), ""));
		}
	},
	
	get: function(o, c) {
		return o.className.match(new RegExp("\\b" + c + "\\b"));
	}
};
Event.modify = function(obj, event, fnct, context, actions, attach) {
	var fn = Function.bind(fnct, (context || obj));
	var custom = obj["_on" + event];
	if (custom && attach) {
		obj["_on" + event] = function() {
			return ((custom.apply(this, arguments) !== false ? true : false) && (fn.apply(this, arguments) !== false ? true : false));
		};
	} else if (!custom) {
		var handle = Function.bind(Event.handle, Event, fn, actions);
		if (obj.addEventListener) {
			obj[(attach ? "add" : "remove") + "EventListener"](event, handle, false);
		} else {
			obj[(attach ? "at" : "de") + "tachEvent"]("on" + event, handle);
		}
	}
};
Event.attach = function (obj, event, fnct, context, actions) { Event.modify(obj, event, fnct, context, actions, true); };
Event.detach = function (obj, event, fnct, context, actions) { Event.modify(obj, event, fnct, context, actions, false); };
Event.handle = function(fnct, actions, e) {
	e = (e || window.event);
	if (!e.target) {
		e.target = e.srcElement;
	}
	if (actions) {
		for (var i = 0, action; action = actions[i]; i++) {
			switch (action) {
				case Event.actions.PREVENT_DEFAULT:
					if (e.preventDefault) {
						e.preventDefault();
					} else {
						e.returnValue = false;
					}
					break;
				
				case Event.actions.STOP_PROPAGATION:
					if (e.stopPropagation) {
						e.stopPropagation();
					} else {
						e.cancelBubble = true;
					}
					break;
				
				case Event.actions.BLUR:
					if (e.target && e.target.blur) {
						e.target.blur();
					}
					break;
			}
		}
	}
	fnct(e);
};
Event.actions = {
	PREVENT_DEFAULT: 1,
	STOP_PROPAGATION: 2,
	BLUR: 4
};
Function.bind = function(fnct, context) {
	var args = $a(arguments).slice(2, arguments.length);
	var cache = Function.bind.cache;
	for (var i = 0, cacheFnct; cacheFnct = cache[i]; i++) {
		if (cacheFnct.fnct == fnct && cacheFnct.context == context && cacheFnct.args.length == args.length) {
			var t = true;
			for (var j = 0, a1, a2; (a1 = cacheFnct.args[j]) && (a2 = a[j]); j++) {
				t = (a1 == a2);
				if (!t) {
					break;
				}
			}
			if (t) {
				return cacheFnct.method;
			}
		}
	}
	
	var newFnct = {
		fnct: fnct,
		obj: context,
		args: args,
		method: function() {
			return fnct.apply(context, (args ? args.concat($a(arguments)) : arguments));
		}
	};
	
	cache.push(newFnct);
	return newFnct.method;
};
Function.bind.cache = [];
function $a(a) {
	var r = new Array();
	for (var i = 0, l = a.length; i < l; i++) {
		r.push(a[i]);
	}
	return r;
}
function $i(s, p) {
	return (p || document).getElementById(s);
}
function $t(t, p) {
	return (p || document).getElementsByTagName(t || "*");
}
function $c(c, t, p) {
	var a = [];
	var ts = $t(t, p);
	var r = new RegExp("\\b" + c + "\\b");
	for (var i = 0, t; t = ts[i]; i++) {
		if (t.className.match(r)) {
			a.push(t);
		}
	}
	return a;
}
function Tabs(parent, className, tag, parentLevel) {
	tag = (tag || "a");
	if (parentLevel === undefined || parentLevel === null) {
		parentLevel = 1;
	}
	this.tabs = [];
	var anchors = (className ? $c(className, tag, parent) : $t(tag, parent));
	for (var i = 0, anchor; anchor = anchors[i]; i++) {
		var contentID = anchor.id.replace(Tabs.idRe, "");
		var tab = new Tab(this, anchor, (contentID != anchor.id ? $i(contentID) : null), Tabs.getParent(anchor, parentLevel));
		this.tabs.push(tab);
		Event.attach(anchor, "click", tab.click, tab, [ Event.actions.PREVENT_DEFAULT, Event.actions.BLUR ]);
	}
}
Tabs.getParent = function(node, level) {
	var parent = node;
	var current = level;
	while (current > 0) {
		parent = parent.parentNode;
		current--;
	}
	return parent;
};
Tabs.idRe = /-[^-]+$/;
Tabs.prototype = {
	_onchange: function(newTab, oldTab) {},
	select: function(selectTab) {
		var oldTab;
		for (var i = 0, tab; tab = this.tabs[i]; i++) {
			if (Class.get(tab.parent, "selected")) {
				oldTab = tab;
			}
		}
		if (selectTab != oldTab && this._onchange(selectTab, oldTab) != false) {
			this.display(oldTab, false);
			this.display(selectTab, true);
		}
	},
	display: function(tab, select) {
		if (tab) {
			Class[select ? "add" : "remove"](tab.parent, "selected");
			if (tab.content) {
				Class[select ? "add" : "remove"](tab.content, "selected");
			}
		}
	},
	clear: function() {
		for (var i = 0, tab; tab = this.tabs[i]; i++) {
			this.display(tab, false);
		}
	}
};
function Tab(container, anchor, content, parent) {
	this.container = container;
	this.anchor = anchor;
	this.content = content;
	this.parent = parent;
}
Tab.prototype = {
	click: function(e) {
		this.container.select(this);
	}
};
function Flipper(parent, duration, pause, easing) {
	this.parent = parent;
	this.items = [];
	var lis = $t("blockquote", parent);
	for (var i = 0, li; li = lis[i]; i++) {
		this.items.push(li);
	}
	// The current visible item is the last one in the list
	this.item = this.items[0];
	
	this.duration = (duration || .5);
	this.pause = (pause || 7);
	this.fps = 200;
	this.frames = this.fps * this.duration;
	this.current = 0;
	this.easing = (easing || Easing.easeInOut);
	this.random = false;
}
Flipper.prototype = {
	start: function() {
		if (this.thread) {
			clearInterval(this.thread);
		}
		this.thread = setInterval(Function.bind(this.flip, this), (this.pause + this.duration) * 1000);
	},
	
	stop: function() {
		if (this.thread) {
			clearInterval(this.thread);
		}
	},
	
	flip: function() {
		var old = this.item;
		this.getNext();
		this.setOpacity(0);
		this.setIndex(old);
		this.current = 0;
		this.started = new Date();
		this.action();
	},
	
	action: function() {
		if (this.current < this.frames) {
			this.check();
			this.setOpacity(this.easing(this.current, 0, 100, this.frames));
			setTimeout(Function.bind(this.action, this), 1);
		}
	},
	
	check: function() {
		var time = (new Date() - this.started);
		var calcFrame = Math.round((time * this.frames) / (this.duration * 1000)) + 1;
		this.current = (calcFrame <= this.frames ? calcFrame : this.frames);
	},
	
	getNext: function() {
		var old = this.item;
		if (this.random) {
			while (this.item == old) {
				this.item = this.items[Math.floor(Math.random() * this.items.length)];
			}
		} else {
			for (var i = 0, l = this.items.length - 1; i <= l; i++) {
				var item = this.items[i];
				if (item == this.item) {
					this.item = this.items[i < l ? i + 1 : 0];
					break;
				}
			}
		}
	},
	
	setOpacity: function(opac) {
		this.item.style.opacity = opac / 100;
		this.item.style.filter = "alpha(opacity=" + opac + ")";
	},
	
	setIndex: function(old) {
		for (var i = 0, item; item = this.items[i]; i++) {
			item.style.zIndex = (item == this.item ? 10 : (item == old ? 5 : 0));
		}
	}
};
var Easing = {
	linear: function(t, b, c, d) { return c*t/d + b; },
	easeIn: function(t, b, c, d) { return c*(t/=d)*t*t + b; },
	easeOut: function(t, b, c, d) { return c*((t=t/d-1)*t*t + 1) + b; },
	easeInOut: function(t, b, c, d) {
		if ((t/=d/2) < 1) return c/2*t*t*t + b;
		return c/2*((t-=2)*t*t + 2) + b;
	}
};