/*
Versione: 321
Lib: Moo, Utility, Array, String, Function, Element, Event, Common, Dom, Drag.Base, Drag.Move, XHR, Ajax, Sortables

Script: Moo.js
 My Object Oriented javascript.

Author:
 Valerio Proietti, <http://mad4milk.net>

License:
 MIT-style license.

Mootools Credits:
 - Class is slightly based on Base.js <http://dean.edwards.name/weblog/2006/03/base/> (c) 2006 Dean Edwards, License <http://creativecommons.org/licenses/LGPL/2.1/>
 - Some functions are based on those found in prototype.js <http://prototype.conio.net/> (c) 2005 Sam Stephenson sam [at] conio [dot] net, MIT-style license
 - Documentation by Aaron Newton (aaron.newton [at] cnet [dot] com) and Valerio Proietti.
*/

/*
Class: Class
 The base class object of the <http://mootools.net> framework.

Arguments:
 properties - the collection of properties that apply to the class. Creates a new class, its initialize method will fire upon class instantiation.

Example:
 (start code)
 var Cat = new Class({
  initialize: function(name){
   this.name = name;
  }
 });
 var myCat = new Cat('Micia');
 alert(myCat.name); //alerts 'Micia'
 (end)
*/

var Class = function(properties){
 var klass = function(){
  if (this.initialize && $type(this.initialize) == 'function') return this.initialize.apply(this, arguments);
  else return this;
 };
 $extend(klass, this);
 klass.prototype = properties;
 return klass;
};

/*
Property: empty
 Returns an empty function
*/

Class.empty = function(){};

Class.prototype = {

 /*
 Property: extend
  Returns the copy of the Class extended with the passed in properties.

 Arguments:
  properties - the properties to add to the base class in this new Class.

 Example:
  (start code)
  var Animal = new Class({
   initialize: function(age){
    this.age = age;
   }
  });
  var Cat = Animal.extend({
   initialize: function(name, age){
    this.parent(age); //will call the previous initialize;
    this.name = name;
   }
  });
  var myCat = new Cat('Micia', 20);
  alert(myCat.name); //alerts 'Micia'
  alert(myCat.age); //alerts 20
  (end)
 */

 extend: function(properties){
  var proto = $merge(this.prototype);
  for (var property in properties){
   var pp = proto[property];
   proto[property] = $mergeClass(pp, properties[property]);
  }
  return new Class(proto);
 },

 /*
 Property: implement
  Implements the passed in properties to the base Class prototypes, altering the base class, unlike <Class.extend>.

 Arguments:
  properties - the properties to add to the base class.

 Example:
  (start code)
  var Animal = new Class({
   initialize: function(age){
    this.age = age;
   }
  });
  Animal.implement({
   setName: function(name){
    this.name = name
   }
  });
  var myAnimal = new Animal(20);
  myAnimal.setName('Micia');
  alert(myAnimal.name); //alerts 'Micia'
  (end)
 */

 implement: function(properties){
  $extend(this.prototype, properties);
 }

};

/* Section: Utility Functions */

/*
Function: $type
 Returns the type of object that matches the element passed in.

Arguments:
 obj - the object to inspect.

Example:
 >var myString = 'hello';
 >$type(myString); //returns "string"

Returns:
 'element' - if obj is a DOM element node
 'textnode' - if obj is a DOM text node
 'whitespace' - if obj is a DOM whitespace node
 'array' - if obj is an array
 '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
 false - (boolean) if the object is not defined or none of the above.
*/

function $type(obj){
 if (obj === null || obj === undefined) return false;
 var type = typeof obj;
 if (type == 'object'){
  if (obj.htmlElement) return 'element';
  if (obj.push) return 'array';
  if (obj.nodeName){
   switch(obj.nodeType){
    case 1: return 'element';
    case 3: return obj.nodeValue.test(/\S/) ? 'textnode' : 'whitespace';
   }
  }
 }
 return type;
};

/*
Function: $merge
 merges a number of objects recursively without referencing them or their sub-objects.

Arguments:
 any number of objects.
*/

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;
};

//internal

function $mergeClass(previous, current){
 if (previous && previous != current){
  var ptype = $type(previous);
  var ctype = $type(current);
  if (ptype == 'function' && ctype == 'function'){
   var merged = function(){
    this.parent = arguments.callee.parent;
    return current.apply(this, arguments);
   };
   merged.parent = previous;
   return merged;
  } else if (ptype == 'object' && ctype == 'object'){
   return $merge(previous, current);
  }
 }
 return current;
};

/*
Function: $extend
 Copies all the properties from the second passed object to the first passed Object.
 If you do myWhatever.extend = $extend the first parameter will become myWhatever, and your extend function will only need one parameter.

Example:
 (start code)
 var firstOb = {
  'name': 'John',
  'lastName': 'Doe'
 };
 var secondOb = {
  'age': '20',
  'sex': 'male',
  'lastName': 'Dorian'
 };
 $extend(firstOb, secondOb);
 //firstOb will become: 
 {
  'name': 'John',
  'lastName': 'Dorian',
  'age': '20',
  'sex': 'male'
 };
 (end)

Returns:
 The first object, extended.
*/

var $extend = Object.extend = function(){
 var args = arguments;
 if (!args[1]) args = [this, args[0]];
 for (var property in args[1]) args[0][property] = args[1][property];
 return args[0];
};

/*
Function: $native
 Will add a .extend method to the objects passed as a parameter, but the property passed in will be copied to the object's prototype only if non previously existent.
 Its handy if you dont want the .extend method of an object to overwrite existing methods.
 Used automatically in mootools to implement Array/String/Function/Number methods to browser that dont support them whitout manual checking.

Arguments:
 a number of classes/native javascript objects

*/

var $native = Object.Native = function(){
 for (var i = 0; i < arguments.length; i++) arguments[i].extend = $native.extend;
};

$native.extend = function(props){
 for (var prop in props){
  if (!this.prototype[prop]) this.prototype[prop] = props[prop];
 }
};

$native(Function, Array, String, Number, Class);

/*
Script: Utility.js
 Contains Utility functions

Author:
 Valerio Proietti, <http://mad4milk.net>

License:
 MIT-style license.
*/

//window, document

window.extend = document.extend = $extend;
var Window = window;

/*
Function: $chk
 Returns true if the passed in value/object exists or is 0, otherwise returns false.
 Useful to accept zeroes.
*/

function $chk(obj){
 return !!(obj || obj === 0);
};

/*
Function: $pick
 Returns the first object if defined, otherwise returns the second.
*/

function $pick(obj, picked){
    return (obj != undefined) ? obj : picked;
};

/*
Function: $random
 Returns a random integer number between the two passed in values.

Arguments:
 min - integer, the minimum value (inclusive).
 max - integer, the maximum value (inclusive).

Returns:
 a random integer between min and max.
*/

function $random(min, max){
 return Math.floor(Math.random() * (max - min + 1) + min);
};

/*
Function: $time
 Returns the current timestamp

Returns:
 a timestamp integer.
*/

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

/*
Function: $duration
 Returns a time interval in seconds from the given time units

Arguments:
 data - Object with values for years, months, days, hours, seconds, milliseconds. For non-objects it returns the parsed argument as integer.
 ms - Boolean, if true return ms, otherwise seconds

Returns:
 an integer for the duration in seconds or ms if second parameter is true.
*/

function $duration(data, ms){
 if ($type(data) != 'object') return parseInt(data);
 this.units = this.units || {years: 'FullYear', months: 'Month', days: 'Date', hours: 'Hours', minutes: 'Minutes', seconds: 'Seconds', milliseconds: 'Milliseconds'};
 var date = new Date();
 for (var unit in data){
  var fn = this.units[unit];
  if (fn) date['set' + fn](date['get' + fn]() + $pick(data[unit], 0));
 }
 return parseInt((date.getTime() - $time()) / (ms ? 1 : 1000));
}

/*
Function: $clear
 clears a timeout or an Interval.

Returns:
 null

Arguments:
 timer - the setInterval or setTimeout to clear.

Example:
 >var myTimer = myFunction.delay(5000); //wait 5 seconds and execute my function.
 >myTimer = $clear(myTimer); //nevermind

See also:
 <Function.delay>, <Function.periodical>
*/

function $clear(timer){
 clearTimeout(timer);
 clearInterval(timer);
 return null;
};

/*
Class: window
 Some properties are attached to the window object by the browser detection.

Properties:
 window.ie - will be set to true if the current browser is internet explorer (any).
 window.ie6 - will be set to true if the current browser is internet explorer 6.
 window.ie7 - will be set to true if the current browser is internet explorer 7.
 window.khtml - will be set to true if the current browser is Safari/Konqueror.
 window.gecko - will be set to true if the current browser is Mozilla/Gecko.
*/

if (window.ActiveXObject) window.ie = window[window.XMLHttpRequest ? 'ie7' : 'ie6'] = true;
else if (document.childNodes && !document.all && !navigator.taintEnabled) window.khtml = true;
else if (document.getBoxObjectFor != null) window.gecko = true;

//htmlelement

if (typeof HTMLElement == 'undefined'){
 var HTMLElement = Class.empty;
 if (window.khtml) document.createElement("iframe"); //fixes safari
 HTMLElement.prototype = (window.khtml) ? window["[[DOMElement.prototype]]"] : {};
}
HTMLElement.prototype.htmlElement = true;

//enables background image cache for internet explorer 6

if (window.ie6) try {document.execCommand("BackgroundImageCache", false, true);} catch(e){};

/*
Script: Array.js
 Contains Array prototypes, <$A>, <$each>

Authors:
 - Christophe Beyls, <http://digitalia.be>
 - Valerio Proietti, <http://mad4milk.net>

License:
 MIT-style license.
*/

/*
Class: Array
 A collection of The Array Object prototype methods.
*/

//custom methods

