Function.prototype.bind = function() {
	var fn = this;
	var args = slice(arguments);
	var reference = args.shift();
	return function binded() {
		var arglist = args.concat(slice(arguments));
		return fn.apply(reference, arglist);
	};
};

function fieldFocus(field, text) {
	if ( domcheck(field).value == text ) { 
		domcheck(field).value = '';
	} 
	addClass(domcheck(field), 'typed');
}

function fieldBlur(field, text) {
	if ( domcheck(field).value == '' || domcheck(field).value == text ) { 
		domcheck(field).value = text; 
		removeClass(domcheck(field), 'typed'); 
	} else { 
		addClass(domcheck(field), 'typed'); 
	}
}

function setupFocusBlur(field, text) {
	if ( domcheck(field).value == '' || domcheck(field).value == text ) {
		domcheck(field).value = text;
		removeClass(domcheck(field), 'typed');
	} else {
		addClass(domcheck(field), 'typed');
	}
	registerEvent(domcheck(field), 'focus', function() { fieldFocus(field, text); });
	registerEvent(domcheck(field), 'blur', function() { fieldBlur(field, text); });
	registerEvent(domcheck(field).form, 'submit', function() { if ( (domcheck(field) != null) && (domcheck(field).value == text) ) { domcheck(field).value = '' } });
}

function updateShipping(parcel_index, url) {
	if ( did("service_" + parcel_index) ) {
		url += "/" + did("service_" + parcel_index).value;
	}
	if ( did("carrier_" + parcel_index) ) {
		url += "/" + did("carrier_" + parcel_index).value;
	}
	async_rpc(url, updateCheckoutModifiers, null);
}

function doUpdateShipping(obj) {	
	if(obj.shipping_method == 'order') {
		did("shipping_total").innerHTML = "$" + obj.shipping;
		did("grand_total").innerHTML = "$" + obj.grand_total;
		showID("grand_total_row");
	}
}

