// @name: js_lib
// @version: 3.1.0a
// @author: Neo Geek {neo@neo-geek.net}
// @website: http://neo-geek.net/
// @copyright: (c) 2007 Neo Geek, Neo Geek Labs

// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

var js_lib = {
	version: '3.1.0a',
	timestamp: '2007-03-23 12:19:29',
	website: 'http://js_lib.com/',
	author: {
		name: 'Neo Geek',
		email: 'neo@neo-geek.net',
		website: 'http://neo-geek.net/'
	}
};

// @name: Object.extend
// @syntax: Object.extend(object destination, function source);
// @dependencies: none

Object.extend = function(destination, source) {
	for (property in source) { destination[property] = source[property]; }
	return destination;
};

// @name: addLoadEvent
// @syntax: addLoadEvent(function func);
// @dependencies: addEvent

var addLoadEvent = function(func) {
	return addEvent('load', function() { func(); }, window);
};

// @name: addEvent
// @syntax: addEvent(string method, function func [, object object]);
// @dependencies: none

function addEvent(method, func, object) {
	method = method.replace(/^on/, '');	
	object = object?$(object):document;
	if (object.addEventListener) { object.addEventListener(method, func, false); }
	else if (object.attachEvent) {
		object[method + func] = func;
		object.attachEvent('on' + method, function() { object[method + func](window.event); });
	} else {
		return object['on' + method] = func;
	} return false;
};

// @name: removeEvent
// @syntax: removeEvent(string method, function func [, object object]);
// @dependencies: none

function removeEvent(method, func, object) {
	method = method.replace(/^on/, '');	
	object = object?$(object):document;
	if (object.removeEventListener) { object.removeEventListener(method, func, false); }
	else if (object.detachEvent) {
		object.detachEvent('on' + method, object[method + func]);
		object[method + func] = null;
	} else {
		return object['on' + method] = function() { };
	} return false;
};

// @name: $
// @syntax: $(string object [, object container]);
// @dependencies: getElementsByAttrib

function $(objects, container) {

	if (!objects) { return false; }
	if (typeof(objects) == 'string') { objects = objects.split(','); } else { return objects; }
	container = container || document;
	var elements = new Array();

	if (container) {

		for (var i = 0; i < objects.length; i++) {
			objects[i] = objects[i].trim();
			if (typeof(objects[i]) == 'string' && container.getElementById && container.getElementById(objects[i])) { return container.getElementById(objects[i]); }
			else if (typeof(objects[i]) == 'string' && getElementsByAttrib(objects[i], 'name', container)) { elements = elements.concat(getElementsByAttrib(objects[i], 'name', container)); }
			else if (typeof(objects[i]) == 'string' && getElementsByAttrib(objects[i], 'class', container)) { elements = elements.concat(getElementsByAttrib(objects[i], 'class', container)); }
		 	else if (typeof(objects[i]) == 'object') { return objects[i]; }
		}

	} return elements.length?elements:false;

}

// @name: getElementsByAttrib
// @syntax: getElementsByAttrib(string value [, string attrib, object container]);
// @dependencies: Browser.Type

function getElementsByAttrib(value, attrib, container) {

	attrib = attrib || 'class';
	container = container || document;

	var children = container.getElementsByTagName('*') || container.all;
	children = children.length?children:document.all;
	
	var elements = new Array();

	if (container && children) {
		
		if (Browser.Type() == 'ie' && attrib == 'class') { attrib = 'className'; }

		for (var i = 0; i < children.length; i++) {
		    if (children[i].getAttribute(attrib) && children[i].getAttribute(attrib).match(RegExp('(^| )(' + value + ')($| )'))) { elements.push(children[i]); }
		}

	} return elements.length?elements:false;

};

function getElementsByAttribName(value, attrib, container) { console.log('Depreciated function "getElementByAttribName" was called. Please advise.'); return getElementsByAttrib(value, attrib, container); }

// @name: getStyle
// @syntax: getStyle(object object, string name);
// @dependencies: String.camelize

function getStyle(object, name) {
	object = $(object);
	if (object) {
		if (object.currentStyle) { return object.currentStyle[name.camelize()] || ''; }
		else if (object.style && object.style[name.camelize()]) { return object.style[name.camelize()]; }
		else if (document.defaultView && document.defaultView.getComputedStyle(object, null)) { return document.defaultView.getComputedStyle(object, null).getPropertyValue(name) || ''; }
		else { return 0; }
	} return false;
}

// @name: setStyle
// @syntax: setStyle(object object, string value);
// @dependencies: forEach, String.trim, String.camelize

function setStyle(object, value) {
	object = $(object);
	if (object) {
		forEach(value.split(';'), function(key, value) { object.style[value.split(':')[0].trim().camelize()] = value.split(':')[1].trim(); });
	} return false;
};

// @name: addStyle
// @syntax: addStyle(object object, string style);
// @dependencies: none

function addStyle(object, style) {
	object = $(object);
	if (object) {
		object.className = object.className.replace(RegExp('(^| )(' + style + ')($| )'), '');
		object.className += ' ' + style;
	} return false;
};

// @name: removeStyle
// @syntax: removeStyle(object object, string style);
// @dependencies: none

function removeStyle(object, style) {
	object = $(object);
	if (object) {
		object.className = object.className.replace(RegExp('(^| )(' + style + ')($| )'), '');
	} return false;
};

// @name: getPos
// @syntax: getPos(object object);
// @dependencies: none

function getPos(object) {
	object = $(object);
	var objLeft = objTop = 0;
	do {
		objLeft += object.offsetLeft;
		objTop += object.offsetTop;
	} while (object = object.offsetParent);
	return [objLeft,objTop];
}

// @name: forEach
// @syntax: forEach(array array, function func);
// @dependencies: none

function forEach(array, func) {
	for (var key in array) {
		if (Array('string','number','object').join(',').match(typeof(array[key])) && array[key]) { func(key, array[key]); }
	}
	return false;
};

// @name: hitTest
// @syntax: hitTest(object object, function func);
// @dependencies: Mouse.GetCoords, getPos

function hitTest(object) {
	object = $(object);
	if (object) {
		var objPos = getPos(object);
		if ((document.mouseY > parseInteger(objPos[1]) && document.mouseY < parseInteger(objPos[1]) + object.offsetHeight) &&
			 (document.mouseX > parseInteger(objPos[0]) && document.mouseX < parseInteger(objPos[0]) + object.offsetWidth)) { return true; }
	} return false;
};

// @name: Element
// @author: Neo Geek {neo@neo-geek.net}
// @website: http://neo-geek.net/
// @copyright: (c) 2007 Neo Geek, Neo Geek Labs

var Element = new Object();