Array.extend({
 
 /*
 Property: forEach
  Iterates through an array; This method is only available for browsers without native *forEach* support.
  For more info see <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:forEach>
 */
 
 forEach: function(fn, bind){
  for (var i = 0, j = this.length; i < j; i++) fn.call(bind, this[i], i, this);
 },
 
 /*
 Property: filter
  This method is provided only for browsers without native *filter* support.
  For more info see <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:filter>
 */
 
 filter: function(fn, bind){
  var results = [];
  for (var i = 0, j = this.length; i < j; i++){
   if (fn.call(bind, this[i], i, this)) results.push(this[i]);
  }
  return results;
 },
 
 /*
 Property: map
  This method is provided only for browsers without native *map* support.
  For more info see <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:map>
 */
 
 map: function(fn, bind){
  var results = [];
  for (var i = 0, j = this.length; i < j; i++) results[i] = fn.call(bind, this[i], i, this);
  return results;
 },
 
 /*
 Property: every
  This method is provided only for browsers without native *every* support.
  For more info see <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:every>
 */
 
 every: function(fn, bind){
  for (var i = 0, j = this.length; i < j; i++){
   if (!fn.call(bind, this[i], i, this)) return false;
  }
  return true;
 },
 
 /*
 Property: some
  This method is provided only for browsers without native *some* support.
  For more info see <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:some>
 */
 
 some: function(fn, bind){
  for (var i = 0, j = this.length; i < j; i++){
   if (fn.call(bind, this[i], i, this)) return true;
  }
  return false;
 },
 
 /*
 Property: indexOf
  This method is provided only for browsers without native *indexOf* support.
  For more info see <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:indexOf>
 */
 
 indexOf: function(item, from){
  from = from || 0;
  var len = this.length;
  if (from < 0) from = Math.max(0, len + from);
  while (from < len){
   if (this[from] === item) return from;
   from++;
  }
  return -1;
 },

 /*
 Property: each
  Same as <Array.forEach>.

 Arguments:
  fn - the function to execute with each item in the array
  bind - optional, the object that the "this" of the function will refer to.

 Example:
  >var Animals = ['Cat', 'Dog', 'Coala'];
  >Animals.each(function(animal){
  > document.write(animal)
  >});
 */

 /*
 Property: copy
  returns a copy of the array.

 Returns:
  a new array which is a copy of the current one.
 Arguments:
  start - optional, the index where to start the copy, default is 0. If negative, it is taken as the offset from the end of the array.
  length - optional, the number of elements to copy. By default, copies all elements from start to the end of the array.

 Example:
  >var letters = ["a","b","c"];
  >var copy = letters.copy();  // ["a","b","c"] (new instance)
 */

 copy: function(start, length){
  start = start || 0;
  if (start < 0) start = this.length + start;
  length = length || (this.length - start);
  var newArray = [];
  for (var i = 0; i < length; i++) newArray[i] = this[start++];
  return newArray;
 },

 /*
 Property: remove
  Removes all occurrences of an item from the array.

 Arguments:
  item - the item to remove

 Returns:
  the Array with all occurrences of the item removed.

 Example:
  >["1","2","3","2"].remove("2") // ["1","3"];
 */

 remove: function(item){
  var i = 0;
  var len = this.length;
  while (i < len){
   if (this[i] === item) this.splice(i, 1);
   else i++;
  }
  return this;
 },

 /*
 Property: test
  Tests an array for the presence of an item.

 Arguments:
  item - the item to search for in the array.
  from - optional, the index at which to begin the search, default is 0. If negative, it is taken as the offset from the end of the array.

 Returns:
  true - the item was found
  false - it wasn't

 Example:
  >["a","b","c"].test("a"); // true
  >["a","b","c"].test("d"); // false
 */

 test: function(item, from){
  return this.indexOf(item, from) != -1;
 },

 /*
 Property: extend
  Extends an array with another one.

 Arguments:
  newArray - the array to extend ours with

 Example:
  >var Animals = ['Cat', 'Dog', 'Coala'];
  >Animals.extend(['Lizard']);
  >//Animals is now: ['Cat', 'Dog', 'Coala', 'Lizard'];
 */

 extend: function(newArray){
  var pos = this.length;
  for (var i = 0, j = newArray.length; i < j; i++) this[pos++] = newArray[i];
  return this;
 },

 /*
 Property: associate
  Creates an object with key-value pairs based on the array of keywords passed in
  and the current content of the array.

 Arguments:
  keys - the array of keywords.

 Example:
  (start code)
  var Animals = ['Cat', 'Dog', 'Coala', 'Lizard'];
  var Speech = ['Miao', 'Bau', 'Fruuu', 'Mute'];
  var Speeches = Animals.associate(speech);
  //Speeches['Miao'] is now Cat.
  //Speeches['Bau'] is now Dog.
  //...
  (end)
 */

 associate: function(keys){
  var obj = {}, length = Math.min(this.length, keys.length);
  for (var i = 0; i < length; i++) obj[keys[i]] = this[i];
  return obj;
 },
 
 /*
 Property: include
  includes the passed in element in the array, only if its not already present.
 */
 
 include: function(item){
  if (!this.test(item)) this.push(item);
  return this;
 }

});

Array.prototype.each =  Array.prototype.forEach;

/* Section: Utility Functions */

/*
Function: $A()
 Same as <Array.copy>, but as function.
 Useful to apply Array prototypes to iterable objects, as a collection of DOM elements or the arguments object.

Example:
 (start code)
 function myFunction(){
  $A(arguments).each(argument, function(){
   alert(argument);
  });
 };
 //the above will alert all the arguments passed to the function myFunction.
 (end)
*/

function $A(array, start, length){
 return Array.prototype.copy.call(array, start, length);
};

/*
Function: $each
 Use to iterate through iterables that are not regular arrays, such as builtin getElementsByTagName calls, arguments of a function, or an object.
Arguments:
 iterable - an iterable element or an objct.
 function - function to apply to the iterable.
 bind - optional, the 'this' of the function will refer to this object.

Function argument:
 The function argument will be passed the following arguments.

 item - the current item in the iterator being procesed
 index - the index of the item, or key in case of an object.

Examples:
 (start code)
 $each(['Sun','Mon','Tue'], function(day, index) {
  alert('name:' + day + ', index: ' + index);
 });
 //alerts "name: Sun, index: 0", "name: Mon, index: 1", etc.
 //over an object
 $each({first: "Sunday", second: "Monday", third: "Tuesday"}, function(value, key){
  alert("the " + key + " day of the week is " + value);
 });
 //alerts "the first day of the week is Sunday",
 //"the second day of the week is Monday", etc.
 (end)
*/

function $each(iterable, fn, bind){
 if ($chk(iterable.length)) Array.prototype.forEach.call(iterable, fn, bind);
 else for (var name in iterable) fn.call(bind, iterable[name], name);
};

/*
Script: String.js
 Contains String prototypes and Number prototypes.

Author:
 Valerio Proietti, <http://mad4milk.net>

License:
 MIT-style license.
*/

/*
Class: String
 A collection of The String Object prototype methods.
*/

String.extend({

 /*
 Property: test
  Tests a string with a regular expression.

 Arguments:
  regex - a string or regular expression object, the regular expression you want to match the string with
  params - optional, if first parameter is a string, any parameters you want to pass to the regex ('g' has no effect)

 Returns:
  true if a match for the regular expression is found in the string, false if not.
  See <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:RegExp:test>

 Example:
  >"I like cookies".test("cookie"); // returns true
  >"I like cookies".test("COOKIE", "i") // ignore case, returns true
  >"I like cookies".test("cake"); // returns false
 */

 test: function(regex, params){
  return ((typeof regex == 'string') ? new RegExp(regex, params) : regex).test(this);
 },

 /*
 Property: toInt
  parses a string to an integer.

 Returns:
  either an int or "NaN" if the string is not a number.

 Example:
  >var value = "10px".toInt(); // value is 10
 */

 toInt: function(){
  return parseInt(this);
 },

 toFloat: function(){
  return parseFloat(this);
 },

 /*
 Property: camelCase
  Converts a hiphenated string to a camelcase string.

 Example:
  >"I-like-cookies".camelCase(); //"ILikeCookies"

 Returns:
  the camel cased string
 */

 camelCase: function(){
  return this.replace(/-\D/g, function(match){
   return match.charAt(1).toUpperCase();
  });
 },

 /*
 Property: hyphenate
  Converts a camelCased string to a hyphen-ated string.

 Example:
  >"ILikeCookies".hyphenate(); //"I-like-cookies"
 */

 hyphenate: function(){
  return this.replace(/\w[A-Z]/g, function(match){
   return (match.charAt(0)+'-'+match.charAt(1).toLowerCase());
  });
 },

 /*
 Property: capitalize
  Converts the first letter in each word of a string to Uppercase.

 Example:
  >"i like cookies".capitalize(); //"I Like Cookies"

 Returns:
  the capitalized string
 */

 capitalize: function(){
  return this.toLowerCase().replace(/\b[a-z]/g, function(match){
   return match.toUpperCase();
  });
 },

 /*
 Property: trim
  Trims the leading and trailing spaces off a string.

 Example:
  >"    i like cookies     ".trim() //"i like cookies"

 Returns:
  the trimmed string
 */

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

 /*
 Property: clean
  trims (<String.trim>) a string AND removes all the double spaces in a string.

 Returns:
  the cleaned string

 Example:
  >" i      like     cookies      \n\n".clean() //"i like cookies"
 */

 clean: function(){
  return this.replace(/\s{2,}/g, ' ').trim();
 },

 /*
 Property: rgbToHex
  Converts an RGB value to hexidecimal. The string must be in the format of "rgb(255,255,255)" or "rgba(255,255,255,1)";

 Arguments:
  array - boolean value, defaults to false. Use true if you want the array ['FF','33','00'] as output instead of "#FF3300"

 Returns:
  hex string or array. returns "transparent" if the output is set as string and the fourth value of rgba in input string is 0.

 Example:
  >"rgb(17,34,51)".rgbToHex(); //"#112233"
  >"rgba(17,34,51,0)".rgbToHex(); //"transparent"
  >"rgb(17,34,51)".rgbToHex(true); //['11','22','33']
 */

 rgbToHex: function(array){
  var rgb = this.match(/\d{1,3}/g);
  return (rgb) ? rgb.rgbToHex(array) : false;
 },

 /*
 Property: hexToRgb
  Converts a hexidecimal color value to RGB. Input string must be the hex color value (with or without the hash). Also accepts triplets ('333');

 Arguments:
  array - boolean value, defaults to false. Use true if you want the array [255,255,255] as output instead of "rgb(255,255,255)";

 Returns:
  rgb string or array.

 Example:
  >"#112233".hexToRgb(); //"rgb(17,34,51)"
  >"#112233".hexToRgb(true); //[17,34,51]
 */

 hexToRgb: function(array){
  var hex = this.match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/);
  return (hex) ? hex.slice(1).hexToRgb(array) : false;
 }

});

Array.extend({

 /*
 Property: rgbToHex
  see <String.rgbToHex>, but as an array method.
 */

 rgbToHex: function(array){
  if (this.length < 3) return false;
  if (this[3] && (this[3] == 0) && !array) return 'transparent';
  var hex = [];
  for (var i = 0; i < 3; i++){
   var bit = (this[i]-0).toString(16);
   hex.push((bit.length == 1) ? '0'+bit : bit);
  }
  return array ? hex : '#'+hex.join('');
 },

 /*
 Property: hexToRgb
  same as <String.hexToRgb>, but as an array method.
 */

 hexToRgb: function(array){
  if (this.length != 3) return false;
  var rgb = [];
  for (var i = 0; i < 3; i++){
   rgb.push(parseInt((this[i].length == 1) ? this[i]+this[i] : this[i], 16));
  }
  return array ? rgb : 'rgb('+rgb.join(',')+')';
 }

});

/*
Class: Number
 contains the internal method toInt.
*/

Number.extend({

 /*
 Property: toInt
  Returns this number; useful because toInt must work on both Strings and Numbers.
 */

 toInt: function(){
  return parseInt(this);
 },

 toFloat: function(){
  return parseFloat(this);
 }

});