function updateCheckoutModifiers(obj) {
	var before_shipping = false;
	
	for ( var parcel_index = 0; parcel_index < obj.parcels.length; parcel_index++ ) {
	
		var tbody = did("checkout_table_" + parcel_index).tBodies[0];
	
		hideID("shipping_row_" + parcel_index);
		
		var sub_total_row_found = false;
		for ( var i = 0; i < tbody.childNodes.length; i++ ) {
			if ( tbody.childNodes[i].nodeName == 'TR' ) {
				if ( tbody.childNodes[i].id == 'grand_total_row_' + parcel_index ) {
					break;
				} else if ( tbody.childNodes[i].id == 'sub_total_row_' + parcel_index ) {
					sub_total_row_found = true;
				} else if ( sub_total_row_found ) {
					if ( tbody.childNodes[i].id != 'shipping_row_' + parcel_index ) {
						tbody.childNodes[i].parentNode.removeChild(tbody.childNodes[i]);
						i--;
					}
				}		
			}	
		}
		
		var insert_before_target = did("shipping_row_" + parcel_index) || did("grand_total_row_" + parcel_index);
		
		for ( var i=0; i < obj.parcels[parcel_index].modifiers.length; i++ ) {
			
			if ( obj.parcels[parcel_index].modifiers[i].service ) {
			
				if ( did("carrier_" + parcel_index) ) {
				
					while ( did("carrier_" + parcel_index).options.length > 0 ) {
						did("carrier_" + parcel_index).remove(0);
					}
					
					for ( var k=0; k < obj.parcels[parcel_index].modifiers[i].carriers.length; k++ ) {
						var optn = document.createElement("option");
						optn.text = obj.parcels[parcel_index].modifiers[i].carriers[k].text;
						optn.value = obj.parcels[parcel_index].modifiers[i].carriers[k].value;
						did("carrier_" + parcel_index).options.add(optn);
					}
					
					did("carrier_" + parcel_index).value = obj.modifiers[i].carrier;
				}
				
				if ( did("service_" + parcel_index) ) {
				
					while ( did("service_" + parcel_index).options.length > 0 ) {
						did("service_" + parcel_index).remove(0);
					}
					
					for ( var k = 0; k < obj.parcels[parcel_index].modifiers[i].services.length; k++ ) {
						var optn = document.createElement("option");
						optn.text = obj.parcels[parcel_index].modifiers[i].services[k].text;
						optn.value = obj.parcels[parcel_index].modifiers[i].services[k].value;
						did("service_" + parcel_index).options.add(optn);
					}
					
					did("service_" + parcel_index).value = obj.parcels[parcel_index].modifiers[i].service;
				}
				
				if ( obj.parcels[parcel_index].modifiers[i].tbd ) {
					showID('collect-shipping_' + parcel_index);
					did("shipping_total_" + parcel_index).innerHTML = 'TBD';
				} else {
					hideID('collect-shipping_' + parcel_index);
					did("shipping_total_" + parcel_index).innerHTML = obj.parcels[parcel_index].modifiers[i].amount;
				}				
			
				insert_before_target = did("grand_total_row_" + parcel_index);	
			} else {
				var tr = document.createElement('tr');
				tr.className = 'discount';
				
				var td = document.createElement('td');
				td.className = 'title right';
				td.colSpan = '4';
				td.appendChild(document.createTextNode(obj.parcels[parcel_index].modifiers[i].name));
				tr.appendChild(td);
				
				var td = document.createElement('td');
				td.className = 'right bold ' + (obj.parcels[parcel_index].modifiers[i].positive ? 'green' : 'red');
				td.appendChild(document.createTextNode(obj.parcels[parcel_index].modifiers[i].amount));
				tr.appendChild(td);
				
				tbody.insertBefore(tr, insert_before_target);
			}
		}
		
		did("grand_total_" + parcel_index).innerHTML = "$" + obj.parcels[parcel_index].total;
		
		showID("shipping_row_" + parcel_index);
	}
	
	var trs = did("grand_total_row").parentNode.childNodes;
	for ( var i = 0; i < trs.length; i++ ) {
		if ( trs[i].nodeName == "TR" && trs[i].className == 'discount' ) {
			did("grand_total_row").parentNode.removeChild(trs[i]);
			i--;
		}
	}
	
	for ( var i = 0; i < obj.modifiers.length; i++ ) {	
		var tr = document.createElement('tr');
		tr.className = 'discount';
		
		var td = document.createElement('td');
		td.className = 'title';
		td.colSpan = '2';
		td.appendChild(document.createTextNode(obj.modifiers[i].name));
		tr.appendChild(td);
		
		var td = document.createElement('td');
		td.className = 'price ' + (obj.modifiers[i].positive ? 'green' : 'red');
		td.appendChild(document.createTextNode(obj.modifiers[i].amount));
		tr.appendChild(td);
		
		did("grand_total_row").parentNode.insertBefore(tr, did("grand_total_row"));
	}
		
	if ( obj.promo_error ) {
		did('promo_code_error').innerHTML = obj.promo_error;
		showID('promo_code_error');
	} else {
		did('promo_code_error').innerHTML = 'fds';
		hideID('promo_code_error');
	}
	
	did("grand_total").innerHTML = "$" + obj.grand_total;
}

var loaded_term;
var loaded_url;
var cached_terms = {};
function loadTerm(event, term_url) {
	var event = fixEvent(event);
	if ( loaded_term != event.target ) {
		loaded_term = event.target;
		showID("term_popin_loading");
		hideID("term_popin_name");
		hideID("term_popin_pronunciation");
		hideID("term_popin_definition");
		hideID("term_popin_img");
		showID("term_popin");
		if ( !event.pageX ) { 
			event.pageX = event.clientX + getScrollXY().x; 
		}
		if ( !event.pageY ) { 
			event.pageY = event.clientY + getScrollXY().y; 
		}
		did("term_popin").style.top = (event.pageY + 5) + 'px';//event.pageY;
		did("term_popin").style.left = (event.pageX + 5) + 'px'; //event.pageX;
		
		loaded_url = term_url;
		if ( typeof cached_terms[loaded_url] == 'object' ) { 
			showTerm(cached_terms[loaded_url]);
		} else {
			async_rpc(term_url, showTerm, null);
		}
	}
}

function showTerm(res) {
	cached_terms[loaded_url] = res;
	hideID("term_popin_loading");
	
	did("term_popin_name").innerHTML = res.name;
	did("term_popin_pronunciation").innerHTML = res.pronunciation;
	did("term_popin_definition").innerHTML = res.definition;
	if ( res.img_src ) {
		did("term_popin_img").src = res.img_src;
		did("term_popin_img").width = res.img_width;
		did("term_popin_img").height = res.img_height;
		showID("term_popin_img");
	} else {
		hideID("term_popin_img");
	}

	showID("term_popin_name");
	showID("term_popin_pronunciation");
	showID("term_popin_definition");
}


