/**
 * Bicycle JLS (Javascript Library Collection)
 * Collected, Hacked & extended by Marco Solazzi - DWJ '2007-2008
 * This Collection Features the following libraries:
 * - liberty - Basic JavaScript Library 0.1
 *   by Andreas Kalsch, Trier
 *   licensed under GPL, look at gnu.org/licenses/gpl.html
 *                                                        
 * - part of ff Javascript Library                        
 *   by Sven Helmberger
 *   Copyright (c) 2006, Sven Helmberger All rights reserved.
 *   
 *   Snippets, functions, prototypes, inspirations by:
 *   - Public Domain 
 *   - Embimedia                                          
 *   - Svend Tofte
 *   - Ben Nadel                                            
 *   - Mootools                                        
 *   - Nomadic Functions                              
 *   - Mega69                                               
 *   - Robert Nyman                                     
 *   - http://programming.arantius.com/dollar-e        
 *   - http://www.thescripts.com/forum/thread596105.html
 *   (see code for details)
 * @author <a href="mailto:hello@dwightjack.com">Marco Solazzi</a>
 * @projectDescription Javascript functions collection
 * @see http://www.buzzurri.net/index.php?id=52
 * @license licensed under GPL, look at gnu.org/licenses/gpl.html (where applicable)
 * @version 1.1 revision 15/07/2008
 */
/**#nocode+*/
$bicycle = {
	version : "1.1b"
}
/**#nocode-*/

try {
	var t = undefined;
}
catch(e) {
	undefined=null;
}

if (!Array.prototype.push)
	/** @lends Array.prototype */
	/**
	 * Add push method to array il not present.
	 * @see Prototype JavaScript framework, version 1.4.0
	 * @return {Array} The new array length
	 */
	Array.prototype.push = function() {
		var startLength = this.length;
		for (var i = 0; i < arguments.length; i++)
			this[startLength + i] = arguments[i];
		return this.length;
	}
/**#@+
     @see liberty - Basic JavaScript Library 0.1
*/
/**
 * Get multiple elements by id.
 * @param {String[]|DOMElement[]} multiple elements id or element reference
 * @return {DOMElement|Array} Returns an element reference if a single argument is passed else an Array of elements references
 * @example
 * 		<div id="myDiv"></div>
 * 		<div id="my2ndDiv"></div>
 * 
 * 		$getEls("myDiv"); //returns a reference to myDiv
 * 
 * 		$getEls("myDiv",DOMElementReference); // returns [myDiv,DOMElementReference]
 */
function $getEls() {
	var elements = new Array();
	
	for (var i = 0; i < arguments.length; i++) {
		var element = arguments[i];
		if (typeof element == 'string')
			element = document.getElementById(element);
	
		if (arguments.length == 1)
			return element;
	
		elements.push(element);
	}
	
	return elements;
}

/**
 * Extends the destination Object with passed in source Object.
 * @param {Object} destination The object to extend
 * @param {Object} source The object to use for extension
 * @example 
 * 		extendObject(String.prototype, {
 * 			escapeXML: function() {
 * 				// function code ...
 * 			},
 *			unescapeXML: function() {
 *				// function code ...
 *			}
 *		}); 
 * @return {Object} The Extended object
 */
extendObject = function(destination, source) {
	for (var property in source)
		destination[property] = source[property];
	return destination;
}

if (!Array.prototype.indexOf) {
	/** @lends Array.prototype */
	/**
	 * Returns the position of an array member.
	 * @param {Object} object A variable to search for
	 * @example
	 * 		var myArray = ['apple', 'lemon', 'orange', 'banana'];
	 * 		alert(myArray.indexOf('orange'));
	 * 		// will alert 2
	 * @return {Number} The position of array member or -1 if not found
	 */
	Array.prototype.indexOf = function(object){
		for (var i = 0; i < this.length; i++) {
			if (this[i] == object) {
				return i;
			}
		}
		return -1;
	}
}
/**
 * Get Element Dimensions.
 * @param {DOMElement|String} element An element reference or a id String
 * @example
 * 		//Get dimensions of element with id 'what'
 *		var dim = getDimension('what');
 *  	alert('Dimensions:'+dim.width+' x '+dim.height); 
 * @return {Object} Returns an object with real width and height of a HTML element in px.
 */
getDimension = function(element) {
  // hacked by DWJ  - border hack from ExtendDOM (CSStyle) by Mega69 --- http://www.sitomega.net/projects/extendDOM/main.php
var el = $getEls(element);
		var border=(function() {
							if($browser.ie) { //IE
									return !getStyle(el,"border-size") ? 0 : getStyle(el,"border-size").toNumber();
							}
							else { //W3C browsers
									return 0; 
							}
					})();
	if (getStyle(el, 'display') != 'none')
		return {width: el.offsetWidth-border, height: el.offsetHeight-border};
	
	var els = el.style;
	var originalVisibility = els.visibility;
	var originalPosition = els.position;
	els.visibility = 'hidden';
	els.position = 'absolute';
	els.display = '';
	var obj = {width: el.clientWidth-border, height: el.clientHeight-border};
	els.display = 'none';
	els.position = originalPosition;
	els.visibility = originalVisibility;
	return obj;
}
/**
 * Get a unique id string for an element.
 * @param {String} prefix Prefix for the id
 * @return {String} Returns a unique string formed by prefix+number (starting from 0), prefix defaults to “id”.
 */
uniqueId = function(prefix) {
	if (prefix == undefined)
		prefix = 'id';
		
	for (var i = 0; $getEls(prefix+i); i++);
	return prefix+i;
}
/**
 * Check if the passed in object is an Array.
 * @param {Object} object The object to check
 * @example
 * 		var myArray = ['apple', 'lemon', 'orange', 'banana']; alert(isArray(myArray));
 * 		// will alert "true"
 * @return {Bool} Returns true if object is an array
 */
isArray = function(object) {
	if (!window.Array || object == null)
		return false;
	return object.constructor == window.Array;
}
/**
 * Get the number of an Object's properties.
 * @param {Object} object The passed in object
 * @return {Number} Returns the number of an Object's properties
 */
getLength = function(object) {
	var i = 0;
	for (var key in object)
		i++;
	return i;
}