/* 
Script: Function.js
 Contains Function prototypes and utility functions .

Author:
 Valerio Proietti, <http://mad4milk.net>

License:
 MIT-style license.

Credits:
 - Some functions are inspired by those found in prototype.js <http://prototype.conio.net/> (c) 2005 Sam Stephenson sam [at] conio [dot] net, MIT-style license
*/

/*
Class: Function
 A collection of The Function Object prototype methods.
*/

Function.extend({

 /*
 Property: create
  Main function to create closures.
 Returns:
  a function.
 Arguments:
  options - An Options object.
 Options:
  bind - The object that the "this" of the function will refer to. Default is the current function.
  event - If set to true, the function will act as an event listener and receive an event as first argument.
    If set to a class name, the function will receive a new instance of this class (with the event passed as argument's constructor) as first argument.
    Default is false.
  arguments - A single argument or array of arguments that will be passed to the function when called.
     If both the event and arguments options are set, the event is passed as first argument and the arguments array will follow.
     Default is no custom arguments, the function will receive the standard arguments when called.
  delay - Numeric value: if set, the returned function will delay the actual execution by this amount of milliseconds and return a timer handle when called.
    Default is no delay.
  periodical - Numeric value: if set, the returned function will periodically perform the actual execution with this specified interval and return a timer handle when called.
    Default is no periodical execution.
  attempt - If set to true, the returned function will try to execute and return either the results or the error when called. Default is false.
 */

 create: function(options){
  var fn = this;
  options = $merge({
   'bind': fn, 
   'event': false, 
   'arguments': null, 
   'delay': false, 
   'periodical': false, 
   'attempt': false
  }, options);
  if ($chk(options.arguments) && $type(options.arguments) != 'array') options.arguments = [options.arguments];
  return function(event){
   var args;
   if (options.event){
    event = event || window.event;
    args = [(options.event === true) ? event : new options.event(event)];
    if (options.arguments) args = args.concat(options.arguments);
   }
   else args = options.arguments || arguments;
   var returns = function(){
    return fn.apply(options.bind, args);
   };
   if (options.delay) return setTimeout(returns, options.delay);
   if (options.periodical) return setInterval(returns, options.periodical);
   if (options.attempt){
    try {
     return returns();
    } catch(err){
     return err;
    }
   }
   return returns();
  };
 },

 /*
 Property: pass
  Shortcut to create closures with arguments and bind.

 Returns:
  a function.

 Arguments:
  args - the arguments passed. must be an array if arguments > 1
  bind - optional, the object that the "this" of the function will refer to.

 Example:
  >myFunction.pass([arg1, arg2], myElement);
 */

 pass: function(args, bind){
  return this.create({'arguments': args, 'bind': bind});
 },

 /*
 Property: attempt
  Tries to execute the function, returns either the function results or the error.

 Arguments:
  args - the arguments passed. must be an array if arguments > 1
  bind - optional, the object that the "this" of the function will refer to.

 Example:
  >myFunction.attempt([arg1, arg2], myElement);
 */

 attempt: function(args, bind){
  return this.create({'arguments': args, 'bind': bind, 'attempt': true})();
 },

 /*
 Property: bind
  method to easily create closures with "this" altered.

 Arguments:
  bind - optional, the object that the "this" of the function will refer to.
  args - optional, the arguments passed. must be an array if arguments > 1

 Returns:
  a function.

 Example:
  >function myFunction(){
  > this.setStyle('color', 'red');
  > // note that 'this' here refers to myFunction, not an element
  > // we'll need to bind this function to the element we want to alter
  >};
  >var myBoundFunction = myFunction.bind(myElement);
  >myBoundFunction(); // this will make the element myElement red.
 */

 bind: function(bind, args){
  return this.create({'bind': bind, 'arguments': args});
 },

 /*
 Property: bindAsEventListener
  cross browser method to pass event firer

 Arguments:
  bind - optional, the object that the "this" of the function will refer to.
  args - optional, the arguments passed. must be an array if arguments > 1

 Returns:
  a function with the parameter bind as its "this" and as a pre-passed argument event or window.event, depending on the browser.

 Example:
  >function myFunction(event){
  > alert(event.clientx) //returns the coordinates of the mouse..
  >};
  >myElement.onclick = myFunction.bindAsEventListener(myElement);
 */

 bindAsEventListener: function(bind, args){
  return this.create({'bind': bind, 'event': true, 'arguments': args});
 },

 /*
 Property: delay
  Delays the execution of a function by a specified duration.

 Arguments:
  ms - the duration to wait in milliseconds
  bind - optional, the object that the "this" of the function will refer to.
  args - optional, the arguments passed. must be an array if arguments > 1

 Example:
  >myFunction.delay(50, myElement) //wait 50 milliseconds, then call myFunction and bind myElement to it
  >(function(){alert('one second later...')}).delay(1000); //wait a second and alert
 */

 delay: function(ms, bind, args){
  return this.create({'delay': ms, 'bind': bind, 'arguments': args})();
 },

 /*
 Property: periodical
  Executes a function in the specified intervals of time

 Arguments:
  ms - the duration of the intervals between executions.
  bind - optional, the object that the "this" of the function will refer to.
  args - optional, the arguments passed. must be an array if arguments > 1
 */

 periodical: function(ms, bind, args){
  return this.create({'periodical': ms, 'bind': bind, 'arguments': args})();
 }

});

/*
Script: Element.js
 Contains useful Element prototypes, to be used with the dollar function <$>.

Authors:
 - Valerio Proietti, <http://mad4milk.net>
 - Christophe Beyls, <http://digitalia.be>

License:
 MIT-style license.

Credits:
 - Some functions are inspired by those found in prototype.js <http://prototype.conio.net/> (c) 2005 Sam Stephenson sam [at] conio [dot] net, MIT-style license
*/

/*
Class: Element
 Custom class to allow all of its methods to be used with any DOM element via the dollar function <$>.
*/

var Element = new Class({

 /*
 Property: initialize
  Creates a new element of the type passed in.

 Arguments:
  el - the tag name for the element you wish to create. you can also pass in an element reference, in which case it will be extended.
  props - an object, the properties you want to add to your element.
  
 Props:
  the key styles will be used as setStyles, the key events will be used as addEvents. any other key is used as setProperty.

 Example:
  (start code)
  new Element('a', {
   'styles': {
    'display': 'block',
    'border': '1px solid black'
   },
   'events': {
    'click': function(){
     //aaa
    },
    'mousedown': function(){
     //aaa
    }
   },
   'class': 'myClassSuperClass',
   'href': 'http://mad4milk.net'
  });
  
  (end)
 */

 initialize: function(el, props){
  if ($type(el) == 'string') el = document.createElement(el);
  el = $(el);
  if (!props || !el) return el;
  for (var prop in props){
   switch(prop){
    case 'styles': el.setStyles(props[prop]); break;
    case 'events': el.addEvents(props[prop]); break;
    case 'properties': el.setProperties(props[prop]); break;
    default: el.setProperty(prop, props[prop]);
   }
  }
  return el;
 }

});

/*
Section: Utility Functions

Function: $
 returns the element passed in with all the Element prototypes applied.

Arguments:
 el - a reference to an actual element or a string representing the id of an element

Example:
 >$('myElement') // gets a DOM element by id with all the Element prototypes applied.
 >var div = document.getElementById('myElement');
 >$(div) //returns an Element also with all the mootools extentions applied.

 You'll use this when you aren't sure if a variable is an actual element or an id, as
 well as just shorthand for document.getElementById().

Returns:
 a DOM element or false (if no id was found).

Note:
 you need to call $ on an element only once to get all the prototypes.
 But its no harm to call it multiple times, as it will detect if it has been already extended.
*/

function $(el){
 if (!el) return false;
 if (el.htmlElement) return Garbage.collect(el);
 if ([window, document].test(el)) return el;
 var type = $type(el);
 if (type == 'string'){
  el = document.getElementById(el);
  type = (el) ? 'element' : false;
 }
 if (type != 'element') return false;
 if (['object', 'embed'].test(el.tagName.toLowerCase())) return el;
 $extend(el, Element.prototype);
 el.htmlElement = true;
 return Garbage.collect(el);
};

//elements class

var Elements = new Class({});

$native(Elements);

document.getElementsBySelector = document.getElementsByTagName;

/*
Function: $$
 Selects, and extends DOM elements.

Arguments:
 HTMLCollection(document.getElementsByTagName, element.childNodes), an array of elements, a string.

Note:
 if you loaded <Dom.js>, $$ will also accept CSS Selectors.

Example:
 >$$('a') //an array of all anchor tags on the page
 >$$('a', 'b') //an array of all anchor and bold tags on the page
 >$$('#myElement') //array containing only the element with id = myElement. (only with <Dom.js>)
 >$$('#myElement a.myClass') //an array of all anchor tags with the class "myClass" within the DOM element with id "myElement" (only with <Dom.js>)

Returns:
 array - array of all the dom elements matched
*/

function $$(){
 if (!arguments) return false;
 var elements = [];
 for (var i = 0, j = arguments.length; i < j; i++){
  var selector = arguments[i];
  switch($type(selector)){
   case 'element': elements.include($(selector)); break;
   case 'string': selector = document.getElementsBySelector(selector, true);
   default:
    if (selector.length){
     for (var k = 0, l = selector.length; k < l; k++){
      var el = $(selector[k]);
      if (el) elements.include(el);
     }
    }
  }
 }
 return $extend(elements, new Elements);
};

Elements.Multi = function(property){
 return function(){
  var args = arguments;
  var items = [];
  var elements = true;
  $each(this, function(el){
   var returns = el[property].apply(el, args);
   if ($type(returns) != 'element') elements = false;
   items.push(returns);
  });
  if (elements) items = $$(items);
  return items;
 };
};

Element.extend = function(properties){
 for (var property in properties){
  HTMLElement.prototype[property] = properties[property];
  Element.prototype[property] = properties[property];
  Elements.prototype[property] = Elements.Multi(property);
 }
};

/*
Class: Element
 Custom class to allow all of its methods to be used with any DOM element via the dollar function <$>.
*/