/**
* rgbToHex - Converts an rgb color value into a hexidecimal value (without the leading '#')
* @param integer r Value of the color red in range 0-255;
* @param integer g Value of the color green in range 0-255;
* @param integer b Value of the color blue in range 0-255;
* @return string Hexidecimal representation of the the color
*/
function rgbToHex(r,g,b){
	var rgb = slice(arguments,0,3), hex = '0123456789ABCDEF';
	for ( var i=0;i < 3;i++ ) {
		rgb[i] = isNaN(parseInt(rgb[i],10)) ? 0 : parseInt(rgb[i],10);
		rgb[i] = Math.round(Math.max(Math.min(255,rgb[i]),0));
		rgb[i] = hex.charAt( (rgb[i]-rgb[i]%16)/16 ) + hex.charAt( rgb[i]%16 );
	}
	return rgb.join('');
}
/**
* getStyle - Retrieve the value of the current style property
* @param mixed obj Element id or object
* @param string prop Name of style property to retrieve
* @return mixed Value of the style property. *Note: Unit values will be returned as integers. (ie. 'px' will be stripped off)*
*/
function getStyle(obj,prop){
	obj = (typeof obj == 'object') ? obj : did(obj);
	if ( !obj || !prop ) { return null; }
	var regRGB = /rgb\((\d+),\s(\d+),\s(\d+)\)/i, color;
	var compVal = obj.currentStyle ? obj.currentStyle[prop] : window.getComputedStyle(obj,null).getPropertyValue(prop);
	if ( (color = regRGB.exec(compVal)) != null ) { color.shift(); compVal = '#'+rgbToHex.apply(null,color); }
	return isNaN(parseFloat(compVal)) ? compVal : parseFloat(compVal);
}
/**
* getStyles - Retrieve the current value of several styles
* @param mixed obj Element id or object
* @param string prop Name of style property to retrieve (pass another parameter for each style property)
* @return object Object whose keys are the style property and values are the style property's value
*/
function getStyles(obj, prop) {
	var args = slice(arguments,1);
	var styles = {};
	args.forEach ( function(arg) {
		this[arg] = getStyle(obj,arg);
	},styles);
	return styles;
}
/**
* DOM Utilities
*/
/**
* did - Shorcut for getElementById
* @param id The element id you are looking for
* @param parent optional;The parent item to search within
* @return Element with matching id
*/
function did(id, parent) {
	return (parent || document).getElementById(id);
}
/**
* dbn - Shorcut for getElementsByName
* @param name The element name you are looking for
* @param parent optional;The parent item to search within
* @return Collection of elements
*/
function dbn(name, parent) {
	return (parent || document).getElementsByName(name);
}
/**
* dbt - Shorcut for getElementsByTagName
* @param tag The element tagName you are looking for
* @param parent optional;The parent item to search within
* @return Collection of elements
*/
function dbt(tag, parent) {
	return (parent || document).getElementsByTagName(tag);
}
/**
* dbc - Shortcut for getElementsByClass
* @param className The className you are looking for
* @param parent optional;The parent item to search within
* @return Array of elements
*/
function dbc(className, parent) {
//use default provided by browser if it exists otherwise use our implementation
	if ( document.getElementsByClassName ) {
		return (parent || document).getElementsByClassName(className);
	}
	var nodes = slice(dbt('*', parent)), elms = [];
	nodes.forEach ( function(node) {
		if ( hasClass(node, className) ) {
			elms.push(node);
		}
	});
	return elms;
}
/**
* next - Returns the next non-whitespace sibling element
* @param el object Element node from which to start
* @return object Next non-whitespace child element
*/
function next(el) {
	if ( !el || !el.nextSibling ) { return null; }
	el=el.nextSibling;
	return (el.nodeType==1) ? el : next(el);
}
/**
* prev - Returns the previous non-whitespace sibling element
* @param el object Element node from which to start
* @return object Previous non-whitespace child element
*/
function prev(el) {
	if ( !el || !el.previousSibling ) { return null; }
	el=el.previousSibling;
	return (el.nodeType==1) ? el : prev(el);
}
/**
* first - Returns the first non-whitespace child element
* @param el object Parent element node
* @return object First non-whitespace child element
*/
function first(el) {
	if ( !el || !el.firstChild ) { return null; }
	el=el.firstChild;
	return (el.nodeType==1) ? el : next(el);
}
/**
* last - Returns the last non-whitespace child element
* @param el object Parent element node
* @return object Last non-whitespace child element
*/
function last(el) {
	if ( !el || !el.lastChild ) { return null; }
	el=el.lastChild;
	return (el.nodeType==1) ? el : prev(el);
}
/**
* owner - Returns the parent of the element
* @param el object Element from which to retrieve the parent
* @return object Parent node of the element
*/
function owner(el){
	if ( !el || !el.parentNode ) { return null; }
	el = el.parentNode;
	return (el.nodeType == 1) ? el : owner(el);
}
/**
 * contains - Returns whether the given node is contained with the element
 * @param el object Element in which to check
 * @param node object Element to check for
 * @return boolean True if node is a child of el, false if not
 */
