You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by hl...@apache.org on 2008/06/08 23:55:43 UTC

svn commit: r664564 [4/5] - in /tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/scriptaculous_1_8_1: builder.js controls.js dragdrop.js effects.js prototype.js scriptaculous.js slider.js sound.js unittest.js

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/scriptaculous_1_8_1/prototype.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/scriptaculous_1_8_1/prototype.js?rev=664564&r1=664563&r2=664564&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/scriptaculous_1_8_1/prototype.js (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/scriptaculous_1_8_1/prototype.js Sun Jun  8 14:55:43 2008
@@ -7,4234 +7,3505 @@
  *--------------------------------------------------------------------------*/
 
 var Prototype = {
-    Version: '1.6.0.1',
+  Version: '1.6.0.1',
 
-    Browser: {
-        IE:     !!(window.attachEvent && !window.opera),
-        Opera:  !!window.opera,
-        WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1,
-        Gecko:  navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1,
-        MobileSafari: !!navigator.userAgent.match(/Apple.*Mobile.*Safari/)
-    },
-
-    BrowserFeatures: {
-        XPath: !!document.evaluate,
-        ElementExtensions: !!window.HTMLElement,
-        SpecificElementExtensions:
-                document.createElement('div').__proto__ &&
-                document.createElement('div').__proto__ !==
-                document.createElement('form').__proto__
-    },
-
-    ScriptFragment: '<script[^>]*>([\\S\\s]*?)<\/script>',
-    JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/,
-
-    emptyFunction: function()
-    {
-    },
-    K: function(x)
-    {
-        return x
-    }
+  Browser: {
+    IE:     !!(window.attachEvent && !window.opera),
+    Opera:  !!window.opera,
+    WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1,
+    Gecko:  navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1,
+    MobileSafari: !!navigator.userAgent.match(/Apple.*Mobile.*Safari/)
+  },
+
+  BrowserFeatures: {
+    XPath: !!document.evaluate,
+    ElementExtensions: !!window.HTMLElement,
+    SpecificElementExtensions:
+      document.createElement('div').__proto__ &&
+      document.createElement('div').__proto__ !==
+        document.createElement('form').__proto__
+  },
+
+  ScriptFragment: '<script[^>]*>([\\S\\s]*?)<\/script>',
+  JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/,
+
+  emptyFunction: function() { },
+  K: function(x) { return x }
 };
 
 if (Prototype.Browser.MobileSafari)
-    Prototype.BrowserFeatures.SpecificElementExtensions = false;
+  Prototype.BrowserFeatures.SpecificElementExtensions = false;
 
 
 /* Based on Alex Arnell's inheritance implementation. */
 var Class = {
-    create: function()
-    {
-        var parent = null, properties = $A(arguments);
-        if (Object.isFunction(properties[0]))
-            parent = properties.shift();
-
-        function klass()
-        {
-            this.initialize.apply(this, arguments);
-        }
+  create: function() {
+    var parent = null, properties = $A(arguments);
+    if (Object.isFunction(properties[0]))
+      parent = properties.shift();
 
-        Object.extend(klass, Class.Methods);
-        klass.superclass = parent;
-        klass.subclasses = [];
-
-        if (parent)
-        {
-            var subclass = function()
-            {
-            };
-            subclass.prototype = parent.prototype;
-            klass.prototype = new subclass;
-            parent.subclasses.push(klass);
-        }
+    function klass() {
+      this.initialize.apply(this, arguments);
+    }
 
-        for (var i = 0; i < properties.length; i++)
-            klass.addMethods(properties[i]);
+    Object.extend(klass, Class.Methods);
+    klass.superclass = parent;
+    klass.subclasses = [];
 
-        if (!klass.prototype.initialize)
-            klass.prototype.initialize = Prototype.emptyFunction;
+    if (parent) {
+      var subclass = function() { };
+      subclass.prototype = parent.prototype;
+      klass.prototype = new subclass;
+      parent.subclasses.push(klass);
+    }
 
-        klass.prototype.constructor = klass;
+    for (var i = 0; i < properties.length; i++)
+      klass.addMethods(properties[i]);
 
-        return klass;
-    }
+    if (!klass.prototype.initialize)
+      klass.prototype.initialize = Prototype.emptyFunction;
+
+    klass.prototype.constructor = klass;
+
+    return klass;
+  }
 };
 
 Class.Methods = {
-    addMethods: function(source)
-    {
-        var ancestor = this.superclass && this.superclass.prototype;
-        var properties = Object.keys(source);
-
-        if (!Object.keys({ toString: true }).length)
-            properties.push("toString", "valueOf");
-
-        for (var i = 0, length = properties.length; i < length; i++)
-        {
-            var property = properties[i], value = source[property];
-            if (ancestor && Object.isFunction(value) &&
-                value.argumentNames().first() == "$super")
-            {
-                var method = value, value = Object.extend((function(m)
-                {
-                    return function()
-                    {
-                        return ancestor[m].apply(this, arguments)
-                    };
-                })(property).wrap(method), {
-                    valueOf:  function()
-                    {
-                        return method
-                    },
-                    toString: function()
-                    {
-                        return method.toString()
-                    }
-                });
-            }
-            this.prototype[property] = value;
-        }
-
-        return this;
+  addMethods: function(source) {
+    var ancestor   = this.superclass && this.superclass.prototype;
+    var properties = Object.keys(source);
+
+    if (!Object.keys({ toString: true }).length)
+      properties.push("toString", "valueOf");
+
+    for (var i = 0, length = properties.length; i < length; i++) {
+      var property = properties[i], value = source[property];
+      if (ancestor && Object.isFunction(value) &&
+          value.argumentNames().first() == "$super") {
+        var method = value, value = Object.extend((function(m) {
+          return function() { return ancestor[m].apply(this, arguments) };
+        })(property).wrap(method), {
+          valueOf:  function() { return method },
+          toString: function() { return method.toString() }
+        });
+      }
+      this.prototype[property] = value;
     }
+
+    return this;
+  }
 };
 
 var Abstract = { };
 
-Object.extend = function(destination, source)
-{
-    for (var property in source)
-        destination[property] = source[property];
-    return destination;
+Object.extend = function(destination, source) {
+  for (var property in source)
+    destination[property] = source[property];
+  return destination;
 };
 
 Object.extend(Object, {
-    inspect: function(object)
-    {
-        try
-        {
-            if (Object.isUndefined(object)) return 'undefined';
-            if (object === null) return 'null';
-            return object.inspect ? object.inspect() : object.toString();
-        }
-        catch (e)
-        {
-            if (e instanceof RangeError) return '...';
-            throw e;
-        }
-    },
-
-    toJSON: function(object)
-    {
-        var type = typeof object;
-        switch (type)
-                {
-            case 'undefined':
-            case 'function':
-            case 'unknown': return;
-            case 'boolean': return object.toString();
-        }
-
-        if (object === null) return 'null';
-        if (object.toJSON) return object.toJSON();
-        if (Object.isElement(object)) return;
-
-        var results = [];
-        for (var property in object)
-        {
-            var value = Object.toJSON(object[property]);
-            if (!Object.isUndefined(value))
-                results.push(property.toJSON() + ': ' + value);
-        }
-
-        return '{' + results.join(', ') + '}';
-    },
-
-    toQueryString: function(object)
-    {
-        return $H(object).toQueryString();
-    },
-
-    toHTML: function(object)
-    {
-        return object && object.toHTML ? object.toHTML() : String.interpret(object);
-    },
-
-    keys: function(object)
-    {
-        var keys = [];
-        for (var property in object)
-            keys.push(property);
-        return keys;
-    },
-
-    values: function(object)
-    {
-        var values = [];
-        for (var property in object)
-            values.push(object[property]);
-        return values;
-    },
-
-    clone: function(object)
-    {
-        return Object.extend({ }, object);
-    },
-
-    isElement: function(object)
-    {
-        return object && object.nodeType == 1;
-    },
-
-    isArray: function(object)
-    {
-        return object && object.constructor === Array;
-    },
-
-    isHash: function(object)
-    {
-        return object instanceof Hash;
-    },
-
-    isFunction: function(object)
-    {
-        return typeof object == "function";
-    },
-
-    isString: function(object)
-    {
-        return typeof object == "string";
-    },
-
-    isNumber: function(object)
-    {
-        return typeof object == "number";
-    },
-
-    isUndefined: function(object)
-    {
-        return typeof object == "undefined";
-    }
+  inspect: function(object) {
+    try {
+      if (Object.isUndefined(object)) return 'undefined';
+      if (object === null) return 'null';
+      return object.inspect ? object.inspect() : object.toString();
+    } catch (e) {
+      if (e instanceof RangeError) return '...';
+      throw e;
+    }
+  },
+
+  toJSON: function(object) {
+    var type = typeof object;
+    switch (type) {
+      case 'undefined':
+      case 'function':
+      case 'unknown': return;
+      case 'boolean': return object.toString();
+    }
+
+    if (object === null) return 'null';
+    if (object.toJSON) return object.toJSON();
+    if (Object.isElement(object)) return;
+
+    var results = [];
+    for (var property in object) {
+      var value = Object.toJSON(object[property]);
+      if (!Object.isUndefined(value))
+        results.push(property.toJSON() + ': ' + value);
+    }
+
+    return '{' + results.join(', ') + '}';
+  },
+
+  toQueryString: function(object) {
+    return $H(object).toQueryString();
+  },
+
+  toHTML: function(object) {
+    return object && object.toHTML ? object.toHTML() : String.interpret(object);
+  },
+
+  keys: function(object) {
+    var keys = [];
+    for (var property in object)
+      keys.push(property);
+    return keys;
+  },
+
+  values: function(object) {
+    var values = [];
+    for (var property in object)
+      values.push(object[property]);
+    return values;
+  },
+
+  clone: function(object) {
+    return Object.extend({ }, object);
+  },
+
+  isElement: function(object) {
+    return object && object.nodeType == 1;
+  },
+
+  isArray: function(object) {
+    return object && object.constructor === Array;
+  },
+
+  isHash: function(object) {
+    return object instanceof Hash;
+  },
+
+  isFunction: function(object) {
+    return typeof object == "function";
+  },
+
+  isString: function(object) {
+    return typeof object == "string";
+  },
+
+  isNumber: function(object) {
+    return typeof object == "number";
+  },
+
+  isUndefined: function(object) {
+    return typeof object == "undefined";
+  }
 });
 
 Object.extend(Function.prototype, {
-    argumentNames: function()
-    {
-        var names = this.toString().match(/^[\s\(]*function[^(]*\((.*?)\)/)[1].split(",").invoke("strip");
-        return names.length == 1 && !names[0] ? [] : names;
-    },
-
-    bind: function()
-    {
-        if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this;
-        var __method = this, args = $A(arguments), object = args.shift();
-        return function()
-        {
-            return __method.apply(object, args.concat($A(arguments)));
-        }
-    },
-
-    bindAsEventListener: function()
-    {
-        var __method = this, args = $A(arguments), object = args.shift();
-        return function(event)
-        {
-            return __method.apply(object, [event || window.event].concat(args));
-        }
-    },
-
-    curry: function()
-    {
-        if (!arguments.length) return this;
-        var __method = this, args = $A(arguments);
-        return function()
-        {
-            return __method.apply(this, args.concat($A(arguments)));
-        }
-    },
-
-    delay: function()
-    {
-        var __method = this, args = $A(arguments), timeout = args.shift() * 1000;
-        return window.setTimeout(function()
-        {
-            return __method.apply(__method, args);
-        }, timeout);
-    },
-
-    wrap: function(wrapper)
-    {
-        var __method = this;
-        return function()
-        {
-            return wrapper.apply(this, [__method.bind(this)].concat($A(arguments)));
-        }
-    },
-
-    methodize: function()
-    {
-        if (this._methodized) return this._methodized;
-        var __method = this;
-        return this._methodized = function()
-        {
-            return __method.apply(null, [this].concat($A(arguments)));
-        };
-    }
+  argumentNames: function() {
+    var names = this.toString().match(/^[\s\(]*function[^(]*\((.*?)\)/)[1].split(",").invoke("strip");
+    return names.length == 1 && !names[0] ? [] : names;
+  },
+
+  bind: function() {
+    if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this;
+    var __method = this, args = $A(arguments), object = args.shift();
+    return function() {
+      return __method.apply(object, args.concat($A(arguments)));
+    }
+  },
+
+  bindAsEventListener: function() {
+    var __method = this, args = $A(arguments), object = args.shift();
+    return function(event) {
+      return __method.apply(object, [event || window.event].concat(args));
+    }
+  },
+
+  curry: function() {
+    if (!arguments.length) return this;
+    var __method = this, args = $A(arguments);
+    return function() {
+      return __method.apply(this, args.concat($A(arguments)));
+    }
+  },
+
+  delay: function() {
+    var __method = this, args = $A(arguments), timeout = args.shift() * 1000;
+    return window.setTimeout(function() {
+      return __method.apply(__method, args);
+    }, timeout);
+  },
+
+  wrap: function(wrapper) {
+    var __method = this;
+    return function() {
+      return wrapper.apply(this, [__method.bind(this)].concat($A(arguments)));
+    }
+  },
+
+  methodize: function() {
+    if (this._methodized) return this._methodized;
+    var __method = this;
+    return this._methodized = function() {
+      return __method.apply(null, [this].concat($A(arguments)));
+    };
+  }
 });
 
 Function.prototype.defer = Function.prototype.delay.curry(0.01);
 
-Date.prototype.toJSON = function()
-{
-    return '"' + this.getUTCFullYear() + '-' +
-           (this.getUTCMonth() + 1).toPaddedString(2) + '-' +
-           this.getUTCDate().toPaddedString(2) + 'T' +
-           this.getUTCHours().toPaddedString(2) + ':' +
-           this.getUTCMinutes().toPaddedString(2) + ':' +
-           this.getUTCSeconds().toPaddedString(2) + 'Z"';
+Date.prototype.toJSON = function() {
+  return '"' + this.getUTCFullYear() + '-' +
+    (this.getUTCMonth() + 1).toPaddedString(2) + '-' +
+    this.getUTCDate().toPaddedString(2) + 'T' +
+    this.getUTCHours().toPaddedString(2) + ':' +
+    this.getUTCMinutes().toPaddedString(2) + ':' +
+    this.getUTCSeconds().toPaddedString(2) + 'Z"';
 };
 
 var Try = {
-    these: function()
-    {
-        var returnValue;
-
-        for (var i = 0, length = arguments.length; i < length; i++)
-        {
-            var lambda = arguments[i];
-            try
-            {
-                returnValue = lambda();
-                break;
-            }
-            catch (e)
-            {
-            }
-        }
+  these: function() {
+    var returnValue;
 
-        return returnValue;
+    for (var i = 0, length = arguments.length; i < length; i++) {
+      var lambda = arguments[i];
+      try {
+        returnValue = lambda();
+        break;
+      } catch (e) { }
     }
+
+    return returnValue;
+  }
 };
 
 RegExp.prototype.match = RegExp.prototype.test;
 
-RegExp.escape = function(str)
-{
-    return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
+RegExp.escape = function(str) {
+  return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
 };
 
 /*--------------------------------------------------------------------------*/
 
 var PeriodicalExecuter = Class.create({
-    initialize: function(callback, frequency)
-    {
-        this.callback = callback;
-        this.frequency = frequency;
+  initialize: function(callback, frequency) {
+    this.callback = callback;
+    this.frequency = frequency;
+    this.currentlyExecuting = false;
+
+    this.registerCallback();
+  },
+
+  registerCallback: function() {
+    this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
+  },
+
+  execute: function() {
+    this.callback(this);
+  },
+
+  stop: function() {
+    if (!this.timer) return;
+    clearInterval(this.timer);
+    this.timer = null;
+  },
+
+  onTimerEvent: function() {
+    if (!this.currentlyExecuting) {
+      try {
+        this.currentlyExecuting = true;
+        this.execute();
+      } finally {
         this.currentlyExecuting = false;
+      }
+    }
+  }
+});
+Object.extend(String, {
+  interpret: function(value) {
+    return value == null ? '' : String(value);
+  },
+  specialChar: {
+    '\b': '\\b',
+    '\t': '\\t',
+    '\n': '\\n',
+    '\f': '\\f',
+    '\r': '\\r',
+    '\\': '\\\\'
+  }
+});
 
-        this.registerCallback();
-    },
+Object.extend(String.prototype, {
+  gsub: function(pattern, replacement) {
+    var result = '', source = this, match;
+    replacement = arguments.callee.prepareReplacement(replacement);
+
+    while (source.length > 0) {
+      if (match = source.match(pattern)) {
+        result += source.slice(0, match.index);
+        result += String.interpret(replacement(match));
+        source  = source.slice(match.index + match[0].length);
+      } else {
+        result += source, source = '';
+      }
+    }
+    return result;
+  },
 
-    registerCallback: function()
-    {
-        this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
-    },
+  sub: function(pattern, replacement, count) {
+    replacement = this.gsub.prepareReplacement(replacement);
+    count = Object.isUndefined(count) ? 1 : count;
+
+    return this.gsub(pattern, function(match) {
+      if (--count < 0) return match[0];
+      return replacement(match);
+    });
+  },
 
-    execute: function()
-    {
-        this.callback(this);
-    },
+  scan: function(pattern, iterator) {
+    this.gsub(pattern, iterator);
+    return String(this);
+  },
+
+  truncate: function(length, truncation) {
+    length = length || 30;
+    truncation = Object.isUndefined(truncation) ? '...' : truncation;
+    return this.length > length ?
+      this.slice(0, length - truncation.length) + truncation : String(this);
+  },
+
+  strip: function() {
+    return this.replace(/^\s+/, '').replace(/\s+$/, '');
+  },
+
+  stripTags: function() {
+    return this.replace(/<\/?[^>]+>/gi, '');
+  },
+
+  stripScripts: function() {
+    return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
+  },
+
+  extractScripts: function() {
+    var matchAll = new RegExp(Prototype.ScriptFragment, 'img');
+    var matchOne = new RegExp(Prototype.ScriptFragment, 'im');
+    return (this.match(matchAll) || []).map(function(scriptTag) {
+      return (scriptTag.match(matchOne) || ['', ''])[1];
+    });
+  },
 
-    stop: function()
-    {
-        if (!this.timer) return;
-        clearInterval(this.timer);
-        this.timer = null;
-    },
+  evalScripts: function() {
+    return this.extractScripts().map(function(script) { return eval(script) });
+  },
+
+  escapeHTML: function() {
+    var self = arguments.callee;
+    self.text.data = this;
+    return self.div.innerHTML;
+  },
+
+  unescapeHTML: function() {
+    var div = new Element('div');
+    div.innerHTML = this.stripTags();
+    return div.childNodes[0] ? (div.childNodes.length > 1 ?
+      $A(div.childNodes).inject('', function(memo, node) { return memo+node.nodeValue }) :
+      div.childNodes[0].nodeValue) : '';
+  },
+
+  toQueryParams: function(separator) {
+    var match = this.strip().match(/([^?#]*)(#.*)?$/);
+    if (!match) return { };
+
+    return match[1].split(separator || '&').inject({ }, function(hash, pair) {
+      if ((pair = pair.split('='))[0]) {
+        var key = decodeURIComponent(pair.shift());
+        var value = pair.length > 1 ? pair.join('=') : pair[0];
+        if (value != undefined) value = decodeURIComponent(value);
+
+        if (key in hash) {
+          if (!Object.isArray(hash[key])) hash[key] = [hash[key]];
+          hash[key].push(value);
+        }
+        else hash[key] = value;
+      }
+      return hash;
+    });
+  },
 
-    onTimerEvent: function()
-    {
-        if (!this.currentlyExecuting)
-        {
-            try
-            {
-                this.currentlyExecuting = true;
-                this.execute();
-            }
-            finally
-            {
-                this.currentlyExecuting = false;
-            }
-        }
-    }
+  toArray: function() {
+    return this.split('');
+  },
+
+  succ: function() {
+    return this.slice(0, this.length - 1) +
+      String.fromCharCode(this.charCodeAt(this.length - 1) + 1);
+  },
+
+  times: function(count) {
+    return count < 1 ? '' : new Array(count + 1).join(this);
+  },
+
+  camelize: function() {
+    var parts = this.split('-'), len = parts.length;
+    if (len == 1) return parts[0];
+
+    var camelized = this.charAt(0) == '-'
+      ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1)
+      : parts[0];
+
+    for (var i = 1; i < len; i++)
+      camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);
+
+    return camelized;
+  },
+
+  capitalize: function() {
+    return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
+  },
+
+  underscore: function() {
+    return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase();
+  },
+
+  dasherize: function() {
+    return this.gsub(/_/,'-');
+  },
+
+  inspect: function(useDoubleQuotes) {
+    var escapedString = this.gsub(/[\x00-\x1f\\]/, function(match) {
+      var character = String.specialChar[match[0]];
+      return character ? character : '\\u00' + match[0].charCodeAt().toPaddedString(2, 16);
+    });
+    if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"';
+    return "'" + escapedString.replace(/'/g, '\\\'') + "'";
+  },
+
+  toJSON: function() {
+    return this.inspect(true);
+  },
+
+  unfilterJSON: function(filter) {
+    return this.sub(filter || Prototype.JSONFilter, '#{1}');
+  },
+
+  isJSON: function() {
+    var str = this;
+    if (str.blank()) return false;
+    str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, '');
+    return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str);
+  },
+
+  evalJSON: function(sanitize) {
+    var json = this.unfilterJSON();
+    try {
+      if (!sanitize || json.isJSON()) return eval('(' + json + ')');
+    } catch (e) { }
+    throw new SyntaxError('Badly formed JSON string: ' + this.inspect());
+  },
+
+  include: function(pattern) {
+    return this.indexOf(pattern) > -1;
+  },
+
+  startsWith: function(pattern) {
+    return this.indexOf(pattern) === 0;
+  },
+
+  endsWith: function(pattern) {
+    var d = this.length - pattern.length;
+    return d >= 0 && this.lastIndexOf(pattern) === d;
+  },
+
+  empty: function() {
+    return this == '';
+  },
+
+  blank: function() {
+    return /^\s*$/.test(this);
+  },
+
+  interpolate: function(object, pattern) {
+    return new Template(this, pattern).evaluate(object);
+  }
 });
-Object.extend(String, {
-    interpret: function(value)
-    {
-        return value == null ? '' : String(value);
-    },
-    specialChar: {
-        '\b': '\\b',
-        '\t': '\\t',
-        '\n': '\\n',
-        '\f': '\\f',
-        '\r': '\\r',
-        '\\': '\\\\'
-    }
+
+if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, {
+  escapeHTML: function() {
+    return this.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
+  },
+  unescapeHTML: function() {
+    return this.replace(/&amp;/g,'&').replace(/&lt;/g,'<').replace(/&gt;/g,'>');
+  }
 });
 
-Object.extend(String.prototype, {
-    gsub: function(pattern, replacement)
-    {
-        var result = '', source = this, match;
-        replacement = arguments.callee.prepareReplacement(replacement);
-
-        while (source.length > 0)
-        {
-            if (match = source.match(pattern))
-            {
-                result += source.slice(0, match.index);
-                result += String.interpret(replacement(match));
-                source = source.slice(match.index + match[0].length);
-            }
-            else
-            {
-                result += source,source = '';
-            }
-        }
-        return result;
-    },
+String.prototype.gsub.prepareReplacement = function(replacement) {
+  if (Object.isFunction(replacement)) return replacement;
+  var template = new Template(replacement);
+  return function(match) { return template.evaluate(match) };
+};
 
-    sub: function(pattern, replacement, count)
-    {
-        replacement = this.gsub.prepareReplacement(replacement);
-        count = Object.isUndefined(count) ? 1 : count;
-
-        return this.gsub(pattern, function(match)
-        {
-            if (--count < 0) return match[0];
-            return replacement(match);
-        });
-    },
+String.prototype.parseQuery = String.prototype.toQueryParams;
 
-    scan: function(pattern, iterator)
-    {
-        this.gsub(pattern, iterator);
-        return String(this);
-    },
+Object.extend(String.prototype.escapeHTML, {
+  div:  document.createElement('div'),
+  text: document.createTextNode('')
+});
 
-    truncate: function(length, truncation)
-    {
-        length = length || 30;
-        truncation = Object.isUndefined(truncation) ? '...' : truncation;
-        return this.length > length ?
-               this.slice(0, length - truncation.length) + truncation : String(this);
-    },
+with (String.prototype.escapeHTML) div.appendChild(text);
 
-    strip: function()
-    {
-        return this.replace(/^\s+/, '').replace(/\s+$/, '');
-    },
+var Template = Class.create({
+  initialize: function(template, pattern) {
+    this.template = template.toString();
+    this.pattern = pattern || Template.Pattern;
+  },
+
+  evaluate: function(object) {
+    if (Object.isFunction(object.toTemplateReplacements))
+      object = object.toTemplateReplacements();
+
+    return this.template.gsub(this.pattern, function(match) {
+      if (object == null) return '';
+
+      var before = match[1] || '';
+      if (before == '\\') return match[2];
+
+      var ctx = object, expr = match[3];
+      var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/;
+      match = pattern.exec(expr);
+      if (match == null) return before;
+
+      while (match != null) {
+        var comp = match[1].startsWith('[') ? match[2].gsub('\\\\]', ']') : match[1];
+        ctx = ctx[comp];
+        if (null == ctx || '' == match[3]) break;
+        expr = expr.substring('[' == match[3] ? match[1].length : match[0].length);
+        match = pattern.exec(expr);
+      }
+
+      return before + String.interpret(ctx);
+    }.bind(this));
+  }
+});
+Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
 
-    stripTags: function()
-    {
-        return this.replace(/<\/?[^>]+>/gi, '');
-    },
+var $break = { };
 
-    stripScripts: function()
-    {
-        return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
-    },
+var Enumerable = {
+  each: function(iterator, context) {
+    var index = 0;
+    iterator = iterator.bind(context);
+    try {
+      this._each(function(value) {
+        iterator(value, index++);
+      });
+    } catch (e) {
+      if (e != $break) throw e;
+    }
+    return this;
+  },
+
+  eachSlice: function(number, iterator, context) {
+    iterator = iterator ? iterator.bind(context) : Prototype.K;
+    var index = -number, slices = [], array = this.toArray();
+    while ((index += number) < array.length)
+      slices.push(array.slice(index, index+number));
+    return slices.collect(iterator, context);
+  },
+
+  all: function(iterator, context) {
+    iterator = iterator ? iterator.bind(context) : Prototype.K;
+    var result = true;
+    this.each(function(value, index) {
+      result = result && !!iterator(value, index);
+      if (!result) throw $break;
+    });
+    return result;
+  },
 
-    extractScripts: function()
-    {
-        var matchAll = new RegExp(Prototype.ScriptFragment, 'img');
-        var matchOne = new RegExp(Prototype.ScriptFragment, 'im');
-        return (this.match(matchAll) || []).map(function(scriptTag)
-        {
-            return (scriptTag.match(matchOne) || ['', ''])[1];
-        });
-    },
+  any: function(iterator, context) {
+    iterator = iterator ? iterator.bind(context) : Prototype.K;
+    var result = false;
+    this.each(function(value, index) {
+      if (result = !!iterator(value, index))
+        throw $break;
+    });
+    return result;
+  },
 
-    evalScripts: function()
-    {
-        return this.extractScripts().map(function(script)
-        {
-            return eval(script)
-        });
-    },
+  collect: function(iterator, context) {
+    iterator = iterator ? iterator.bind(context) : Prototype.K;
+    var results = [];
+    this.each(function(value, index) {
+      results.push(iterator(value, index));
+    });
+    return results;
+  },
 
-    escapeHTML: function()
-    {
-        var self = arguments.callee;
-        self.text.data = this;
-        return self.div.innerHTML;
-    },
-
-    unescapeHTML: function()
-    {
-        var div = new Element('div');
-        div.innerHTML = this.stripTags();
-        return div.childNodes[0] ? (div.childNodes.length > 1 ?
-                                    $A(div.childNodes).inject('', function(memo, node)
-                                    {
-                                        return memo + node.nodeValue
-                                    }) :
-                                    div.childNodes[0].nodeValue) : '';
-    },
-
-    toQueryParams: function(separator)
-    {
-        var match = this.strip().match(/([^?#]*)(#.*)?$/);
-        if (!match) return { };
-
-        return match[1].split(separator || '&').inject({ }, function(hash, pair)
-        {
-            if ((pair = pair.split('='))[0])
-            {
-                var key = decodeURIComponent(pair.shift());
-                var value = pair.length > 1 ? pair.join('=') : pair[0];
-                if (value != undefined) value = decodeURIComponent(value);
-
-                if (key in hash)
-                {
-                    if (!Object.isArray(hash[key])) hash[key] = [hash[key]];
-                    hash[key].push(value);
-                }
-                else hash[key] = value;
-            }
-            return hash;
-        });
-    },
+  detect: function(iterator, context) {
+    iterator = iterator.bind(context);
+    var result;
+    this.each(function(value, index) {
+      if (iterator(value, index)) {
+        result = value;
+        throw $break;
+      }
+    });
+    return result;
+  },
 
-    toArray: function()
-    {
-        return this.split('');
-    },
+  findAll: function(iterator, context) {
+    iterator = iterator.bind(context);
+    var results = [];
+    this.each(function(value, index) {
+      if (iterator(value, index))
+        results.push(value);
+    });
+    return results;
+  },
 
-    succ: function()
-    {
-        return this.slice(0, this.length - 1) +
-               String.fromCharCode(this.charCodeAt(this.length - 1) + 1);
-    },
+  grep: function(filter, iterator, context) {
+    iterator = iterator ? iterator.bind(context) : Prototype.K;
+    var results = [];
+
+    if (Object.isString(filter))
+      filter = new RegExp(filter);
+
+    this.each(function(value, index) {
+      if (filter.match(value))
+        results.push(iterator(value, index));
+    });
+    return results;
+  },
 
-    times: function(count)
-    {
-        return count < 1 ? '' : new Array(count + 1).join(this);
-    },
+  include: function(object) {
+    if (Object.isFunction(this.indexOf))
+      if (this.indexOf(object) != -1) return true;
+
+    var found = false;
+    this.each(function(value) {
+      if (value == object) {
+        found = true;
+        throw $break;
+      }
+    });
+    return found;
+  },
 
-    camelize: function()
-    {
-        var parts = this.split('-'), len = parts.length;
-        if (len == 1) return parts[0];
+  inGroupsOf: function(number, fillWith) {
+    fillWith = Object.isUndefined(fillWith) ? null : fillWith;
+    return this.eachSlice(number, function(slice) {
+      while(slice.length < number) slice.push(fillWith);
+      return slice;
+    });
+  },
 
-        var camelized = this.charAt(0) == '-'
-                ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1)
-                : parts[0];
+  inject: function(memo, iterator, context) {
+    iterator = iterator.bind(context);
+    this.each(function(value, index) {
+      memo = iterator(memo, value, index);
+    });
+    return memo;
+  },
 
-        for (var i = 1; i < len; i++)
-            camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);
+  invoke: function(method) {
+    var args = $A(arguments).slice(1);
+    return this.map(function(value) {
+      return value[method].apply(value, args);
+    });
+  },
 
-        return camelized;
-    },
+  max: function(iterator, context) {
+    iterator = iterator ? iterator.bind(context) : Prototype.K;
+    var result;
+    this.each(function(value, index) {
+      value = iterator(value, index);
+      if (result == null || value >= result)
+        result = value;
+    });
+    return result;
+  },
 
-    capitalize: function()
-    {
-        return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
-    },
+  min: function(iterator, context) {
+    iterator = iterator ? iterator.bind(context) : Prototype.K;
+    var result;
+    this.each(function(value, index) {
+      value = iterator(value, index);
+      if (result == null || value < result)
+        result = value;
+    });
+    return result;
+  },
 
-    underscore: function()
-    {
-        return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/, '#{1}_#{2}').gsub(/([a-z\d])([A-Z])/, '#{1}_#{2}').gsub(/-/, '_').toLowerCase();
-    },
+  partition: function(iterator, context) {
+    iterator = iterator ? iterator.bind(context) : Prototype.K;
+    var trues = [], falses = [];
+    this.each(function(value, index) {
+      (iterator(value, index) ?
+        trues : falses).push(value);
+    });
+    return [trues, falses];
+  },
 
-    dasherize: function()
-    {
-        return this.gsub(/_/, '-');
-    },
+  pluck: function(property) {
+    var results = [];
+    this.each(function(value) {
+      results.push(value[property]);
+    });
+    return results;
+  },
 
-    inspect: function(useDoubleQuotes)
-    {
-        var escapedString = this.gsub(/[\x00-\x1f\\]/, function(match)
-        {
-            var character = String.specialChar[match[0]];
-            return character ? character : '\\u00' + match[0].charCodeAt().toPaddedString(2, 16);
-        });
-        if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"';
-        return "'" + escapedString.replace(/'/g, '\\\'') + "'";
-    },
+  reject: function(iterator, context) {
+    iterator = iterator.bind(context);
+    var results = [];
+    this.each(function(value, index) {
+      if (!iterator(value, index))
+        results.push(value);
+    });
+    return results;
+  },
 
-    toJSON: function()
-    {
-        return this.inspect(true);
-    },
+  sortBy: function(iterator, context) {
+    iterator = iterator.bind(context);
+    return this.map(function(value, index) {
+      return {value: value, criteria: iterator(value, index)};
+    }).sort(function(left, right) {
+      var a = left.criteria, b = right.criteria;
+      return a < b ? -1 : a > b ? 1 : 0;
+    }).pluck('value');
+  },
+
+  toArray: function() {
+    return this.map();
+  },
+
+  zip: function() {
+    var iterator = Prototype.K, args = $A(arguments);
+    if (Object.isFunction(args.last()))
+      iterator = args.pop();
+
+    var collections = [this].concat(args).map($A);
+    return this.map(function(value, index) {
+      return iterator(collections.pluck(index));
+    });
+  },
 
-    unfilterJSON: function(filter)
-    {
-        return this.sub(filter || Prototype.JSONFilter, '#{1}');
-    },
+  size: function() {
+    return this.toArray().length;
+  },
+
+  inspect: function() {
+    return '#<Enumerable:' + this.toArray().inspect() + '>';
+  }
+};
 
-    isJSON: function()
-    {
-        var str = this;
-        if (str.blank()) return false;
-        str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, '');
-        return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str);
-    },
+Object.extend(Enumerable, {
+  map:     Enumerable.collect,
+  find:    Enumerable.detect,
+  select:  Enumerable.findAll,
+  filter:  Enumerable.findAll,
+  member:  Enumerable.include,
+  entries: Enumerable.toArray,
+  every:   Enumerable.all,
+  some:    Enumerable.any
+});
+function $A(iterable) {
+  if (!iterable) return [];
+  if (iterable.toArray) return iterable.toArray();
+  var length = iterable.length || 0, results = new Array(length);
+  while (length--) results[length] = iterable[length];
+  return results;
+}
 
-    evalJSON: function(sanitize)
-    {
-        var json = this.unfilterJSON();
-        try
-        {
-            if (!sanitize || json.isJSON()) return eval('(' + json + ')');
-        }
-        catch (e)
-        {
-        }
-        throw new SyntaxError('Badly formed JSON string: ' + this.inspect());
-    },
+if (Prototype.Browser.WebKit) {
+  function $A(iterable) {
+    if (!iterable) return [];
+    if (!(Object.isFunction(iterable) && iterable == '[object NodeList]') &&
+        iterable.toArray) return iterable.toArray();
+    var length = iterable.length || 0, results = new Array(length);
+    while (length--) results[length] = iterable[length];
+    return results;
+  }
+}
 
-    include: function(pattern)
-    {
-        return this.indexOf(pattern) > -1;
-    },
+Array.from = $A;
 
-    startsWith: function(pattern)
-    {
-        return this.indexOf(pattern) === 0;
-    },
+Object.extend(Array.prototype, Enumerable);
 
-    endsWith: function(pattern)
-    {
-        var d = this.length - pattern.length;
-        return d >= 0 && this.lastIndexOf(pattern) === d;
-    },
+if (!Array.prototype._reverse) Array.prototype._reverse = Array.prototype.reverse;
 
-    empty: function()
-    {
-        return this == '';
-    },
+Object.extend(Array.prototype, {
+  _each: function(iterator) {
+    for (var i = 0, length = this.length; i < length; i++)
+      iterator(this[i]);
+  },
+
+  clear: function() {
+    this.length = 0;
+    return this;
+  },
+
+  first: function() {
+    return this[0];
+  },
+
+  last: function() {
+    return this[this.length - 1];
+  },
+
+  compact: function() {
+    return this.select(function(value) {
+      return value != null;
+    });
+  },
 
-    blank: function()
-    {
-        return /^\s*$/.test(this);
-    },
+  flatten: function() {
+    return this.inject([], function(array, value) {
+      return array.concat(Object.isArray(value) ?
+        value.flatten() : [value]);
+    });
+  },
 
-    interpolate: function(object, pattern)
-    {
-        return new Template(this, pattern).evaluate(object);
-    }
-});
+  without: function() {
+    var values = $A(arguments);
+    return this.select(function(value) {
+      return !values.include(value);
+    });
+  },
 
-if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, {
-    escapeHTML: function()
-    {
-        return this.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
-    },
-    unescapeHTML: function()
-    {
-        return this.replace(/&amp;/g, '&').replace(/&lt;/g, '<').replace(/&gt;/g, '>');
-    }
+  reverse: function(inline) {
+    return (inline !== false ? this : this.toArray())._reverse();
+  },
+
+  reduce: function() {
+    return this.length > 1 ? this : this[0];
+  },
+
+  uniq: function(sorted) {
+    return this.inject([], function(array, value, index) {
+      if (0 == index || (sorted ? array.last() != value : !array.include(value)))
+        array.push(value);
+      return array;
+    });
+  },
+
+  intersect: function(array) {
+    return this.uniq().findAll(function(item) {
+      return array.detect(function(value) { return item === value });
+    });
+  },
+
+  clone: function() {
+    return [].concat(this);
+  },
+
+  size: function() {
+    return this.length;
+  },
+
+  inspect: function() {
+    return '[' + this.map(Object.inspect).join(', ') + ']';
+  },
+
+  toJSON: function() {
+    var results = [];
+    this.each(function(object) {
+      var value = Object.toJSON(object);
+      if (!Object.isUndefined(value)) results.push(value);
+    });
+    return '[' + results.join(', ') + ']';
+  }
 });
 
-String.prototype.gsub.prepareReplacement = function(replacement)
-{
-    if (Object.isFunction(replacement)) return replacement;
-    var template = new Template(replacement);
-    return function(match)
-    {
-        return template.evaluate(match)
-    };
-};
+// use native browser JS 1.6 implementation if available
+if (Object.isFunction(Array.prototype.forEach))
+  Array.prototype._each = Array.prototype.forEach;
 
-String.prototype.parseQuery = String.prototype.toQueryParams;
+if (!Array.prototype.indexOf) Array.prototype.indexOf = function(item, i) {
+  i || (i = 0);
+  var length = this.length;
+  if (i < 0) i = length + i;
+  for (; i < length; i++)
+    if (this[i] === item) return i;
+  return -1;
+};
 
-Object.extend(String.prototype.escapeHTML, {
-    div:  document.createElement('div'),
-    text: document.createTextNode('')
-});
+if (!Array.prototype.lastIndexOf) Array.prototype.lastIndexOf = function(item, i) {
+  i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1;
+  var n = this.slice(0, i).reverse().indexOf(item);
+  return (n < 0) ? n : i - n - 1;
+};
 
-with (String.prototype.escapeHTML) div.appendChild(text);
+Array.prototype.toArray = Array.prototype.clone;
 
-var Template = Class.create({
-    initialize: function(template, pattern)
-    {
-        this.template = template.toString();
-        this.pattern = pattern || Template.Pattern;
-    },
-
-    evaluate: function(object)
-    {
-        if (Object.isFunction(object.toTemplateReplacements))
-            object = object.toTemplateReplacements();
-
-        return this.template.gsub(this.pattern, function(match)
-        {
-            if (object == null) return '';
-
-            var before = match[1] || '';
-            if (before == '\\') return match[2];
-
-            var ctx = object, expr = match[3];
-            var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/;
-            match = pattern.exec(expr);
-            if (match == null) return before;
-
-            while (match != null)
-            {
-                var comp = match[1].startsWith('[') ? match[2].gsub('\\\\]', ']') : match[1];
-                ctx = ctx[comp];
-                if (null == ctx || '' == match[3]) break;
-                expr = expr.substring('[' == match[3] ? match[1].length : match[0].length);
-                match = pattern.exec(expr);
-            }
+function $w(string) {
+  if (!Object.isString(string)) return [];
+  string = string.strip();
+  return string ? string.split(/\s+/) : [];
+}
 
-            return before + String.interpret(ctx);
-        }.bind(this));
+if (Prototype.Browser.Opera){
+  Array.prototype.concat = function() {
+    var array = [];
+    for (var i = 0, length = this.length; i < length; i++) array.push(this[i]);
+    for (var i = 0, length = arguments.length; i < length; i++) {
+      if (Object.isArray(arguments[i])) {
+        for (var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++)
+          array.push(arguments[i][j]);
+      } else {
+        array.push(arguments[i]);
+      }
     }
+    return array;
+  };
+}
+Object.extend(Number.prototype, {
+  toColorPart: function() {
+    return this.toPaddedString(2, 16);
+  },
+
+  succ: function() {
+    return this + 1;
+  },
+
+  times: function(iterator) {
+    $R(0, this, true).each(iterator);
+    return this;
+  },
+
+  toPaddedString: function(length, radix) {
+    var string = this.toString(radix || 10);
+    return '0'.times(length - string.length) + string;
+  },
+
+  toJSON: function() {
+    return isFinite(this) ? this.toString() : 'null';
+  }
 });
-Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
 
-var $break = { };
+$w('abs round ceil floor').each(function(method){
+  Number.prototype[method] = Math[method].methodize();
+});
+function $H(object) {
+  return new Hash(object);
+};
 
-var Enumerable = {
-    each: function(iterator, context)
-    {
-        var index = 0;
-        iterator = iterator.bind(context);
-        try
-        {
-            this._each(function(value)
-            {
-                iterator(value, index++);
-            });
-        }
-        catch (e)
-        {
-            if (e != $break) throw e;
-        }
-        return this;
-    },
+var Hash = Class.create(Enumerable, (function() {
 
-    eachSlice: function(number, iterator, context)
-    {
-        iterator = iterator ? iterator.bind(context) : Prototype.K;
-        var index = -number, slices = [], array = this.toArray();
-        while ((index += number) < array.length)
-            slices.push(array.slice(index, index + number));
-        return slices.collect(iterator, context);
-    },
-
-    all: function(iterator, context)
-    {
-        iterator = iterator ? iterator.bind(context) : Prototype.K;
-        var result = true;
-        this.each(function(value, index)
-        {
-            result = result && !!iterator(value, index);
-            if (!result) throw $break;
-        });
-        return result;
-    },
+  function toQueryPair(key, value) {
+    if (Object.isUndefined(value)) return key;
+    return key + '=' + encodeURIComponent(String.interpret(value));
+  }
 
-    any: function(iterator, context)
-    {
-        iterator = iterator ? iterator.bind(context) : Prototype.K;
-        var result = false;
-        this.each(function(value, index)
-        {
-            if (result = !!iterator(value, index))
-                throw $break;
-        });
-        return result;
+  return {
+    initialize: function(object) {
+      this._object = Object.isHash(object) ? object.toObject() : Object.clone(object);
     },
 
-    collect: function(iterator, context)
-    {
-        iterator = iterator ? iterator.bind(context) : Prototype.K;
-        var results = [];
-        this.each(function(value, index)
-        {
-            results.push(iterator(value, index));
-        });
-        return results;
+    _each: function(iterator) {
+      for (var key in this._object) {
+        var value = this._object[key], pair = [key, value];
+        pair.key = key;
+        pair.value = value;
+        iterator(pair);
+      }
     },
 
-    detect: function(iterator, context)
-    {
-        iterator = iterator.bind(context);
-        var result;
-        this.each(function(value, index)
-        {
-            if (iterator(value, index))
-            {
-                result = value;
-                throw $break;
-            }
-        });
-        return result;
+    set: function(key, value) {
+      return this._object[key] = value;
     },
 
-    findAll: function(iterator, context)
-    {
-        iterator = iterator.bind(context);
-        var results = [];
-        this.each(function(value, index)
-        {
-            if (iterator(value, index))
-                results.push(value);
-        });
-        return results;
+    get: function(key) {
+      return this._object[key];
     },
 
-    grep: function(filter, iterator, context)
-    {
-        iterator = iterator ? iterator.bind(context) : Prototype.K;
-        var results = [];
-
-        if (Object.isString(filter))
-            filter = new RegExp(filter);
-
-        this.each(function(value, index)
-        {
-            if (filter.match(value))
-                results.push(iterator(value, index));
-        });
-        return results;
+    unset: function(key) {
+      var value = this._object[key];
+      delete this._object[key];
+      return value;
     },
 
-    include: function(object)
-    {
-        if (Object.isFunction(this.indexOf))
-            if (this.indexOf(object) != -1) return true;
-
-        var found = false;
-        this.each(function(value)
-        {
-            if (value == object)
-            {
-                found = true;
-                throw $break;
-            }
-        });
-        return found;
+    toObject: function() {
+      return Object.clone(this._object);
     },
 
-    inGroupsOf: function(number, fillWith)
-    {
-        fillWith = Object.isUndefined(fillWith) ? null : fillWith;
-        return this.eachSlice(number, function(slice)
-        {
-            while (slice.length < number) slice.push(fillWith);
-            return slice;
-        });
+    keys: function() {
+      return this.pluck('key');
     },
 
-    inject: function(memo, iterator, context)
-    {
-        iterator = iterator.bind(context);
-        this.each(function(value, index)
-        {
-            memo = iterator(memo, value, index);
-        });
-        return memo;
+    values: function() {
+      return this.pluck('value');
     },
 
-    invoke: function(method)
-    {
-        var args = $A(arguments).slice(1);
-        return this.map(function(value)
-        {
-            return value[method].apply(value, args);
-        });
+    index: function(value) {
+      var match = this.detect(function(pair) {
+        return pair.value === value;
+      });
+      return match && match.key;
     },
 
-    max: function(iterator, context)
-    {
-        iterator = iterator ? iterator.bind(context) : Prototype.K;
-        var result;
-        this.each(function(value, index)
-        {
-            value = iterator(value, index);
-            if (result == null || value >= result)
-                result = value;
-        });
-        return result;
+    merge: function(object) {
+      return this.clone().update(object);
     },
 
-    min: function(iterator, context)
-    {
-        iterator = iterator ? iterator.bind(context) : Prototype.K;
-        var result;
-        this.each(function(value, index)
-        {
-            value = iterator(value, index);
-            if (result == null || value < result)
-                result = value;
-        });
+    update: function(object) {
+      return new Hash(object).inject(this, function(result, pair) {
+        result.set(pair.key, pair.value);
         return result;
+      });
     },
 
-    partition: function(iterator, context)
-    {
-        iterator = iterator ? iterator.bind(context) : Prototype.K;
-        var trues = [], falses = [];
-        this.each(function(value, index)
-        {
-            (iterator(value, index) ?
-             trues : falses).push(value);
-        });
-        return [trues, falses];
-    },
-
-    pluck: function(property)
-    {
-        var results = [];
-        this.each(function(value)
-        {
-            results.push(value[property]);
-        });
-        return results;
-    },
+    toQueryString: function() {
+      return this.map(function(pair) {
+        var key = encodeURIComponent(pair.key), values = pair.value;
 
-    reject: function(iterator, context)
-    {
-        iterator = iterator.bind(context);
-        var results = [];
-        this.each(function(value, index)
-        {
-            if (!iterator(value, index))
-                results.push(value);
-        });
-        return results;
+        if (values && typeof values == 'object') {
+          if (Object.isArray(values))
+            return values.map(toQueryPair.curry(key)).join('&');
+        }
+        return toQueryPair(key, values);
+      }).join('&');
     },
 
-    sortBy: function(iterator, context)
-    {
-        iterator = iterator.bind(context);
-        return this.map(function(value, index)
-        {
-            return {value: value, criteria: iterator(value, index)};
-        }).sort(function(left, right)
-        {
-            var a = left.criteria, b = right.criteria;
-            return a < b ? -1 : a > b ? 1 : 0;
-        }).pluck('value');
-    },
-
-    toArray: function()
-    {
-        return this.map();
-    },
-
-    zip: function()
-    {
-        var iterator = Prototype.K, args = $A(arguments);
-        if (Object.isFunction(args.last()))
-            iterator = args.pop();
-
-        var collections = [this].concat(args).map($A);
-        return this.map(function(value, index)
-        {
-            return iterator(collections.pluck(index));
-        });
+    inspect: function() {
+      return '#<Hash:{' + this.map(function(pair) {
+        return pair.map(Object.inspect).join(': ');
+      }).join(', ') + '}>';
     },
 
-    size: function()
-    {
-        return this.toArray().length;
+    toJSON: function() {
+      return Object.toJSON(this.toObject());
     },
 
-    inspect: function()
-    {
-        return '#<Enumerable:' + this.toArray().inspect() + '>';
+    clone: function() {
+      return new Hash(this);
     }
-};
+  }
+})());
 
-Object.extend(Enumerable, {
-    map:     Enumerable.collect,
-    find:    Enumerable.detect,
-    select:  Enumerable.findAll,
-    filter:  Enumerable.findAll,
-    member:  Enumerable.include,
-    entries: Enumerable.toArray,
-    every:   Enumerable.all,
-    some:    Enumerable.any
-});
-function $A(iterable)
-{
-    if (!iterable) return [];
-    if (iterable.toArray) return iterable.toArray();
-    var length = iterable.length || 0, results = new Array(length);
-    while (length--) results[length] = iterable[length];
-    return results;
-}
-
-if (Prototype.Browser.WebKit)
-{
-    function $A(iterable)
-    {
-        if (!iterable) return [];
-        if (!(Object.isFunction(iterable) && iterable == '[object NodeList]') &&
-            iterable.toArray) return iterable.toArray();
-        var length = iterable.length || 0, results = new Array(length);
-        while (length--) results[length] = iterable[length];
-        return results;
-    }
-}
+Hash.prototype.toTemplateReplacements = Hash.prototype.toObject;
+Hash.from = $H;
+var ObjectRange = Class.create(Enumerable, {
+  initialize: function(start, end, exclusive) {
+    this.start = start;
+    this.end = end;
+    this.exclusive = exclusive;
+  },
+
+  _each: function(iterator) {
+    var value = this.start;
+    while (this.include(value)) {
+      iterator(value);
+      value = value.succ();
+    }
+  },
+
+  include: function(value) {
+    if (value < this.start)
+      return false;
+    if (this.exclusive)
+      return value < this.end;
+    return value <= this.end;
+  }
+});
 
-Array.from = $A;
+var $R = function(start, end, exclusive) {
+  return new ObjectRange(start, end, exclusive);
+};
 
-Object.extend(Array.prototype, Enumerable);
+var Ajax = {
+  getTransport: function() {
+    return Try.these(
+      function() {return new XMLHttpRequest()},
+      function() {return new ActiveXObject('Msxml2.XMLHTTP')},
+      function() {return new ActiveXObject('Microsoft.XMLHTTP')}
+    ) || false;
+  },
 
-if (!Array.prototype._reverse) Array.prototype._reverse = Array.prototype.reverse;
+  activeRequestCount: 0
+};
 
-Object.extend(Array.prototype, {
-    _each: function(iterator)
-    {
-        for (var i = 0, length = this.length; i < length; i++)
-            iterator(this[i]);
-    },
+Ajax.Responders = {
+  responders: [],
 
-    clear: function()
-    {
-        this.length = 0;
-        return this;
-    },
+  _each: function(iterator) {
+    this.responders._each(iterator);
+  },
+
+  register: function(responder) {
+    if (!this.include(responder))
+      this.responders.push(responder);
+  },
+
+  unregister: function(responder) {
+    this.responders = this.responders.without(responder);
+  },
+
+  dispatch: function(callback, request, transport, json) {
+    this.each(function(responder) {
+      if (Object.isFunction(responder[callback])) {
+        try {
+          responder[callback].apply(responder, [request, transport, json]);
+        } catch (e) { }
+      }
+    });
+  }
+};
 
-    first: function()
-    {
-        return this[0];
-    },
+Object.extend(Ajax.Responders, Enumerable);
 
-    last: function()
-    {
-        return this[this.length - 1];
-    },
+Ajax.Responders.register({
+  onCreate:   function() { Ajax.activeRequestCount++ },
+  onComplete: function() { Ajax.activeRequestCount-- }
+});
 
-    compact: function()
-    {
-        return this.select(function(value)
-        {
-            return value != null;
-        });
-    },
+Ajax.Base = Class.create({
+  initialize: function(options) {
+    this.options = {
+      method:       'post',
+      asynchronous: true,
+      contentType:  'application/x-www-form-urlencoded',
+      encoding:     'UTF-8',
+      parameters:   '',
+      evalJSON:     true,
+      evalJS:       true
+    };
+    Object.extend(this.options, options || { });
 
-    flatten: function()
-    {
-        return this.inject([], function(array, value)
-        {
-            return array.concat(Object.isArray(value) ?
-                                value.flatten() : [value]);
-        });
-    },
+    this.options.method = this.options.method.toLowerCase();
 
-    without: function()
-    {
-        var values = $A(arguments);
-        return this.select(function(value)
-        {
-            return !values.include(value);
-        });
-    },
+    if (Object.isString(this.options.parameters))
+      this.options.parameters = this.options.parameters.toQueryParams();
+    else if (Object.isHash(this.options.parameters))
+      this.options.parameters = this.options.parameters.toObject();
+  }
+});
 
-    reverse: function(inline)
-    {
-        return (inline !== false ? this : this.toArray())._reverse();
-    },
-
-    reduce: function()
-    {
-        return this.length > 1 ? this : this[0];
-    },
-
-    uniq: function(sorted)
-    {
-        return this.inject([], function(array, value, index)
-        {
-            if (0 == index || (sorted ? array.last() != value : !array.include(value)))
-                array.push(value);
-            return array;
-        });
-    },
+Ajax.Request = Class.create(Ajax.Base, {
+  _complete: false,
 
-    intersect: function(array)
-    {
-        return this.uniq().findAll(function(item)
-        {
-            return array.detect(function(value)
-            {
-                return item === value
-            });
-        });
-    },
+  initialize: function($super, url, options) {
+    $super(options);
+    this.transport = Ajax.getTransport();
+    this.request(url);
+  },
 
-    clone: function()
-    {
-        return [].concat(this);
-    },
+  request: function(url) {
+    this.url = url;
+    this.method = this.options.method;
+    var params = Object.clone(this.options.parameters);
 
-    size: function()
-    {
-        return this.length;
-    },
+    if (!['get', 'post'].include(this.method)) {
+      // simulate other verbs over post
+      params['_method'] = this.method;
+      this.method = 'post';
+    }
 
-    inspect: function()
-    {
-        return '[' + this.map(Object.inspect).join(', ') + ']';
-    },
+    this.parameters = params;
 
-    toJSON: function()
-    {
-        var results = [];
-        this.each(function(object)
-        {
-            var value = Object.toJSON(object);
-            if (!Object.isUndefined(value)) results.push(value);
-        });
-        return '[' + results.join(', ') + ']';
+    if (params = Object.toQueryString(params)) {
+      // when GET, append parameters to URL
+      if (this.method == 'get')
+        this.url += (this.url.include('?') ? '&' : '?') + params;
+      else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent))
+        params += '&_=';
     }
-});
 
-// use native browser JS 1.6 implementation if available
-if (Object.isFunction(Array.prototype.forEach))
-    Array.prototype._each = Array.prototype.forEach;
+    try {
+      var response = new Ajax.Response(this);
+      if (this.options.onCreate) this.options.onCreate(response);
+      Ajax.Responders.dispatch('onCreate', this, response);
 
-if (!Array.prototype.indexOf) Array.prototype.indexOf = function(item, i)
-{
-    i || (i = 0);
-    var length = this.length;
-    if (i < 0) i = length + i;
-    for (; i < length; i++)
-        if (this[i] === item) return i;
-    return -1;
-};
+      this.transport.open(this.method.toUpperCase(), this.url,
+        this.options.asynchronous);
 
-if (!Array.prototype.lastIndexOf) Array.prototype.lastIndexOf = function(item, i)
-{
-    i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1;
-    var n = this.slice(0, i).reverse().indexOf(item);
-    return (n < 0) ? n : i - n - 1;
-};
+      if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1);
 
-Array.prototype.toArray = Array.prototype.clone;
+      this.transport.onreadystatechange = this.onStateChange.bind(this);
+      this.setRequestHeaders();
 
-function $w(string)
-{
-    if (!Object.isString(string)) return [];
-    string = string.strip();
-    return string ? string.split(/\s+/) : [];
-}
+      this.body = this.method == 'post' ? (this.options.postBody || params) : null;
+      this.transport.send(this.body);
 
-if (Prototype.Browser.Opera)
-{
-    Array.prototype.concat = function()
-    {
-        var array = [];
-        for (var i = 0, length = this.length; i < length; i++) array.push(this[i]);
-        for (var i = 0, length = arguments.length; i < length; i++)
-        {
-            if (Object.isArray(arguments[i]))
-            {
-                for (var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++)
-                    array.push(arguments[i][j]);
-            }
-            else
-            {
-                array.push(arguments[i]);
-            }
-        }
-        return array;
-    };
-}
-Object.extend(Number.prototype, {
-    toColorPart: function()
-    {
-        return this.toPaddedString(2, 16);
-    },
+      /* Force Firefox to handle ready state 4 for synchronous requests */
+      if (!this.options.asynchronous && this.transport.overrideMimeType)
+        this.onStateChange();
 
-    succ: function()
-    {
-        return this + 1;
-    },
+    }
+    catch (e) {
+      this.dispatchException(e);
+    }
+  },
 
-    times: function(iterator)
-    {
-        $R(0, this, true).each(iterator);
-        return this;
-    },
+  onStateChange: function() {
+    var readyState = this.transport.readyState;
+    if (readyState > 1 && !((readyState == 4) && this._complete))
+      this.respondToReadyState(this.transport.readyState);
+  },
 
-    toPaddedString: function(length, radix)
-    {
-        var string = this.toString(radix || 10);
-        return '0'.times(length - string.length) + string;
-    },
+  setRequestHeaders: function() {
+    var headers = {
+      'X-Requested-With': 'XMLHttpRequest',
+      'X-Prototype-Version': Prototype.Version,
+      'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
+    };
 
-    toJSON: function()
-    {
-        return isFinite(this) ? this.toString() : 'null';
+    if (this.method == 'post') {
+      headers['Content-type'] = this.options.contentType +
+        (this.options.encoding ? '; charset=' + this.options.encoding : '');
+
+      /* Force "Connection: close" for older Mozilla browsers to work
+       * around a bug where XMLHttpRequest sends an incorrect
+       * Content-length header. See Mozilla Bugzilla #246651.
+       */
+      if (this.transport.overrideMimeType &&
+          (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005)
+            headers['Connection'] = 'close';
     }
-});
 
-$w('abs round ceil floor').each(function(method)
-{
-    Number.prototype[method] = Math[method].methodize();
+    // user-defined headers
+    if (typeof this.options.requestHeaders == 'object') {
+      var extras = this.options.requestHeaders;
+
+      if (Object.isFunction(extras.push))
+        for (var i = 0, length = extras.length; i < length; i += 2)
+          headers[extras[i]] = extras[i+1];
+      else
+        $H(extras).each(function(pair) { headers[pair.key] = pair.value });
+    }
+
+    for (var name in headers)
+      this.transport.setRequestHeader(name, headers[name]);
+  },
+
+  success: function() {
+    var status = this.getStatus();
+    return !status || (status >= 200 && status < 300);
+  },
+
+  getStatus: function() {
+    try {
+      return this.transport.status || 0;
+    } catch (e) { return 0 }
+  },
+
+  respondToReadyState: function(readyState) {
+    var state = Ajax.Request.Events[readyState], response = new Ajax.Response(this);
+
+    if (state == 'Complete') {
+      try {
+        this._complete = true;
+        (this.options['on' + response.status]
+         || this.options['on' + (this.success() ? 'Success' : 'Failure')]
+         || Prototype.emptyFunction)(response, response.headerJSON);
+      } catch (e) {
+        this.dispatchException(e);
+      }
+
+      var contentType = response.getHeader('Content-type');
+      if (this.options.evalJS == 'force'
+          || (this.options.evalJS && contentType
+          && contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i)))
+        this.evalResponse();
+    }
+
+    try {
+      (this.options['on' + state] || Prototype.emptyFunction)(response, response.headerJSON);
+      Ajax.Responders.dispatch('on' + state, this, response, response.headerJSON);
+    } catch (e) {
+      this.dispatchException(e);
+    }
+
+    if (state == 'Complete') {
+      // avoid memory leak in MSIE: clean up
+      this.transport.onreadystatechange = Prototype.emptyFunction;
+    }
+  },
+
+  getHeader: function(name) {
+    try {
+      return this.transport.getResponseHeader(name) || null;
+    } catch (e) { return null }
+  },
+
+  evalResponse: function() {
+    try {
+      return eval((this.transport.responseText || '').unfilterJSON());
+    } catch (e) {
+      this.dispatchException(e);
+    }
+  },
+
+  dispatchException: function(exception) {
+    (this.options.onException || Prototype.emptyFunction)(this, exception);
+    Ajax.Responders.dispatch('onException', this, exception);
+  }
 });
-function $H(object)
-{
-    return new Hash(object);
-}
-;
 
-var Hash = Class.create(Enumerable, (function()
-{
+Ajax.Request.Events =
+  ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
 
-    function toQueryPair(key, value)
-    {
-        if (Object.isUndefined(value)) return key;
-        return key + '=' + encodeURIComponent(String.interpret(value));
+Ajax.Response = Class.create({
+  initialize: function(request){
+    this.request = request;
+    var transport  = this.transport  = request.transport,
+        readyState = this.readyState = transport.readyState;
+
+    if((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) {
+      this.status       = this.getStatus();
+      this.statusText   = this.getStatusText();
+      this.responseText = String.interpret(transport.responseText);
+      this.headerJSON   = this._getHeaderJSON();
+    }
+
+    if(readyState == 4) {
+      var xml = transport.responseXML;
+      this.responseXML  = Object.isUndefined(xml) ? null : xml;
+      this.responseJSON = this._getResponseJSON();
+    }
+  },
+
+  status:      0,
+  statusText: '',
+
+  getStatus: Ajax.Request.prototype.getStatus,
+
+  getStatusText: function() {
+    try {
+      return this.transport.statusText || '';
+    } catch (e) { return '' }
+  },
+
+  getHeader: Ajax.Request.prototype.getHeader,
+
+  getAllHeaders: function() {
+    try {
+      return this.getAllResponseHeaders();
+    } catch (e) { return null }
+  },
+
+  getResponseHeader: function(name) {
+    return this.transport.getResponseHeader(name);
+  },
+
+  getAllResponseHeaders: function() {
+    return this.transport.getAllResponseHeaders();
+  },
+
+  _getHeaderJSON: function() {
+    var json = this.getHeader('X-JSON');
+    if (!json) return null;
+    json = decodeURIComponent(escape(json));
+    try {
+      return json.evalJSON(this.request.options.sanitizeJSON);
+    } catch (e) {
+      this.request.dispatchException(e);
+    }
+  },
+
+  _getResponseJSON: function() {
+    var options = this.request.options;
+    if (!options.evalJSON || (options.evalJSON != 'force' &&
+      !(this.getHeader('Content-type') || '').include('application/json')) ||
+        this.responseText.blank())
+          return null;
+    try {
+      return this.responseText.evalJSON(options.sanitizeJSON);
+    } catch (e) {
+      this.request.dispatchException(e);
     }
+  }
+});
 
-    return {
-        initialize: function(object)
-        {
-            this._object = Object.isHash(object) ? object.toObject() : Object.clone(object);
-        },
-
-        _each: function(iterator)
-        {
-            for (var key in this._object)
-            {
-                var value = this._object[key], pair = [key, value];
-                pair.key = key;
-                pair.value = value;
-                iterator(pair);
-            }
-        },
-
-        set: function(key, value)
-        {
-            return this._object[key] = value;
-        },
+Ajax.Updater = Class.create(Ajax.Request, {
+  initialize: function($super, container, url, options) {
+    this.container = {
+      success: (container.success || container),
+      failure: (container.failure || (container.success ? null : container))
+    };
 
-        get: function(key)
-        {
-            return this._object[key];
-        },
+    options = Object.clone(options);
+    var onComplete = options.onComplete;
+    options.onComplete = (function(response, json) {
+      this.updateContent(response.responseText);
+      if (Object.isFunction(onComplete)) onComplete(response, json);
+    }).bind(this);
+
+    $super(url, options);
+  },
+
+  updateContent: function(responseText) {
+    var receiver = this.container[this.success() ? 'success' : 'failure'],
+        options = this.options;
+
+    if (!options.evalScripts) responseText = responseText.stripScripts();
+
+    if (receiver = $(receiver)) {
+      if (options.insertion) {
+        if (Object.isString(options.insertion)) {
+          var insertion = { }; insertion[options.insertion] = responseText;
+          receiver.insert(insertion);
+        }
+        else options.insertion(receiver, responseText);
+      }
+      else receiver.update(responseText);
+    }
+  }
+});
 
-        unset: function(key)
-        {
-            var value = this._object[key];
-            delete this._object[key];
-            return value;
-        },
+Ajax.PeriodicalUpdater = Class.create(Ajax.Base, {
+  initialize: function($super, container, url, options) {
+    $super(options);
+    this.onComplete = this.options.onComplete;
+
+    this.frequency = (this.options.frequency || 2);
+    this.decay = (this.options.decay || 1);
+
+    this.updater = { };
+    this.container = container;
+    this.url = url;
+
+    this.start();
+  },
+
+  start: function() {
+    this.options.onComplete = this.updateComplete.bind(this);
+    this.onTimerEvent();
+  },
+
+  stop: function() {
+    this.updater.options.onComplete = undefined;
+    clearTimeout(this.timer);
+    (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
+  },
+
+  updateComplete: function(response) {
+    if (this.options.decay) {
+      this.decay = (response.responseText == this.lastText ?
+        this.decay * this.options.decay : 1);
+
+      this.lastText = response.responseText;
+    }
+    this.timer = this.onTimerEvent.bind(this).delay(this.decay * this.frequency);
+  },
+
+  onTimerEvent: function() {
+    this.updater = new Ajax.Updater(this.container, this.url, this.options);
+  }
+});
+function $(element) {
+  if (arguments.length > 1) {
+    for (var i = 0, elements = [], length = arguments.length; i < length; i++)
+      elements.push($(arguments[i]));
+    return elements;
+  }
+  if (Object.isString(element))
+    element = document.getElementById(element);
+  return Element.extend(element);
+}
 
-        toObject: function()
-        {
-            return Object.clone(this._object);
-        },
+if (Prototype.BrowserFeatures.XPath) {
+  document._getElementsByXPath = function(expression, parentElement) {
+    var results = [];
+    var query = document.evaluate(expression, $(parentElement) || document,
+      null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
+    for (var i = 0, length = query.snapshotLength; i < length; i++)
+      results.push(Element.extend(query.snapshotItem(i)));
+    return results;
+  };
+}
 
-        keys: function()
-        {
-            return this.pluck('key');
-        },
+/*--------------------------------------------------------------------------*/
 
-        values: function()
-        {
-            return this.pluck('value');
-        },
+if (!window.Node) var Node = { };
 
-        index: function(value)
-        {
-            var match = this.detect(function(pair)
-            {
-                return pair.value === value;
-            });
-            return match && match.key;
-        },
+if (!Node.ELEMENT_NODE) {
+  // DOM level 2 ECMAScript Language Binding
+  Object.extend(Node, {
+    ELEMENT_NODE: 1,
+    ATTRIBUTE_NODE: 2,
+    TEXT_NODE: 3,
+    CDATA_SECTION_NODE: 4,
+    ENTITY_REFERENCE_NODE: 5,
+    ENTITY_NODE: 6,
+    PROCESSING_INSTRUCTION_NODE: 7,
+    COMMENT_NODE: 8,
+    DOCUMENT_NODE: 9,
+    DOCUMENT_TYPE_NODE: 10,
+    DOCUMENT_FRAGMENT_NODE: 11,
+    NOTATION_NODE: 12
+  });
+}
 
-        merge: function(object)
-        {
-            return this.clone().update(object);
-        },
+(function() {
+  var element = this.Element;
+  this.Element = function(tagName, attributes) {
+    attributes = attributes || { };
+    tagName = tagName.toLowerCase();
+    var cache = Element.cache;
+    if (Prototype.Browser.IE && attributes.name) {
+      tagName = '<' + tagName + ' name="' + attributes.name + '">';
+      delete attributes.name;
+      return Element.writeAttribute(document.createElement(tagName), attributes);
+    }
+    if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName));
+    return Element.writeAttribute(cache[tagName].cloneNode(false), attributes);
+  };
+  Object.extend(this.Element, element || { });
+}).call(window);
 
-        update: function(object)
-        {
-            return new Hash(object).inject(this, function(result, pair)
-            {
-                result.set(pair.key, pair.value);
-                return result;
-            });
-        },
+Element.cache = { };
 
-        toQueryString: function()
-        {
-            return this.map(function(pair)
-            {
-                var key = encodeURIComponent(pair.key), values = pair.value;
-
-                if (values && typeof values == 'object')
-                {
-                    if (Object.isArray(values))
-                        return values.map(toQueryPair.curry(key)).join('&');
-                }
-                return toQueryPair(key, values);
-            }).join('&');
-        },
+Element.Methods = {
+  visible: function(element) {
+    return $(element).style.display != 'none';
+  },
+
+  toggle: function(element) {
+    element = $(element);
+    Element[Element.visible(element) ? 'hide' : 'show'](element);
+    return element;
+  },
+
+  hide: function(element) {
+    $(element).style.display = 'none';
+    return element;
+  },
+
+  show: function(element) {
+    $(element).style.display = '';
+    return element;
+  },
+
+  remove: function(element) {
+    element = $(element);
+    element.parentNode.removeChild(element);
+    return element;
+  },
+
+  update: function(element, content) {
+    element = $(element);
+    if (content && content.toElement) content = content.toElement();
+    if (Object.isElement(content)) return element.update().insert(content);
+    content = Object.toHTML(content);
+    element.innerHTML = content.stripScripts();
+    content.evalScripts.bind(content).defer();
+    return element;
+  },
+
+  replace: function(element, content) {
+    element = $(element);
+    if (content && content.toElement) content = content.toElement();
+    else if (!Object.isElement(content)) {
+      content = Object.toHTML(content);
+      var range = element.ownerDocument.createRange();
+      range.selectNode(element);
+      content.evalScripts.bind(content).defer();
+      content = range.createContextualFragment(content.stripScripts());
+    }
+    element.parentNode.replaceChild(content, element);
+    return element;
+  },
+
+  insert: function(element, insertions) {
+    element = $(element);
+
+    if (Object.isString(insertions) || Object.isNumber(insertions) ||
+        Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML)))
+          insertions = {bottom:insertions};
+
+    var content, insert, tagName, childNodes;
+
+    for (position in insertions) {
+      content  = insertions[position];
+      position = position.toLowerCase();
+      insert = Element._insertionTranslations[position];
+
+      if (content && content.toElement) content = content.toElement();
+      if (Object.isElement(content)) {
+        insert(element, content);
+        continue;
+      }
+
+      content = Object.toHTML(content);
+
+      tagName = ((position == 'before' || position == 'after')
+        ? element.parentNode : element).tagName.toUpperCase();
+
+      childNodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
+
+      if (position == 'top' || position == 'after') childNodes.reverse();
+      childNodes.each(insert.curry(element));
+
+      content.evalScripts.bind(content).defer();
+    }
+
+    return element;
+  },
+
+  wrap: function(element, wrapper, attributes) {
+    element = $(element);
+    if (Object.isElement(wrapper))
+      $(wrapper).writeAttribute(attributes || { });
+    else if (Object.isString(wrapper)) wrapper = new Element(wrapper, attributes);
+    else wrapper = new Element('div', wrapper);
+    if (element.parentNode)
+      element.parentNode.replaceChild(wrapper, element);
+    wrapper.appendChild(element);
+    return wrapper;
+  },
+
+  inspect: function(element) {
+    element = $(element);
+    var result = '<' + element.tagName.toLowerCase();
+    $H({'id': 'id', 'className': 'class'}).each(function(pair) {
+      var property = pair.first(), attribute = pair.last();
+      var value = (element[property] || '').toString();
+      if (value) result += ' ' + attribute + '=' + value.inspect(true);
+    });
+    return result + '>';
+  },
 
-        inspect: function()
-        {
-            return '#<Hash:{' + this.map(function(pair)
-            {
-                return pair.map(Object.inspect).join(': ');
-            }).join(', ') + '}>';
-        },
+  recursivelyCollect: function(element, property) {
+    element = $(element);
+    var elements = [];
+    while (element = element[property])
+      if (element.nodeType == 1)
+        elements.push(Element.extend(element));
+    return elements;
+  },
+
+  ancestors: function(element) {
+    return $(element).recursivelyCollect('parentNode');
+  },
+
+  descendants: function(element) {
+    return $(element).getElementsBySelector("*");
+  },
+
+  firstDescendant: function(element) {
+    element = $(element).firstChild;
+    while (element && element.nodeType != 1) element = element.nextSibling;
+    return $(element);
+  },
+
+  immediateDescendants: function(element) {
+    if (!(element = $(element).firstChild)) return [];
+    while (element && element.nodeType != 1) element = element.nextSibling;
+    if (element) return [element].concat($(element).nextSiblings());
+    return [];
+  },
+
+  previousSiblings: function(element) {
+    return $(element).recursivelyCollect('previousSibling');
+  },
+
+  nextSiblings: function(element) {
+    return $(element).recursivelyCollect('nextSibling');
+  },
+
+  siblings: function(element) {
+    element = $(element);
+    return element.previousSiblings().reverse().concat(element.nextSiblings());
+  },
+
+  match: function(element, selector) {
+    if (Object.isString(selector))
+      selector = new Selector(selector);
+    return selector.match($(element));
+  },
+
+  up: function(element, expression, index) {
+    element = $(element);
+    if (arguments.length == 1) return $(element.parentNode);
+    var ancestors = element.ancestors();
+    return Object.isNumber(expression) ? ancestors[expression] :
+      Selector.findElement(ancestors, expression, index);
+  },
+
+  down: function(element, expression, index) {
+    element = $(element);
+    if (arguments.length == 1) return element.firstDescendant();
+    return Object.isNumber(expression) ? element.descendants()[expression] :
+      element.select(expression)[index || 0];
+  },
+
+  previous: function(element, expression, index) {
+    element = $(element);
+    if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element));
+    var previousSiblings = element.previousSiblings();
+    return Object.isNumber(expression) ? previousSiblings[expression] :
+      Selector.findElement(previousSiblings, expression, index);
+  },
+
+  next: function(element, expression, index) {
+    element = $(element);
+    if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element));
+    var nextSiblings = element.nextSiblings();
+    return Object.isNumber(expression) ? nextSiblings[expression] :
+      Selector.findElement(nextSiblings, expression, index);
+  },
+
+  select: function() {
+    var args = $A(arguments), element = $(args.shift());
+    return Selector.findChildElements(element, args);
+  },
+
+  adjacent: function() {
+    var args = $A(arguments), element = $(args.shift());
+    return Selector.findChildElements(element.parentNode, args).without(element);
+  },
+
+  identify: function(element) {
+    element = $(element);
+    var id = element.readAttribute('id'), self = arguments.callee;
+    if (id) return id;
+    do { id = 'anonymous_element_' + self.counter++ } while ($(id));
+    element.writeAttribute('id', id);
+    return id;
+  },
+
+  readAttribute: function(element, name) {
+    element = $(element);
+    if (Prototype.Browser.IE) {
+      var t = Element._attributeTranslations.read;
+      if (t.values[name]) return t.values[name](element, name);
+      if (t.names[name]) name = t.names[name];
+      if (name.include(':')) {
+        return (!element.attributes || !element.attributes[name]) ? null :
+         element.attributes[name].value;
+      }
+    }
+    return element.getAttribute(name);
+  },
+
+  writeAttribute: function(element, name, value) {
+    element = $(element);
+    var attributes = { }, t = Element._attributeTranslations.write;
+
+    if (typeof name == 'object') attributes = name;
+    else attributes[name] = Object.isUndefined(value) ? true : value;
+
+    for (var attr in attributes) {
+      name = t.names[attr] || attr;
+      value = attributes[attr];
+      if (t.values[attr]) name = t.values[attr](element, value);
+      if (value === false || value === null)
+        element.removeAttribute(name);
+      else if (value === true)
+        element.setAttribute(name, name);
+      else element.setAttribute(name, value);
+    }
+    return element;
+  },
+
+  getHeight: function(element) {
+    return $(element).getDimensions().height;
+  },
+
+  getWidth: function(element) {
+    return $(element).getDimensions().width;
+  },
+
+  classNames: function(element) {
+    return new Element.ClassNames(element);
+  },
+
+  hasClassName: function(element, className) {
+    if (!(element = $(element))) return;
+    var elementClassName = element.className;
+    return (elementClassName.length > 0 && (elementClassName == className ||
+      new RegExp("(^|\\s)" + className + "(\\s|$)").test(elementClassName)));
+  },
+
+  addClassName: function(element, className) {
+    if (!(element = $(element))) return;
+    if (!element.hasClassName(className))
+      element.className += (element.className ? ' ' : '') + className;
+    return element;
+  },
+
+  removeClassName: function(element, className) {
+    if (!(element = $(element))) return;
+    element.className = element.className.replace(
+      new RegExp("(^|\\s+)" + className + "(\\s+|$)"), ' ').strip();
+    return element;
+  },
+
+  toggleClassName: function(element, className) {
+    if (!(element = $(element))) return;
+    return element[element.hasClassName(className) ?
+      'removeClassName' : 'addClassName'](className);
+  },
+
+  // removes whitespace-only text node children
+  cleanWhitespace: function(element) {
+    element = $(element);
+    var node = element.firstChild;
+    while (node) {
+      var nextNode = node.nextSibling;
+      if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
+        element.removeChild(node);
+      node = nextNode;
+    }
+    return element;
+  },
+
+  empty: function(element) {
+    return $(element).innerHTML.blank();
+  },
+
+  descendantOf: function(element, ancestor) {
+    element = $(element), ancestor = $(ancestor);
+    var originalAncestor = ancestor;
+
+    if (element.compareDocumentPosition)
+      return (element.compareDocumentPosition(ancestor) & 8) === 8;
+
+    if (element.sourceIndex && !Prototype.Browser.Opera) {
+      var e = element.sourceIndex, a = ancestor.sourceIndex,
+       nextAncestor = ancestor.nextSibling;
+      if (!nextAncestor) {
+        do { ancestor = ancestor.parentNode; }
+        while (!(nextAncestor = ancestor.nextSibling) && ancestor.parentNode);
+      }
+      if (nextAncestor) return (e > a && e < nextAncestor.sourceIndex);
+    }
+
+    while (element = element.parentNode)
+      if (element == originalAncestor) return true;
+    return false;
+  },
+
+  scrollTo: function(element) {
+    element = $(element);
+    var pos = element.cumulativeOffset();
+    window.scrollTo(pos[0], pos[1]);
+    return element;
+  },
+
+  getStyle: function(element, style) {
+    element = $(element);
+    style = style == 'float' ? 'cssFloat' : style.camelize();
+    var value = element.style[style];
+    if (!value) {
+      var css = document.defaultView.getComputedStyle(element, null);
+      value = css ? css[style] : null;
+    }
+    if (style == 'opacity') return value ? parseFloat(value) : 1.0;
+    return value == 'auto' ? null : value;
+  },
+
+  getOpacity: function(element) {
+    return $(element).getStyle('opacity');
+  },
+
+  setStyle: function(element, styles) {
+    element = $(element);
+    var elementStyle = element.style, match;
+    if (Object.isString(styles)) {
+      element.style.cssText += ';' + styles;
+      return styles.include('opacity') ?
+        element.setOpacity(styles.match(/opacity:\s*(\d?\.?\d*)/)[1]) : element;
+    }
+    for (var property in styles)
+      if (property == 'opacity') element.setOpacity(styles[property]);
+      else
+        elementStyle[(property == 'float' || property == 'cssFloat') ?
+          (Object.isUndefined(elementStyle.styleFloat) ? 'cssFloat' : 'styleFloat') :
+            property] = styles[property];
+
+    return element;
+  },
+
+  setOpacity: function(element, value) {
+    element = $(element);
+    element.style.opacity = (value == 1 || value === '') ? '' :
+      (value < 0.00001) ? 0 : value;
+    return element;
+  },
+
+  getDimensions: function(element) {
+    element = $(element);
+    var display = $(element).getStyle('display');
+    if (display != 'none' && display != null) // Safari bug
+      return {width: element.offsetWidth, height: element.offsetHeight};
 
-        toJSON: function()
-        {
-            return Object.toJSON(this.toObject());
-        },
+    // All *Width and *Height properties give 0 on elements with display none,
+    // so enable the element temporarily
+    var els = element.style;
+    var originalVisibility = els.visibility;
+    var originalPosition = els.position;
+    var originalDisplay = els.display;
+    els.visibility = 'hidden';
+    els.position = 'absolute';
+    els.display = 'block';
+    var originalWidth = element.clientWidth;
+    var originalHeight = element.clientHeight;
+    els.display = originalDisplay;
+    els.position = originalPosition;
+    els.visibility = originalVisibility;
+    return {width: originalWidth, height: originalHeight};
+  },
+

[... 5715 lines stripped ...]