Object.extend(Element, {

	delay: 1000,

	// @name: Element.create
	// @syntax: Element.create(object object, string tag);
	// @dependencies: none

	create: function(object, tag) {
		object = $(object);
		if (object) {
			var element = document.createElement(tag);
			object.appendChild(element);
			return element;
		} return false;
	},

	// @name: Element.clone
	// @syntax: Element.clone(object object);
	// @dependencies: none

	clone: function(object) {
		object = $(object);
		if (object) {
			
			var element = object.cloneNode(true);
			
			if (object.onblur) { element.onblur = object.onblur; }
			if (object.onclick) { element.onclick = object.onclick; }
			if (object.onfocus) { element.onfocus = object.onfocus; }
			if (object.onmousedown) { element.onmousedown = object.onmousedown; }
			if (object.onmouseout) { element.onmouseout = object.onmouseout; }
			if (object.onmouseover) { element.onmouseover = object.onmouseover; }
			if (object.onmouseup) { element.onmouseup = object.onmouseup; }

			element.innerHTML = object.innerHTML;

			return element;
		} return false;
	},

	// @name: Element.empty
	// @syntax: Element.empty(object object);
	// @dependencies: none

	empty: function(object) {
		object = $(object);
		if (object) {
			return object.innerHTML = '';
		} return false;
	},

	// @name: Element.hide
	// @syntax: Element.hide(object object [, integer delay]);
	// @dependencies: parseInteger

	hide: function(object, delay) {
		object = $(object);
		delay = parseInteger(delay) || 0;
		if (object) {
			if (object.timeout_hide) { clearTimeout(object.timeout_hide); }
			object.timeout_hide = setTimeout(function() {
				if (!object.style) { object.style = ''; }
				return object.style.display = 'none';
			}, delay * this.delay);
		} return false;
	},

	// @name: Element.remove
	// @syntax: Element.remove(object object [, integer delay]);
	// @dependencies: parseInteger

	remove: function(object, delay) {
		object = $(object);
		delay = parseInteger(delay) || 0;
		if (object) {
			if (object.timeout_remove) { clearTimeout(object.timeout_remove); }
			object.timeout_remove = setTimeout(function() {
				return object.parentNode?object.parentNode.removeChild(object):false;
			}, delay * this.delay);
		} return false;
	},

	// @name: Element.replace
	// @syntax: Element.replace(object object, object replacement);
	// @dependencies: none

	replace: function(object, replacement) {
		object = $(object);
		if (object) {
			return object.parentNode?object.parentNode.replaceChild(typeof(replacement) != 'string'?replacement:document.createElement(replacement), object):false;
		} return false;
	},

	// @name: Element.scroll
	// @syntax: Element.scroll(object object [, integer offset]);
	// @dependencies: parseInteger

	scroll: function(object, offset) {
		object = $(object);
		if (object) {
			var objPos = getPos(object);
			return window.scrollTo(parseInteger(objPos[0]), parseInteger(objPos[1]));
		} return false;
	},

	// @name: Element.show
	// @syntax: Element.show(object object [,integer delay]);
	// @dependencies: parseInteger

	show: function(object, delay) {
		object = $(object);
		delay = parseInteger(delay) || 0;
		if (object) {
			if (object.timeout_show) { clearTimeout(object.timeout_show); }
			object.timeout_show = setTimeout(function() {
				if (!object.style) { object.style = ''; }
				return object.style.display = '';
			}, delay * this.delay);
		} return false;
	},

	// @name: Element.toggle
	// @syntax: Element.toggle(object object [,integer delay]);
	// @dependencies: Element.visible, Element.hide, Element.show, parseInteger

	toggle: function(object, delay) {
		object = $(object);
		delay = parseInteger(delay) || 0;
		if (object) {
			return Element.visible(object)?Element.hide(object, delay):Element.show(object, delay);
		} return false;
	},

	// @name: Object.visible
	// @syntax: Object.visible(object object);
	// @dependencies: none

	visible: function(object) {
		object = $(object);
		if (object) {
			return (!object.style.display || object.style.display != 'none')?true:false;
		} return false;
	}

});

// @name: String.prototype
// @author: Neo Geek {neo@neo-geek.net}
// @website: http://neo-geek.net/
// @copyright: (c) 2007 Neo Geek, Neo Geek Labs

Object.extend(String.prototype, {

	// @name: String.camelize
	// @syntax: String.camelize();
	// @dependencies: none

	camelize: function() {
		var subject = this.split('-');
		for (var i = 1; i < subject.length; i++) { subject[i] = subject[i].substring(0, 1).toUpperCase() + subject[i].substring(1); }
		return subject.join('');
	},

	// @name: String.hextorgb
	// @syntax: String.hextorgb();
	// @dependencies: none

	hextorgb: function() {
		var subject = this.toUpperCase().match(/([A-Z0-9]{2})([A-Z0-9]{2})([A-Z0-9]{2})/);
		return Array(parseInteger(subject[1], 16), parseInteger(subject[2], 16), parseInteger(subject[3], 16));
	},

	// @name: String.strip_tags
	// @syntax: String.strip_tags();
	// @dependencies: none

	strip_tags: function() {
		return this.replace(/<(\/)?[^>]+( \/)?>/gim, '');
	},

	// @name: String.str_replace
	// @syntax: String.str_replace(array search, array replace, interger matches);
	// @dependencies: none

	str_replace: function(search, replace, matches) {

		var subject = this;

		if (typeof(search) == 'string') { search = Array(search); }
		if (typeof(replace) == 'string') { replace = Array(replace); }

		for (var i = 0; i < search.length; i++) {
			var current_matches = 0;
			while (subject.indexOf(search[i]) > -1) {
				subject = subject.replace(search[i] || '', replace[i] || '');
				current_matches++;
				if (current_matches == matches) { break; }
			}
		}

		return subject;

	},

	// @name: String.str_repeat
	// @syntax: String.str_repeat(integer length);
	// @dependencies: none

	str_repeat: function(length) {
		return new Array(length + 1).join(this);
	},

	// @name: String.str_pad
	// @syntax: String.str_pad(integer length, string string [, string type]);
	// @dependencies: none

	str_pad: function(length, string, type) {

		var subject = this;
		type = type || 'STR_PAD_LEFT';

		if (subject.length < length) {
			length = length - subject.length;
			if (type == 'STR_PAD_LEFT') { subject = Array(length + 1).join(String(string)) + subject; }
			else if (type == 'STR_PAD_RIGHT') { subject = subject + Array(length + 1).join(String(string)); }
			else if (type == 'STR_PAD_BOTH') {
				subject = Array(Math.round(length / 2) + 1).join(String(string)) + subject;
				subject = subject + Array((length - subject.length) + 2).join(String(string));
			}
		}

		return subject;

	},

	// @name: String.str_split
	// @syntax: String.str_split(integer length);
	// @dependencies: none

	str_split: function(length) {

		var subject = this;
		var results = Array();

		while (subject) {
			results.push(subject.substring(0, length));
			subject = subject.substring(length);
		}

		return results;

	},

	// @name: String.trim
	// @syntax: String.trim();
	// @dependencies: none

	trim: function() {
		return this.replace(/^\s*|\s*$/g, '');
	},

	// @name: String.ucwords
	// @syntax: String.ucwords();
	// @dependencies: none

	ucwords: function() {
		var subject = this.split(' ');
		for (var i = 0; i < subject.length; i++) { subject[i] = subject[i].substring(0, 1).toUpperCase() + subject[i].substring(1); }
		return subject.join(' ');
	},

	// @name: String.urlencode
	// @syntax: String.urlencode();
	// @dependencies: none

	urlencode: function() {
		return encodeURIComponent(this);
	},

	// @name: String.urldecode
	// @syntax: String.urldecode();
	// @dependencies: none

	urldecode: function() {
		return decodeURIComponent(this.replace('&amp;', '&'));
	},

	// @name: String.validate
	// @syntax: String.validate(string type);
	// @dependencies: none

	validate: function(type) {
		if (type == 'empty') { return !this?true:false; }
		else if (type == 'number') { return this.match(/^[.0-9]+$/)?true:false; }
		else if (type == 'email') { return this.toLowerCase().match(/^([-.a-z0-9])+(@)+([-.a-z])+(.)+([a-z])$/)?true:false; }
		else if (type == 'website') { return this.toLowerCase().match(/^(http:\/\/)+([-.a-z])/)?true:false; }
		return false;
	}

});

// @name: Array.prototype
// @author: Neo Geek {neo@neo-geek.net}
// @website: http://neo-geek.net/
// @copyright: (c) 2007 Neo Geek, Neo Geek Labs