function contains(el, node){
  return el.contains ?
    el != node && el.contains(node) :
    !!(el.compareDocumentPosition(node) & 16);
}
/**
* createElement - Shortcut for document.createElement
* @param tag Tag of the element to create
* @return Element or null if no tag specified
*/
function createElement(tag) {
	if ( !tag ) { return null; }
	return document.createElement(tag);
}
/**
* createTextNode - Shortcut for document.createTextNode
* @param text Text to place inside the new node
* @return New text node
*/
function createTextNode(text) {
	return document.createTextNode(String(text));
}
/**
* hasClass - Returns true if the element has the given class applied
* @param obj Element on which to check for the class
* @param className Class to look for on the element
* @return True (if element has the class) / False (if it doesn't)
*/
function hasClass(obj, className) {
	if ( !obj || className.trim() == '' ) { return false; }
	return (String(obj.className).split(' ').indexOf(className) != -1);
}
/**
* addClass - Adds a class to an element
* @param obj Element on which to add the class
* @param className Class to add to the element
* @return True (if successfully added class) / False (if invalid object or empty classname given)
*/
function addClass(obj, className) {
	if ( !obj || className.trim() == '' || hasClass(obj, className) ) { return false; }
	obj.className = String(obj.className).split(' ').concat([className]).join(' ').trim();
	return true;
}
/**
* removeClass - Removes a class from an element
* @param obj Element from which to remove the class
* @param className Class to remove from the element
* @return True (if successfully removed class) / False (if invalid object or empty classname given)
*/
function removeClass(obj, className) {
	if ( !obj || className.trim() == '' ) { return false; }
	obj.className = String(obj.className).split(' ').filter(function(cls){
		return (cls != className);
	}).join(' ');
	return true;
}
/**
 * getDocSize - Get the size of the current viewable document area
 * @return	object		The width, height of the current viewable document area in a keyed object ( obj.width obj.height )
 */
function getDocSize() {
	var w = 0, h = 0;
	if ( typeof(window.innerWidth) == 'number' ) {
		//Non-IE
		w = window.innerWidth;
		h = window.innerHeight;
		var sbar = getScrollbarWidth();
		if ( window.scrollMaxY > 0 ) { w -= sbar['right']; }
		if ( window.scrollMaxX > 0 ) { h -= sbar['bottom']; }
	} else {
		if ( document.compatMode == 'CSS1Compat' ) {
			w = document.documentElement.clientWidth;
			h = document.documentElement.clientHeight;
		} else {
			w = document.body.clientWidth;
			h = document.body.clientHeight;
		}
	}
	return {'width':w,'height':h};
}

/**
 * getMaxDocSize - Get the total document size
 * @return	object		The width, height of the total document size in a keyed object ( obj.width obj.height )
 */