Element.extend({

 inject: function(el, where){
  el = $(el);
  switch(where){
   case "before": el.parentNode.insertBefore(this, el); break;
   case "after":
    var next = el.getNext();
    if (!next) el.parentNode.appendChild(this);
    else el.parentNode.insertBefore(this, next);
    break;
   case "inside": el.appendChild(this);
  }
  return this;
 },

 /*
 Property: injectBefore
  Inserts the Element before the passed element.

 Parameteres:
  el - a string representing the element to be injected in (myElementId, or div), or an element reference.
  If you pass div or another tag, the element will be created.

 Example:
  >html:
  ><div id="myElement"></div>
  ><div id="mySecondElement"></div>
  >js:
  >$('mySecondElement').injectBefore('myElement');
  >resulting html:
  ><div id="mySecondElement"></div>
  ><div id="myElement"></div>

 */

 injectBefore: function(el){
  return this.inject(el, 'before');
 },

 /*
 Property: injectAfter
  Same as <Element.injectBefore>, but inserts the element after.
 */

 injectAfter: function(el){
  return this.inject(el, 'after');
 },

 /*
 Property: injectInside
  Same as <Element.injectBefore>, but inserts the element inside.
 */

 injectInside: function(el){
  return this.inject(el, 'inside');
 },

 /*
 Property: adopt
  Inserts the passed element inside the Element. Works as <Element.injectInside> but in reverse.

 Parameteres:
  el - a string representing the element to be injected in (myElementId, or div), or an element reference.
  If you pass div or another tag, the element will be created.
 */

 adopt: function(){
  $each(arguments, function(el){
   this.appendChild($(el));
  }, this);
  return this;
 },

 /*
 Property: remove
  Removes the Element from the DOM.

 Example:
  >$('myElement').remove() //bye bye
 */

 remove: function(){
  this.parentNode.removeChild(this);
  return this;
 },

 /*
 Property: clone
  Clones the Element and returns the cloned one.

 Returns: 
  the cloned element

 Example:
  >var clone = $('myElement').clone().injectAfter('myElement');
  >//clones the Element and append the clone after the Element.
 */

 clone: function(contents){
  return $(this.cloneNode(contents !== false));
 },

 /*
 Property: replaceWith
  Replaces the Element with an element passed.

 Parameteres:
  el - a string representing the element to be injected in (myElementId, or div), or an element reference.
  If you pass div or another tag, the element will be created.

 Returns:
  the passed in element

 Example:
  >$('myOldElement').replaceWith($('myNewElement')); //$('myOldElement') is gone, and $('myNewElement') is in its place.
 */

 replaceWith: function(el){
  this.parentNode.replaceChild(el, this);
  return $(el);
 },

 /*
 Property: appendText
  Appends text node to a DOM element.

 Arguments:
  text - the text to append.

 Example:
  ><div id="myElement">hey</div>
  >$('myElement').appendText(' howdy'); //myElement innerHTML is now "hey howdy"
 */

 appendText: function(text){
  if (window.ie){
   switch(this.getTag()){
    case 'style': this.styleSheet.cssText = text; return this;
    case 'script': this.setProperty('text', text); return this;
   }
  }
  this.appendChild(document.createTextNode(text));
  return this;
 },

 /*
 Property: hasClass
  Tests the Element to see if it has the passed in className.

 Returns:
  true - the Element has the class
  false - it doesn't
 Arguments:
  className - the class name to test.
 Example:
  ><div id="myElement" class="testClass"></div>
  >$('myElement').hasClass('testClass'); //returns true
 */

 hasClass: function(className){
  return this.className.test('(?:^|\\s)'+className+'(?:\\s|$)');
 },

 /*
 Property: addClass
  Adds the passed in class to the Element, if the element doesnt already have it.

 Arguments:
  className - the class name to add

 Example: 
  ><div id="myElement" class="testClass"></div>
  >$('myElement').addClass('newClass'); //<div id="myElement" class="testClass newClass"></div>
 */

 addClass: function(className){
  if (!this.hasClass(className)) this.className = (this.className+' '+className).clean();
  return this;
 },

 /*
 Property: removeClass
  works like <Element.addClass>, but removes the class from the element.
 */

 removeClass: function(className){
  this.className = this.className.replace(new RegExp('(^|\\s)'+className+'(?:\\s|$)'), '$1').clean();
  return this;
 },

 /*
 Property: toggleClass
  Adds or removes the passed in class name to the element, depending on if it's present or not.

 Arguments:
  className - the class to add or remove

 Example:
  ><div id="myElement" class="myClass"></div>
  >$('myElement').toggleClass('myClass');
  ><div id="myElement" class=""></div>
  >$('myElement').toggleClass('myClass');
  ><div id="myElement" class="myClass"></div>
 */

 toggleClass: function(className){
  return this.hasClass(className) ? this.removeClass(className) : this.addClass(className);
 },

 /*
 Property: setStyle
  Sets a css property to the Element.

  Arguments:
   property - the property to set
   value - the value to which to set it

  Example:
   >$('myElement').setStyle('width', '300px'); //the width is now 300px
 */

 setStyle: function(property, value){
  switch(property){
   case 'opacity': return this.setOpacity(parseFloat(value));
   case 'float': property = (window.ie) ? 'styleFloat' : 'cssFloat';
  }
  property = property.camelCase();
  switch($type(value)){
   case 'number': if (property != 'zIndex') value += 'px'; break;
   case 'array': value = 'rgb(' + value.join(',') + ')';
  }
  this.style[property] = value;
  return this;
 },

 /*
 Property: setStyles
  Applies a collection of styles to the Element.

 Arguments:
  source - an object or string containing all the styles to apply. You cannot set the opacity using a string.

 Examples:
  >$('myElement').setStyles({
  > border: '1px solid #000',
  > width: '300px',
  > height: '400px'
  >});

  OR

  >$('myElement').setStyles('border: 1px solid #000; width: 300px; height: 400px;');
 */

 setStyles: function(source){
  switch($type(source)){
   case 'object':
    for (var property in source) this.setStyle(property, source[property]);
    break;
   case 'string': this.style.cssText = source;
  }
  return this;
 },

 /*
 Property: setOpacity
  Sets the opacity of the Element, and sets also visibility == "hidden" if opacity == 0, and visibility = "visible" if opacity > 0.

 Arguments:
  opacity - Accepts numbers from 0 to 1.

 Example:
  >$('myElement').setOpacity(0.5) //make it 50% transparent
 */

 setOpacity: function(opacity){
  if (opacity == 0){
   if (this.style.visibility != "hidden") this.style.visibility = "hidden";
  } else {
   if (this.style.visibility != "visible") this.style.visibility = "visible";
  }
  if (!this.currentStyle || !this.currentStyle.hasLayout) this.style.zoom = 1;
  if (window.ie) this.style.filter = "alpha(opacity=" + opacity * 100 + ")";
  this.style.opacity = this.opacity = opacity;
  return this;
 },

 /*
 Property: getStyle
  Returns the style of the Element given the property passed in.

 Arguments:
  property - the css style property you want to retrieve

 Example:
  >$('myElement').getStyle('width'); //returns "400px"
  >//but you can also use
  >$('myElement').getStyle('width').toInt(); //returns "400"

 Returns:
  the style as a string
 */

 getStyle: function(property){
  property = property.camelCase();
  var style = this.style[property];
  if (!$chk(style)){
   if (property == 'opacity') return $chk(this.opacity) ? this.opacity : 1;
   if (['margin', 'padding'].test(property)){
    var result = [];
    ['top', 'right', 'bottom', 'left'].each(function(prop){
     result.push(this.getStyle(property + '-' + prop) || '0');
    }, this);
    var every = result.every(function(val){
     return val == result[0];
    });
    return (every) ? result[0] : result;
   }
   if (document.defaultView) style = document.defaultView.getComputedStyle(this, null).getPropertyValue(property.hyphenate());
   else if (this.currentStyle) style = this.currentStyle[property];
  }
  if (style == 'auto' && ['height', 'width'].test(property)) return this['offset'+property.capitalize()] + 'px';
  return (style && property.test(/color/i) && style.test(/rgb/)) ? style.rgbToHex() : style;
 },

 /*
 Property: getStyles
  Returns an object of styles of the Element for each argument passed in.
  Arguments:
  properties - any number of style properties
 Example:
  >$('myElement').getStyles('width','height','padding');
  >//returns an object like:
  >{width: "10px", height: "10px", padding: "10px 0px 10px 0px"}
 */

 getStyles: function(){
  var result = {};
  $each(arguments, function(argument){
   result[argument] = this.getStyle(argument);
  }, this);
  return result;
 },

 walk: function(brother, start){
  brother += 'Sibling';
  var el = (start) ? this[start] : this[brother];
  while ($type(el) == 'whitespace') el = el[brother];
  return $(el);
 },

 /*
 Property: getPrevious
  Returns the previousSibling of the Element, excluding text nodes.

 Example:
  >$('myElement').getPrevious(); //get the previous DOM element from myElement

 Returns:
  the sibling element or undefined if none found.
 */

 getPrevious: function(){
  return this.walk('previous');
 },

 /*
 Property: getNext
  Works as Element.getPrevious, but tries to find the nextSibling.
 */

 getNext: function(){
  return this.walk('next');
 },

 /*
 Property: getFirst
  Works as <Element.getPrevious>, but tries to find the firstChild.
 */

 getFirst: function(){
  return this.walk('next', 'firstChild');
 },

 /*
 Property: getLast
  Works as <Element.getPrevious>, but tries to find the lastChild.
 */

 getLast: function(){
  return this.walk('previous', 'lastChild');
 },

 /*
 Property: getParent
  returns the $(element.parentNode)
 */

 getParent: function(){
  return $(this.parentNode);
 },

 /*
 Property: getChildren
  returns all the $(element.childNodes), excluding text nodes. Returns as <Elements>.
 */

 getChildren: function(){
  return $$(this.childNodes);
 },
 
 /*
 Property: hasChild
  returns true if the passed in element is a child of the $(element).
 */
 
 hasChild: function(el) {
  return ($A(this.getElementsByTagName('*')).test(el)) ? true : false;
 },

 /*
 Property: setProperty
  Sets an attribute for the Element.

 Arguments:
  property - the property to assign the value passed in
  value - the value to assign to the property passed in

 Example:
  >$('myImage').setProperty('src', 'whatever.gif'); //myImage now points to whatever.gif for its source
 */

 setProperty: function(property, value){
  switch(property){
   case 'class': this.className = value; break;
   case 'style': this.setStyles(value); break;
   case 'name': 
    if (window.ie6){
     var el = new Element('<' + this.getTag() + ' name="' + value + '" />');
     ['value', 'id', 'className', 'style'].each(function(attribute){
      el[attribute] = this[attribute];
     });
     if (this.parentNode) this.replaceWith(el);
     return el;
    }
   default: this.setAttribute(property, value);
  }
  return this;
 },

 /*
 Property: setProperties
  Sets numerous attributes for the Element.

 Arguments:
  source - an object with key/value pairs.

 Example:
  (start code)
  $('myElement').setProperties({
   src: 'whatever.gif',
   alt: 'whatever dude'
  });
  <img src="whatever.gif" alt="whatever dude">
  (end)
 */

 setProperties: function(source){
  for (var property in source) this.setProperty(property, source[property]);
  return this;
 },

 /*
 Property: setHTML
  Sets the innerHTML of the Element.

 Arguments:
  html - the new innerHTML for the element.

 Example:
  >$('myElement').setHTML(newHTML) //the innerHTML of myElement is now = newHTML
 */

 setHTML: function(){
  this.innerHTML = $A(arguments).join('');
  return this;
 },

 /*
 Property: getProperty
  Gets the an attribute of the Element.

 Arguments:
  property - the attribute to retrieve

 Example:
  >$('myImage').getProperty('src') // returns whatever.gif

 Returns:
  the value, or an empty string
 */

 getProperty: function(property){
  return (property == 'class') ? this.className : this.getAttribute(property);
 },

 /*
 Property: getTag
  Returns the tagName of the element in lower case.

 Example:
  >$('myImage').getTag() // returns 'img'

 Returns:
  The tag name in lower case
 */

 getTag: function(){
  return this.tagName.toLowerCase();
 },

 /*
 Property: scrollTo
  scrolls the element to the specified coordinated (if the element has an overflow)

 Arguments:
  x - the x coordinate
  y - the y coordinate

 Example:
  >$('myElement').scrollTo(0, 100)
 */

 scrollTo: function(x, y){
  this.scrollLeft = x;
  this.scrollTop = y;
 },

 /*
 Property: getValue
  Returns the value of the Element, if its tag is textarea, select or input. getValue called on a multiple select will return an array.
 */

 getValue: function(){
  switch(this.getTag()){
   case 'select':
    var values = [];
    $each(this.options, function(opt){
     if (opt.selected) values.push($pick(opt.value, opt.text));
    });
    return (this.multiple) ? values : values[0];
   case 'input': if (!(this.checked && ['checkbox', 'radio'].test(this.type)) && !['hidden', 'text', 'password'].test(this.type)) break;
   case 'textarea': return this.value;
  }
  return false;
 },

 /*
 Property: getSize
  return an Object representing the size/scroll values of the element.

 Example:
  (start code)
  $('myElement').getSize();
  (end)

 Returns:
  (start code)
  {
   'scroll': {'x': 100, 'y': 100},
   'size': {'x': 200, 'y': 400},
   'scrollSize': {'x': 300, 'y': 500}
  }
  (end)
 */

 getSize: function(){
  return {
   'scroll': {'x': this.scrollLeft, 'y': this.scrollTop},
   'size': {'x': this.offsetWidth, 'y': this.offsetHeight},
   'scrollSize': {'x': this.scrollWidth, 'y': this.scrollHeight}
  };
 },

 /*
 Property: getPosition
  Returns the real offsets of the element.

 Example:
  >$('element').getPosition();

 Returns:
  >{x: 100, y:500};
 */

 getPosition: function(overflown){
  overflown = overflown || [];
  var el = this, left = 0, top = 0;
  do {
   left += el.offsetLeft || 0;
   top += el.offsetTop || 0;
   el = el.offsetParent;
  } while (el);
  overflown.each(function(element){
   left -= element.scrollLeft || 0;
   top -= element.scrollTop || 0;
  });
  return {'x': left, 'y': top};
 },

 /*
 Property: getTop
  Returns the distance from the top of the window to the Element.
 */

 getTop: function(){
  return this.getPosition().y;
 },

 /*
 Property: getLeft
  Returns the distance from the left of the window to the Element.
 */

 getLeft: function(){
  return this.getPosition().x;
 },
 /*
 Property: getCoordinates
  Returns an object with width, height, left, right, top, and bottom, representing the values of the Element

 Example:
  (start code)
  var myValues = $('myElement').getCoordinates();
  (end)

 Returns:
  (start code)
  {
   width: 200,
   height: 300,
   left: 100,
   top: 50,
   right: 300,
   bottom: 350
  }
  (end)
 */

 getCoordinates: function(overflown){
  var position = this.getPosition(overflown);
  var obj = {
   'width': this.offsetWidth,
   'height': this.offsetHeight,
   'left': position.x,
   'top': position.y
  };
  obj.right = obj.left + obj.width;
  obj.bottom = obj.top + obj.height;
  return obj;
 }

});