Object.extend(Array.prototype, {

	// @name: Array.add
	// @syntax: Array.add(string value [, boolean unique]);
	// @dependencies: Array.indexOf

	add: function(value, method) {

		var output = new Array();

		if (method == 'unique') {

			output.push(value);

			for (var i = 0; i < this.length; i++) {
				if (output.indexOf(this[i]) == -1) { output.push(this[i]); }
			}

			output.push(output.shift());

		} else if (method == 'toggle') {

			output = this;

			if (output.indexOf(value) == -1) { output.push(value); } else {
				while (output.indexOf(value) != -1) { output.splice(output.indexOf(value), 1); }
			}

		} else {

			output = this;
			output.push(value);

		}

		return output;

	},

	// @name: Array.clear
	// @syntax: Array.clear();
	// @dependencies: none

	clear: function() {
		return this.length = 0;
	},

	// @name: Array.first
	// @syntax: Array.first();
	// @dependencies: none

	first: function() {
		return this[0];
	},

	// @name: Array.last
	// @syntax: Array.last([integer offset]);
	// @dependencies: none

	last: function(offset) {
		return this[this.length - 1 + (offset || 0)];
	},
	
	// @name: Array.rgbtohex
	// @syntax: Array.rgbtohex();
	// @dependencies: none
	
	rgbtohex: function() {
		var output = '';
		var hex = '0123456789ABCDEF'.split('');
		for (var i = 0; i < this.length; i++) { output += hex[Math.floor(Math.round(this[i]) / 16)] + hex[(Number(Math.round(this[i]) / 16) % 1) * 16]; }
		return output?'#' + output:false;
	},

	// @name: Array.remove
	// @syntax: Array.remove(string value);
	// @dependencies: none

	remove: function(value) {
		while (this.indexOf(value) != -1) { this.splice(this.indexOf(value), 1); }
		return this;
	},

	// @name: Array.sum
	// @syntax: Array.sum();
	// @dependencies: parseInteger

	sum: function() {
		var output = 0;
		for (var i = 0; i < this.length; i++) { output += parseInteger(this[i]); }
		return output;
	},

	// @name: Array.update
	// @syntax: Array.update(integer key, string value);
	// @dependencies: none

	update: function(key, value) {
		this[key] = value;
		return this;
	},

	// @name: Array.unique
	// @syntax: Array.unique();
	// @dependencies: Array.indexOf

	unique: function() {
		var output = Array();
		for (var i = 0; i < this.length; i++) {
			if (output.indexOf(this[i]) == -1) { output.push(this[i]); }
		}
		return output;
	}

});

// @name: Array.prototype
// @author: Neo Geek {neo@neo-geek.net}
// @website: http://neo-geek.net/
// @copyright: (c) 2007 Neo Geek, Neo Geek Labs

Object.extend(Array.prototype, {

	indexOf: function(value, offset) {

		for (var i = offset || 0; i < this.length; i++) {
			if (this[i] == value) { return i; }
		}

		return -1;

	}

});

// @name: Console
// @author: Neo Geek {neo@neo-geek.net}
// @website: http://neo-geek.net/
// @copyright: (c) 2007 Neo Geek, Neo Geek Labs

var console = console || { log: function(value) { window.status = value; } };


// @name: parseInteger
// @author: Neo Geek {neo@neo-geek.net}
// @website: http://neo-geek.net/
// @copyright: (c) 2007 Neo Geek, Neo Geek Labs

function parseInteger(value, radix) {
	if (radix) { return parseInt(value, radix); }
	return value?Number(String(value).match(/[-.0-9]+/)?String(value).match(/[-.0-9]+/)[0]:0):false;
}

// @name: AJAX
// @author: Neo Geek {neo@neo-geek.net}
// @website: http://neo-geek.net/
// @copyright: (c) 2007 Neo Geek, Neo Geek Labs

var AJAX = {

	// @name: AJAX.options
	// @syntax: AJAX.options(array options);
	// @dependencies: none

	options: {
		method: 'get', // post
		asynchronous: true,
		contentType: 'text/plain', // application/x-www-form-urlencoded
		parameters: '',
		onstart: function(http) { },
		onload: function(http) { },
		onerror: function(http) { }
	},

	// @name: AJAX.Option
	// @syntax: AJAX.Option(string key, string value);
	// @dependencies: AJAX.options

	Option: function(key, value) { return value || this.options[key]; },

	// @name: AJAX.Request
	// @syntax: AJAX.Request(string url [, array options]);
	// @dependencies: AJAX.Option

	Request: function(url, options) {
		options = options || Array();
		var http = window.XMLHttpRequest?new XMLHttpRequest():new ActiveXObject('Microsoft.XMLHTTP');
		if (AJAX.Option('method', options.method || 'post') == 'post' && !options.contentType) { options.contentType = 'application/x-www-form-urlencoded'; }
		http.onreadystatechange = function() {
			if (http.readyState == 1) { return AJAX.Option('onstart', options.onstart || '')(http); }
			else if (http.readyState == 4 && http.status != 404) { return AJAX.Option('onload', options.onload || '')(http); }
			else if (http.readyState == 4 && http.status == 404) { return AJAX.Option('onerror', options.onerror || '')(http); }
			return false;
		}
		http.open(AJAX.Option('method', options.method || ''), url, AJAX.Option('asynchronous', options.asynchronous || ''));
		http.setRequestHeader('Content-Type', AJAX.Option('contentType', options.contentType || ''));
		http.send(AJAX.Option('parameters', options.parameters || ''));
		return false;
	}

};

// @name: Browser
// @author: Neo Geek {neo@neo-geek.net}
// @website: http://neo-geek.net/
// @copyright: (c) 2007 Neo Geek, Neo Geek Labs

var Browser = {

	nav: navigator.userAgent,

	// @name: Browser.Type
	// @syntax: Browser.Type();
	// @dependencies: Browser.nav

	Type: function() {
		if (navigator.userAgent.indexOf('Firefox') != -1) { return 'moz'; }
		else if (navigator.userAgent.indexOf('Flock') != -1) { return 'moz'; }
		else if (navigator.userAgent.indexOf('Camino') != -1) { return 'moz'; }
		else if (navigator.userAgent.indexOf('Opera') != -1) { return 'opera'; }
		else if (navigator.userAgent.indexOf('MSIE') != -1) { return 'ie'; }
		else if (navigator.userAgent.indexOf('Safari') != -1) { return 'safari'; }
		else if (navigator.userAgent.indexOf('Netscape') != -1) { return 'netscape'; }
		else { return navigator.userAgent; }
	}

};

// @name: Clipboard
// @author: Neo Geek {neo@neo-geek.net}
// @website: http://neo-geek.net/
// @copyright: (c) 2007 Neo Geek, Neo Geek Labs

var Clipboard = {

	// @name: Clipboard.Clear
	// @syntax: Clipboard.Clear();
	// @dependencies: Cookies.Remove

	Clear: function() {
		return Cookies.Remove('clipboard');
	},

	// @name: Clipboard.Copy
	// @syntax: Clipboard.Copy(object object);
	// @dependencies: Cookies.Create

	Copy: function(object) {
		if (typeof(object) != 'string') { object = object.innerHTML || object.value || ''; }
		if (object) { return Cookies.Create('clipboard', object, 30); } else { return false; }
	},

	// @name: Clipboard.Paste
	// @syntax: Clipboard.Paste(object object);
	// @dependencies: Cookies.Retrieve

	Paste: function(object) {
		if (object && object.value) { return object.value = Cookies.Retrieve('clipboard') || ''; }
		else if (object && !object.value) { return object.innerHTML = Cookies.Retrieve('clipboard') || ''; }
		return Cookies.Retrieve('clipboard') || '';
	}

};

// @name: Cookies
// @author: Neo Geek {neo@neo-geek.net}
// @website: http://neo-geek.net/
// @copyright: (c) 2007 Neo Geek, Neo Geek Labs

var Cookies = {

	// @name: Cookies.Create
	// @syntax: Cookies.Create(string name, string value [, integer days, string path]);
	// @dependencies: Cookies.Retrieve

	Create: function(name, value, days, path) {

		var date = new Date;
		date.setTime(date.getTime() + ((days || 1) * 24 * 60 * 60 * 1000));
		date = date.toGMTString();

		document.cookie = name + '=' + value + ';expires=' + date + ';path=' + (path || '/');

		return Cookies.Retrieve(name);

	},

	// @name: Cookies.Retrieve
	// @syntax: Cookies.Retrieve(string name);
	// @dependencies: forEach

	Retrieve: function(name) {

		var stored = Array();

		forEach(document.cookie.split(';'), function(key, value) { stored[value.substring(0, value.indexOf('=')).replace(/^\s*|\s*$/g,'')] = value.substring(value.indexOf('=') + 1); });

		return stored[name] || false;

	},

	// @name: Cookies.Remove
	// @syntax: Cookies.Remove(string name);
	// @dependencies: Cookies.Create

	Remove: function(name) { return Cookies.Create(name, '', 0); }

};