function getMaxDocSize() {
	var w = 0, h = 0;
	if ( window.innerHeight && typeof window.scrollMaxY == 'number' ) {
		w = window.innerWidth + window.scrollMaxX;
		h = window.innerHeight + window.scrollMaxY;
		var sbar = getScrollbarWidth();
		if ( window.scrollMaxY > 0 ) { w -= sbar['right']; }
		if ( window.scrollMaxX > 0 ) { h -= sbar['bottom']; }
	} else {
		var scroll = getScrollXY();
		if ( document.compatMode == 'CSS1Compat' ) {
			w = document.documentElement.clientWidth+scroll.x;
			h = document.documentElement.clientHeight+scroll.y;
		} else {
			w = document.body.clientWidth+scroll.x;
			h = document.body.clientHeight+scroll.y;
		}
	}
	return {'width':w,'height':h};
}
/**
* getScrollbarWidth - Get the width of the scrollbars on the right/bottom
* @return object The width of the scrollbars on the right/bottom of the window if present ( obj.right, obj.bottom )
*/
function getScrollbarWidth() {
	var size = {'right': 0, 'bottom': 0};
	if ( !document || !document.documentElement ) {
		return size;
	}
	var docEl = document.documentElement;
	size['right'] = ((typeof window.innerWidth == 'number') ? window.innerWidth : docEl.offsetWidth) - docEl.clientWidth;
	size['bottom'] = ((typeof window.innerHeight == 'number') ? window.innerHeight : docEl.offsetHeight) - docEl.clientHeight;
	return size;
}
/**
* getScrollXY - Gets the distance the page has been scrolled vertically and horizontally
* @return object The x,y distance in a keyed object ( obj.x obj.y )
*/
function getScrollXY() {
	var sX = 0, sY = 0;
	if ( typeof(window.pageYOffset)=='number' ) {
		//Non-IE
		sY = window.pageYOffset;
		sX = window.pageXOffset;
	}else if ( document.documentElement && (document.documentElement.scrollLeft || document.documentElement.scrollTop) ) {
		//IE 6+ in 'standards mode'
		sY = document.documentElement.scrollTop;
		sX = document.documentElement.scrollLeft;
	}else if ( document.body && (document.body.scrollLeft || document.body.scrollTop) ) {
		//IE 6 in 'strict mode' & some other browsers
		sY = document.body.scrollTop;
		sX = document.body.scrollLeft;
	}
	return {'x':sX,'y':sY};
}
/**
* Array and object functions
*/
/**
* Array methods indexOf, forEach, map, filter
* Added for browsers without native support
*/
if ( !Array.indexOf ) {
	Array.prototype.indexOf = function(obj,start){
		var len = this.length;
		start = Number(start) || 0;
		start = (start < 0) ? Math.ceil(start) : Math.floor(start);
		if ( start < 0 ) { start+= len; }
		for ( ;start < len;start++ ) {
			if ( start in this && this[start]===obj ) { return start; }
		}
		return -1;
	}
}
if ( !Array.forEach ) {
	Array.prototype.forEach = function(fn /*, bind*/){
		var len = this.length;
		if ( typeof(fn) != 'function' ) { throw new TypeError(); }
		var bind = arguments[1];
		for ( var i=0;i < len;i++ ) {
		if ( i in this ) { fn.call(bind, this[i], i, this); }
		}
	};
}
if ( !Array.map ) {
	Array.prototype.map = function(fn /*, bind*/){
		var len = this.length;
		if ( typeof(fn) != 'function' ) { throw new TypeError(); }
		var ret = [], bind = arguments[1];
		for ( var i=0;i < len;i++ ) {
			if ( i in this ) { ret[i] = fn.call(bind, this[i], i, this); }
		}
		return ret;
	};
}
if ( !Array.filter ) {
	Array.prototype.filter = function(fn /*, bind*/){
		var len = this.length;
		if ( typeof(fn) != 'function' ) { throw new TypeError(); }
		var ret = [], bind = arguments[1], val=null;
		for ( var i=0;i < len;i++ ) {
			if ( i in this ) {
				val=this[i];
				if ( fn.call(bind,val,i,this) ) { ret.push(val); }
			}
		}
		return ret;
	};
}
if ( !Array.every ) {
	Array.prototype.every = function(fn /*, bind*/){
		return this.filter.apply(this,slice(arguments)).length === this.length;
	};
}
if ( !Array.some ) {
	Array.prototype.some = function(fn /*, bind*/){
		return this.filter.apply(this,slice(arguments)).length >0;
	};
}
/**
* slice - Shortcut for Array.prototype.slice.call(obj, idx)
* @param obj mixed Object to call array.slice on
* @param start integer Index at which to begin slicing
* @param end integer Index at which to end slicing
* @return array New array containing values from the idx to the end of the obj
* Note: Useful for transforming arguments object and collections into regular arrays
* ex. function(){ var args = slice(arguments); alert(args instanceof Array); }
*/
function slice(obj, start, end){
	var ret = obj;
	if ( window.ActiveXObject ) {
		if ( typeof obj.length=='undefined' ) { obj.length = getLength(obj); }
		ret = Array.prototype.map.call(obj,function(item){return item;});
	}
	var args = [(start || 0)];
	if ( end && !isNaN(Number(end)) ) {
		args.push(Number(end));
	}
	return Array.prototype.slice.apply(ret,args);
}
/**
* getLength - Finds the total number of all non-function properties owned by the object (see hasOwnProperty)
* @param obj object The object whose properties to count.
* @return int The length of the object or 0 if obj was invalid
*/
function getLength(obj){
	if ( !obj ) { return 0; }
	var i=0;
	for ( var key in obj ) {
		if ( obj.hasOwnProperty(key) && typeof obj[key] !='function' ) {i++;}
	}
	return i;
}
/**
* DOM Event Functions & Objects
*/
/* domLoader - detects when the DOM is ready in the browser (typically before onload would fire).
* Also allows registration of functions to execute once ready.
* 
* Example using the optional object and args parameters:
* -keyword 'this' will be the person object
* -arg1 and arg2 become 'name' and 'job'
* -function will log:
* name: bob job: plummer
* 
* var person = {'name':'bob','job':'plummer'};
* domLoader.register(function(arg1, arg2){
* console.log(arg1+': '+this[arg1]+' arg2: '+this[arg2]);
* }, person, ['name','job']); 
*/
var domLoader = {
	isReady: false,
	isBound: false,
	queue: [],
	binds: [],
	args: [],
	/**
	 * register - Register a function to be executed when the dom is ready
	 * @param	fn		function	Function to execute
	 * @param	obj		object		optional;Object that will be the scope for fn(keyword 'this' inside function, default is window)
	 * @param	args	array		optional;Array of parameters to be passed to the function upon execution
	 */
	register: function register(fn, obj, args) {
		this.checkReady();
		this.queue = (this.queue instanceof Array) ? this.queue : [];
		if ( !fn || typeof fn != 'function' ) {
			return;
		}
		
		var offset = this.queue.push(fn) - 1;
		
		obj = obj || null;
		this.binds = (this.binds instanceof Array) ? this.binds : [];
		this.binds[offset] = obj;
		
		args = args ? ((args instanceof Array) ? args :  slice(args)) : [];
		this.args = (this.args instanceof Array) ? this.args : [];
		this.args[offset] = args;
		if ( this.isReady ) {
			this.ready();
		}
		return this;
	},
	/**
	 * checkReady - Starts checking the for the dom to be ready (internal use)
	 */
	checkReady: function checkReady() {
		if ( this.isBound ) {
			return;
		}
		this.isBound = true;
		var self = this;
		var events = {'load': window};
		// Mozilla, Opera and Safari
		if ( document.addEventListener ) {
			events['DOMContentLoaded'] = document;
		// IE
		} else if ( document.attachEvent ) {
			events['onreadystatechange'] = document;
			// If IE and not an iframe -- continually check to see if the document is ready
			if ( document.documentElement.doScroll && window == window.top ) {
				(function ieDoScrollTest(){
					if ( self.isReady ) {
						return;
					}
					try {
						// If IE is used, use the trick by Diego Perini -- http://javascript.nwbox.com/IEContentLoaded/
						document.documentElement.doScroll("left");
						// and execute any waiting functions
						self.isReady = true;
						self.ready();
					} catch ( error ) {
						setTimeout(arguments.callee, 0);
						return;
					}
				})();
			}
		}
		var idDoScrollTest = null;
		//Faster Safari detection
		if ( typeof navigator.taintEnabled === 'undefined' ) {
			var timer = window.setInterval(function safariReadyTest() {
				if ( /loaded|complete/.test(document.readyState) ) {
					window.clearInterval(timer);
					if ( self.isReady ) {
						return;
					}
					self.isReady = true;
					self.ready();
				}
			}, 10);
		}
		var safariReadyTest = null;
		for ( var name in events ) {
			if ( !events.hasOwnProperty(name) ) {
				continue;
			}
			(function scopeFix(name, obj) {
				registerEvent(obj, name, function pageLoadEventWrapper() {
					unregisterEvent(obj, name, arguments.callee);
					if ( !self.isReady ) {
						self.isReady = true;
						self.ready();
					}
				});
				var pageLoadEventWrapper = null;
			})(name, events[name]);
		}
		var varprotector = null;
	},
	/**
	 * ready - Executes all registered functions with any bound scope & args (internal use)
	 */
	ready: function ready(){
		if ( !this.isReady || !(this.queue instanceof Array) ) {
			return;
		}
		var fn, obj, args;
		while(fn = this.queue.shift()) {
			obj = this.binds.shift() || window;
			args = this.args.shift();
			fn.apply(obj, args);
		}
		
		this.queue = [];
		this.binds = [];
		this.args = [];
	}
};