Element.eventMethods = {

 /*
 Property: addEvent
  Attaches an event listener to a DOM element.

 Arguments:
  type - the event to monitor ('click', 'load', etc) without the prefix 'on'.
  fn - the function to execute

 Example:
  >$('myElement').addEvent('click', function(){alert('clicked!')});
 */

 addEvent: function(type, fn){
  this.events = this.events || {};
  this.events[type] = this.events[type] || {'keys': [], 'values': []};
  if (!this.events[type].keys.test(fn)){
   this.events[type].keys.push(fn);
   if (this.addEventListener){
    this.addEventListener((type == 'mousewheel' && window.gecko) ? 'DOMMouseScroll' : type, fn, false);
   } else {
    fn = fn.bind(this);
    this.attachEvent('on'+type, fn);
    this.events[type].values.push(fn);
   }
  }
  return this;
 },

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

 /*
 Property: removeEvent
  Works as Element.addEvent, but instead removes the previously added event listener.
 */

 removeEvent: function(type, fn){
  if (this.events && this.events[type]){
   var pos = this.events[type].keys.indexOf(fn);
   if (pos == -1) return this;
   var key = this.events[type].keys.splice(pos,1)[0];
   if (this.removeEventListener){
    this.removeEventListener((type == 'mousewheel' && window.gecko) ? 'DOMMouseScroll' : type, key, false);
   } else {
    this.detachEvent('on'+type, this.events[type].values.splice(pos,1)[0]);
   }
  }
  return this;
 },

 /*
 Property: removeEvents
  removes all events of a certain type from an element. if no argument is passed in, removes all events.
 */

 removeEvents: function(type){
  if (this.events){
   if (type){
    if (this.events[type]){
     this.events[type].keys.each(function(fn){
      this.removeEvent(type, fn);
     }, this);
     this.events[type] = null;
    }
   } else {
    for (var evType in this.events) this.removeEvents(evType);
    this.events = null;
   }
  }
  return this;
 },

 /*
 Property: fireEvent
  executes all events of the specified type present in the element.
 */

 fireEvent: function(type, args){
  if (this.events && this.events[type]){
   this.events[type].keys.each(function(fn){
    fn.bind(this, args)();
   }, this);
  }
 }

};

window.extend(Element.eventMethods);
document.extend(Element.eventMethods);
Element.extend(Element.eventMethods);

var Garbage = {

 elements: [],

 collect: function(el){
  if (!el.collected) Garbage.elements.push(el);
  el.collected = true;
  return el;
 },

 trash: function(){
  Garbage.collect(window);
  Garbage.collect(document);
  Garbage.elements.each(function(el){
   el.removeEvents();
   for (var p in Element.prototype) el[p] = null;
   el.htmlElement = null;
   el.collected = null;
  });
 }

};

window.addEvent('unload', Garbage.trash);

/*
Script: Event.js
 Event class

Authors:
 - Valerio Proietti, <http://mad4milk.net>
 - Michael Jackson, <http://ajaxon.com/michael>

License:
 MIT-style license.
*/

/*
Class: Event
 Cross browser methods to manage events.

Arguments:
 event - the event

Properties:
 shift - true if the user pressed the shift
 control - true if the user pressed the control 
 alt - true if the user pressed the alt
 meta - true if the user pressed the meta key
 wheel - the amount of third button scrolling
 code - the keycode of the key pressed
 page.x - the x position of the mouse, relative to the full window
 page.y - the y position of the mouse, relative to the full window
 client.x - the x position of the mouse, relative to the viewport
 client.y - the y position of the mouse, relative to the viewport
 key - the key pressed as a lowercase string. key also returns 'enter', 'up', 'down', 'left', 'right', 'space', 'backspace', 'delete', 'esc'. Handy for these special keys.
 target - the event target
 relatedTarget - the event related target

Example:
 (start code)
 $('myLink').onkeydown = function(event){
  var event = new Event(event);
  //event is now the Event class.
  alert(event.key); //returns the lowercase letter pressed
  alert(event.shift); //returns true if the key pressed is shift
  if (event.key == 's' && event.control) alert('document saved');
 };
 (end)
*/

var Event = new Class({

 initialize: function(event){
  this.event = event || window.event;
  this.type = this.event.type;
  this.target = this.event.target || this.event.srcElement;
  if (this.target.nodeType == 3) this.target = this.target.parentNode; // Safari
  this.shift = this.event.shiftKey;
  this.control = this.event.ctrlKey;
  this.alt = this.event.altKey;
  this.meta = this.event.metaKey;
  if (['DOMMouseScroll', 'mousewheel'].test(this.type)){
   this.wheel = this.event.wheelDelta ? (this.event.wheelDelta / (window.opera ? -120 : 120)) : -(this.event.detail || 0) / 3;
  } else if (this.type.test(/key/)){
   this.code = this.event.which || this.event.keyCode;
   for (var name in Event.keys){
    if (Event.keys[name] == this.code){
     this.key = name;
     break;
    }
   }
   var fKey = this.code - 111;
   if (fKey > 0 && fKey < 13) this.key = 'f' + fKey;
   this.key = this.key || String.fromCharCode(this.code).toLowerCase();
  } else if (this.type.test(/mouse/) || (this.type == 'click')){
   this.page = {
    'x': this.event.pageX || this.event.clientX + document.documentElement.scrollLeft,
    'y': this.event.pageY || this.event.clientY + document.documentElement.scrollTop
   };
   this.client = {
    'x': this.event.pageX ? this.event.pageX - window.pageXOffset : this.event.clientX,
    'y': this.event.pageY ? this.event.pageY - window.pageYOffset : this.event.clientY
   };
   this.rightClick = (this.event.which == 3) || (this.event.button == 2);
   switch(this.type){
    case 'mouseover': this.relatedTarget = this.event.relatedTarget || this.event.fromElement; break;
    case 'mouseout': this.relatedTarget = this.event.relatedTarget || this.event.toElement;
   }
  }
 },

 /*
 Property: stop
  cross browser method to stop an event
 */

 stop: function() {
  this.stopPropagation();
  this.preventDefault();
  return this;
 },

 /*
 Property: stopPropagation
  cross browser method to stop the propagation of an event
 */

 stopPropagation: function(){
  if (this.event.stopPropagation) this.event.stopPropagation();
  else this.event.cancelBubble = true;
  return this;
 },

 /*
 Property: preventDefault
  cross browser method to prevent the default action of the event
 */

 preventDefault: function(){
  if (this.event.preventDefault) this.event.preventDefault();
  else this.event.returnValue = false;
  return this;
 }

});

Event.keys = {
 'enter': 13,
 'up': 38,
 'down': 40,
 'left': 37,
 'right': 39,
 'esc': 27,
 'space': 32,
 'backspace': 8,
 'delete': 46
};

Function.extend({

 /*
 Property: bindWithEvent
  automatically passes mootools Event Class.

 Arguments:
  bind - optional, the object that the "this" of the function will refer to.

 Returns:
  a function with the parameter bind as its "this" and as a pre-passed argument event or window.event, depending on the browser.

 Example:
  >function myFunction(event){
  > alert(event.clientx) //returns the coordinates of the mouse..
  >};
  >myElement.onclick = myFunction.bindWithEvent(myElement);
 */

 bindWithEvent: function(bind, args){
  return this.create({'bind': bind, 'arguments': args, 'event': Event});
 }

});