// @name: Date.BuildCalendar
// @author: Neo Geek {neo@neo-geek.net}
// @website: http://neo-geek.net/
// @copyright: (c) 2007 Neo Geek, Neo Geek Labs

Object.extend(Date, {

	months: Array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'),
	days: Array('Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'),

	// @name: Date.BuildCalendar
	// @syntax: Date.BuildCalendar([array options]);
	// @dependencies: String.str_pad

	BuildCalendar: function(options) {

		options = options || Array();
		var output = '';

		options.container = options.container || 'calendar';
		options.label = options.label || 'short';

		var now = options.date || new Date();
		var year = now.getFullYear();
		var month = now.getMonth();
		var date = now.getDate();
		var day_count = 32 - new Date(now.getFullYear(), now.getMonth(), 32).getDate();
		var week_start = new Date(now.getFullYear(), now.getMonth(), 1).getDay();
		var day_count_live = 1;


		var table = document.createElement('table');
		var table_body = document.createElement('tbody');
		var table_header = document.createElement('tr');


		var table_column = document.createElement('th');
		var table_contents = document.createElement('a');

		table_contents.onclick = function() {
			$(options.container).innerHTML = '';
			$(options.container).appendChild(Date.BuildCalendar({date:new Date(year - 1, month, 1), container:options.container, onclick:options.onclick || function() {}}));
			return false;
		};
		table_contents.innerHTML = '&#171;';

		table_column.appendChild(table_contents);
		table_header.appendChild(table_column);


		var table_column = document.createElement('th');
		var table_contents = document.createElement('a');

		table_contents.onclick = function() {
			$(options.container).innerHTML = '';
			$(options.container).appendChild(Date.BuildCalendar({date:new Date(year, month - 1, 1), container:options.container, onclick:options.onclick || function() {}}));
			return false;
		};
		table_contents.innerHTML = '&#8249;';

		table_column.appendChild(table_contents);
		table_header.appendChild(table_column);


		var table_column = document.createElement('th');
		var table_contents = document.createElement('span');

		table_column.colSpan = 3;
		table_contents.align = 'center';
		if (options.label == 'short') { table_contents.innerHTML = this.months[month].substring(0, 3) + ' ' + year; } else { table_contents.innerHTML = this.months[month] + ' ' + year; }

		table_column.appendChild(table_contents);
		table_header.appendChild(table_column);


		var table_column = document.createElement('th');
		var table_contents = document.createElement('a');

		table_contents.style.cursor = 'pointer';
		table_contents.onclick = function() {
			$(options.container).innerHTML = '';
			$(options.container).appendChild(Date.BuildCalendar({date:new Date(year, month + 1, 1), container:options.container, onclick:options.onclick || function() {}}));
			return false;
		};
		table_contents.innerHTML = '&#8250;';

		table_column.appendChild(table_contents);
		table_header.appendChild(table_column);


		var table_column = document.createElement('th');
		var table_contents = document.createElement('a');

		table_contents.onclick = function() {
			$(options.container).innerHTML = '';
			$(options.container).appendChild(Date.BuildCalendar({date:new Date(year + 1, month, 1), container:options.container, onclick:options.onclick || function() {}}));
			return false;
		};
		table_contents.innerHTML = '&#187;';

		table_column.appendChild(table_contents);
		table_header.appendChild(table_column);

		table_body.appendChild(table_header);


		var table_header = document.createElement('tr');

		for (var i = 0; i < this.days.length; i++) {

			var table_column = document.createElement('th');
			if (options.label == 'short') { var table_contents = document.createTextNode(this.days[i].substring(0, 3)); } else { var table_contents = document.createTextNode(this.days[i]); }

			table_column.appendChild(table_contents);
			table_header.appendChild(table_column);

		}

		table_body.appendChild(table_header);


		var table_header = document.createElement('tr');

		for (var i = 0; i < week_start; i++) {

			var table_column = document.createElement('td');
			var table_contents = document.createTextNode(' ');

			table_column.appendChild(table_contents);
			table_header.appendChild(table_column);

		}

		for (var i = week_start; i < 7; i++) {

			var table_column = document.createElement('td');
			var table_contents = document.createTextNode(day_count_live);

			table_column.dateID = year + '-' + String(month + 1).str_pad(2, '0') + '-' + String(day_count_live).str_pad(2, '0');
			table_column.onclick = options.onclick?function() { options.onclick(this.dateID); }:function() { };
			day_count_live++;

			table_column.appendChild(table_contents);
			table_header.appendChild(table_column);

		}

		table_body.appendChild(table_header);

		while (day_count_live <= day_count) {

			var table_header = document.createElement('tr');

			for (var i = 0; i < 7; i++) {

				var table_column = document.createElement('td');

				if (day_count_live <= day_count) {

					var table_contents = document.createTextNode(day_count_live);

					table_column.dateID = year + '-' + String(month + 1).str_pad(2, '0') + '-' + String(day_count_live).str_pad(2, '0');
					table_column.onclick = options.onclick?function() { options.onclick(this.dateID); }:function() { };

					day_count_live++;

				} else { var table_contents = document.createTextNode(' '); }

				table_column.appendChild(table_contents);
				table_header.appendChild(table_column);

			}

			table_body.appendChild(table_header);

		}

		table.appendChild(table_body);

		return table;

	}

});


// @name: Element.drag
// @author: Neo Geek {neo@neo-geek.net}
// @website: http://neo-geek.net/
// @copyright: (c) 2007 Neo Geek, Neo Geek Labs

Object.extend(Element, {

	zindex: 1000,

	// @name: Element.drag()
	// @syntax: Element.drag(object object [, array options]);
	// @dependencies: parseInteger, getPos, getStyle, Element.remove

	drag: function(object, options) {
		
		object = $(object);
		if (object) {
			
			options = options || Array();
			options.revert = options.revert || false;
			options.ghosting = options.ghosting || false;

			startX = parseInteger(document.mouseX);
			startY = parseInteger(document.mouseY);
		
			var clone = object.cloneNode(true);
			clone.style.display = 'none';
			if (options.ghosting) { clone.style.opacity = '.2'; } else { clone.style.visibility = 'hidden'; }
		
			object.parentNode.insertBefore(clone, object);
		
			var objPos = getPos(object);
		
			if (!options.constraint || options.constraint == 'y') { object.style.top = (parseInteger(getStyle(object,'top')) || parseInteger(objPos[1]) - parseInteger(getStyle(object, 'margin-top'))) + 'px'; }
			if (!options.constraint || options.constraint == 'x') { object.style.left = (parseInteger(getStyle(object,'left')) || parseInteger(objPos[0]) - parseInteger(getStyle(object, 'margin-left'))) + 'px'; }
			object.style.position = 'absolute';
		
			Element.zindex++;
			object.style.zIndex = Element.zindex;
		
			clone.style.display = '';

			document.onselectstart = function () { return false; };
			object.style.MozUserSelect = 'none';
			document.getElementsByTagName('body')[0].style.MozUserSelect = 'none';
	
			document.onmousemove = function() {
			
				if (options.revert) { document.activeDrag = clone; } else { document.activeDrag = object; }
			
				if (!options.constraint || options.constraint == 'y') { object.style.top = (parseInteger(object.style.top) - (startY - parseInteger(document.mouseY))) + 'px'; }
				if (!options.constraint || options.constraint == 'x') { object.style.left = (parseInteger(object.style.left) - (startX - parseInteger(document.mouseX))) + 'px'; }
			
				startX = parseInteger(document.mouseX);
				startY = parseInteger(document.mouseY);

				document.onmouseup = function() {

					if (options.revert) {

						var marginTop = parseInteger(getStyle(object, 'margin-top'));
						var marginLeft = parseInteger(getStyle(object, 'margin-left'));

						if (options.revert == 'animate') {
							FX.Animate(object, {end:{top:objPos[1] - marginTop, left:objPos[0] - marginLeft}, oncomplete:function(object) {
								if (options.ghosting) { clone.style.opacity = '.99'; } else { clone.style.visibility = 'visible'; }
								Element.remove(object);
							}});
						} else {
							if (options.ghosting) { clone.style.opacity = '.99'; } else { clone.style.visibility = 'visible'; }
							Element.remove(object);
						}

					} else { Element.remove(clone); }

					setTimeout(function() { document.activeDrag = null; }, 1);

					document.onmouseup = function() {};
					document.onmousemove = function() {};
					document.onselectstart = function() {};
					document.getElementsByTagName('body')[0].style.MozUserSelect = '';

				};

			};
			
			document.onmouseup = function() {

				setTimeout(function() { document.activeDrag = null; }, 1);

				document.onmouseup = function() {};
				document.onmousemove = function() {};
				document.onselectstart = function() {};
				document.getElementsByTagName('body')[0].style.MozUserSelect = '';

			};
		
		} return false;

	}

});