function triggerEvent(el, type, bubbles, cancelable) {
	try{
		el = typeof el == 'object' ? el : did(el);
		bubbles = bubbles || true;
		cancelable = cancelable || true;
		if ( document.createEvent ) {
			if ( el == window && !el.dispatchEvent ) {
				el = document; /* safari 3 doesn't have window.dispatchEvent() */
			}
			var groups = {
				'UIEvents':['focusin','focusout','activate','deactivate'],
				'MouseEvents': ['click','dblclick','mousedown','mouseup','mouseover','mouseout','mousemove'],
				'HTMLEvents': ['load','unload','abort','error','select','change','submit','reset','focus','blur','resize','scroll']
			};
			var groupName = null;
			for ( var group in groups ) {
				if ( groups[group].indexOf(type) != -1 ) {
					groupName = group;
					break;
				}
			}
			if ( groupName ) {
				var event = document.createEvent(groupName);
				event.initEvent(type, bubbles, cancelable);
				el.dispatchEvent(event);
				return true;
			}
		}else if ( document.createEventObject ) {
			if ( el == document ) {
				// IE6,IE7 thinks window==document and doesn't have window.fireEvent()
				// IE6,IE7 cannot properly call document.fireEvent()
				el = document.documentElement;
			}
			var event = document.createEventObject();
			el.fireEvent("on"+type, event);
			return true;
		}
	}catch ( e ) {}
	return false;
}

