var Prototype = {
  Version: '1.6.1',

  Browser: (function(){
    var ua = navigator.userAgent;
    var isOpera = Object.prototype.toString.call(window.opera) == '[object Opera]';
    return {
      IE:             !!window.attachEvent && !isOpera,
      Opera:          isOpera,
      WebKit:         ua.indexOf('AppleWebKit/') > -1,
      Gecko:          ua.indexOf('Gecko') > -1 && ua.indexOf('KHTML') === -1,
      MobileSafari:   /Apple.*Mobile.*Safari/.test(ua)
    }
  })(),

  BrowserFeatures: {
    XPath: !!document.evaluate,
    SelectorsAPI: !!document.querySelector,
    ElementExtensions: (function() {
      var constructor = window.Element || window.HTMLElement;
      return !!(constructor && constructor.prototype);
    })(),
    SpecificElementExtensions: (function() {
      if (typeof window.HTMLDivElement !== 'undefined')
        return true;

      var div = document.createElement('div');
      var form = document.createElement('form');
      var isSupported = false;

      if (div['__proto__'] && (div['__proto__'] !== form['__proto__'])) {
        isSupported = true;
      }

      div = form = null;

      return isSupported;
    })()
  },

  ScriptFragment: '<script[^>]*>([\\S\\s]*?)<\/script>',
  JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/,

  emptyFunction: function() { },
  K: function(x) { return x }
};


/* Based on Alex Arnell's inheritance implementation. */

function $A(iterable) {
    if (!iterable)
        return [];
    if ('toArray' in Object(iterable))
        return iterable.toArray();
    var length = iterable.length || 0, results = new Array(length);
    while (length--)
        results[length] = iterable[length];
    return results;
}