// @name: Form
// @author: Neo Geek {neo@neo-geek.net}
// @website: http://neo-geek.net/
// @copyright: (c) 2007 Neo Geek, Neo Geek Labs

var Form = {

	// @name: Form.Capture
	// @syntax: Form.Capture(object object [, boolean updated]);
	// @dependencies: Array.indexOf

	Capture: function(object, updated) {
	
		object = $(object);
		if (object) {
		
			updated = updated || false;
			var query = '';
			var form = object.getElementsByTagName('*').length?object.getElementsByTagName('*'):object.all;

			for (var i = 0; i < form.length; i++) {

				if (Array('input', 'textarea').indexOf(form[i].nodeName.toLowerCase()) != -1 && Array('checkbox', 'radiobox').indexOf(form[i].type) != -1) {

					if ((!updated || form[i].checked != form[i].defaultChecked) && !form[i].checked) { query += form[i].name + '=&'; }
					else if ((!updated || form[i].checked != form[i].defaultChecked) && form[i].checked) { query += form[i].name + '=' + encodeURIComponent(form[i].value) + '&'; }

				} else if (Array('input', 'textarea').indexOf(form[i].nodeName.toLowerCase()) != -1 && form[i].name) {

					if (!updated || (updated && form[i].value != form[i].defaultValue)) { query += form[i].name + '=' + encodeURIComponent(form[i].value) + '&'; }

				} else if (Array('select').indexOf(form[i].nodeName.toLowerCase()) != -1) {

					if (!updated || (updated && !form[i].options[form[i].selectedIndex].defaultSelected)) { query += form[i].name + '=' + encodeURIComponent(form[i].value) + '&'; }

				}

			}

			return query.length?(query.substring(0, query.length - 1) || ''):'';
		
		} return false;

	},

	// @name: Form.Clear
	// @syntax: Form.Clear(object object);
	// @dependencies: Array.indexOf

	Clear: function(object) {
		
		object = $(object);
		if (object) {
			
			var form = object.getElementsByTagName('*').length?object.getElementsByTagName('*'):object.all;

			for (var i = 0; i < form.length; i++) {
				if (form[i].name && Array('input').indexOf(form[i].nodeName.toLowerCase()) != -1 && Array('checkbox', 'radiobox').indexOf(form[i].type) != -1) { form[i].checked = false; }
				else if (form[i].name && Array('input', 'textarea').indexOf(form[i].nodeName.toLowerCase()) != -1) { form[i].value = ''; }
				else if (form[i].name && Array('select').indexOf(form[i].nodeName.toLowerCase()) != -1) { form[i].selectedIndex = 0; }
			}
			
		} return false;

	},

	// @name: Form.CreateElement
	// @syntax: Form.CreateElement([string type, array options]);
	// @dependencies: setStyle, Array.indexOf

	CreateElement: function(type, options) {

		type = type || 'input';
		options = options || Array();

		var element = document.createElement(type);

		element.name = options.name || 'tmp';
		element.className = options.class_name || '';

		if (type == 'input') {

			element.type = options.type || 'text';
			element.value = element.defaultValue = options.value || '';

		} else if (type == 'textarea') {

			element.value = element.defaultValue = options.value || '';

		} else if (type == 'select') {

			options.options = options.options || Array(options.value || '');
			options.selected = options.selected || Array();

			if (typeof(options.selected) != 'object') { options.selected = Array(options.selected); }

			for (var i = 0; i < options.options.length; i++) {
				if (typeof(options.options[i]) != 'object') { options.options[i] = Array(options.options[i], options.options[i]); }
				element.options[i] = new Option(options.options[i][0], options.options[i][1]);
				if (options.options[i][1] == 'element::disabled') { element.options[i].disabled = true; element.options[i].defaultValue = element.options[i].value = ''; }
				if (options.selected.indexOf(options.options[i][0]) != -1 || options.selected.indexOf(i) != -1) { element.options[i].selected = 'selected'; }
			}

		} else if (type == 'button') {

			element.innerHTML = options.value || '';

		}

		if (options.attrib) {
			forEach(options.attrib, function(key, value) { if (key == 'style') { setStyle(element, value); } else { element.setAttribute(key, value); } });
		}

		if (!element.style.marginRight) { element.style.marginRight = '1px'; }

		return element;

	},

	// @name: Form.Insertion
	// @syntax: Form.Insertion(object object, string value);
	// @dependencies: none

	Insertion: function(object, value) {
	
		object = $(object);
		if (object) {
		
			if (object.selectionStart != undefined) {
				
				object.focus();

				var selection_start = object.selectionStart;
				var selection_end = object.selectionEnd;

				object.value = object.value.substring(0, selection_start) + value + object.value.substring(selection_end);
				object.setSelectionRange(selection_start + 1, selection_start + 1);

			} else if (document.selection) {

				object.focus();
				range = document.selection.createRange();
				range.text = value;
				range.moveStart('character', -value.length);
			
			} else { object.value += value; }
		
		} return false;

	},

	// @name: Form.MultipleSelect
	// @syntax: Form.MultipleSelect(object object);
	// @dependencies: Array.add
	
	MultipleSelect: function(object) {
		
		object = $(object);
		if (object) {
			
			if (!object.options) { return false; }

			object.selectedIndexes = object.selectedIndexes || Array();

			object.parentNode.focus();

			for (var i = 0; i < object.options.length; i++) {
				if (object.options[i].selected) { object.selectedIndexes = object.selectedIndexes.add(i, 'toggle'); }
				object.options[i].selected = '';
			}

			for (var i = 0; i < object.selectedIndexes.length; i++) { object.options[object.selectedIndexes[i]].selected = 'selected'; }			
			
		} return false;

	},

	// @name: Form.PlaceholderText
	// @syntax: Form.PlaceholderText(object object [, array options]);
	// @dependencies: none
	
	PlaceholderText: function(object, options) {
		
		object = $(object);
		if (object) {
			
			if (object.value == options.value || object.value == '') {
				
				object.value = '';
				
				if (options.class_name) { removeStyle(object, options.class_name); }
				if (options.maxlength) { object.maxLength = options.maxlength; }
				
				addEvent('blur', function() {
					
					if (object.value == options.value || object.value == '') {
						
						if (options.maxlength) { object.maxLength = options.value.length; }
						if (options.class_name) { addStyle(object, options.class_name); }
							
						object.value = options.value;
					
					
					}
					
				}, object);
				
			}
			
		} return false;
		
	},

	// @name: Form.Reset
	// @syntax: Form.Reset(object object);
	// @dependencies: none

	Reset: function(object) {
		
		object = $(object);
		if (object) {

			if (object.reset) { object.reset(); }
			
		} return false;

	},

	// @name: Form.SetFocus
	// @syntax: Form.SetFocus(object object [, array options]);
	// @dependencies: none

	SetFocus: function(object, options) {
		
		object = $(object);
		if (object) {
			
			options = options || Array();

			options.tag = options.tag || 'input';
			options.offset = options.offset || 0;

			if (object.getElementsByTagName(options.tag)[options.offset]) { object.getElementsByTagName(options.tag)[options.offset].focus(); }
			
			
		} return false;

	},

	// @name: Form.Update
	// @syntax: Form.Update(object object, string query);
	// @dependencies: forEach, getElementsByAttrib

	Update: function(object, query) {
		
		object = $(object);
		if (object) {
		
			query = query.split('&') || Array();

			forEach(query, function(key, value) {
				var element = getElementsByAttrib(value.split('=')[0], 'name', object)[0];
				if (element) {
					element.value = element.defaultValue = decodeURIComponent(value.split('=')[1]);
					if (element.nodeName.toLowerCase() == 'select') { element[element.selectedIndex].defaultSelected = element.selectedIndex; }
					if (element.type == 'checkbox') { element.checked = element.defaultChecked = value.split('=')[1]; }
				}
			});		
			
		} return false;

	}

};