/*
Script: Common.js
 Contains common implementations for custom classes. In Mootools is implemented in <Ajax>, <XHR> and <Fx.Base>.

Author:
 Valerio Proietti, <http://mad4milk.net>

License:
 MIT-style license.
*/

/*
Class: Chain
 An "Utility" Class. Its methods can be implemented with <Class.implement> into any <Class>.
 Currently implemented in <Fx.Base>, <XHR> and <Ajax>. In <Fx.Base> for example, is used to execute a list of function, one after another, once the effect is completed.
 The functions will not be fired all togheter, but one every completion, to create custom complex animations.

Example:
 (start code)
 var myFx = new Fx.Style('element', 'opacity');

 myFx.start(1,0).chain(function(){
  myFx.start(0,1);
 }).chain(function(){
  myFx.start(1,0);
 }).chain(function(){
  myFx.start(0,1);
 });
 //the element will appear and disappear three times
 (end)
*/

var Chain = new Class({

 /*
 Property: chain
  adds a function to the Chain instance stack.

 Arguments:
  fn - the function to append.
 */

 chain: function(fn){
  this.chains = this.chains || [];
  this.chains.push(fn);
  return this;
 },

 /*
 Property: callChain
  Executes the first function of the Chain instance stack, then removes it. The first function will then become the second.
 */

 callChain: function(){
  if (this.chains && this.chains.length) this.chains.shift().delay(10, this);
 },

 /*
 Property: clearChain
  Clears the stack of a Chain instance.
 */

 clearChain: function(){
  this.chains = [];
 }

});

/*
Class: Events
 An "Utility" Class. Its methods can be implemented with <Class.implement> into any <Class>.
 In <Fx.Base> Class, for example, is used to give the possibility add any number of functions to the Effects events, like onComplete, onStart, onCancel

Example:
 (start code)
 var myFx = new Fx.Style('element', 'opacity').addEvent('onComplete', function(){
  alert('the effect is completed');
 }).addEvent('onComplete', function(){
  alert('I told you the effect is completed');
 });

 myFx.start(0,1);
 //upon completion it will display the 2 alerts, in order.
 (end)
*/

var Events = new Class({

 /*
 Property: addEvent
  adds an event to the stack of events of the Class instance.
 */

 addEvent: function(type, fn){
  if (fn != Class.empty){
   this.events = this.events || {};
   this.events[type] = this.events[type] || [];
   this.events[type].include(fn);
  }
  return this;
 },

 /*
 Property: fireEvent
  fires all events of the specified type in the Class instance.
 */

 fireEvent: function(type, args, delay){
  if (this.events && this.events[type]){
   this.events[type].each(function(fn){
    fn.create({'bind': this, 'delay': delay, 'arguments': args})();
   }, this);
  }
  return this;
 },

 /*
 Property: removeEvent
  removes an event from the stack of events of the Class instance.
 */

 removeEvent: function(type, fn){
  if (this.events && this.events[type]) this.events[type].remove(fn);
  return this;
 }

});

/*
Class: Options
 An "Utility" Class. Its methods can be implemented with <Class.implement> into any <Class>.
 Used to automate the options settings, also adding Class <Events> when the option begins with on.
*/

var Options = new Class({

 /*
 Property: setOptions
  sets this.options

 Arguments:
  defaults - the default set of options
  options - the user entered options. can be empty too.

 Note:
  if your Class has <Events> implemented, every option beginning with on, followed by a capital letter (onComplete) becomes an Class instance event.
 */

 setOptions: function(){
  var args = (arguments.length == 1) ? [this.options, arguments[0]] : arguments;
  this.options = $merge.apply(this, args);
  if (this.addEvent){
   for (var option in this.options){
    if (($type(this.options[option]) == 'function') && option.test(/^on[A-Z]/)) this.addEvent(option, this.options[option]);
   }
  }
  return this;
 }

});

/*
Class: Group
 An "Utility" Class.
*/

var Group = new Class({

 initialize: function(){
  this.instances = $A(arguments);
  this.events = {};
  this.checker = {};
 },

 addEvent: function(type, fn){
  this.checker[type] = this.checker[type] || {};
  this.events[type] = this.events[type] || [];
  if (this.events[type].test(fn)) return false;
  else this.events[type].push(fn);
  this.instances.each(function(instance, i){
   instance.addEvent(type, this.check.bind(this, [type, instance, i]));
  }, this);
  return this;
 },

 check: function(type, instance, i){
  this.checker[type][i] = true;
  var every = this.instances.every(function(current, j){
   return this.checker[type][j] || false;
  }, this);
  if (!every) return;
  this.instances.each(function(current, j){
   this.checker[type][j] = false;
  }, this);
  this.events[type].each(function(event){
   event.call(this, this.instances, instance);
  }, this);
 }

});

/*
Script: Dom.js
 Css Query related function and <Element> extensions

Authors:
 - Valerio Proietti, <http://mad4milk.net>
 - Christophe Beyls, <http://digitalia.be>

License:
 MIT-style license.
*/

/* Section: Utility Functions */

/* 
Function: $E 
 Selects a single (i.e. the first found) Element based on the selector passed in and an optional filter element.

Arguments:
 selector - the css selector to match
 filter - optional; a DOM element to limit the scope of the selector match; defaults to document.

Example:
 >$E('a', 'myElement') //find the first anchor tag inside the DOM element with id 'myElement'

Returns:
 a DOM element - the first element that matches the selector
*/

function $E(selector, filter){
 return ($(filter) || document).getElement(selector);
};

/*
Function: $ES
 Returns a collection of Elements that match the selector passed in limited to the scope of the optional filter.
 See Also: <Element.getElements> for an alternate syntax.

Returns:
 an array of dom elements that match the selector within the filter

Arguments:
 selector - css selector to match
 filter - optional; a DOM element to limit the scope of the selector match; defaults to document.

Examples:
 >$ES("a") //gets all the anchor tags; synonymous with $$("a")
 >$ES('a','myElement') //get all the anchor tags within $('myElement')
*/

function $ES(selector, filter){
 return ($(filter) || document).getElementsBySelector(selector);
};

/*
Class: Element
 Custom class to allow all of its methods to be used with any DOM element via the dollar function <$>.
*/