function toggleReturn(name) {
	if ( !domcheck(name) ) {
		return;
	}
	var action = '';
	if ( domcheck(name).style.display == 'none' ) {
		domcheck(name).style.display = '';
		action = 'hide';
	} else {
		domcheck(name).style.display = 'none';
		action = 'show';
	}
	return action;
}

/**
 * A function to return an array of elements by multiple tag names.
*/
function getElementsByTagNames(tags,top) {
	var parent = top||document;
	if(parent.querySelectorAll) {
		return slice((top||document).querySelectorAll(tags.join(',')));
	}
	var arr = [];
	var dTags = dbt('*',parent);
	slice(dTags).forEach(function(tag){
		if(tags.indexOf(tag.tagName.toLowerCase()) != -1) {
			arr.push(tag);
		}
	});
	return arr;
};

/**
 * Effect base class.
 * @param options - Object that holds settings
 * @return none
 */
var Effect = function(options){
	this.constructor = Effect;
	this.setOptions(options);
};
Effect.prototype={
	playing:false,
	timer:null,
	time:0,
	options:{
		from:0,
		to:0,
		fps:50,
		duration:500,
		wait:false,
		transition:null,
		onStart:function(){},
		onComplete:function(){}
	},
	setOptions:function(options){
		for(var i in options){
			this.options[i] = options[i];
		}
	},
	start:function(from,to,overrideWait){
		if(this.playing && this.options.wait && !overrideWait){return false;}
		clearInterval(this.timer);
		this.from = from;
		this.to = to;
		this.time=0;
		this.startTimer();
		this.transition = this.getTransition();
		return this;
	},
	getTransition:function(){
		return function(p){
			return -(Math.cos(Math.PI * p) - 1) / 2;
		};
	},
	frame:function(){
		var time = Number(new Date().getTime());
		if(time < this.time + this.options.duration){
			var d = this.transition((time-this.time)/this.options.duration);
			this.set(this.compute(this.from,this.to,d));
		}else{
			this.set(this.compute(this.from,this.to,1));
			this.stop();
		}
	},
	set:function(value){
		return value;
	},
	stop:function(){
		this.playing = false;
		clearInterval(this.timer);
		this.options.onComplete();
	},
	compute:function(from,to,d){
		return (to-from) * d + from;
	},
	startTimer:function(){
		this.playing = true;
		var self = this;
		this.time = new Date().getTime();
		this.timer = setInterval(function(){self.frame.apply(self);},(1000/this.options.fps));
		this.options.onStart();
	}
};