// @name: Form.Editable
// @author: Neo Geek {neo@neo-geek.net}
// @website: http://neo-geek.net/
// @copyright: (c) 2007 Neo Geek, Neo Geek Labs

Form.Editable = {

	// @name: Form.Editable.options
	// @syntax: Form.Editable.options(array options);
	// @dependencies: none

	options: {
		type: 'input',
		name: 'tmp_editable',
		class_name: 'editable',
		options: Array(),
		selected: Array(),
		multiple: false,
		attrib: {},
		method: 'default',
		placeholder: 'click here to add text',
		onactivate: function(name, value) { },
		onsave: function(name, value) { },
		oncancel: function(name, value) { },
		onchange: function(name, value) { }
	},

	// @name: Form.Editable.Option
	// @syntax: Form.Editable.Option(string key, string value);
	// @dependencies: Form.Editable.options

	Option: function(key, value) { return value || this.options[key]; },

	// @name: Form.Editable.Activate
	// @syntax: Form.Editable.Activate(object object, array options);
	// @dependencies: setStyle, Form.CreateElement, Form.Editable.Option, Form.Editable.Revert, Array.indexOf, Element.replace, Element.clone

	Activate: function(object, options) {

		object = $(object);
		options = options || Array();
		options.attrib = options.attrib || Array();

		if (!object) { return false; }

		if (object.innerHTML.toLowerCase() == this.Option('placeholder', options.placeholder || '').toLowerCase()) { object.innerHTML = ''; }

		var value = object.innerHTML;
		value = value.replace(/<(\/)?[^>]+( \/)?>/gim, '');
		value = value.replace('&amp;', '&');
		
		options.nodeCopy = Element.clone(object);

		var stage = document.createElement(object.nodeName);
		Element.replace(object, stage);
		object = stage;

		if (Array('input', 'textarea').indexOf(this.Option('type', options.type || '')) != -1) {
			var element = Form.CreateElement(this.Option('type', options.type || ''), {name:this.Option('name', options.name || ''), attrib:this.Option('attrib', options.attrib || ''), value:value});
		} else if (Array('select').indexOf(this.Option('type', options.type || '')) != -1) {
			var element = Form.CreateElement(this.Option('type', options.type || ''), {name:this.Option('name', options.name || ''), attrib:this.Option('attrib', options.attrib || ''), options:this.Option('options', options.options || ''), selected:this.Option('selected', options.selected || '')});
		}	
		
		element.defaultValue = value;

		if (element) {

			object.appendChild(element);
			element.customOptions = options;

			if (Array('textarea').indexOf(this.Option('type', options.type || '')) != -1 && this.Option('method', options.method || '') != 'blur') { object.appendChild(document.createElement('br')); }

			var button_save = Form.CreateElement('input', {type:'button', value:'Save', class_name:'btn_editable'});
			button_save.onclick = function() {
				if (element.defaultValue != element.value) { Form.Editable.Option('onsave', element.customOptions.onsave || '')(Form.Editable.Option('name', element.customOptions.name || ''), element.value); }
				object.parentNode.replaceChild(element.customOptions.nodeCopy, object);
				element.customOptions.nodeCopy.innerHTML = element.value || Form.Editable.Option('placeholder', element.customOptions.placeholder || '');
				return false;
			};

			element.onkeypress = function() {
				if (Key.active == 13 && this.nodeName.toLowerCase() != 'textarea') { button_save.onclick(); }
				else if (Key.active == 27) { button_cancel.onclick(); }
				else if (Key.active == 9) { return false; }
				return true;
			}

			var button_cancel = Form.CreateElement('input', {type:'button', value:'Cancel', class_name:'btn_editable'});
			button_cancel.onclick = function() {
				Form.Editable.Option('oncancel', element.customOptions.oncancel || '')();
				object.parentNode.replaceChild(element.customOptions.nodeCopy, object);
				element.customOptions.nodeCopy.innerHTML = element.defaultValue || Form.Editable.Option('placeholder', element.customOptions.placeholder || '');
				return false;
			};

			if (this.Option('method', options.method || '') == 'blur') { element.onfocus = function() { element.onblur = button_save.onclick; } }
			else if (this.Option('method', options.method || '') == 'change') { element.onfocus = function() { element.onchange = button_save.onclick; } }
			else { object.appendChild(button_save);	object.appendChild(button_cancel); }
			
			element.onchange = function() { Form.Editable.Option('onchange', element.customOptions.onchange || '')(element.getAttribute('name'), element.value); }

			element.focus();
			
			Form.Editable.Option('onactivate', element.customOptions.onactivate || '')(Form.Editable.Option('name', element.customOptions.name || ''), element.value);

		}

		return false;

	},

	// @name: Form.Editable.SaveAll
	// @syntax: Form.Editable.SaveAll();
	// @dependencies: getElementsByAttrib

	SaveAll: function() {

		var editables = getElementsByAttrib('btn_editable_save', 'class');		
		for (var i = 0; i < editables.length; i++) { editables[i].click(); }

		return false;

	},

	// @name: Form.Editable.CancelAll
	// @syntax: Form.Editable.CancelAll();
	// @dependencies: getElementsByAttrib

	CancelAll: function() {

		var editables = getElementsByAttrib('btn_editable_cancel', 'class');		
		for (var i = 0; i < editables.length; i++) { editables[i].click(); }

		return false;

	}

};

// @name: FX
// @author: Neo Geek {neo@neo-geek.net}
// @website: http://neo-geek.net/
// @copyright: (c) 2006 Neo Geek, Neo Geek Labs