var Class = (function() {
    function subclass() {
    }
    ;
    function create() {
        var parent = null, properties = $A(arguments);
        if (Object.isFunction(properties[0]))
            parent = properties.shift();

        function klass() {
            this.initialize.apply(this, arguments);
        }

        Object.extend(klass, Class.Methods);
        klass.superclass = parent;
        klass.subclasses = [];

        if (parent) {
            subclass.prototype = parent.prototype;
            klass.prototype = new subclass;
            parent.subclasses.push(klass);
        }

        for ( var i = 0; i < properties.length; i++)
            klass.addMethods(properties[i]);

        if (!klass.prototype.initialize)
            klass.prototype.initialize = Prototype.emptyFunction;

        klass.prototype.constructor = klass;
        return klass;
    }

    function addMethods(source) {
        var ancestor = this.superclass && this.superclass.prototype;
        var properties = Object.keys(source);

        if (!Object.keys( {
            toString : true
        }).length) {
            if (source.toString != Object.prototype.toString)
                properties.push("toString");
            if (source.valueOf != Object.prototype.valueOf)
                properties.push("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 = (function(m) {
                    return function() {
                        return ancestor[m].apply(this, arguments);
                    };
                })(property).wrap(method);

                value.valueOf = method.valueOf.bind(method);
                value.toString = method.toString.bind(method);
            }
            this.prototype[property] = value;
        }

        return this;
    }

    return {
        create : create,
        Methods : {
            addMethods : addMethods
        }
    };
})();
(function() {

    var _toString = Object.prototype.toString;

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

    function inspect(object) {
        try {
            if (isUndefined(object))
                return 'undefined';
            if (object === null)
                return 'null';
            return object.inspect ? object.inspect() : String(object);
        } catch (e) {
            if (e instanceof RangeError)
                return '...';
            throw e;
        }
    }

    function toQueryString(object) {
        return $H(object).toQueryString();
    }

    function toHTML(object) {
        return object && object.toHTML ? object.toHTML() : String
                .interpret(object);
    }

    function keys(object) {
        var results = [];
        for ( var property in object)
            results.push(property);
        return results;
    }

    function values(object) {
        var results = [];
        for ( var property in object)
            results.push(object[property]);
        return results;
    }

    function clone(object) {
        return extend( {}, object);
    }

    function isElement(object) {
        return !!(object && object.nodeType == 1);
    }

    function isArray(object) {
        return _toString.call(object) == "[object Array]";
    }

    function isHash(object) {
        return object instanceof Hash;
    }

    function isFunction(object) {
        return typeof object === "function";
    }

    function isString(object) {
        return _toString.call(object) == "[object String]";
    }

    function isNumber(object) {
        return _toString.call(object) == "[object Number]";
    }

    function isUndefined(object) {
        return typeof object === "undefined";
    }

    extend(Object, {
        extend : extend,
        inspect : inspect,
        toQueryString : toQueryString,
        toHTML : toHTML,
        keys : keys,
        values : values,
        clone : clone,
        isElement : isElement,
        isArray : isArray,
        isHash : isHash,
        isFunction : isFunction,
        isString : isString,
        isNumber : isNumber,
        isUndefined : isUndefined
    });
})();
Object.extend(Function.prototype,
        (function() {
            var slice = Array.prototype.slice;

            function update(array, args) {
                var arrayLength = array.length, length = args.length;
                while (length--)
                    array[arrayLength + length] = args[length];
                return array;
            }

            function merge(array, args) {
                array = slice.call(array, 0);
                return update(array, args);
            }

            function argumentNames() {
                var names = this.toString().match(
                        /^[\s\(]*function[^(]*\(([^)]*)\)/)[1].replace(
                        /\/\/.*?[\r\n]|\/\*(?:.|[\r\n])*?\*\//g, '').replace(
                        /\s+/g, '').split(',');
                return names.length == 1 && !names[0] ? [] : names;
            }

            function bind(context) {
                if (arguments.length < 2 && Object.isUndefined(arguments[0]))
                    return this;
                var __method = this, args = slice.call(arguments, 1);
                return function() {
                    var a = merge(args, arguments);
                    return __method.apply(context, a);
                }
            }

            function bindAsEventListener(context) {
                var __method = this, args = slice.call(arguments, 1);
                return function(event) {
                    var a = update( [ event || window.event ], args);
                    return __method.apply(context, a);
                }
            }

            function curry() {
                if (!arguments.length)
                    return this;
                var __method = this, args = slice.call(arguments, 0);
                return function() {
                    var a = merge(args, arguments);
                    return __method.apply(this, a);
                }
            }

            function delay(timeout) {
                var __method = this, args = slice.call(arguments, 1);
                timeout = timeout * 1000
                return window.setTimeout(function() {
                    return __method.apply(__method, args);
                }, timeout);
            }

            function defer() {
                var args = update( [ 0.01 ], arguments);
                return this.delay.apply(this, args);
            }

            function wrap(wrapper) {
                var __method = this;
                return function() {
                    var a = update( [ __method.bind(this) ], arguments);
                    return wrapper.apply(this, a);
                }
            }

            function methodize() {
                if (this._methodized)
                    return this._methodized;
                var __method = this;
                return this._methodized = function() {
                    var a = update( [ this ], arguments);
                    return __method.apply(null, a);
                };
            }

            return {
                argumentNames : argumentNames,
                bind : bind,
                bindAsEventListener : bindAsEventListener,
                curry : curry,
                delay : delay,
                defer : defer,
                wrap : wrap,
                methodize : methodize
            }
        })());

function $w(string) {
    if (!Object.isString(string))
        return [];
    string = string.strip();
    return string ? string.split(/\s+/) : [];
}

Array.from = $A;

Array.from = $A;

(function() {
    var arrayProto = Array.prototype, slice = arrayProto.slice, _each = arrayProto.forEach; // use
                                                                                            // native
                                                                                            // browser
                                                                                            // JS
                                                                                            // 1.6
                                                                                            // implementation
                                                                                            // if
                                                                                            // available

    function each(iterator) {
        for ( var i = 0, length = this.length; i < length; i++)
            iterator(this[i]);
    }
    if (!_each)
        _each = each;

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

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

    function last() {
        return this[this.length - 1];
    }

    function compact() {
        return this.select(function(value) {
            return value != null;
        });
    }

    function flatten() {
        return this.inject( [], function(array, value) {
            if (Object.isArray(value))
                return array.concat(value.flatten());
            array.push(value);
            return array;
        });
    }

    function without() {
        var values = slice.call(arguments, 0);
        return this.select(function(value) {
            return !values.include(value);
        });
    }

    function reverse(inline) {
        return (inline !== false ? this : this.toArray())._reverse();
    }

    function uniq(sorted) {
        return this.inject( [],
                function(array, value, index) {
                    if (0 == index
                            || (sorted ? array.last() != value : !array
                                    .include(value)))
                        array.push(value);
                    return array;
                });
    }

    function intersect(array) {
        return this.uniq().findAll(function(item) {
            return array.detect(function(value) {
                return item === value
            });
        });
    }

    function clone() {
        return slice.call(this, 0);
    }

    function size() {
        return this.length;
    }

    function inspect() {
        return '[' + this.map(Object.inspect).join(', ') + ']';
    }

    function indexOf(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;
    }

    function lastIndexOf(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;
    }

    function concat() {
        var array = slice.call(this, 0), item;
        for ( var i = 0, length = arguments.length; i < length; i++) {
            item = arguments[i];
            if (Object.isArray(item) && !('callee' in item)) {
                for ( var j = 0, arrayLength = item.length; j < arrayLength; j++)
                    array.push(item[j]);
            } else {
                array.push(item);
            }
        }
        return array;
    }

    Object.extend(arrayProto, Enumerable);

    if (!arrayProto._reverse)
        arrayProto._reverse = arrayProto.reverse;

    Object.extend(arrayProto, {
        _each : _each,
        clear : clear,
        first : first,
        last : last,
        compact : compact,
        flatten : flatten,
        without : without,
        reverse : reverse,
        uniq : uniq,
        intersect : intersect,
        clone : clone,
        toArray : clone,
        size : size,
        inspect : inspect
    });

    var CONCAT_ARGUMENTS_BUGGY = (function() {
        return [].concat(arguments)[0][0] !== 1;
    })(1, 2)

    if (CONCAT_ARGUMENTS_BUGGY)
        arrayProto.concat = concat;

    if (!arrayProto.indexOf)
        arrayProto.indexOf = indexOf;
    if (!arrayProto.lastIndexOf)
        arrayProto.lastIndexOf = lastIndexOf;
})();

var Enumerable = (function() {
    function each(iterator, context) {
        var index = 0;
        try {
            this._each(function(value) {
                iterator.call(context, value, index++);
            });
        } catch (e) {
            if (e != $break)
                throw e;
        }
        return this;
    }

    function eachSlice(number, iterator, context) {
        var index = -number, slices = [], array = this.toArray();
        if (number < 1)
            return array;
        while ((index += number) < array.length)
            slices.push(array.slice(index, index + number));
        return slices.collect(iterator, context);
    }

    function all(iterator, context) {
        iterator = iterator || Prototype.K;
        var result = true;
        this.each(function(value, index) {
            result = result && !!iterator.call(context, value, index);
            if (!result)
                throw $break;
        });
        return result;
    }

    function any(iterator, context) {
        iterator = iterator || Prototype.K;
        var result = false;
        this.each(function(value, index) {
            if (result = !!iterator.call(context, value, index))
                throw $break;
        });
        return result;
    }

    function collect(iterator, context) {
        iterator = iterator || Prototype.K;
        var results = [];
        this.each(function(value, index) {
            results.push(iterator.call(context, value, index));
        });
        return results;
    }

    function detect(iterator, context) {
        var result;
        this.each(function(value, index) {
            if (iterator.call(context, value, index)) {
                result = value;
                throw $break;
            }
        });
        return result;
    }

    function findAll(iterator, context) {
        var results = [];
        this.each(function(value, index) {
            if (iterator.call(context, value, index))
                results.push(value);
        });
        return results;
    }

    function grep(filter, iterator, context) {
        iterator = iterator || Prototype.K;
        var results = [];

        if (Object.isString(filter))
            filter = new RegExp(RegExp.escape(filter));

        this.each(function(value, index) {
            if (filter.match(value))
                results.push(iterator.call(context, value, index));
        });
        return results;
    }

    function include(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;
    }

    function inGroupsOf(number, fillWith) {
        fillWith = Object.isUndefined(fillWith) ? null : fillWith;
        return this.eachSlice(number, function(slice) {
            while (slice.length < number)
                slice.push(fillWith);
            return slice;
        });
    }

    function inject(memo, iterator, context) {
        this.each(function(value, index) {
            memo = iterator.call(context, memo, value, index);
        });
        return memo;
    }

    function invoke(method) {
        var args = $A(arguments).slice(1);
        return this.map(function(value) {
            return value[method].apply(value, args);
        });
    }

    function max(iterator, context) {
        iterator = iterator || Prototype.K;
        var result;
        this.each(function(value, index) {
            value = iterator.call(context, value, index);
            if (result == null || value >= result)
                result = value;
        });
        return result;
    }

    function min(iterator, context) {
        iterator = iterator || Prototype.K;
        var result;
        this.each(function(value, index) {
            value = iterator.call(context, value, index);
            if (result == null || value < result)
                result = value;
        });
        return result;
    }

    function partition(iterator, context) {
        iterator = iterator || Prototype.K;
        var trues = [], falses = [];
        this
                .each(function(value, index) {
                    (iterator.call(context, value, index) ? trues : falses)
                            .push(value);
                });
        return [ trues, falses ];
    }

    function pluck(property) {
        var results = [];
        this.each(function(value) {
            results.push(value[property]);
        });
        return results;
    }

    function reject(iterator, context) {
        var results = [];
        this.each(function(value, index) {
            if (!iterator.call(context, value, index))
                results.push(value);
        });
        return results;
    }

    function sortBy(iterator, context) {
        return this.map(function(value, index) {
            return {
                value : value,
                criteria : iterator.call(context, value, index)
            };
        }).sort(function(left, right) {
            var a = left.criteria, b = right.criteria;
            return a < b ? -1 : a > b ? 1 : 0;
        }).pluck('value');
    }

    function toArray() {
        return this.map();
    }

    function zip() {
        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));
        });
    }

    function size() {
        return this.toArray().length;
    }

    function inspect() {
        return '#<Enumerable:' + this.toArray().inspect() + '>';
    }

    return {
        each : each,
        eachSlice : eachSlice,
        all : all,
        every : all,
        any : any,
        some : any,
        collect : collect,
        map : collect,
        detect : detect,
        findAll : findAll,
        select : findAll,
        filter : findAll,
        grep : grep,
        include : include,
        member : include,
        inGroupsOf : inGroupsOf,
        inject : inject,
        invoke : invoke,
        max : max,
        min : min,
        partition : partition,
        pluck : pluck,
        reject : reject,
        sortBy : sortBy,
        toArray : toArray,
        entries : toArray,
        zip : zip,
        size : size,
        inspect : inspect,
        find : detect
    };
})();