/**
 * StyleTween extends the base Effect object and applies basic CSS effects to elements.
 * 
 * Supports:
 * left
 * top
 * width
 * height
 * opacity
 * 
 * @param elm
 * @param options
 * @return
 */
var StyleTween = function(elm,options){
	this.elm = elm;
	this.unit = '';
	this.setOptions(options);
};

StyleTween.prototype = new Effect;
StyleTween.prototype.parent = Effect.prototype;

StyleTween.prototype.set = function(value){
	this.setStyle(value);
};

StyleTween.prototype.start = function(style, from, to) {
	this.style = style;
	this.getUnit();
	if(!to){
		var to = from;
		var from = this.getStyle();
	}
	this.parent.start.call(this,from,to);
};

StyleTween.prototype.getStyle = function(){
	if(this.style == 'opacity'){
		return this.getOpacity();
	}
	return getStyle(this.elm,this.style);
};

StyleTween.prototype.setStyle = function(value){
	if(this.style == 'opacity'){
		return this.setOpacity(value);
	}
	this.elm.style[this.style] = value+this.options.unit;
};

StyleTween.opacities={};

StyleTween.prototype.getOpacity=function(){
	if(typeof StyleTween.opacities[this.elm] != 'undefined'){
		return StyleTween.opacities[this.elm];
	}
	var style = getStyle(this.elm,'opacity');
	return style || 1;
};

StyleTween.prototype.setOpacity = function(value) {
	value = Math.abs(value);
	if(window.ActiveXObject){
		this.elm.style.filter = 'alpha(opacity = '+Math.round(value*100)+')';
		this.elm.style.zoom = '1';
	}else{
		this.elm.style.opacity = Math.round(value*100)/100;
	}
	StyleTween.opacities[this.elm]=value;
}

StyleTween.prototype.getUnit = function(){
	switch(this.style){
		default:
			this.options.unit = 'px';
		break;
	};
	return this.options.unit;
};
/**
 * Wraps StyleTween and creates shortcuts for fading elements.
 * @param elm
 * @param options
 * @return
 */
var Fade = function(elm,options){
	this.effect = new StyleTween(elm,options);
	this.effect.style = 'opacity';
	this.inout = 'in';
};

Fade.prototype.start=function(){
	var args = slice(arguments);
	args.unshift('opacity');
	this.effect.start.apply(this.effect,args);
};

Fade.prototype.set = function(value){
	return this.effect.set(value)
};

Fade.prototype.hide = function(){
	return this.set(0);
};

Fade.prototype.show = function(){
	return this.set(1);
};

Fade.prototype.stop = function(){
	return this.effect.stop();
};

Fade.prototype.fadeIn=function(){
	return this.effect.start('opacity',1);
};

Fade.prototype.fadeOut=function(){
	return this.effect.start('opacity',0);
};

Fade.prototype.toggle=function(){
	if(!this.inout){this.inout = 'in';}
	if(this.inout == 'in'){
		this.inout = 'out';
		this.fadeOut();
	}else{
		this.inout = 'in';
		this.fadeIn();
	}
};
function postFormRPC(form, url, callback) {

	var obj = new Object();
	
	var inputs = dbt("input", form);
	for ( var i = 0; i < inputs.length; i++ ) {
		if ( inputs[i].type && ((inputs[i].type.toLowerCase() == "checkbox" && inputs[i].checked) || inputs[i].type.toLowerCase() != "checkbox") && inputs[i].value ) {
			obj[inputs[i].name] = inputs[i].value;
		}
	}
	
	var selects = dbt("select", form);
	for ( var i = 0; i < selects.length; i++ ) {
		if ( selects[i].value ) {
			obj[selects[i].name] = selects[i].value;
		}
	}
	
	async_rpc(url, callback, obj);
	
	return false;
}
function setName(element, newName) {
	element = (typeof element === "string") ? document.getElementById(element) : element;
	element.name = newName;
	var inputID = element.id;
	element.mergeAttributes(document.createElement("<input name='" + newName + "'/>"), false);
	element.id = inputID;
}

function isBrowserIE() {
	if(navigator.appName == 'Microsoft Internet Explorer') {
		return true;		
	} else {
		return false;
	}
}