var FX = {

	// @name: FX.Animate
	// @syntax: FX.Animate(object [, array options]);
	// @dependencies: none

	Animate: function(object, options) {

		object = $(object);
		options = options || Array();
		options.start = options.start || Array();
		options.end = options.end || Array();
		options.delay = parseInteger(options.delay) || 0;

		if (!object) { return false; }
		
		clearTimeout(object.timeout);
		
		object.timeout = setTimeout(function() {
		
			object.style.display = '';
			object.style.overflow = 'hidden';	
			object.style.visibility = 'visible';
			
			var start = {width:options.start.width?parseInteger(options.start.width):object.offsetWidth - parseInteger(getStyle(object, 'padding-left')) - parseInteger(getStyle(object, 'padding-right')) - parseInteger(getStyle(object, 'border-left-width')) - parseInteger(getStyle(object, 'border-right-width')) || 0,
			             height:options.start.height?parseInteger(options.start.height):object.offsetHeight - parseInteger(getStyle(object, 'padding-top')) - parseInteger(getStyle(object, 'padding-bottom')) - parseInteger(getStyle(object, 'border-top-width')) - parseInteger(getStyle(object, 'border-bottom-width')) || 0,
						 left:options.start.left?parseInteger(options.start.left):parseInteger(object.style.marginLeft) || 0,
						 top:options.start.top?parseInteger(options.start.top):parseInteger(object.style.marginTop) || 0,
			             opacity:options.start.opacity?parseInteger(options.start.opacity):parseInteger(Math.round(object.style.opacity * 100))};

			var end = {width:options.end.width?parseInteger(options.end.width):start.width,
					   height:options.end.height?parseInteger(options.end.height):start.height,
					   left:options.end.left?parseInteger(options.end.left):start.left,
					   top:options.end.top?parseInteger(options.end.top):start.top,
				       opacity:options.end.opacity?parseInteger(options.end.opacity):start.opacity};
			
			if (object.style.position == 'absolute') {

				var start = {left:options.start.left?parseInteger(options.start.left):parseInteger(object.style.left),
						 	top:options.start.top?parseInteger(options.start.top):parseInteger(object.style.top)};
						
				end.left -= object.style.marginLeft?parseInteger(object.style.marginLeft):0;
				end.top -= object.style.marginTop?parseInteger(object.style.marginTop):0;
	
			}

			var speed = options.speed?parseInteger(options.speed):10;

			if (options.onstart) { options.onstart(object); }

			if (object.interval) { clearInterval(object.interval); }

			object.interval = setInterval(function() {

				if (start.width != end.width) { start.width += (end.width - start.width) * (speed / 100); }
				if (start.height != end.height) { start.height += (end.height - start.height) * (speed / 100); }
				start.left += (end.left - start.left) * (speed / 100);
				start.top += (end.top - start.top) * (speed / 100);
				start.opacity += (end.opacity - start.opacity) * (speed / 100);
				
				if (start.width != end.width) { object.style.width = start.width + 'px'; }
				if (start.height != end.height) { object.style.height = start.height + 'px'; }

				if (object.style.position == 'absolute') {
					if (start.left) { object.style.left = start.left + 'px'; }
					if (start.top) { object.style.top = start.top + 'px'; }
				} else {
					if (start.left) { object.style.marginLeft = start.left + 'px'; }
					if (start.top) { object.style.marginTop = start.top + 'px'; }
				}
				
				if (start.opacity) { object.style.opacity = start.opacity / 100; }

				if ((!start.width || Math.round(start.width) == end.width) &&
				    (!start.height || Math.round(start.height) == end.height) &&
					(!start.left || Math.round(start.left) == end.left) &&
					(!start.top || Math.round(start.top) == end.top) &&
				    (!start.opacity || Math.round(start.opacity) == end.opacity)) {
						if (Math.round(start.width) == 0 || Math.round(start.height) == 0) { object.style.visibility = 'hidden'; }
						clearInterval(object.interval);
						if (options.oncomplete) { options.oncomplete(object); }
				}

			}, speed);
		
		}, (parseInteger(options.delay) || 1) * 100);

		return false;

	},

	// @name: FX.FadeBG
	// @syntax: FX.FadeBG(object object [, array options]);
	// @dependencies: Element.set, String.hextorgb, Array.rgbtohex

	FadeColor: function(object, options) {

		object = $(object);
		options = options || Array();
		options.method = options.method || 'background';
		options.delay = options.delay || 0;
		options.transparent = options.transparent || false;

		if (!object) { return false; }
		
		clearTimeout(object.timeout);
		
		object.timeout = setTimeout(function() {

			var start = options.start || Array(255, 255, 0);
			var end = options.end || Array(255, 255, 255);

			if (typeof(start) == 'string') { start = start.hextorgb(); }
			if (typeof(end) == 'string') { end = end.hextorgb(); }

			var speed = options.speed?parseInteger(options.speed):10;

			if (object.interval) { clearInterval(object.interval); }

			object.interval = setInterval(function() {

				start[0] += (end[0] - start[0]) * (speed / 100);
				start[1] += (end[1] - start[1]) * (speed / 100);
				start[2] += (end[0] - start[2]) * (speed / 100);

				object.style[options.method] = start.rgbtohex();

				if (start.rgbtohex() == end.rgbtohex()) {
					if (options.method == 'background' && options.transparent) { object.style.background = 'transparent'; }
					if (options.oncomplete) { options.oncomplete(object); }
					clearInterval(object.interval);
				}

			}, speed);
		
		}, (parseInteger(options.delay) || 1) * 100);

		return false;

	},
	
	// @name: FX.ScrollTo
	// @syntax: FX.ScrollTo(array options);
	// @dependencies: none

	ScrollTo: function(options) {

		options = options || Array();
		
		var objName = '';
		
		if (typeof(options.end) == 'object') {
			var objPos = getPos(options.end);
			objName = options.end.id;
			options.end = parseInteger(objPos[1]);
		}
		
		var start = parseInteger(options.start || (document.getElementsByTagName('html')[0].scrollTop || document.getElementsByTagName('body')[0].scrollTop));
		var end = parseInteger(options.end || start);
				
		var speed = options.speed?parseInteger(options.speed):10;
		
		clearInterval(window.interval);
		
		window.interval = setInterval(function() {

			start += (end - start) * (speed / 100);
			
			window.scrollTo(0, Math.round(start));
			
			if (Math.round(start) == end) {
				if (options.oncomplete) { options.oncomplete(object); }
				clearTimeout(window.interval);		
				if (objName) { document.location = String(document.location).substring(0, String(document.location).indexOf('#')) + '#' + objName; }
			}	
			
		}, speed);

		return false;

	},

	// @name: FX.Toggle
	// @syntax: FX.Toggle(object [, array options]);
	// @dependencies: FX.Animate

	Toggle: function(object, options) {

		object = $(object);
		options = options || Array();
		options.end = options.end || Array();
		options.delay = options.delay || 0;

		if (!object) { return false; }
		
		clearTimeout(object.timeout);
		
		object.timeout = setTimeout(function() {

			if ((options.end.width && Math.floor(object.offsetWidth - parseInteger(getStyle(object, 'padding-left')) - parseInteger(getStyle(object, 'padding-right')) - parseInteger(getStyle(object, 'border-left-width')) - parseInteger(getStyle(object, 'border-right-width'))) > 0) ||
			    (options.end.height && Math.floor(object.offsetHeight - parseInteger(getStyle(object, 'padding-top')) - parseInteger(getStyle(object, 'padding-bottom')) - parseInteger(getStyle(object, 'border-top-width')) - parseInteger(getStyle(object, 'border-bottom-width'))) > 0) ||
				(options.end.opacity && Math.floor(object.style.opacity) > 0)) {

					if (options.end.width) { options.end.width = '0'; }
					if (options.end.height) { options.end.height = '0'; }
					if (options.end.opacity) { options.end.opacity = '0'; }

			}

			FX.Animate(object, {end:{width:options.end.width, height:options.end.height, opacity:options.end.opacity}, speed:options.speed || '10', onstart:options.onstart || function() {}, oncomplete:options.oncomplete || function() {}});
	
		}, (parseInteger(options.delay) || 1) * 100);
		
		return false;

	}

};

FX.Custom = {

	// @name: FX.Custom.Wipe
	// @syntax: FX.Custom.Wipe(object object [, array options]);
	// @dependencies: FX.Animate

	Wipe: function(object, options) {

		object = $(object);
		options = options || Array();
		options.delay = options.delay || 0;

		if (!object) { return false; }
		
		clearTimeout(object.timeout);
		
		object.timeout = setTimeout(function() {

			if (options.method == 'down' && options.end.height) { FX.Animate(object, {start:{height:'0', opacity:'0'}, end:{height:options.end.height, opacity:'99'}, speed:options.speed || '10'}); }
			else if (options.method == 'up' && options.end.height) { FX.Animate(object, {start:{height:options.end.height, opacity:'99'}, end:{height:'0', opacity:'0'}, speed:options.speed || '10'}); }
			else if (options.method == 'toggle' && options.end.height) { FX.Toggle(object, {start:{height:object.offsetHeight || '0', opacity:object.style.opacity || '99'}, end:{height:options.end.height, opacity:'99'}, speed:options.speed || '10'}); }

		}, (parseInteger(options.delay) || 1) * 100);
		
		return false;

	},

	// @name: FX.Custom.Blink
	// @syntax: FX.Custom.Blink(object object);
	// @dependencies: FX.Animate

	Blink: function(object) {

		object = $(object);
		options = options || Array();
		options.delay = options.delay || 0;

		if (!object) { return false; }
		
		clearTimeout(object.timeout);
		
		object.timeout = setTimeout(function() {

			FX.Animate(object, {start:{opacity:'99'}, end:{opacity:'0'}, speed:options.speed || '10', oncomplete: function() { FX.Animate(object, {start:{opacity:'0'}, end:{opacity:'99'}, speed:options.speed || '10'}); }});

		}, (parseInteger(options.delay) || 1) * 100);
	
		return false;

	}

};