extendObject(String.prototype, {
	/** @lends String.prototype */
	/**
	 * Escape XML relevant symbols from string. 
	 * @example
	 * 		var myString = "<b>This is a sample text</b>";
	 * 		myString.escapeXML(); // returns "&lt;b&gtThis is a sample text&lt;/b&gt"
	 * @return {String} Returns the escaped string
	 */
	escapeXML: function() {
		var value = this;
		
		value = value.replace(/&/g, '&amp;');
		value = value.replace(/</g, '&lt;');
		value = value.replace(/>/g, '&gt;');
		value = value.replace(/\"/g, '&quot;');
		value = value.replace(/\'/g, '&apos;');
		
		return value;
	},
	/**
	 * Unescape XML relevant symbols from string. 
	 * @return {String} Returns the unescaped string 
	 */
	unescapeXML: function() {
		var value = this;
		
		value = value.replace(/&lt;/gi, '<');
		value = value.replace(/&gt;/gi, '>');
		value = value.replace(/&quot;/gi, '"');
		value = value.replace(/&apos;/gi, '\'');
		value = value.replace(/&amp;/gi, '&');
		
		return value;
	},
	/**#@-*/

	/**
	 * Searches a string for a given string or regular expression.
	 * @param {String|Object} exp String or Regular expression to match
	 * @param {String} [flag] If exp is a string function accepts a flag, for example "i" will ignore uppercase or lowercase
	 * @see See http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Guide:Regular_Expressions for RegExp info.
	 * @see Mootools 1.0
	 * @author Valerio Proietti
	 * @example
	 * 		var myString = "This is a SAMPLE text";
	 *   		myString.test("sample"); // returns false
	 *   		myString.test("sample","i"); // returns true
	 *   		myString.test(/SAMPLE/); // returns true
	 * @return {Bool} true if a match is found
	 */
	test: function(exp, flag){
		return ((typeof exp == 'string') ? new RegExp(exp, flag) : exp).test(this);
	},

	/**
	 * Converts a string to a number. If the string is mixed, not numerical characters are stripped out (except "." and "-"). Accepts both integer and float conversions.
	 * @see ExtendDOM (String.js) - by Mega69 http://www.sitomega.net/projects/extendDOM/main.php
	 * @example
	 * 		number_1="text_01".toString(); // 01 
	 * 		number_2="70.567".toString(); // 70.567
	 * 		number_3="(-70.567)".toString(); // -70.567
	 * @return {Number} The parsed string as integer of float
	 */
	toNumber: function () {
	var str=this.replace(/[^0-9\.\-]/g, "");
	if(str.match(".")) { return parseFloat(str) }
		return parseInt(str);
}
});
/**#@+
     @see liberty - Basic JavaScript Library 0.1
*/

Number.prototype = {
	/** @lends Number.prototype */
		/**
		 * Checks if a number is contained in the specified range, and adjusts it to the range limits.
		 * @param {Number} from Smallest number in range
		 * @param {Number} to Bigger number in range
		 * @example
		 * 		var myNumber = 20;
		 * 		myNumber.setInRange(1,15); //returns 15;
		 * 		myNumber.setInRange(30,50); //returns 30;
		 * @return {Number}
		 * 
		 */
		setInRange : function(from, to) {
		if (this < from)
			return from;
		if (this > to)
			return to;
		return this;
	}
};
/**
 * Returns the value of a specific style of an element.
 * @param {DOMElement|String} element Could be an element reference or a ID string
 * @param {String} property  The name of the CSS property
 * @example
 * 		//Get the backgrond color of an element with ID "myId"
 *      getStyle("myId", "background-color");
 * @return {String} The CSS style value
 */
getStyle = function(element, property) {
  // hacked by DWJ
var el = $getEls(element);
	if (typeof el == 'object' && typeof property == 'string') {
  // hacked by DWJ
var style = camelCase(property);
		if (el != null) {
			var value = el.style[style];
			if (value != '')
				return value;
			try {
				return el.currentStyle[style];
			} catch(e) {}
			try {
				return window.getComputedStyle(el, null)[style];
			} catch(e) {}
		}
	}
	
	return '';
}
/**
 * Attach specified event(s) function to passed in element(s)
 * @param {Array|DOMElement|String} element ID string reference, or DOM element reference. Either single or as array  
 * @param {String|Array} types Event type(s) without "on" prefix. Either single or as array
 * @param {Function} handler Function to bind to element(s) on specified event(s)
 * @example
 * 		// Fire the function “tryMe()” when clicking on the element with ID “myId”
 *		addHandler('myId', 'click', tryMe);
 * 
 * 		// Set the links title attribute of the document to show the query of each Google link
 *      var elements = getElements('a',{'href':/google/i});
 *
 * 		//now add an event handler function to those elements
 * 		// - for the events 'mouseover' and 'mouseout'
 *       var changeTitle = function(event) {
 *       	if (event.type == 'mouseover') {
 *      		document._title = document.title;
 *       		document.title = this.href;
 *       	}
 *       	else if (event.type == 'mouseout') {
 *       		document.title = document._title;
 *       	}
 *       }
 *
 * 		addHandler(elements, ['mouseover', 'mouseout'], changeTitle);
 * @return {Bool} Returns true if handler is a function
 */
addHandler = function(elements, types, handler) {
	if (!isArray(elements))
		elements = [elements];
	if (!isArray(types))
		types = [types];
	if (typeof handler == 'function') {
		for (var i = 0; i < elements.length; i++) {
			var el = $getEls(elements[i]);
			for (var j = 0; j < types.length; j++) {
				var type = types[j].toLowerCase();
				if (type.substr(0,2) == 'on')
					type = type.substr(2);
				var ontype = 'on'+type; 
					
				for (var k = 0; typeof el[type+k] == 'function'; k++);
				if (k == 0) {
					if (el[ontype]) {
						el[type+k] = el[ontype];
						el[ontype] = null;
						k++;
					}
				}
				el[type+k] = handler;
				if (!el[ontype])
					el[ontype] = function(e) {
						if (!e)
							e = window.event;

						for (var i = 0; typeof this[e.type+i] == 'function'; i++) {
							this[e.type+i](e);
						}
					}
			}
		}
		
		return true;
	}
	
	return false;
}
/**
 * Removes an event handler. If you let handler undefined, all handlers for the specified events are removed.
 * @param {Array|DOMElement|String} element ID string reference, or DOM element reference. Either single or as array  
 * @param {String|Array} types Event type(s) without "on" prefix. Either single or as array
 * @param {Function} [handler] Function to bind to element(s) on specified event(s)
 * @example
 * 		//Remove all link handlers from link elements: 
		removeHandler(getElements('a'), ['mouseover', 'mouseout']);
 * @return {Bool} Returns true if handler is specified and is a function
 */
removeHandler = function(elements, types, handler) {
	if (!isArray(elements))
		elements = [elements];
	if (!isArray(types))
		types = [types];
		
	var ok = false;
	for (var i = 0; i < elements.length; i++) {
		var el = $getEls(elements[i]);
		
		for (var j = 0; j < types.length; j++) {
			var type = types[j].toLowerCase();
			if (type.substr(0,2) == 'on')
				type = type.substr(2);
			var ontype = 'on'+type; 
				
			if (typeof handler == 'function') {
				for (var k = 0; typeof el[type+k] != 'undefined'; k++) {
					if (el[type+k] == handler) {
						el[type+k] = function(e){};
						ok = true;
					}	
				}
			}
			else {
				el[ontype] = null;
				ok = true;
			}
		}
	}
	
	return ok;
}
/**
 * Returns an object with the position in px of an element relative to an ancestor. 
 * @param {DOMElement|String} element Element Reference or ID string
 * @param {DOMElement|String} [top="document.body"]  Ancestor of passed in element. If not defined defaults to 
 * @param {Bool} [scrolling] Defines if the scrolling inside of elements should be subtracted (default: true - better for absolute positioning). 
 * @example 
 * 		var position = getPosition('elementId', $('anchestorId'));
 *		alert('Position: '+position.x+', '+position.y); 
 * @return {Object} Object with x and y keys
 */
getPosition = function(element, top, scrolling) {
  // hacked by DWJ
var el = $getEls(element);
	
	if (top == undefined)
		top = document.body;
	else
		top = $getEls(top);
	if (scrolling != undefined)
		scrolling = Math.round(Number(scrolling).setInRange(0, 1));
	else
		scrolling = 1;

	for (var lx = 0, ly = 0; el != top; el = el.offsetParent) {
		var par = el.offsetParent;
		var offsetLeft = el.offsetLeft;
		var offsetTop = el.offsetTop;
			
		if (scrolling) {
			offsetLeft -= par.scrollLeft;
			offsetTop -= par.scrollTop;
		}
		
		lx += offsetLeft;
		ly += offsetTop;
	}

	return {x: lx, y: ly};
}
/**
 * Returns the position of your cursor, relative to an element. You have to set an event as first argument. 
 * @param {Object} e Event reference
 * @param {DOMElement|String} [element] A reference element, either DOM element or ID string 
 * @example
 * 		// alert mouse position when clicking on a specified element
 * 		addHandler($('elementId'),'click',function (e) {
 * 			var position = getMousePosition(e,this);
 * 			alert('Mouse Position: '+position.x+', '+position.y);
 * 		});
 * @return {Object} Object with x and y keys
 */
getMousePosition = function(e, element) {
	if (!e)
		e = window.event;
	if (!e.target)
		e.target = e.srcElement;
	
	if (element == undefined)
		return {x: e.clientX, y: e.clientY};
	
	var x, y;
	if (e.layerX) {
		x = e.layerX;
		y = e.layerY;
	}
	else {
		x = e.offsetX;
		y = e.offsetY;
	}
	
	var el = $getEls(element);
	if (el != e.target) {
		var pos = getPosition(e.target, el);
		x += pos.x;
		y += pos.y;
	}
	
	return {x: x, y: y};
}
/**
 * Toggle element visibility (CSS display)
 * @param {DOMElement|String} element Element to show or hide
 * @return {String} CSS display property value
 */
changeDisplay = function(element) {
// hacked by DWJ
	var el = $getEls(element); 
	var display = getStyle(el, 'display');
	if (typeof el._display == 'undefined')
		el._display = '';
	$S(el).display = (display == 'none') ? el._display : 'none';	
	el._display = display;	
	return $S(el).display;
}
/**#@-*/

/**
 * ff js API (c) 2005 by Sven Helmberger ( sven dot helmberger at gmx dot de )
 * project homepage: http://fforw.de/post/ff_javascript_library/
 * available under a revised BSD-like library
 * @name ff
 * @author Sven Helmberger ( sven dot helmberger at gmx dot de )
 * @version 1.11
 */
var ff = {};
/** @namespace */
ff.dom = {
	/**#@+
	 * @memberOf ff.dom
     * @function
     * @static
	 * @see ff javascript library 1.11
	 */
		/**
		 * Removes all children from the given DOMElement
		 * @name clear
		 * @param {DOMElement} elem DOM element
		 */
		clear: function(elem){
			while (elem.hasChildNodes()) 
				elem.removeChild(elem.firstChild);
		},
		/**
		 * Replaces the current children of the DOM element with the given child(ren)
		 * @name replace
		 * @param {DOMElement} elem DOM element
		 * @param {DOMElement|Array} The new child/children
		 */
		replace: function(elem, newChildren){
			ff.dom.clear(elem);
			ff.dom.append(elem, newChildren);
		},
		/**
		 * Appends the given child(ren) to the children of the given DOM element
		 * @name append
		 * @param {DOMElement} e DOM element
		 * @param {DOMElement|Array} c Child/children to append
		 */
		append: function(e, c){
			if (c.length && isArray(c)) {
				while (c.length) {
					e.appendChild(c[0]);
				}
			}
			else 
				if (typeof c == "string") {
					var current = e.innerHTML;
					e.innerHTML = current + c;
				}
				else {
					e.appendChild(c);
				}
		},
		/**
		 * Sets the given attribute on the given DOM element to the given value.
		 * @name setAttribute
		 * @param {DOMElement|String} e DOM element or ID string
		 * @param {String} a Attribute name
		 * @param {String} v Value
		 */
		setAttribute:  // hacked by DWJ
		function(e, a, v){
			var el = $getEls(e);
			
			var a2 = this._ar[a];
			if (a2) 
				el.setAttribute(a2, v);
			else 
				if (a == "style") 
					el.style.cssText = v;
				else 
					if (a.substring(0, 2) == "on") 
						el[a] = new Function(v);
					else 
						el.setAttribute(a, v);
		},
		/**
		 * Returns the value of the given attribute of the given DOM element
		 * @name getAttribute
		 * @param {DOMElement|String} e DOM element or ID string
		 * @param {String} a Attribute name
		 * @return {String} Attribute value
		 */
		getAttribute:  // hacked by DWJ    
		
		function(e, a){
			var el = $getEls(e);
			
			var a2 = this._ar[a];
			if (a2) 
				return el.getAttribute(a2);
			else 
				return el.getAttribute(a);
		}
	};
/**#@-*/
/**#nocode+*/
ff.dom._ar=
{
    "class": "className",
    "checked": "defaultChecked",
    "usemap": "useMap",
    "for": "htmlFor"
};
/**#nocode-*/

/**
 * Inserts the node element inside the parent node and after a reference node.
 * @see http://www.dustindiaz.com/top-ten-javascript/
 * @license public domain
 * @param {DOMElement} parent The parent node
 * @param {DOMElement} node The Element to insert inside the parent
 * @param {DOMElement} [referenceNode] The node after which insert passed in node  
 */
function insertAfter(parent, node, referenceNode){
if(referenceNode.nextSibling){
parent.insertBefore(node, referenceNode.nextSibling);
} else {
parent.appendChild(node);
}
}
extendObject(Array.prototype,{
	/** @lends Array.prototype */

	/**
	 * Checks if "value" is an array member.
	 * @author EmbiMedia
	 * @see http://code.mikebrittain.com/2006/01/inarray-method-for-javascript-and-actionscript/
	 * @param {Object} value The element to search inside the array
	 * @example
	 * 		var myArray = ['apple', 'lemon', 'orange', 'banana'];
	 * 		alert(myArray.inArray('apple')); // will alert "true"
	 * @return {Bool} Returns true if "value" is an array member
	 */
	inArray : function (value) {
		var i;
		for (i=0; i < this.length; i++) {
		if (this[i] === value) {
			return true;
		}
		}
		return false;
	},
	/**#@+
    * @author Svend Tofte
    * @see http://www.svendtofte.com/
	*/

	/**
	 * Filters all array members on a function condition and returns the new array.
	 * @param {Function} fnc Function to filter array members
	 * @example
	 * 		var myArray = [1,2,-2,3,-4,4,5];
	 * 		myArray.filter(function (n){
	 * 			return n>0;
	 *		});
	 *		//returns myArray = [1,2,3,4,5] 
	 * @return {Array} The filtered array
	 */
	filter : function(fnc) {
    		var a = [];
    		for (var i = 0; i < this.length; i++) {
       			if (fnc(this[i])) {
           			a.push(this[i]);
        			}
		}
    		return a;
	},
	
	/**
	 * Applies a function to each elements of the given array.
	 * @param {Function} fnc Function to iterate on each element may have two arguments: element and its array index.
	 * @example
	 * 		// create a string named "arrayString" listing element value and index number
	 * 		var myArray = ['apple', 'lemon', 'orange', 'banana'];
	 * 		var arrayString = "";
	 * 		myArray.map( function (el,i) {
	 *			arrayString += el+i+", ";
	 * 		});
	 * 		alert(arrayString); // will alert "apple0, lemon1, orange2, banana3"
	 */
	map : function(fnc) {
    // hacked by DWJ
			var a = new Array(this.length);
    		for (var i = 0; i < this.length; i++) {
        		a[i] = fnc(this[i],i);
    		}
    	return a;
	},
	/**#@-*/
	
	/**
	 * Checks if value is in array, if not adds value to array.
	 * @param {Object} value The element to insert in the array
	 * @example
	 * 		var my1stArray = ['apple', 'lemon'];
	 * 		var my2ndArray = ['lemon', 'orange', 'banana'];
	 * 		for (i=0;i&lt;my2ndArray.length;i++) {
	 * 			my1stArray.checkAgainst(my2ndArray[i]);
	 * 		}
	 *		// will return my1stArray = ['apple', 'lemon', 'orange', 'banana']
	 * @return {Array} The new array
	 */
	// Bicyle native
	checkAgainst : function (value) {
         if (this.inArray(value) != true) {
            this.push(value);
         }
         return this;
	}
});
/**
 * Return width of the current window in pixel.
 * @author Svend Tofte
 * @see http://www.svendtofte.com/
 * @return {String} Return widthof the current window in pixel
 * @lends window.prototype
 */
window.getInnerWidth = function() {
    if (window.innerWidth) {
        return window.innerWidth;
    } else if (document.body.clientWidth) {
        return document.body.clientWidth;
    } else if (document.documentElement.clientWidth) {
        return document.documentElement.clientWidth;
    }
} 
/**
 * Return height of the current window in pixel
 * @author Svend Tofte
 * @see http://www.svendtofte.com/
 * @return {String} Return height of the current window in pixel
 * @lends window.prototype
 */
window.getInnerHeight = function() {
    if (window.innerHeight) {
        return window.innerHeight;
    } else if (document.body.clientHeight) {
        return document.body.clientHeight;
    } else if (document.documentElement.clientHeight) {
        return document.documentElement.clientHeight;
    }
}

/**#@+
* @author Ben Nadel
* @see http://www.bennadel.com/snippets/categories/4-Javascript-Library-snippets.htm
*/
/**
 * Returns the next non-text element relative to the node element.
 * @param {DOMElement} node The reference node
 * @return {DOMElement} The next non-text element relative to the node element
 */
function getNext( node ){

// Travel down the sibling chain looking for a non-text node.
for (
node = node.nextSibling ;
(
node &&
node.nodeType == 3
) ;
node = node.nextSibling
){
// Nothing has to happen here. The FOR loop itself is taking care
// of the node traversing. We don't have to really worry about any
// error checking as we can't really make it outside of HTML DOM
// elements without hitting a structured node, or coming up with NULL.
}

// Return the sibling node.
return( node );

}
/**
 * Returns the previous non-text element relative to the node element.
 * @param {DOMElement} node The reference node
 * @return {DOMElement} The previous non-text element relative to the node element
 */
function getPrev( node ){
 
// Travel up the sibling chain looking for a non-text node.
for ( 
node = node.previousSibling ;
(
node && 
node.nodeType == 3
) ;
node = node.previousSibling
){
// Nothing has to happen here. The FOR loop itself is taking care
// of the node traversing. We don't have to really worry about any
// error checking as we can't really make it outside of HTML DOM
// elements without hitting a structured node, or coming up with NULL.
}

// Return the sibling node.
return( node );

}
/**#@-*/

/**
 * Get the text inside a given element with no regards to childrens.
 * @see http://www.thescripts.com/forum/thread596105.html
 * @param {DOMElement} el Element containing the text 
 * @return {String} The text inside a given element with no regards to childrens
 */
function getText (el) {

   if (el.textContent) {return el.textContent;}
   if (el.innerText) {return el.innerText;}
   if (typeof el.innerHTML == 'string') {return el.innerHTML.replace(/<[^<>]+>/g,'');}
}
	/**
	 * Converts a hyphenate string to camelcase.
	 * @author Valerio Proietti
	 * @see Mootools 1.0
	 * @param {String} string The string to convert
	 * @example 
	 * 		camelCase("just-simple-test"); //returns justSimpleTest
	 * @return {String} The converted string
	 */
function camelCase (string) {
		return string.replace(/-\D/g, function(match){
			return match.charAt(1).toUpperCase();
		});
	}

/**
 * document.createElement convenience wrapper
 *
 * The data parameter is an object that must have the "tag" key, containing
 * a string with the tagname of the element to create.  It can optionally have
 * a "children" key which can be: a string, "data" object, or an array of "data"
 * objects to append to this element as children.  Any other key is taken as an
 * attribute to be applied to this tag.
 *
 * @see http://programming.arantius.com/dollar-e
 *
 * @license MIT license http://www.opensource.org/licenses/mit-license.php
 *
 * @param {Object} data The data representing the element to create
 * @example
		 var element=$E({
		    tag:'div',
		    className:'toolGroup',
		    id:'toolGroup_1',
		    children:{
		        tag:'div',
		        className:'roundBarTop',
		        children:[{
		            tag:'div',
		            className:'leftEdge'
		        },{
		            tag:'div',
		            className:'rightEdge'
		        },{
		            tag:'div',
		            className:'heading',
		            children:[{
		                tag:'a',
		                className:'collapser'
		            },
		                'Group Heading'
		            ]
		        }]
		    }
		});
 * @return {Element} The element created.
 */
function $E(data) {
   var el;
   if ('string'==typeof data) {
       el=document.createTextNode(data);
   } else {
       //create the element
       el=document.createElement(data.tag);
       delete(data.tag);

       //append the children
       if ('undefined'!=typeof data.children) {
           if ('string'==typeof data.children ||
               'undefined'==typeof data.children.length
           ) {
               //strings and single elements
               el.appendChild($E(data.children));
           } else {
               //arrays of elements
               for (var i=0, child=null; 'undefined'!=typeof (child=data.children[i]); i++) {
                   el.appendChild($E(child));
               }
           }
           delete(data.children);
       }

       //any other data is attributes
       for (attr in data) {
         // hacked by DWJ
attr == "style" ? el.style.cssText = data[attr] : el[attr]=data[attr];
       }
   }

   return el;
}


//mine functions and shortcuts

/**
 * Collects elements with options
 * @author Marco Solazzi, inspired by Liberty getElements
 * @param {String} tagName Tag name to collect or '*' for all tags
 * @param {Object} [opt] attributes filter, specify html attribute and value as string or regular expression. Use '*' to just check attribute presence;
 *                       You can pass a parent element by adding property 'parent' : DOMElement    
 * @example
 * 		// Get a list of all links, with class myClass. 
 *		var elements = getElements('a',{'class':'myClass'});
 *
 * 		// Get a list of all links, which have class myClass and a url that contains 'google'. 
 * 		var elements2 = getElements('a',{'class':'myClass', 'href':/google/});
 *
 * 		// Get a list of all links, which have class myClass inside the element with id myId. 
 *		var elements2 = getElements('a',{'class':'myClass', parent:$getEls('myId')});
 * @return {Array} Returns an array of matched Elements
 */

function getElements (tagName, opt) {

	var options = (opt || {});
	var parent = (options.parent || document);
        if (options.parent) {
			delete options.parent;
		}
	
        var children;
	if (tagName == '*') {
		children = parent.getElementsByTagName('*');
		if (children.length == 0) {
				children = document.all;
			}
	}
	else {
		children = parent.getElementsByTagName(tagName);
	}
	var elements = [];
	var optsL = getLength(options);
        for (var i = 0; i < children.length; i++) {
             var child = children[i];
			if (optsL != 0) {
			 var points = 0;
             for (var opt in options) {
             var optTrans = ff.dom._ar[opt] != undefined ? ff.dom._ar[opt] : opt;
			 /**
			  * todo: fix the href absolute bug;
			  */
		if (options[opt] == "*" && child[optTrans]) {
			points++;
		} else if (opt == "class" && getElementsByClassName(options[opt],tagName,parent).inArray(child)){
			points++;
		}
		else if (options[opt] != "*" && (typeof(options[opt]) == "string" ? child[optTrans] == options[opt] : child[optTrans].test(options[opt]))) {
              points++;       
             }
           }
		   	if (points == optsL) {
		   		elements.checkAgainst(child);
		   	} 
           } else {
		   		elements.checkAgainst(child);
		   }

 	}

        return elements;
}

// 
/**
 * shortcut to extract the first or the last element of an "elementsByTagName()" array
 * Returns the first (if index is not defined) or last (if index is "last") element in the array of elements found inside the parent node. If parent is not defined defaults to whole document.
 * @param {String} tag Name of tags to collect
 * @param {String} [index] if "last" returns the last element of the array
 * @param {DOMElement} [parent] Parent element
 * @return {DOMElement} Returns the first (if index is not defined) or last (if index is "last") element in the array
 */
function $TN(tag,index,parent) {
	var elArray = (parent || document).getElementsByTagName(tag);
	return elArray[(index == "last" ? (elArray.length-1) : 0)];
}

/**
 * shortcut to extract the first or the last element of an "elementsByName()" array
 * Returns the first (if index is not defined) or last (if index is "last") element with given name attribute inside the parent node. If parent is not defined defaults to whole document.
 * @param {String} name Name of elements to collect
 * @param {String} [index] if "last" returns the last element of the array
 * @param {DOMElement} [parent] Parent element
 * @return Returns the first (if index is not defined) or last (if index is "last") element in the array
 */
function $EN(name,index,parent) {
	var elArray = (parent || document).getElementsByName(name);
	return elArray[(index == "last" ? (elArray.length-1) : 0)];
}
// shortcut to style
// inspired from http://www.nofunc.com/
/**
 * Shortcut to the .style of an element.
 * note that, differently from GetStyle(), CSS properties use Javascript names: http://codepunk.hardwar.org.uk/css2js.htm
 * @param {DOMElement|String} el Element reference or ID string
 * @example 
 * 		//Set the backgrond color of an element with ID “myId” to “#FFFF00”
 *		$S(“myId”).backgroundColor = “#FFFF00”;
 */
function $S(el) { 
	return $getEls(el).style;
}
// shortcut to generate a DIV element with id and optional text and append it to an element (div as string or other)
/**
 * Creates a new DIV element with given ID and appends it to the given AppendElement. 
 * @param {String} id The ID of the new DIV
 * @param {DOMElement|String} [parent] Parent container Element, either an element reference or ID string
 * @param {String} [text] Text to insert in the new DIV
 * @example
 * 		<div id=”parentEl”></div>
 *
 * 		addDIV('child','parentEl','this is a test');
 * 		// returns <div id=”parentEl”><div id=”child”>this is a test</div></div>
 * @return {DOMElement} the new DIV element 
 */
function addDIV (id,parent,text) {
	$getEls(parent).appendChild($E({
		tag:'div',
		id:id,
		children:(text || '')
		})
	);
}

/**
 * Browser sniffer.
 * Possible browser match:
 * 	$browser.ie // Internet Explorer
 * 	$browser.ie6 // Internet Explorer 6
 * 	$browser.ie7 // Internet Explorer 7
 * 	$browser.ff // Firefox
 * 	$browser.moz // Mozilla
 * 	$browser.ns // Netscape
 * 	$browser.op // Opera
 * 	$browser.saf // Safari
 * 	$browser.kq // Konqueror
 * @author Mega69 - ExtendDOM 0.8
 * @see http://www.sitomega.net/projects/extendDOM/main.php
 * @return {Bool} Returns true if specified browser is catched
 */
$browser=(function() {
	var browser=navigator.userAgent;
	return { 
		'ie':browser.test(/MSIE/i),
		'ie6':this.ie||!window.XMLHttpRequest,
		'ie7':this.ie||window.XMLHttpRequest,
		'ff':browser.test(/Firefox/),
		'moz':browser.test(/Mozilla/),
		'ns':browser.test(/Netscape/),
		'op':Boolean(window.opera),
		'saf':browser.test(/WebKit/i),
		'kq':browser.test(/Khtml/i)
	}
})();

/**
 * Get an elements collection filtered by class name
 * @function
 * @name getElementsByClassName
 * @author Robert Nyman, http://www.robertnyman.com
 * @see http://code.google.com/p/getelementsbyclassname/
 * @param {String} className The class name 
 * @param {String} [tag] Tag name 
 * @param {DOMElement} [elm] Parent element
 */
var getElementsByClassName = function (className, tag, elm){
	/**#nocode+*/
	if (document.getElementsByClassName) {
		getElementsByClassName = function (className, tag, elm) {
			elm = elm || document;
			var elements = elm.getElementsByClassName(className),
				nodeName = (tag)? new RegExp("\\b" + tag + "\\b", "i") : null,
				returnElements = [],
				current;
			for(var i=0, il=elements.length; i<il; i+=1){
				current = elements[i];
				if(!nodeName || nodeName.test(current.nodeName)) {
					returnElements.push(current);
				}
			}
			return returnElements;
		};
	}
	else if (document.evaluate) {
		getElementsByClassName = function (className, tag, elm) {
			tag = tag || "*";
			elm = elm || document;
			var classes = className.split(" "),
				classesToCheck = "",
				xhtmlNamespace = "http://www.w3.org/1999/xhtml",
				namespaceResolver = (document.documentElement.namespaceURI === xhtmlNamespace)? xhtmlNamespace : null,
				returnElements = [],
				elements,
				node;
			for(var j=0, jl=classes.length; j<jl; j+=1){
				classesToCheck += "[contains(concat(' ', @class, ' '), ' " + classes[j] + " ')]";
			}
			try	{
				elements = document.evaluate(".//" + tag + classesToCheck, elm, namespaceResolver, 0, null);
			}
			catch (e) {
				elements = document.evaluate(".//" + tag + classesToCheck, elm, null, 0, null);
			}
			while ((node = elements.iterateNext())) {
				returnElements.push(node);
			}
			return returnElements;
		};
	}
	else {
		getElementsByClassName = function (className, tag, elm) {
			tag = tag || "*";
			elm = elm || document;
			var classes = className.split(" "),
				classesToCheck = [],
				elements = (tag === "*" && elm.all)? elm.all : elm.getElementsByTagName(tag),
				current,
				returnElements = [],
				match;
			for(var k=0, kl=classes.length; k<kl; k+=1){
				classesToCheck.push(new RegExp("(^|\\s)" + classes[k] + "(\\s|$)"));
			}
			for(var l=0, ll=elements.length; l<ll; l+=1){
				current = elements[l];
				match = false;
				for(var m=0, ml=classesToCheck.length; m<ml; m+=1){
					match = classesToCheck[m].test(current.className);
					if (!match) {
						break;
					}
				}
				if (match) {
					returnElements.push(current);
				}
			}
			return returnElements;
		};
	}
	return getElementsByClassName(className, tag, elm);
	/**#nocode-*/
};/**
 * Bicyle Chain
 * @projectDescription Adds chainability to the Bicycle Javascript Library Collection
 * @author             Marco "DWJ" Solazzi
 * @license            CC-GNU GPL (where applicable)
 * @version            0.1b revision 23/05/2008
 * @requires 		   Requires Bicycle Core
 */
(function() {
  /**
   * @name $b
   * @function
   * Collect elements by various means.
   * @param {String|Array|Collection} els Comma separated arguments can be a CSS simple string to get single class,id,tag, a DOM element, and array or Collection of Elements.
   * @namespace
   * @example 
   * $b("#myId",document.getElementById("otherId"),"a",".myClass",[element1,element2]);
   *  
   */
  function _$(els) {
  	this.elements = [];
	for (var i=0; i<els.length; i++) {
		var element = els[i];
		switch ($type(element)) {
			case 'string':
				if (element.charAt(0) == '.') {
					var el = getElementsByClassName(element.substr(1));
					this.elements.merge(el);	
				} else if (element.charAt(0) == '#') {
					var el = document.getElementById(element.substr(1));
					if (el != null) {
						this.elements.checkAgainst(el);
					}
				} else {
					this.elements.merge(getElements(element));
				}
			break;
			case "array":
				this.elements.merge(element);
			break;
			case "collection":
				for (var i=0; i<element.length; i++) {
					this.elements.checkAgainst(element[i]);
				}
			break;
			default:
				this.elements.checkAgainst(element);
			break;
		}
	} 
	return this;
  }

	
  _$.prototype = {
  	/** @lends $b.prototype */
	
	 	 
  	/**
  	 * Get elements contained  by current matched elements. Replace previously matched elements.
  	 * @param {String} tag Search a specific tag or * for all tags
  	 * @param {Object} [opts] Object containing pairs of tag attribute : attribute value
  	 * @see getElements in bicycle-core
  	 * @example
  	 * $b("myId").get("a",{"class":"myClass"});
  	 * @return {Object} this
  	 */
	get : function (tag,opts) {
		var els = [];
		this.each(function (el) {
			var options = {parent : el};
			extendObject(options,(opts || {}));
			var e = getElements(tag,options);
			els.merge(e);		
		});
		this.elements = els;
		return this;
	},
	/**
	 * Add elements to the elements stack.
	 * @param {String} ... mixed arguments
	 * @see #$b
	 * @example 
	 * .add("#otherId"); //element stack is [myId,otherId]
	 * @return {Object} this
	 */
	add : function () {
		var els = _$(arguments);
		this.elements.merge(els.elements);
		return this;
	},
	/**
	 * Count elements contained in stack
	 * @return {Integer} elements stack count
	 */
	length : function () {
		return this.elements.length;
	},
	/**
	 * Extract a specific item from the stack.
	 * @param {Number|String} i Can be the index of the element or "last" to extract the last element in the stack
	 * @example 
	 * $b("a").item(0); // element stack is reduced to the first element in the stack
	 * $b("a").item(0,true); //returns the first element reference
	 * @return {Object} this or element if grab is true (default: false)
	 */
	item : function (i,grab) {
		var el = [];
		var index = i == "last" ? this.elements.length-1 : i;
		el.push(this.elements[index]);
		this.elements = el;
		return (grab || false) ?  this.elements[0] : this;
	},
	/**
	 * Shortcut to get elements by classname.
	 * @param {String} c The searched class name
	 * @param {String} [tag] Optional tag name
	 * @see #get
	 * @example $b("#myId").byClass("myClass");
	 * @return {Object} this
	 */
	byClass : function (c,tag) {
		this.get( (tag || '*') , {'class' : c});	
		return this;
	},
	/**
	 * Iterate a function on elements stack.
	 * @param {Function} fn The function to iterate takes as optional arguments the element and it's index in the stack
	 * @see Array.map in bicycle-core
	 * @return {Object} this
	 */
    each: function(fn) {
      this.elements.map(fn);
      return this;
    },
	/**
	 * Single CSS style manipulation.
	 * @param {String} prop The CSS property
	 * @param {String} [val] New value for the CSS property
	 * $b("#myId").Styles("color"); //returns element color
	 * $b("#myId").Styles("color","#000"); //sets element color
	 * @return {Object,String} If val is not defined returns the CSS property value, else returns this
	 */
    Styles: function(prop, val) {
      if ($type(val)) {
		  this.each(function(el) {
	        el.style[prop.camelize()] = val;
	      });
	      return this;
	  } else {
	  	return getStyle(this.elements[0],prop);
	  }
    },
	/**
	 * Single - Multiple CSS manipulation
	 * @param {Object|String} o Object with CSS property : CSS value or a CSS property string
	 * @param {String} [val] if o is a string, the new CSS value
	 * @see #Styles
	 * $b("#myId").css("color","#000"); //sets element color
	 * $b("#myId").css({"color","#000","margin-bottom":"10px"}); //sets element color and bottom margin
	 * @return {Object,String} if o is a string and value is not defined returns the CSS propoerty value, else returns this
	 */
    css: function(o,val) {
      var that = this;
	  if ($type(o) == "object") {
	  	this.each(function(el){
	  		for (var prop in o) {
	  			that.Styles(prop, o[prop]);
	  		}
	  	});
	  	return this;
	  } else {
	  	return that.Styles(o,val);
	  }
    },
	/**
	 * Fire a function on a specific event on the elements stack
	 * @param {String|Array} type Type of event, either string or events array
	 * @param {Function} fn The function to fire
	 * @see addHlandler in bicycle-core
	 * @example 
	 * $b("#myId").on("click",myFunction);
	 * @return {Object} this 
	 */
    on: function(type, fn) {
		if (!isArray(type) && $b.events[type]) {
			$b.events[type].apply(this,[this.elements,fn]);
		} else {
			addHandler(this.elements, type, fn);
		}
    	return this;
    },
	/**
	 * Remove a registered event handler from elements stack 
	 * @param {String|Array} e Event(s) to remove, either string or events array
	 * @param {Function} h Specific handler to remove
	 * @example
	 * $b("#myId").removeEvent("click",myFunction);
	 * @return {Object} this
	 */
	removeEvent : function (e,fn) {
		removeHandler(this.elements,e,fn);
		return this;
	},
	/**
	 * Removes all handlers registered for the specified event(s)
	 * @param {String|Array} e The event(s) handler to clear, either string or events array
	 * @example
	 * $b("#myId").removeEvents("click");
	 * @return {Object} this
	 */
	removeEvents : function (e) {
		removeHandler(this.elements,e);
		return this;
	},
	/**
	 * Get or Set elements attribute
	 * @param {Object} attr
	 * @param {Object} [val] value of the attribute
	 * @example
	 * $b("#myId").attr("title"); // get element title
	 * $b("#myId").attr("title","new title"); // set elements title
	 * @return {Object|String} if v is not defined returns this, else returns attribute value of the first element in the stack 
	 */
	attr : function (attr,val) {
		if ($type(val)) {
			var that = this;
			this.each(function (el) {
				ff.dom.setAttribute(el,attr,val);
			});
			return this;
		 } else {
			return ff.dom.getAttribute(this.elements[0],attr);
		}  
	},
	/**
	 * Return text of first element in the stack stripping all childs html tags
	 * @return {String} contained text
	 */
	txt : function () { return getText(this.elements[0]).replace(/^\s+|\s+$/g, ''); 
	},
	/**
	 * Get next simbling element of the first element in the stack
	 * @return {Object} this
	 */
	getNext : function () {
		this.elements = [getNext(this.elements[0])];
		return this;
	},
	/**
	 * Get previous simbling element of the first element in the stack
	 * @return {Object} this
	 */ 
	getPrev : function () {
		this.elements = [getPrev(this.elements[0])];
		return this;
	},
	/**
	 * Returns the dimensions in px of the first element in the stack
	 * @param {String} [d] return a specific dimension: "w" for width, "h" for heigth
	 * @example 
	 * $b(window).dimension("w"); // get window dimension
	 * $b("#myId").dimension(); // {width:'100px',height:'200px'}
	 * @return {Object|String} if no specific dimension is requested returns an object {width:value,height:value} 
	 */
	dimension : function (d) {
		if (this.elements[0] == window) {
			var dims = {
				width: window.getInnerWidth(),
				height: window.getInnerWidth()
			};
		} else {
			var dims = getDimension(this.elements[0]);
		}
		if (d && d=="h") {
			return dims.height;
		} else if (d && d=="w") {
			return dims.width;
		} else if (!d) {
			return dims;
		}
	},
	/**
	 * Returns the position in px of the first element in the stack.
	 * @param {Object} [axis] Specific position to get "x" or "y"
	 * @param {Object|String} [parent] The parent element to start measures from, if is a string than referes to a ID, defaults to body
	 * @param {Bool} [scrolling] Scrolling inside of elements should be subtracted (default: true - better for absolute positioning).
	 * @example
	 * $b("#myId").position(); // get element position
	 * $b("#myId").position(false,"containerId"); // position relative to containerId {x:'100px',y:'200px'}
	 * @return {Object|String} if no specific dimension is requested returns an object {x:value,y:value} 
	 */
	position : function (axis,parent, scrolling) {
		var pos = getPosition(this.elements[0],(parent || document.body),(scrolling || true));
		if (axis && axis=="x") {
			return pos.x;
		} else if (axis && axis=="y") {
			return pos.y;
		} else if (!axis) {
			return pos;
		}
	},
	/**
	 * An object containing dimensions and position of the first element in the stack.
	 * @see #position
	 * @see #dimension
	 * @return {Object} Object with dimensions and position
	 */
	space : function () {
		var pos = getPosition(this.elements[0]);
		return extendObject(pos,this.dimension());
	},
	/**
	 * Get the current mouse position relative to the first element in the stack.
	 * @param {Object} e The event attached to the mouse action
	 * @return {Object} x,y position of the mouse
	 */
	mousePosition: function(e){
		return getMousePosition(e, this.elements[0]);
	},
	/**
	 * Toggle visibility of stack elements by CSS
	 * @return {Object} this 
	 */
	toggle : function () {
		this.each(function (el) {
			changeDisplay(el);
			});
		return this;
	},
	/**
	 * Removes all child elements of the stack elements.
	 * @return {Object} this 
	 */
	clear : function () {
		this.each(function (el) {
			ff.dom.clear(el);
		});
		return this;
	},
	/**
	 * Append the given child(ren) element(s) to each element in the stack
	 * @param {Object|Array} c Child(ren), can be either a DOM element or an array of DOM elements.
	 * @return {Object} this 
	 */
	append : function (c) {
		this.each(function(el) {
			ff.dom.append(el,c);
		});
		return this;
	},
	/**
	 * Replaces the current children elements of each element in the stack with the passed in element(s). 
	 * @param {Object|Array} e New child(ren) element(s). Can be either a DOM element or an array of DOM elements.
	 * @return {Object} this 
	 */
	replace : function (e) {
		this.each(function(el){
			ff.dom.replace(el,e);
		});
		return this;
	},
	/**
	 * Inserts stack elements inside a parent node and after a reference node.
	 * @param {Object} [ref] Reference node. If None is found just appends the node element inside the parent.
	 * @param {Object|String} [parent] Parent element, can be a DOM element or a string that refer to a ID, defaults to document
	 * @return {Object} this  
	 */
	queueTo : function (parent,ref) {
		var r = typeof(ref) == "string" ? $getEls(ref) : (ref || false);
		this.each(function(el){
			insertAfter(($getEls(parent) || document),el,r);
		});
		return this;
	}
	
  };
  
  /* Init the $b class  */
  window.$b = function() {
    return new _$(arguments);
  };

  /**
   * Static method to extend Bicycle Chain
   * @name extend
   * @function
   * @memberOf $b
   * @param {Object} obj An object cointaining functions to extend Bicycle
   * @example
   * $b.extend({
   * 	myfunction : function (v) {
   * 		alert(v);
   * 		return this; // add this line to make this method chainable
   * 	}
   * });
   */
  window.$b.extend = function (obj) {
		for (var property in obj) {
			_$.prototype[property] = obj[property];
		}
	};
})();
extendObject(window.$b,{
	/**#nocode+*/
	components : {
		core : $bicycle.version,
		chain : "0.1b"
	},
	release : "0808",
	/**#nocode-*/
	/**
	 * Custom events object
	 * @name events
	 */
	events : {}
});

extendObject(String.prototype,{
	/** @lends String.prototype */
	/**
	 * Extend String Object by add camelize function
	 * @return {String} a camelized string
	 * @example
	 * "my-string-with-hypens".camelize();
	 * // returns "myStringWithHypens"
	 * @see camelCase
	 */
	camelize : function () {
		return camelCase(this);
	},
	/**
	 * Removes the leading and trailing spaces off a string.
	 * @return {String} The trimmed string
	 */
	trim : function () {
		var	str = this.replace(/^\s\s*/, ''),
			ws = /\s/,
			i = str.length;
		while (ws.test(str.charAt(--i)));
		return str.slice(0, i + 1);
	}
});

extendObject(Array.prototype,{
	/** @lends Array.prototype */
	/**
	 * Merge two arrays filtering duplicates
	 * @param {Array} array The array to merge with
	 * @return {Array} the merged array
	 * @example
	 * var array1 = ["one","two","three"];
	 * var array2 = ["three","four","five"];
	 * array1.merge(array2);
	 * // returns ["one","two","three","four","five"]
	 */
	merge : function (array) {
		for (var i = 0; i < array.length; i++) {
		        if ( !this.inArray(array[i])) {
            			this.push(array[i]);
         		}	
		}
         return this;
	},
	/**
	 * Removes elements from an array
	 * @author John Resig (MIT Licensed)
	 * @param {Number} from Index of the element to remove. Positive or negative
	 * @param {NUmber} to How many elements to remove. Positive or negative
	 * @return {Number} Sliced array lengths
	 * @example
	 * // Remove the second item from the array
	 * array.remove(1);
	 * // Remove the second-to-last item from the array
	 * array.remove(-2);
	 * // Remove the second and third items from the array
	 * array.remove(1,2);
	 * // Remove the last and second-to-last items from the array
	*  array.remove(-2,-1);
	 */
	remove : function(from, to) {
  		var rest = this.slice((to || from) + 1 || this.length);
  		this.length = from < 0 ? this.length + from : from;
  		return this.push.apply(this, rest);
	}
});

/**
 * Check if the passed in value/object is defined
 * @name $defined
 * @function
 * @author Valerio Proietti (from MooTools 1.11)
 * @param {Object} obj Any type of variable to check
 * @return {Bool} Returns true if the passed in value/object is defined, that means is not null or undefined.
 */
function $defined(obj){
	return (obj != undefined);
};

/**
 *	Returns the type of object that matches the element passed in.
 * @author Valerio Proietti (from MooTools 1.11)
 * @param {Object} obj Any type of variable
 * @memberOf
 * @return 	{String|Bool} 'element' - if obj is a DOM element node
 *	'textnode' - if obj is a DOM text node
 *	'whitespace' - if obj is a DOM whitespace node
 *	'arguments' - if obj is an arguments object
 *	'object' - if obj is an object
 * 	'string' - if obj is a string
 *	'number' - if obj is a number
 *	'boolean' - if obj is a boolean
 *	'function' - if obj is a function
 *	'regexp' - if obj is a regular expression
 *	'class' - if obj is a Class. (created with new Class, or the extend of another class).
 *	'collection' - if obj is a native htmlelements collection, such as childNodes, getElementsByTagName .. etc.
 *	false - (boolean) if the object is not defined or none of the above.
 *	@example 
 *	var myString = 'hello';
 *	$type(myString); //returns "string"
 */
function $type(obj){
	if (!$defined(obj)) return false;
	if (obj.htmlElement) return 'element';
	var type = typeof obj;
	if (type == 'object' && obj.nodeName){
		switch(obj.nodeType){
			case 1: return 'element';
			case 3: return (/\S/).test(obj.nodeValue) ? 'textnode' : 'whitespace';
		}
	}
	if (type == 'object' || type == 'function'){
		switch(obj.constructor){
			case Array: return 'array';
			case RegExp: return 'regexp';
			//case Class: return 'class';
		}
		if (typeof obj.length == 'number'){
			if (obj.item) return 'collection';
			if (obj.callee) return 'arguments';
		}
	}
	return type;
};
/**
 * Merges a number of objects recursively without referencing them or their sub-objects.
 * @author Valerio Proietti (from MooTools 1.11)
 * @param {Object} obj Any number of objects
 * @return {Object} Merged object
*/
function $merge(){
	var mix = {};
	for (var i = 0; i < arguments.length; i++) {
		for (var property in arguments[i]) {
			var ap = arguments[i][property];
			var mp = mix[property];
			if (mp && $type(ap) == 'object' && $type(mp) == 'object') 
				mix[property] = $merge(mp, ap);
			else 
				mix[property] = ap;
		}
	}
	return mix;
}/**
 * Bicyle Chain Addons
 * @projectDescription Addictional methods for Bicycle Javascript Library Collection
 * @author             Marco "DWJ" Solazzi
 * @license            CC-GNU GPL (where applicable)
 * @version            0.1b revision 04/08/2008
 * @requires 		   Requires Bicycle Core
 * @requires 		   Requires Bicycle Chain
 */
$b.extend({
	/** @lends $b.prototype */
	/**
	 * Get specific(s) element(s) from the stack, or returns elements stack array.
	 * @param {Number} [num] Number of items to extract (defaults to 0, extract 1 element)
	 * @param {Number} [offset] Start index for extraction (can be negative, defaults to 0)
	 * @example 
	 * $b("a").items(); // returns an array containing all link items
	 * $b("a").items(2).attr("title","new title"); //change title to the first 2 link items
	 * $b("a").items(2,-1).attr("title","new title"); //change title to the last two link items
	 * $b("a").items(2,0,true); // returns an array containing just the first two link items
	 * @return {Object|Array} if num is specified and grab is false (default) returns this, else returns all elements in stack as an array
	 */
	items : function (num,offset,grab) {
		if ($type(num)) {
			var o = (offset || 0);
			var endSlice = num+o;
			if (num.toString().charAt(0) == "-") {
				o = howmany-(offset || 0);
				endSlice = this.elements.length-(offset || 0);
			}
			this.elements = this.elements.slice(o,endSlice);
			return $type(grab) ?  this.elements : this;
		} else {
			return this.elements; 
		}
	},

	/** 
	 * Test if the first element in the stack has passed in class name.
	 * @author Robert Nyman/DOMAssistant team: http://code.google.com/p/domassistant/
	 * @param {String} className The class name to test
	 * @return {Bool} Returns true if item has passed in class
	 */
	hasClass : function (className) {
			return new RegExp(("(^|\\s)" + className + "(\\s|$)"), "i").test((this.elements[0]).className);
	},
	
	/**
	 * Add a className to each element of the stack.
	 * @author Robert Nyman/DOMAssistant team: http://code.google.com/p/domassistant/
	 * @param {String} className The class to add
	 * @return {Object} this
	 */
	addClass : function (className) {
			this.each(function (el){
				var currentClass = el.className;
				if (!new RegExp(("(^|\\s)" + className + "(\\s|$)"), "i").test(currentClass)) {
					el.className = currentClass + (currentClass.length ? " " : "") + className;
				}
			});
			return this;
	},
	
	/**
	 * Removes a class from each element of the stack.
	 * @author Robert Nyman/DOMAssistant team: http://code.google.com/p/domassistant/
	 * @param {String} className The class to remove
	 * @return {Object} this
	 */
	removeClass : function (className) {
			var classToRemove = new RegExp(("(^|\\s)" + className + "(\\s|$)"), "i");
			this.each(function (el){
				el.className = el.className.replace(classToRemove, function (match) {
				var retVal = "";
				if (new RegExp("^\\s+.*\\s+$").test(match)) {
					retVal = match.replace(/(\s+).+/, "$1");
				}
				return retVal;
				}).replace(/^\s+|\s+$/g, "");
			});

			return this;
		},
	/**
	 * Event delegation shortcut.
	 * @param {String|Array} eventType Type of event
	 * @param {Object} rules Object with Element class Name : function to fire 
	 * @param {Bool} [prevent] Prevent the default element behaviour, defaults to true 
	 * @see #on
	 * @example
	 * // all elements with class "myClass" inside container "myId"
	 * // run a function on click event
	 * $b("#myId).delegate("click",{
	 * 		"myClass": function () {
	 * 			alert($b(this).attr("href"));
	 * 		}
	 * }); 
	 * @return {Object} this
	 */
	delegate : function (eventType,rules,prevent) {
		return this.on(eventType, function(e) {
			var target = $b.getTarget(e);
			var prevent = prevent || true;
			for (var selector in rules) {
				if ($b(target).hasClass(selector)) {
					if (prevent) {$b.preventDefault(e); }
					return rules[selector].apply(target, arguments);
				}
			}
		});
	},
	/**
	 * Get or Set HTML for the first element in the stack.
	 * @param {String} [c] HTML String inject in the element
	 * @return {Object|String} If c is defined returns this else returns the content on the element as a string 
	 */
	html : function (c) {
		var el = this.elements[0];
		if ($type(c)) {
			el.innerHTML = c;
			return this;
		} else {
			return el.innerHTML;
		}
	},
	/**
	 * Removes all the elements in the stack.
	 * @return {Object} this
	 */
	remove : function () {
		this.elements.map(function (el) {
			el.parentNode.removeChild(el);
		});
		return this;
	},
	/**
	 * Filters elements in the stack by a function.
	 * @param {Function} fn
	 * @see Array.filter
	 * @return {Object} this
	 */
	filter : function (fn) {
		var els = this.elements.filter(fn);
		this.elements = els;
		return this;
	},
	/**
	 * Filters elements in the stack by class or tag name.
	 * @param {String} filter Accepts a CSS class name (ie: ".myClass" ) or a tag name
	 * @example
	 * $b("a").filterByString(".myClass"); //gets all link element with class "myClass"
	 * @return {Object} this
	 */
	filterByString : function (filter) {
		var str = filter;
		this.filter(function (el) {
			return (str.charAt(0) == "." ? $b(el).hasClass(str.substr(1)) : (el.tagName.toLowerCase()).test(str));
		});
		return this;
	},
	/**
	 * Gets the parent element of each element in the stack.
	 * @param {String} [str] Optional filter for parent {@link #filterByString}
	 * @return {Object} this
	 */
	parent: function(str){
		var filter = (str || false);
		var els = [];
		this.each(function (el){
			els.push(el.parentNode);
		});
		this.elements = els;
		
		if ($type(filter) == "string") {
			this.filterByString(filter);
		}
		
		return this;
	},
	/**
	 * Get all parent elements of each element in the stack
	 * @param {String} [str] Optional filter for parent {@link #filterByString}
	 * @example
	 * $b("#myId").parents("div"); //get all div elements contaning selected element
	 * @return {Object} this
	 */
	parents : function (str) {
		var matched = [];
		var filter = str || false;
		this.each(function (elem) {
			var cur = elem["parentNode"];
			while ( cur && cur != document ) {
				if (cur.nodeType == 1) {
					matched.push(cur);
				}
				cur = cur["parentNode"];
			}
		});	
		this.elements = matched;
		if ($type(filter) == "string") {
			this.filterByString(filter);
		}
		return this;
	},
	/**
	 * Load via AJAX content of a given file inside stack elements.
	 * @param {String} url Url of the filename which holds the content
	 * @param {Object} [fn] A callback function
	 * @return {Object} this
	 */
	ajaxload : function (url,fn) {
		var ajax = new ajaxObject(url);
		var cb = fn || function () {};
		var that = this;
		ajax.callback = function (responseText) {
			that.replace(responseText);
			cb();
		};
		ajax.update();
		return this;
	}	
});
/* Add custom events to the .on method */
extendObject(window.$b.events,{
	/**#@+	
	 * @memberOf $b.events
	 * @see #on
	 * @static
	 */
	/**
	 * Add DOM loaded handler.
	 * @param {Array} elements Stack elements
	 * @see Robert Nyman/DOMAssistant team: http://code.google.com/p/domassistant/
	 * @param {Function} fn Function to run 
	 */
	"domready" : function (elements,fn) {
		if (elements.length == 1 && elements[0] == document && typeof(DOMAssistant) != "undefined") {
			DOMAssistant.DOMReady(fn);
		}
	},
	/**
	 * Fix mouseover event for elements with children.
	 * @param {Array} elements Stack elements
	 * @param {Function} fn Function to run 
	 */
	"mouseenter" : function (elements,fn) {
		this.on("mouseover",function (e) {
			var callback = fn;
			if ($b.isMouseLeaveOrEnter(e,this)) {
				callback();
			}
		});
	},
	/**
	 * Fix mouseout event for elements with children.
	 * @param {Array} elements Stack elements
	 * @param {Function} fn Function to run 
	 */
	"mouseleave" : function (elements,fn) {
		this.on("mouseout",function (e) {
			var callback = fn;
			if ($b.isMouseLeaveOrEnter(e,this)) {
				callback();
			}
		});
	},
	/**
	 * Fix MouseWheel scrolling event handling.
	 * @author	Andrea Giammarchi		[http://www.devpro.it/]
	 * @license	MIT 				[http://www.opensource.org/licenses/mit-license.php]
	 * @credits	Adomas Paltanavicius 		[http://adomas.org/javascript-mouse-wheel/]
	 * @param {Array} elements Elements stack
	 * @param {Function} callback A callback function to launch. takes delta as argument
	 */
	"mousewheel": function onmousewheel(elements, callback) {
		var element = elements[0];		
		function __onwheel(event) {
			var	delta = 0;
			if(event.wheelDelta) {
				delta = event.wheelDelta / 120;
				if(window.opera)
					delta = -delta;
			}
			else if(event.detail)
				delta = -event.detail / 3;
			if(delta)
				callback.call(element, delta);
			$b.preventDefault(event);
		};
		
		if(element.addEventListener && !window.opera)
			element.addEventListener("DOMMouseScroll", __onwheel, false);
		else
			element.onmousewheel = (function(base){return function(evt){
				if(!evt) evt = window.event;
				if(base) base.call(element, evt);
				return __onwheel(evt);
			}})(element.onmousewheel);
	}
	/**#@-*/
});

/**
 * Crossbrowser event management and DOMready shortcut
 */
extendObject(window.$b,{
	/**#@+
	 * @memberOf $b
	 * @function
	 */
	/**
	 * Prevent the default behaviour to be launched.
	 * @param {Object} evt event
	 */
	preventDefault: function(evt){
		if (evt && evt.preventDefault) {
			evt.preventDefault();
		}
		else {
			window.event.returnValue = false;
		}
	},
	/**
	 * Prevent the propagation of the event.
	 * @param {Object} evt event
	 */
	cancelBubble : function (evt) {
			if (evt && evt.stopPropagation) {
				evt.stopPropagation();
			}
			else {
				window.event.cancelBubble = true;
			}
	},
	/**
	 * Get a reference to the element which triggered the event. 
	 * @param {Object} evt event
	 * @return {Object} the target reference. You can work on it using $b() wrapper
	 */
	getTarget: function(evt){
		var event = evt || window.event;
        return event.target || event.srcElement;
	},
	/**
	 * Fix for mouseover and mouseout event handlers.
	 * @author http://www.dynamic-tools.net/toolbox/isMouseLeaveOrEnter/
	 * @param {Object} e The event
	 * @param {Object} handler The object which handles the event 
	 */
	isMouseLeaveOrEnter : function (e, handler) { 
		if (e.type != 'mouseout' && e.type != 'mouseover') {
			return false; 
		}
		var reltg = e.relatedTarget ? e.relatedTarget : e.type == 'mouseout' ? e.toElement : e.fromElement;
		while (reltg && reltg != handler) {
			reltg = reltg.parentNode; 
		}
		return (reltg != handler); 
	},
	/**
	 * Shortcut for $b(document).on("domready",fn).
	 * @see #on
	 * @param {Function} fn The function to fire on DOM ready
	 * @return {Object} this
	 */
	ready : function (fn) {
		return $b(document).on("domready",fn);
	}
	/**#@-*/
});
/**#nocode+*/
window.$b.components.addons = "0.1b";



// Developed by Robert Nyman/DOMAssistant team, code/licensing: http://code.google.com/p/domassistant/, documentation: http://www.domassistant.com/documentation. Module inspiration by Dean Edwards, Matthias Miller, and John Resig: http://dean.edwards.name/weblog/2006/06/again/
/*extern DOMAssistant */
if (typeof DOMAssistant == "undefined") {
		DOMAssistant = {};
}
DOMAssistant.DOMLoad = function () {
	var DOMLoaded = false;
	var DOMLoadTimer = null;
	var functionsToCall = [];
	var addedStrings = {};
	var errorHandling = null;
	var execFunctions = function () {
		for (var i=0, il=functionsToCall.length; i<il; i++) {
			try {
				functionsToCall[i]();
			}
			catch (e) {
				if (errorHandling && typeof errorHandling === "function") {
					errorHandling(e);
				}
			}
		}
		functionsToCall = [];
	};
	var DOMHasLoaded = function () {
		if (DOMLoaded) {
			return;
		}
		DOMLoaded = true;
		execFunctions();
	};
	/* Internet Explorer */
	/*@cc_on
	@if (@_win32 || @_win64)
		if (document.getElementById) {
			document.write("<script id=\"ieScriptLoad\" defer src=\"//:\"><\/script>");
			document.getElementById("ieScriptLoad").onreadystatechange = function() {
				if (this.readyState === "complete") {
					DOMHasLoaded();
				}
			};
		}
	@end @*/
	/* Mozilla/Opera 9 */
	if (document.addEventListener) {
		document.addEventListener("DOMContentLoaded", DOMHasLoaded, false);
	}
	/* Safari, iCab, Konqueror */
	if (/KHTML|WebKit|iCab/i.test(navigator.userAgent)) {
		DOMLoadTimer = setInterval(function () {
			if (/loaded|complete/i.test(document.readyState)) {
				DOMHasLoaded();
				clearInterval(DOMLoadTimer);
			}
		}, 10);
	}
	/* Other web browsers */
	window.onload = DOMHasLoaded;
	
	return {
		DOMReady : function () {
			for (var i=0, il=arguments.length, funcRef; i<il; i++) {
				funcRef = arguments[i];
				if (!funcRef.DOMReady && !addedStrings[funcRef]) {
					if (typeof funcRef === "string") {
						addedStrings[funcRef] = true;
						funcRef = new Function(funcRef);
					}
					funcRef.DOMReady = true;
					functionsToCall.push(funcRef);
				}
			}
			if (DOMLoaded) {
				execFunctions();
			}
		},
		
		setErrorHandling : function (funcRef) {
			errorHandling = funcRef;
		}
	};
}();
DOMAssistant.DOMReady = DOMAssistant.DOMLoad.DOMReady;
/**#nocode-*/

/**
 * @projectDescription Ultimate AJAX Object : http://www.hunlock.com/blogs/The_Ultimate_Ajax_Object
 * @author Patrick Hunlock
 * @copyright Patrick Hunlock 2007
 * @license public domain
 * @param {String} url Url to load with AJAX
 * @param {Function} [callbackFunction] Callback function
 * @see http://www.hunlock.com/blogs/The_Ultimate_Ajax_Object 
 */
function ajaxObject(url, callbackFunction) {
  var that=this;      
  this.updating = false;
  this.abort = function() {
    if (that.updating) {
      that.updating=false;
      that.AJAX.abort();
      that.AJAX=null;
    }
  }

  this.update = function(passData,postMethod) { 
  var urlCall = url;  
	if (that.updating) { return false; }
    that.AJAX = null;                          
    if (window.XMLHttpRequest) {              
      that.AJAX=new XMLHttpRequest();              
    } else {                                  
      that.AJAX=new ActiveXObject("Microsoft.XMLHTTP");
    }                                             
    if (that.AJAX==null) {                             
      return false;                               
    } else {
      that.AJAX.onreadystatechange = function() {  
        if (that.AJAX.readyState==4) {             
          that.updating=false;                
          that.callback(that.AJAX.responseText,that.AJAX.status,that.AJAX.responseXML);        
          that.AJAX=null;                                         
        }                                                      
      }                                                        
      that.updating = new Date(); 
	  /**
	   * Patched by DWJ
	   */
	  var urlCall = urlCall + (/\?/.test(urlCall) ? '&timestamp=' : '?timestamp=');     
	  
      if (/post/i.test(postMethod)) {
        var uri=urlCall+that.updating.getTime();
        that.AJAX.open("POST", uri, true);
        that.AJAX.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
        that.AJAX.setRequestHeader("Content-Length", passData.length);
        that.AJAX.send(passData);
      } else {
        var uri=urlCall + (that.updating.getTime()) + (passData ? "&" + passData : ""); 
        that.AJAX.open("GET", uri, true);                             
        that.AJAX.send(null);                                         
      }              
      return true;                                             
    }                                                                           
  }  
  this.callback = callbackFunction || function () { };
}/**
 * Telegraph - Bicyle Form Handler
 * @projectDescription Extends Bicycle by adding support for form handling 
 * @author             Marco "DWJ" Solazzi
 * @license            CC-GNU GPL (where applicable)
 * @version            0.1b revision 27/08/2008 (1st revision revision 25/01/2008)
 * @requires 		   Requires Bicycle Core
 * @requires 		   Requires Bicycle Chain
 */

(function(){
	/**
	 * Selects the form and fills an array with it's children elements excluding buttons.
	 * The returned object has some static properties:
	 * - .f: reference to the form DOM element
	 * - .fId: id of the form element
	 * - .fields: an array of form fields
	 * - .buttons: an object containing as properties .submits .resets .buttons and as values an array of Form elements references 
	 * 
	 * @name $b.getForm
	 * @namespace
	 * @param {String} id Id assigned to the form
	 * @return {Object} Returns a new Form Object
	 * @constructor
	 */
	function _$F(id){
		var reference = $type(id[0]) == "string" ? $getEls(id[0]) : id[0];
		this.f = reference;
		this.fId = (reference.id || false);
		this.fields = [];
		this.buttons = {submits:[],resets:[],buttons:[]};
		
		var excluded = ["submit", "reset", "button"];
		for (i = 0; i < this.f.elements.length; i++) {
			var field = this.f.elements[i];
			if ($defined(field.type)) {
				if (!excluded.inArray(field.type)) {
					this.fields.push(field);
				}
				else {
					this.buttons[field.type + "s"].push(field);
				}
			}
		}
		return this;
	}

	_$F.prototype = {
		/** @lends $b.getForm.prototype */
		/**
		 * Fills the form fields array with specific named field(s).
		 * @param {String} name Name attribute of the field(s)
		 * @return {Object} Returns the form object 
		 */
		field : function (name) {
			this.fields = new Array();
			if (this.f.elements[name].length > 1 && this.f.elements[name].type != "select-one") {
				this.fields = this.f.elements[name];
			}
			else {
				this.fields.push(this.f.elements[name]);
			}
			return this;
		},
		
		/**
		 * Return an object with elements names sorted by type.
		 * @param {Bool} [buttons] Set to true to add buttons elements {@see $b.getForm}
		 * @example 
		 * $b.getForm("myForm").getTypes();
		 * //returns { "text" : ["field1","field2"], "select-one" : ["select1","select2"]} 
		 * @return {Object} Returns an object with elements sorted by type
		 *  
		 */
		getTypes : function (buttons) {
			var obj = {};
			var _this = this;
			this.fields.map(function(el){
				var name = el.name;
				var type = el.type;
				if (isArray(obj[type])) {
					if (!obj[type].inArray(name)) {
						obj[type].push(name);
					}
				} else {
					obj[type] = [name];
				}
			});
			return (buttons || false) ? $merge(obj,this.buttons) : obj;		
		},
		
		/**
		 * Returns an object containing field:value pairs by field specified type.
		 * @param {String} type Type can be: text,textarea,select-one,checkbox,radio,buttons
		 * @see #value
		 * @see #getTypes
		 */
		fieldsByType : function (type) {
			var obj = {};
			var types = this.getTypes(true);
			var searchtype = $defined(types[type]) ? types[type] : [];
			var _this = this;
			searchtype.map(function (el){
				obj[el] = _this.field(el).value();
			});
			return obj;
		},
		
		/**
		 * Set or get the value of a field.
		 * @param {String} [v] Set the field value 
		 * @return {Object|String|Array} If param v is set returns the form object, else returns the field value or an array of checked fields values (for checkboxes) 
		 */
		value : function (v) {
			if ($type(v)) {
				for (i=0; i < this.fields.length; i++) {
						var el = this.fields[i];
						switch (el.type) {
							case "radio":
							case "checkbox":
								if (el.value == v) {
									el.checked = true;
								}
							break;
							case "select-one":
								el.selectedOption = v;
							break;
							default:
								el.value = v;
							break;
						}
				}
				return this;
			}
			else {
				var value = []; 
				if (this.fields.length > 1) {
					if (this.fields.type != "select-one") {
						for (i = 0; i < this.fields.length; i++) {
							var el = this.fields[i];
							switch (el.type) {
								case "radio":
									if (el.checked) {
										return el.value;
									}
									break;
								case "checkbox":
									if (el.checked) {
										value.push(el.value);
									}
									break;
								default:
									if (el.value.trim() != "") {
										value.push(el.value);
									}
									break;
							}
						}
					} else {
						return this.fields.value;
					}
					return value.length > 0 ? value : false;
				}
				if (this.fields[0].type == "checkbox" && !this.fields[0].checked) {
					return false;
				}
				else {
					return this.fields[0].value.trim() != "" ? this.fields[0].value : false;
				}
				
			}
		},
/*		encode : function (value) {
			return encodeURIComponent(value);
		},
		*/
		
		/**
		 * Builds an object from the fields array excluding empty fields.
		 * @param {String} [o] an object to be merged to the fields' serialization
		 * @see #value 
		 * @return {Object} Returns an object with pairs fieldName : fieldValue (String or Array)  
		 */
		serialize: function(o){
			var obj = {};
			var _this = this;
			this.fields.map(function(el){
				var value = _this.field(el.name).value();
				if (value) {
					obj[el.name] = value;
				}
			});
			return $merge(obj,o || {});
		},
		
		/** 
		 * Converts fields name and value to a query string.
		 * @param {String} [d] Delimiter to use for joined array values on fields with same name. Defaults to ":".
		 * @see #serialize
		 * @return {String} Returns a query string of not empty fields: fieldName=fieldValue&... 
		 */
		toQuery: function(d){
			var query = "";
			var obj = this.serialize();
			for (var prop in obj)
			{
				query += prop + "=" + (isArray(obj[prop]) ? obj[prop].join(d || ":") : obj[prop]) + "&";
			}
			return query.substr(0,query.length - 1);
		},
		
		/**
		 * Shortcut to send form data via AJAX. 
		 * @param {String} url Url to processing script
		 * @param {String} [m] Method to send data: "POST" or "GET". Defaults to "POST". 
		 * @param {Function} [fn] A callback function to launch on AJAX complete
		 * @see #toQuery
		 * @return {Object} Returns the Form Object
		 */
		send: function(url, fn, m){
			var query = this.toQuery();
			var ajax = new ajaxObject(url);
			if (fn) {
				ajax.callback = fn;
			}
			ajax.update(query, m || 'POST');
			return this;
		},
		
		/**
		 * Intialize a new ajax call and send form data.
		 * @param {Object} [opts] An object with options:
		 * url {String} Url to processing script
		 * method {String} Method to send data: "POST" or "GET". Defaults to "POST".
		 * data {Object} addictional data to send
		 * onComplete {Function} A callback function to launch on AJAX complete
		 * @see #serialize
		 * @return {Object} Returns the Form Object
		 */
		ajax: function(opts){
			var options = $merge({
				url : '', // the url to send data
				method : 'GET', // method GET or POST
				data : {}, // Additional data object to attach to the request
				onComplete : function () {} // a callback function
			},opts || {});
			var dataObject = this.serialize(options.data);
			var ajax = new ajaxObject(options.url);
			ajax.callback = options.onComplete;
			ajax.update(dataObject,options.method);
			return this;
		},
		
		/**
		 * Prevents submitting of form and other default buttons behaviours.
		 * @param {Object} [el] Also prevent the behaviours of these optional elements {@see $b#add}
		 * @return {Object} Returns the Form Object 
		 */
		preventSubmit : function (el) {
			var els = $b(this.buttons.submits);
			if ($type(el)) {
				els.add(el);
			}
			els.on("click",function (e){
				$b.preventDefault(e);
			});
			$b(this.f).on("submit",function (e){
				$b.preventDefault(e);
			});
			return this;
		}
	};
	/*
	 * Attach the new class to the $b namespace as getForm
	 */
	window.$b.getForm = function(){
		return new _$F(arguments);
	};
})();

$b.extend({
	/** @lends $b.prototype */
	/**
	 * Get or set elements value.
	 * @see $b.getForm#value
	 * @param {Object} [v] Fields value to set
	 * @return {Object|String|Array} If param v is set returns the form object, else returns the field value or an array of checked fields values (for checkboxes)
	 */
	val: function (v) {
		var el = $b(this.elements[0]).attr("name");
		var form = $b(this.elements[0]).parents("form").item(0,true);
		var formObj = $b.getForm(form).field(el);
		if ($type(v)) {
			formObj.value(v);
			return this;
		} else {
			return formObj.value();
		}
	} 
});
/**#nocode+*/
window.$b.components.telegraph="0.1b";
/**#nocode-*/