Element.domMethods = {

 /*
 Property: getElements 
  Gets all the elements within an element that match the given (single) selector.

 Arguments:
  selector - the css selector to match

 Example:
  >$('myElement').getElements('a'); // get all anchors within myElement
  
 Notes:
  Supports these operators in attribute selectors:
  
  - = : is equal to
  - ^= : starts-with
  - $= : ends-with
  - != : is not equal to
  
  Xpath is used automatically for compliant browsers.
 */

 getElements: function(selector, nocash){
  var items = [];
  var xpath = (document.evaluate) ? true : false;
  selector = selector.clean().split(' ');
  for (var i = 0, j = selector.length; i < j; i++){
   var sel = selector[i];
   var param = sel.match(/^(\w*|\*)(?:#([\w-]+)|\.([\w-]+))?(?:\[(\w+)(?:([!*^$]?=)["']?([^"'\]]*)["']?)?])?$/);
   if (!param) break;
   param[1] = (param[1]) ? param[1].toLowerCase() : '*';
   if (xpath){
    var temp = this.namespaceURI ? ['xhtml:'] : [];
    temp.push(param[1]);
    if (param[2]) temp.push('[@id="', param[2], '"]');
    if (param[3]) temp.push('[contains(concat(" ", @class, " "), " ', param[3], ' ")]');
    if (param[4]){
     if (param[5] && param[6]){
      switch(param[5]){
       case '*=':  temp.push('[contains(@', param[4], ', "', param[6], '")]'); break;
       case '^=':  temp.push('[starts-with(@', param[4], ', "', param[6], '")]'); break;
       case '$=': temp.push('[substring(@', param[4], ', string-length(@', param[4], ') - ', param[6].length, ' + 1) = "', param[6], '"]'); break;
       case '=':  temp.push('[@', param[4], '="', param[6], '"]'); break;
       case '!=':  temp.push('[@', param[4], '!="', param[6], '"]');
      }
     } else temp.push('[@', param[4], ']');
    }
    items.push(temp.join(''));
    continue;
   }
   Filters.selector = param;
   if (i == 0){
    if (param[2]){
     var el = this.getElementById(param[2]);
     if (!el || ((param[1] != '*') && (Element.prototype.getTag.call(el) != param[1]))) break;
     items = [el];
    } else {
     items = $A(this.getElementsByTagName(param[1]));
    }
   } else {
    items = Elements.prototype.getElementsByTagName.call(items, param[1], true);
    if (param[2]) items = items.filter(Filters.id);
   }
   if (param[3]) items = items.filter(Filters.className);
   if (param[4]) items = items.filter(Filters.attribute);
  }
  if (xpath) items = this.getElementsByXpath(items.join('//'));
  return (nocash) ? items : $$(items);
 },
 
 getElementsByXpath: function(xp){
  var result = [];
  var resolver = function(prefix){
   return (prefix == 'xhtml') ? 'http://www.w3.org/1999/xhtml' : false;
  };
  var xpath = document.evaluate('.//' + xp, this, resolver, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
  for (var i = 0, j = xpath.snapshotLength; i < j; i++) result.push(xpath.snapshotItem(i));
  return result;
 },

 /*
 Property: getElement
  Same as <Element.getElements>, but returns only the first. Alternate syntax for <$E>, where filter is the Element.
 */

 getElement: function(selector){
  return this.getElementsBySelector(selector)[0];
 },

 /*
 Property: getElementsBySelector
  Same as <Element.getElements>, but allows for comma separated selectors, as in css. Alternate syntax for <$$>, where filter is the Element.

 */

 getElementsBySelector: function(selector, nocash){
  var els = [];
  var sel = selector.split(',');
  for (var i = 0, j = sel.length; i < j; i++) els.extend(this.getElements(sel[i], true));
  return (nocash) ? els : $$(els);
 },
 
 /*
 Property: getElementsByClassName 
  Returns all the elements that match a specific class name.
  Here for compatibility purposes. can also be written: document.getElements('.className'), or $$('.className')
 */

 getElementsByClassName: function(className){
  return this.getElements('.' + className);
 }

};

Element.extend({

 /*
 Property: getElementById
  Targets an element with the specified id found inside the Element. Does not overwrite document.getElementById.

 Arguments:
  id - the id of the element to find.
 */

 getElementById: function(id){
  var el = document.getElementById(id);
  if (!el) return false;
  for (var parent = el.parentNode; parent != this; parent = parent.parentNode){
   if (!parent) return false;
  }
  return el;
 }
 
});

/* Section: document related functions */

document.extend(Element.domMethods);
Element.extend(Element.domMethods);

//dom filters, internal methods.

var Filters = {

 selector: [],

 id: function(el){
  return (el.id == Filters.selector[2]);
 },

 className: function(el){
  return (Element.prototype.hasClass.call(el, Filters.selector[3]));
 },

 attribute: function(el){
  var current = el.getAttribute(Filters.selector[4]);
  if (!current) return false;
  var operator = Filters.selector[5];
  if (!operator) return true;
  var value = Filters.selector[6];
  switch(operator){
   case '=': return (current == value);
   case '*=': return (current.test(value));
   case '^=': return (current.test('^' + value));
   case '$=': return (current.test(value + '$'));
   case '!=': return (current != value);
  }
  return false;
 }

};

/*
Class: Elements
 Methods for dom queries arrays, <$$>.
*/

Elements.extend({

 getElementsByTagName: function(tagName){
  var found = [];
  for (var i = 0, j = this.length; i < j; i++) found.extend(this[i].getElementsByTagName(tagName));
  return found;
 }

});

/*
Script: Drag.Base.js
 Contains <Drag.Base>, <Element.makeResizable>

Author:
 Valerio Proietti, <http://mad4milk.net>

License:
 MIT-style license.
*/

var Drag = {};

/*
Class: Drag.Base
 Modify two css properties of an element based on the position of the mouse.

Arguments:
 el - the $(element) to apply the transformations to.
 options - optional. The options object.

Options:
 handle - the $(element) to act as the handle for the draggable element. defaults to the $(element) itself.
 modifiers - an object. see Modifiers Below.
 onStart - optional, function to execute when the user starts to drag (on mousedown);
 onComplete - optional, function to execute when the user completes the drag.
 onDrag - optional, function to execute at every step of the drag
 limit - an object, see Limit below.
 snap - optional, the distance you have to drag before the element starts to respond to the drag. defaults to false

 modifiers:
  x - string, the style you want to modify when the mouse moves in an horizontal direction. defaults to 'left'
  y - string, the style you want to modify when the mouse moves in a vertical direction. defaults to 'top'

 limit:
  x - array with start and end limit relative to modifiers.x
  y - array with start and end limit relative to modifiers.y
*/

Drag.Base = new Class({

 options: {
  handle: false,
  unit: 'px',
  onStart: Class.empty,
  onBeforeStart: Class.empty,
  onComplete: Class.empty,
  onSnap: Class.empty,
  onDrag: Class.empty,
  limit: false,
  modifiers: {x: 'left', y: 'top'},
  snap: 6
 },

 initialize: function(el, options){
  this.setOptions(options);
  this.element = $(el);
  this.handle = $(this.options.handle) || this.element;
  this.mouse = {'now': {}, 'pos': {}};
  this.value = {'start': {}, 'now': {}};
  this.bound = {'start': this.start.bindWithEvent(this)};
  this.attach();
  if (this.options.initialize) this.options.initialize.call(this);
 },

 attach: function(){
  this.handle.addEvent('mousedown', this.bound.start);
 },

 start: function(event){
  this.fireEvent('onBeforeStart', this.element);
  this.mouse.start = event.page;
  var limit = this.options.limit;
  this.limit = {'x': [], 'y': []};
  for (var z in this.options.modifiers){
   if (!$chk(this.options.modifiers[z])) continue;
   this.value.now[z] = this.element.getStyle(this.options.modifiers[z]).toInt();
   this.mouse.pos[z] = event.page[z] - this.value.now[z];
   if (limit && limit[z]){
    for (var i = 0; i < 2; i++){
     if ($chk(limit[z][i])) this.limit[z][i] = limit[z][i].apply ? limit[z][i].call(this) : limit[z][i];
    }
   }
  }
  this.bound.drag = this.drag.bindWithEvent(this);
  this.bound.stop = this.stop.bind(this);
  this.bound.move = this.options.snap ? this.checkAndDrag.bindWithEvent(this) : this.bound.drag;
  document.addEvent('mousemove', this.bound.move);
  document.addEvent('mouseup', this.bound.stop);
  this.fireEvent('onStart', this.element);
  event.stop();
 },

 checkAndDrag: function(event){
  var distance = Math.round(Math.sqrt(Math.pow(event.page.x - this.mouse.start.x, 2) + Math.pow(event.page.y - this.mouse.start.y, 2)));
  if (distance > this.options.snap){
   document.removeEvent('mousemove', this.bound.move);
   this.bound.move = this.bound.drag;
   document.addEvent('mousemove', this.bound.move);
   this.drag(event);
   this.fireEvent('onSnap', this.element);
  }
  event.stop();
 },

 drag: function(event){
  this.out = false;
  this.mouse.now = event.page;
  for (var z in this.options.modifiers){
   if (!$chk(this.options.modifiers[z])) continue;
   this.value.now[z] = this.mouse.now[z] - this.mouse.pos[z];
   if (this.limit[z]){
    if ($chk(this.limit[z][1]) && (this.value.now[z] > this.limit[z][1])){
     this.value.now[z] = this.limit[z][1];
     this.out = true;
    } else if ($chk(this.limit[z][0]) && (this.value.now[z] < this.limit[z][0])){
     this.value.now[z] = this.limit[z][0];
     this.out = true;
    }
   }
   this.element.setStyle(this.options.modifiers[z], this.value.now[z] + this.options.unit);
  }
  this.fireEvent('onDrag', this.element);
  event.stop();
 },

 detach: function(){
  this.handle.removeEvent('mousedown', this.bound.start);
 },

 stop: function(){
  document.removeEvent('mousemove', this.bound.move);
  document.removeEvent('mouseup', this.bound.stop);
  this.fireEvent('onComplete', this.element);
 }

});

Drag.Base.implement(new Events);
Drag.Base.implement(new Options);

/*
Class: Element
 Custom class to allow all of its methods to be used with any DOM element via the dollar function <$>.
*/

Element.extend({

 /*
 Property: makeResizable
  Makes an element resizable (by dragging) with the supplied options.

 Arguments:
  options - see <Drag.Base> for acceptable options.
 */

 makeResizable: function(options){
  return new Drag.Base(this, $merge({modifiers: {x: 'width', y: 'height'}}, options));
 }

});

/*
Script: Drag.Move.js
 Contains <Drag.Move>, <Element.makeDraggable>

Author:
 Valerio Proietti, <http://mad4milk.net>

License:
 MIT-style license.
*/

/*
Class: Drag.Move
 Extends <Drag.Base>, has additional functionality for dragging an element, support snapping and droppables.
 Drag.move supports either position absolute or relative. If no position is found, absolute will be set.

Arguments:
 el - the $(element) to apply the drag to.
 options - optional. see Options below.

Options:
 all the drag.Base options, plus:
 container - an element, will fill automatically limiting options based on the $(element) size and position. defaults to false (no limiting)
 droppables - an array of elements you can drop your draggable to.
*/

Drag.Move = Drag.Base.extend({

 options: {
  droppables: [],
  container: false,
  overflown: []
 },

 initialize: function(el, options){
  this.setOptions(options);
  this.element = $(el);
  this.position = this.element.getStyle('position');
  this.droppables = $$(this.options.droppables);
  if (!['absolute', 'relative'].test(this.position)) this.position = 'absolute';
  var top = this.element.getStyle('top').toInt();
  var left = this.element.getStyle('left').toInt();
  if (this.position == 'absolute'){
   top = $chk(top) ? top : this.element.getTop();
   left = $chk(left) ? left : this.element.getLeft();
  } else {
   top = $chk(top) ? top : 0;
   left = $chk(left) ? left : 0;
  }
  this.element.setStyles({
   'top': top,
   'left': left,
   'position': this.position
  });
  this.parent(this.element, this.options);
 },

 start: function(event){
  this.container = $(this.options.container);
  if (this.container){
   var cont = this.container.getCoordinates();
   var el = this.element.getCoordinates();
   if (this.position == 'absolute'){
    this.options.limit = {
     'x': [cont.left, cont.right - el.width],
     'y': [cont.top, cont.bottom - el.height]
    };
   } else {
    var diffx = el.left - this.element.getStyle('left').toInt();
    var diffy = el.top - this.element.getStyle('top').toInt();
    this.options.limit = {
     'y': [-(diffy) + cont.top, cont.bottom - diffy - el.height],
     'x': [-(diffx) + cont.left, cont.right - diffx - el.width]
    };
   }
  }
  this.parent(event);
 },

 drag: function(event){
  this.parent(event);
  if (this.out) return this;
  this.droppables.each(function(drop){
   if (this.checkAgainst($(drop))){
    if (!drop.overing) drop.fireEvent('over', [this.element, this]);
    drop.overing = true;
   } else {
    if (drop.overing) drop.fireEvent('leave', [this.element, this]);
    drop.overing = false;
   }
  }, this);
  return this;
 },

 checkAgainst: function(el){
  el = el.getCoordinates(this.options.overflown);
  return (this.mouse.now.x > el.left && this.mouse.now.x < el.right && this.mouse.now.y < el.bottom && this.mouse.now.y > el.top);
 },

 stop: function(){
  if (!this.out){
   var dropped = false;
   this.droppables.each(function(drop){
    if (this.checkAgainst(drop)){
     drop.fireEvent('drop', [this.element, this]);
     dropped = true;
    }
   }, this);
   if (!dropped) this.element.fireEvent('emptydrop', this);
  }
  this.parent();
  return this;
 }

});

/*
Class: Element
 Custom class to allow all of its methods to be used with any DOM element via the dollar function <$>.
*/

Element.extend({

 /*
 Property: makeDraggable
  Makes an element draggable with the supplied options.

 Arguments:
  options - see <Drag.Move> and <Drag.Base> for acceptable options.
 */

 makeDraggable: function(options){
  return new Drag.Move(this, options);
 }

});

/*
Script: XHR.js
 Contains the basic XMLHttpRequest Class Wrapper.

Author:
 Valerio Proietti, <http://mad4milk.net>

License:
 MIT-style license.
*/

/*
Class: XHR
 Basic XMLHttpRequest Wrapper.

Arguments:

Options:
 method - 'post' or 'get' - the protocol for the request; optional, defaults to 'post'.
 async - boolean: asynchronous option; true uses asynchronous requests. Defaults to true.
 onRequest - function to execute when the XHR request is fired.
 onSuccess - function to execute when the XHR request completes.
 onStateChange - function to execute when the state of the XMLHttpRequest changes.
 onFailure - function to execute when the state of the XMLHttpRequest changes.
 headers - accepts an object, that will be set to request headers.

Example:
 >var myXHR = new XHR({method: 'get'}).send('http://site.com/requestHandler.php', 'name=john&lastname=doe');
*/

var XHR = new Class({

 options: {
  method: 'post',
  async: true,
  onRequest: Class.empty,
  onStateChange: Class.empty,
  onSuccess: Class.empty,
  onFailure: Class.empty,
  headers: {}
 },

 initialize: function(options){
  this.transport = window.XMLHttpRequest ? new XMLHttpRequest() : (window.ie ? new ActiveXObject('Microsoft.XMLHTTP') : false);
  this.setOptions(options);
  this.options.isSuccess = this.options.isSuccess || this.isSuccess;
  if (!this.transport) return;
  this.headers = {};
  if (this.options.initialize) this.options.initialize.call(this);
 },

 onStateChange: function(){
  this.fireEvent('onStateChange', this.transport);
  if (this.transport.readyState != 4) return;
  var status = 0;
  try {status = this.transport.status} catch(e){}
  if (this.options.isSuccess(status)) this.onSuccess();
  else this.onFailure();
  this.transport.onreadystatechange = Class.empty;
 },

 isSuccess: function(status){
  return ((status >= 200) && (status < 300));
 },

 onSuccess: function(){
  this.response = {
   'text': this.transport.responseText,
   'xml': this.transport.responseXML
  };
  this.fireEvent('onSuccess', [this.response.text, this.response.xml]);
  this.callChain();
 },
 
 onFailure: function(){
  this.fireEvent('onFailure', this.transport);
 },

 setHeader: function(name, value){
  this.headers[name] = value;
  return this;
 },

 send: function(url, data){
  this.fireEvent('onRequest');
  this.transport.open(this.options.method, url, this.options.async);
  this.transport.onreadystatechange = this.onStateChange.bind(this);
  if ((this.options.method == 'post') && this.transport.overrideMimeType) this.setHeader('Connection', 'close');
  $extend(this.headers, this.options.headers);
  for (var type in this.headers) this.transport.setRequestHeader(type, this.headers[type]);
  this.transport.send(data);
  return this;
 }

});

XHR.implement(new Chain);
XHR.implement(new Events);
XHR.implement(new Options);

/*
Script: Ajax.js
 Contains the <Ajax> class. Also contains methods to generate querystings from forms and Objects.

Authors:
 - Valerio Proietti, <http://mad4milk.net>
 - Christophe Beyls, <http://www.digitalia.be>

Credits:
 Loosely based on the version from prototype.js <http://prototype.conio.net>

License:
 MIT-style license.
*/

/*
Class: Ajax
 An Ajax class, For all your asynchronous needs. Inherits methods, properties and options from <XHR>.

Arguments:
 url - the url pointing to the server-side script.
 options - optional, an object containing options.

Options:
 data - you can write parameters here. Can be a querystring, an object or a Form element.
 onComplete - function to execute when the ajax request completes.
 update - $(element) to insert the response text of the XHR into, upon completion of the request.
 evalScripts - boolean; default is false. Execute scripts in the response text onComplete.
 evalResponse - boolean; should you eval the whole responsetext? I dont know, but this option makes it possible.
 encoding - the encoding, defaults to utf-8.

Example:
 >var myAjax = new Ajax(url, {method: 'get'}).request();
*/

var Ajax = XHR.extend({

 options: {
  data: null,
  update: null,
  onComplete: Class.empty,
  evalScripts: false,
  evalResponse: false,
  encoding: 'utf-8'
 },

 initialize: function(url, options){
  this.addEvent('onSuccess', this.onComplete);
  this.setOptions(options);
  this.options.data = this.options.data || this.options.postBody;
  this.parent(this.options);
  if (!['post', 'get'].test(this.options.method)){
   this._method = '_method=' + this.options.method;
   this.options.method = 'post';
  }
  if (this.options.method == 'post'){
   var encoding = (this.options.encoding) ? '; charset=' + this.options.encoding : '';
   this.setHeader('Content-type', 'application/x-www-form-urlencoded' + encoding);
  }
  this.setHeader('X-Requested-With', 'XMLHttpRequest');
  this.setHeader('Accept', 'text/javascript, text/html, application/xml, text/xml, */*');
  this.url = url;
 },

 onComplete: function(){
  if (this.options.update) $(this.options.update).setHTML(this.response.text);
  if (this.options.evalResponse) eval(this.response.text);
  if (this.options.evalScripts) this.evalScripts.delay(30, this);
  this.fireEvent('onComplete', [this.response.text, this.response.xml], 20);
 },

 /*
 Property: request
  Executes the ajax request.

 Example:
  >var myAjax = new Ajax(url, {method: 'get'});
  >myAjax.request();

  OR

  >new Ajax(url, {method: 'get'}).request();
 */

 request: function(data){
  data = data || this.options.data;
  switch($type(data)){
   case 'element': data = $(data).toQueryString(); break;
   case 'object': data = Object.toQueryString(data);
  }
  if (this._method) data = (data) ? [this._method, data].join('&') : this._method;
  if (this.options.method == 'get' && !this.url.test(/^\?/)) data = '?' + data;
  return this.send(this.url, data);
 },

 /*
 Property: evalScripts
  Executes scripts in the response text
 */

 evalScripts: function(){
  var script, regexp = /<script[^>]*>([\s\S]*?)<\/script>/gi;
  while ((script = regexp.exec(this.response.text))) eval(script[1]);
 }

});

/* Section: Object related Functions */

/*
Function: Object.toQueryString
 Generates a querystring from key/pair values in an object

Arguments:
 source - the object to generate the querystring from.

Returns:
 the query string.

Example:
 >Object.toQueryString({apple: "red", lemon: "yellow"}); //returns "apple=red&lemon=yellow"
*/

Object.toQueryString = function(source){
 var queryString = [];
 for (var property in source) queryString.push(encodeURIComponent(property) + '=' + encodeURIComponent(source[property]));
 return queryString.join('&');
};

/*
Class: Element
 Custom class to allow all of its methods to be used with any DOM element via the dollar function <$>.
*/

Element.extend({

 /*
 Property: send
  Sends a form with an ajax post request

 Arguments:
  options - option collection for ajax request. See <Ajax> for the options list.

 Returns:
  The Ajax Class Instance

 Example:
  (start code)
  <form id="myForm" action="submit.php">
  <input name="email" value="bob@bob.com">
  <input name="zipCode" value="90210">
  </form>
  <script>
  $('myForm').send()
  </script>
  (end)
 */

 send: function(options){
  return new Ajax(this.getProperty('action'), $merge({postBody: this.toQueryString()}, options, {method: 'post'})).request();
 },

 /*
 Property: toQueryString
  Reads the children inputs of the Element and generates a query string, based on their values. Used internally in <Ajax>

 Example:
  (start code)
  <form id="myForm" action="submit.php">
  <input name="email" value="bob@bob.com">
  <input name="zipCode" value="90210">
  </form>

  <script>
   $('myForm').toQueryString()
  </script>
  (end)

  Returns:
   email=bob@bob.com&zipCode=90210
 */

 toQueryString: function(){
  var queryString = [];
  $$(this.getElementsByTagName('input'), this.getElementsByTagName('select'), this.getElementsByTagName('textarea')).each(function(el){
   var name = $(el).name;
   var value = el.getValue();
   if (!el.disabled && $chk(value)){
    var qs = function(val){
     queryString.push(name + '=' + encodeURIComponent(val));
    };
    if ($type(value) == 'array') value.each(qs);
    else qs(value);
   }
  });
  return queryString.join('&');
 }

});

/*
Script: Sortables.js
    Contains <Sortables> Class.

Author:
    Valerio Proietti, <http://mad4milk.net>

License:
    MIT-style license.
*/

/*
Class: Sortables
    Creates an interface for <Drag.Base> and drop, resorting of a list.

Arguments:
    list - required, the list that will become sortable.
    options - an Object, see options below.

Options:
    handles - a collection of elements to be used for drag handles. defaults to the elements.
    onStart - function executed when the item starts dragging
    onComplete - function executed when the item ends dragging
*/

var Sortables = new Class({

    getOptions: function() {
        return {
            handles: false,
            onStart: Class.empty,
            onComplete: Class.empty,
            ghost: true,
            snap: 3,
            onDragStart: function(element, ghost){
                ghost.setStyle('opacity', 0.5);
            },
            onDragComplete: function(element, ghost){
                ghost.remove();
            }
        };
    },

    initialize: function(list, options){
        this.setOptions(this.getOptions(), options);
        this.list = $(list);

        //Added by Levis
        //this.elements = this.list.getChildren();
        this.elements = $$(this.options.handles);

        this.handles = $$(this.options.handles) || this.elements;
        this.drag = [];
        this.bound = {'start': []};
        this.elements.each(function(el, i){
            this.bound.start[i] = this.start.bindWithEvent(this, el);
            if (this.options.ghost){
                this.trash = new Element('div').injectInside(document.body);
                var limit = this.list.getCoordinates();
                this.drag[i] = new Drag.Base(el, {
                    handle: this.handles[i],
                    snap: this.options.snap,
                    modifiers: {y: 'top'},

                    //Added by Levis
                    //limit: {y: [limit.top, limit.bottom - el.offsetHeight]},
                    limit: {y: [limit.top + el.offsetHeight, limit.bottom - el.offsetHeight]},

                    onBeforeStart: function(element){
                        var offsets = element.getPosition();
                        this.old = element;
                        this.drag[i].element = this.ghost = element.clone().setStyles({
                            'position': 'absolute',
                            'top': offsets.y+'px',
                            'left': offsets.x+'px'
                        }).injectInside(this.trash);
                        this.fireEvent('onDragStart', [el, this.ghost]);
                    }.bind(this),

                    //Added by Levis
                    onDrag: function(){updateAltBG(this.handles[1].getParent());}.bind(this),

                    onComplete: function(element){
                        this.drag[i].element = this.old;
                        this.fireEvent('onDragComplete', [el, this.ghost]);
                    }.bind(this)
                });
            }
            this.handles[i].addEvent('mousedown', this.start.bindWithEvent(this, el));
        }, this);
        if (this.options.initialize) this.options.initialize.call(this);
    },

    start: function(event, el){
        this.bound.move = this.move.bindWithEvent(this, el);
        this.bound.end = this.end.bind(this, el);
        document.addEvent('mousemove', this.bound.move);
        document.addEvent('mouseup', this.bound.end);
        this.fireEvent('onStart', el);
        event.stop();
    },

    move: function(event, el){
        var prev = el.getPrevious();
        var next = el.getNext();

        //Added by Levis
        //if (prev.id){
        if (prev.id!=""){

            var prevPos = prev.getCoordinates();
            if (event.page.y < prevPos.bottom) el.injectBefore(prev);
        }
        if (next){
            var nextPos = next.getCoordinates();
            if (event.page.y > nextPos.top) el.injectAfter(next);
        }
        event.stop();
    },
    
    detach: function(){
        this.elements.each(function(el, i){
            this.handles[i].removeEvent('mousedown', this.bound.start[i]);
        }, this);
    },
    
    serialize: function(){
        var serial = [];

        //Added by Levis
        //this.list.getChildren().each(function(el, i){
        $$(this.options.handles).each(function(el, i){

            serial[i] = this.elements.indexOf(el);
        }, this);
        return serial;
    },

    end: function(el){
        document.removeEvent('mousemove', this.bound.move);
        document.removeEvent('mouseup', this.bound.end);
        this.fireEvent('onComplete', el);
    }

});

Sortables.implement(new Events);
Sortables.implement(new Options);