// @name: Key
// @author: Neo Geek {neo@neo-geek.net}
// @website: http://neo-geek.net/
// @copyright: (c) 2007 Neo Geek, Neo Geek Labs

var Key = {

	active: null,
	listeners: Array(),
	keys: {
		KEY_BACKSPACE: 8,
		KEY_TAB:       9,
		KEY_RETURN:   13,
		KEY_ESC:      27,
		KEY_LEFT:     37,
		KEY_UP:       38,
		KEY_RIGHT:    39,
		KEY_DOWN:     40,
		KEY_DELETE:   46,
		KEY_HOME:     36,
		KEY_END:      35,
		KEY_PAGEUP:   33,
		KEY_PAGEDOWN: 34
	},

	// @name: Key.Capture
	// @syntax: Key.Capture(event e);
	// @dependencies: Key.listeners

	Capture: function(e) {
		e = e || window.event;
		if (Key.listeners[e.keyCode]) { Key.listeners[e.keyCode](); }
		return Key.active = e.keyCode;
	},

	// @name: Key.AddListener
	// @syntax: Key.AddListener(integer key, function func);
	// @dependencies: Key.listeners

	AddListener: function(key, func) {
		Key.listeners[key] = func;
	},

	// @name: Key.RemoveListener
	// @syntax: Key.RemoveListener(integer key);
	// @dependencies: Key.listeners

	RemoveListener: function(key) {
		Key.listeners[key] = function() { };
	}

};

addEvent('keydown', Key.Capture);
addEvent('keyup', function() { Key.active = null; });

// @name: Mouse
// @author: Neo Geek {neo@neo-geek.net}
// @website: http://neo-geek.net/
// @copyright: (c) 2007 Neo Geek, Neo Geek Labs

var Mouse = {

	// @name: Mouse.GetCoords
	// @syntax: Mouse.GetCoords(event e);
	// @dependencies: none

	GetCoords: function(e) {
		e = e || window.event;
		if (document.mouseY != document.mousePrev) {
			if (document.mouseY >= document.mousePrev) { document.mouseDir = 'down'; } else { document.mouseDir = 'up'; }
		} document.mousePrev = document.mouseY;
		document.mouseX = e.pageX || e.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft);
		document.mouseY = e.pageY || e.clientY + (document.documentElement.scrollTop || document.body.scrollTop);
		return false;
	}

}; addEvent('mousemove', function(e) { Mouse.GetCoords(e); });


// @name: Table
// @author: Neo Geek {neo@neo-geek.net}
// @website: http://neo-geek.net/
// @copyright: (c) 2006 Neo Geek, Neo Geek Labs

var Table = {

	// @name: Table.Initialize
	// @syntax: Table.Initialize(object object);
	// @dependencies: none

	Initialize: function(object) {

        object = $(object);

        if (object) {

	        for (var i = 0; i < object.rows.length; i++) {
	        	for (var j = 0; j < object.rows[i].cells.length; j++) {
	        		object.rows[i].cells[j].rowNum = i;
	        		object.rows[i].cells[j].cellNum = j;
	        	}
	        }

        } return false;

	},

	// @name: Table.InsertRow
	// @syntax: Table.InsertRow(object object, array options);
	// @dependencies: forEach, Table.Initialize, Browser.Type

	InsertRow: function(object, options) {
		
		object = $(object);
		options = options || Array();
		
		if (object) {
			
			if (Browser.Type() == 'ie') { var row = object.insertRow(options.offset || object.rows.length); }
			else { var row = Element.create(object, 'tr'); }
			
			for (var i = 0; i < options.data.length; i++) { var column = row.insertCell(i).innerHTML = options.data[i] || ''; }
			
			if (options.oncomplete) { options.oncomplete(); }
			
			Table.Initialize(object);

			return row;
			
		} return false;

	},

	// @name: Table.InsertColumn
	// @syntax: Table.InsertColumn(object object, array options);
	// @dependencies: Table.Initialize

	InsertColumn: function(object, options) {
		
		object = $(object);
		options = options || Array();
		
		if (object) {
			
			for (var i = 0; i < object.rows.length; i++) {				
				var column = object.rows[i].cells[0].parentNode.appendChild(document.createElement(object.rows[i].cells[0].nodeName)).innerHTML = options.data[i] || '';
			}

			if (options.oncomplete) { options.oncomplete(); }
			
			Table.Initialize(object);
			
		} return false;

	},

	// @name: Table.RemoveRow
	// @syntax: Table.RemoveRow(object object, array options);
	// @dependencies: Table.Initialize

	RemoveRow: function(object, options) {
		
		object = $(object);
		options = options || Array();
		
		if (object) {
			
			if (object.rows[options.data]) { object.deleteRow(options.data); }

			if (options.oncomplete) { options.oncomplete(); }
			
			Table.Initialize(object);
			
		} return false;

	},

	// @name: Table.RemoveColumn
	// @syntax: Table.RemoveColumn(object object, array options);
	// @dependencies: Table.Initialize

	RemoveColumn: function(object, options) {
		
		object = $(object);
		options = options || Array();
		
		if (object) {

			for (var i = 0; i < object.rows.length; i++) {
				if (object.rows[i].cells[options.data]) { object.rows[i].cells[options.data].parentNode.removeChild(object.rows[i].cells[options.data]); }
			}

			if (options.oncomplete) { options.oncomplete(); }
			
			Table.Initialize(object);
			
		} return false;

	},

	// @name: Table.SwitchRows
	// @syntax: Table.SwitchRows(object object, array options);
	// @dependencies: Table.Initialize, Array.indexOf
	
	SwitchRows: function(object, options) {
		
		object = $(object);
		options = options || Array();
		
		if (object) {
			
			if (options.locked && options.locked.indexOf(options.data[1]) != -1 || options.data[1] < 0 || options.data[1] > object.rows.length -1) { return false; }
			
			var rows = Array(object.rows[options.data[0]].cloneNode(true), object.rows[options.data[1]].cloneNode(true));
			
			object.rows[options.data[0]].parentNode.replaceChild(rows[1], object.rows[options.data[0]]);
			object.rows[options.data[1]].parentNode.replaceChild(rows[0], object.rows[options.data[1]]);
			
			if (options.oncomplete) { options.oncomplete(); }
			
			Table.Initialize(object);
			
		} return false;

	},

	// @name: Table.SwitchColumns
	// @syntax: Table.SwitchColumns(object object, array options);
	// @dependencies: Table.Initialize, Array.indexOf

	SwitchColumns: function(object, options) {
		
		object = $(object);
		options = options || Array();
		
		if (object) {
			
			if (options.locked && options.locked.indexOf(options.data[1]) != -1 || options.data[1] < 0 || options.data[1] > object.rows[object.rows.length -1].cells.length -1) { return false; }
			
			for (var i = 0; i < object.rows.length; i++) {
				
				if (!object.rows[i].cells[options.data[0]] || !object.rows[i].cells[options.data[1]]) { continue; }

				var columns = Array(object.rows[i].cells[options.data[0]].cloneNode(true), object.rows[i].cells[options.data[1]].cloneNode(true));

				object.rows[i].cells[options.data[0]].parentNode.replaceChild(columns[1], object.rows[i].cells[options.data[0]]);
				object.rows[i].cells[options.data[1]].parentNode.replaceChild(columns[0], object.rows[i].cells[options.data[1]]);
				
			}	

			if (options.oncomplete) { options.oncomplete(); }		
			
			Table.Initialize(object);			
			
		} return false;

	}

};
