﻿/*
    all.js -   an amalgamation of script libraries (including legacy prototype.js for compatibility, v1.6.0.3) combining to 
               provide modal lightbox functionality courtesy of the the LivePipe UI (http://livepipe.net/) Control.Window toolkit.
               More information/API available here: http://livepipe.net/control/window.
*/

var Prototype = { Version: '1.6.0.3', Browser: { IE: !!(window.attachEvent && navigator.userAgent.indexOf('Opera') === -1), Opera: navigator.userAgent.indexOf('Opera') > -1, 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, SelectorsAPI: !!document.querySelector, 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; 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); }
        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); }
        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;
    } 
    }; 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 = (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;
    } 
    }; var Abstract = {}; 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() : String(object); } 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 != null && typeof object == "object" && 'splice' in object && 'join' in object; }, 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].replace(/\s+/g, '').split(','); 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); }, defer: function() { var args = [0.01].concat($A(arguments)); return this.delay.apply(this, args); }, 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))); }; } }); 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) { } }
        return returnValue;
    } 
    }; RegExp.prototype.match = RegExp.prototype.test; RegExp.escape = function(str) { return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1'); }; var PeriodicalExecuter = Class.create({ 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', '\\': '\\\\'} }); 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;
    }, 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); }); }, 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]; }); }, 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;
        });
    }, 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); } 
    }); 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.stripTags().replace(/&amp;/g, '&').replace(/&lt;/g, '<').replace(/&gt;/g, '>'); } }); String.prototype.gsub.prepareReplacement = function(replacement) { if (Object.isFunction(replacement)) return replacement; var template = new Template(replacement); return function(match) { return template.evaluate(match) }; }; String.prototype.parseQuery = String.prototype.toQueryParams; Object.extend(String.prototype.escapeHTML, { div: document.createElement('div'), text: document.createTextNode('') }); String.prototype.escapeHTML.div.appendChild(String.prototype.escapeHTML.text); 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);
            });
    } 
    }); Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/; var $break = {}; var Enumerable = { each: function(iterator, context)
    {
        var index = 0; try { this._each(function(value) { iterator.call(context, value, index++); }); } catch (e) { if (e != $break) throw e; }
        return this;
    }, eachSlice: function(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);
    }, all: function(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; }, any: function(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;
    }, collect: function(iterator, context) { iterator = iterator || Prototype.K; var results = []; this.each(function(value, index) { results.push(iterator.call(context, value, index)); }); return results; }, detect: function(iterator, context) { var result; this.each(function(value, index) { if (iterator.call(context, value, index)) { result = value; throw $break; } }); return result; }, findAll: function(iterator, context)
    {
        var results = []; this.each(function(value, index)
        {
            if (iterator.call(context, value, index))
                results.push(value);
        }); return results;
    }, grep: function(filter, iterator, context)
    {
        iterator = iterator || Prototype.K; var results = []; if (Object.isString(filter))
            filter = new RegExp(filter); this.each(function(value, index)
            {
                if (filter.match(value))
                    results.push(iterator.call(context, value, index));
            }); return results;
    }, 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;
    }, 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; }); }, inject: function(memo, iterator, context) { this.each(function(value, index) { memo = iterator.call(context, memo, value, index); }); return memo; }, invoke: function(method) { var args = $A(arguments).slice(1); return this.map(function(value) { return value[method].apply(value, args); }); }, max: function(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;
    }, min: function(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;
    }, partition: function(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]; }, pluck: function(property) { var results = []; this.each(function(value) { results.push(value[property]); }); return results; }, reject: function(iterator, context)
    {
        var results = []; this.each(function(value, index)
        {
            if (!iterator.call(context, value, index))
                results.push(value);
        }); return results;
    }, sortBy: function(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'); }, 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)); });
    }, size: function() { return this.toArray().length; }, inspect: function() { return '#<Enumerable:' + this.toArray().inspect() + '>'; } 
    }; 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)
{
    $A = function(iterable)
    {
        if (!iterable) return []; if (!(typeof iterable === 'function' && typeof iterable.length === 'number' && typeof iterable.item === 'function') && iterable.toArray)
            return iterable.toArray(); var length = iterable.length || 0, results = new Array(length); while (length--) results[length] = iterable[length]; return results;
    };
}
Array.from = $A; Object.extend(Array.prototype, Enumerable); if (!Array.prototype._reverse) Array.prototype._reverse = Array.prototype.reverse; 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; }); }, flatten: function() { return this.inject([], function(array, value) { return array.concat(Object.isArray(value) ? value.flatten() : [value]); }); }, without: function() { var values = $A(arguments); return this.select(function(value) { return !values.include(value); }); }, 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(', ') + ']'; } 
}); if (Object.isFunction(Array.prototype.forEach))
    Array.prototype._each = Array.prototype.forEach; 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;
    }; 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; }; Array.prototype.toArray = Array.prototype.clone; function $w(string) { if (!Object.isString(string)) return []; string = string.strip(); return string ? string.split(/\s+/) : []; }
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, context) { $R(0, this, true).each(iterator, context); 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'; } }); $w('abs round ceil floor').each(function(method) { Number.prototype[method] = Math[method].methodize(); }); function $H(object) { return new Hash(object); }; var Hash = Class.create(Enumerable, (function()
{
    function toQueryPair(key, value) { if (Object.isUndefined(value)) return key; return key + '=' + encodeURIComponent(String.interpret(value)); }
    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; }, get: function(key)
    {
        if (this._object[key] !== Object.prototype[key])
            return this._object[key];
    }, unset: function(key) { var value = this._object[key]; delete this._object[key]; return value; }, toObject: function() { return Object.clone(this._object); }, keys: function() { return this.pluck('key'); }, values: function() { return this.pluck('value'); }, index: function(value) { var match = this.detect(function(pair) { return pair.value === value; }); return match && match.key; }, merge: function(object) { return this.clone().update(object); }, update: function(object) { return new Hash(object).inject(this, function(result, pair) { result.set(pair.key, pair.value); return result; }); }, toQueryString: function()
    {
        return this.inject([], function(results, pair)
        {
            var key = encodeURIComponent(pair.key), values = pair.value; if (values && typeof values == 'object')
            {
                if (Object.isArray(values))
                    return results.concat(values.map(toQueryPair.curry(key)));
            } else results.push(toQueryPair(key, values)); return results;
        }).join('&');
    }, inspect: function() { return '#<Hash:{' + this.map(function(pair) { return pair.map(Object.inspect).join(': '); }).join(', ') + '}>'; }, toJSON: function() { return Object.toJSON(this.toObject()); }, clone: function() { return new Hash(this); } }
    })()); 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;
    } 
    }); var $R = function(start, end, exclusive) { return new ObjectRange(start, end, exclusive); }; var Ajax = { getTransport: function() { return Try.these(function() { return new XMLHttpRequest() }, function() { return new ActiveXObject('Msxml2.XMLHTTP') }, function() { return new ActiveXObject('Microsoft.XMLHTTP') }) || false; }, activeRequestCount: 0 }; Ajax.Responders = { responders: [], _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) { } } }); } 
    }; Object.extend(Ajax.Responders, Enumerable); Ajax.Responders.register({ onCreate: function() { Ajax.activeRequestCount++ }, onComplete: function() { Ajax.activeRequestCount-- } }); 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 || {}); this.options.method = this.options.method.toLowerCase(); 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();
    } 
    }); Ajax.Request = Class.create(Ajax.Base, { _complete: false, initialize: function($super, url, options) { $super(options); this.transport = Ajax.getTransport(); this.request(url); }, request: function(url)
    {
        this.url = url; this.method = this.options.method; var params = Object.clone(this.options.parameters); if (!['get', 'post'].include(this.method)) { params['_method'] = this.method; this.method = 'post'; }
        this.parameters = params; if (params = Object.toQueryString(params))
        {
            if (this.method == 'get')
                this.url += (this.url.include('?') ? '&' : '?') + params; else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent))
                params += '&_=';
        }
        try
        {
            var response = new Ajax.Response(this); if (this.options.onCreate) this.options.onCreate(response); Ajax.Responders.dispatch('onCreate', this, response); this.transport.open(this.method.toUpperCase(), this.url, this.options.asynchronous); if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1); this.transport.onreadystatechange = this.onStateChange.bind(this); this.setRequestHeaders(); this.body = this.method == 'post' ? (this.options.postBody || params) : null; this.transport.send(this.body); if (!this.options.asynchronous && this.transport.overrideMimeType)
                this.onStateChange();
        }
        catch (e) { this.dispatchException(e); } 
    }, onStateChange: function()
    {
        var readyState = this.transport.readyState; if (readyState > 1 && !((readyState == 4) && this._complete))
            this.respondToReadyState(this.transport.readyState);
    }, setRequestHeaders: function()
    {
        var headers = { 'X-Requested-With': 'XMLHttpRequest', 'X-Prototype-Version': Prototype.Version, 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*' }; if (this.method == 'post')
        {
            headers['Content-type'] = this.options.contentType +
(this.options.encoding ? '; charset=' + this.options.encoding : ''); if (this.transport.overrideMimeType && (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0, 2005])[1] < 2005)
                headers['Connection'] = 'close';
        }
        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 && this.isSameOrigin() && 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') { this.transport.onreadystatechange = Prototype.emptyFunction; } 
    }, isSameOrigin: function() { var m = this.url.match(/^\s*https?:\/\/[^\/]*/); return !m || (m[0] == '#{protocol}//#{domain}#{port}'.interpolate({ protocol: location.protocol, domain: document.domain, port: location.port ? ':' + location.port : '' })); }, 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); } 
    }); Ajax.Request.Events = ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; 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 || !this.request.isSameOrigin()); } 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 || !this.request.isSameOrigin()); } catch (e) { this.request.dispatchException(e); } 
    } 
    }); 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)) }; 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);
        } 
    } 
    }); 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);
    }
    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;
        };
    }
    if (!window.Node) var Node = {}; if (!Node.ELEMENT_NODE) { 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 }); }
    (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 || {}); if (element) this.Element.prototype = element.prototype;
    }).call(window); Element.cache = {}; 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 = $(element); element.style.display = 'none'; return element; }, show: function(element) { element = $(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 (var 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 + '>'; }, 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).select("*"); }, 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(element, 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); }, 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); if (element.compareDocumentPosition)
            return (element.compareDocumentPosition(ancestor) & 8) === 8; if (ancestor.contains)
            return ancestor.contains(element) && ancestor !== element; while (element = element.parentNode)
            if (element == ancestor) 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 || value == 'auto') { 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)
            return { width: element.offsetWidth, height: element.offsetHeight }; 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 };
    }, makePositioned: function(element)
    {
        element = $(element); var pos = Element.getStyle(element, 'position'); if (pos == 'static' || !pos) { element._madePositioned = true; element.style.position = 'relative'; if (Prototype.Browser.Opera) { element.style.top = 0; element.style.left = 0; } }
        return element;
    }, undoPositioned: function(element)
    {
        element = $(element); if (element._madePositioned) { element._madePositioned = undefined; element.style.position = element.style.top = element.style.left = element.style.bottom = element.style.right = ''; }
        return element;
    }, makeClipping: function(element)
    {
        element = $(element); if (element._overflow) return element; element._overflow = Element.getStyle(element, 'overflow') || 'auto'; if (element._overflow !== 'hidden')
            element.style.overflow = 'hidden'; return element;
    }, undoClipping: function(element) { element = $(element); if (!element._overflow) return element; element.style.overflow = element._overflow == 'auto' ? '' : element._overflow; element._overflow = null; return element; }, cumulativeOffset: function(element) { var valueT = 0, valueL = 0; do { valueT += element.offsetTop || 0; valueL += element.offsetLeft || 0; element = element.offsetParent; } while (element); return Element._returnOffset(valueL, valueT); }, positionedOffset: function(element) { var valueT = 0, valueL = 0; do { valueT += element.offsetTop || 0; valueL += element.offsetLeft || 0; element = element.offsetParent; if (element) { if (element.tagName.toUpperCase() == 'BODY') break; var p = Element.getStyle(element, 'position'); if (p !== 'static') break; } } while (element); return Element._returnOffset(valueL, valueT); }, absolutize: function(element) { element = $(element); if (element.getStyle('position') == 'absolute') return element; var offsets = element.positionedOffset(); var top = offsets[1]; var left = offsets[0]; var width = element.clientWidth; var height = element.clientHeight; element._originalLeft = left - parseFloat(element.style.left || 0); element._originalTop = top - parseFloat(element.style.top || 0); element._originalWidth = element.style.width; element._originalHeight = element.style.height; element.style.position = 'absolute'; element.style.top = top + 'px'; element.style.left = left + 'px'; element.style.width = width + 'px'; element.style.height = height + 'px'; return element; }, relativize: function(element) { element = $(element); if (element.getStyle('position') == 'relative') return element; element.style.position = 'relative'; var top = parseFloat(element.style.top || 0) - (element._originalTop || 0); var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0); element.style.top = top + 'px'; element.style.left = left + 'px'; element.style.height = element._originalHeight; element.style.width = element._originalWidth; return element; }, cumulativeScrollOffset: function(element) { var valueT = 0, valueL = 0; do { valueT += element.scrollTop || 0; valueL += element.scrollLeft || 0; element = element.parentNode; } while (element); return Element._returnOffset(valueL, valueT); }, getOffsetParent: function(element)
    {
        if (element.offsetParent) return $(element.offsetParent); if (element == document.body) return $(element); while ((element = element.parentNode) && element != document.body)
            if (Element.getStyle(element, 'position') != 'static')
            return $(element); return $(document.body);
    }, viewportOffset: function(forElement) { var valueT = 0, valueL = 0; var element = forElement; do { valueT += element.offsetTop || 0; valueL += element.offsetLeft || 0; if (element.offsetParent == document.body && Element.getStyle(element, 'position') == 'absolute') break; } while (element = element.offsetParent); element = forElement; do { if (!Prototype.Browser.Opera || (element.tagName && (element.tagName.toUpperCase() == 'BODY'))) { valueT -= element.scrollTop || 0; valueL -= element.scrollLeft || 0; } } while (element = element.parentNode); return Element._returnOffset(valueL, valueT); }, clonePosition: function(element, source)
    {
        var options = Object.extend({ setLeft: true, setTop: true, setWidth: true, setHeight: true, offsetTop: 0, offsetLeft: 0 }, arguments[2] || {}); source = $(source); var p = source.viewportOffset(); element = $(element); var delta = [0, 0]; var parent = null; if (Element.getStyle(element, 'position') == 'absolute') { parent = element.getOffsetParent(); delta = parent.viewportOffset(); }
        if (parent == document.body) { delta[0] -= document.body.offsetLeft; delta[1] -= document.body.offsetTop; }
        if (options.setLeft) element.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px'; if (options.setTop) element.style.top = (p[1] - delta[1] + options.offsetTop) + 'px'; if (options.setWidth) element.style.width = source.offsetWidth + 'px'; if (options.setHeight) element.style.height = source.offsetHeight + 'px'; return element;
    } 
    }; Element.Methods.identify.counter = 1; Object.extend(Element.Methods, { getElementsBySelector: Element.Methods.select, childElements: Element.Methods.immediateDescendants }); Element._attributeTranslations = { write: { names: { className: 'class', htmlFor: 'for' }, values: {}} }; if (Prototype.Browser.Opera)
    {
        Element.Methods.getStyle = Element.Methods.getStyle.wrap(function(proceed, element, style)
        {
            switch (style)
            {
                case 'left': case 'top': case 'right': case 'bottom': if (proceed(element, 'position') === 'static') return null; case 'height': case 'width': if (!Element.visible(element)) return null; var dim = parseInt(proceed(element, style), 10); if (dim !== element['offset' + style.capitalize()])
                        return dim + 'px'; var properties; if (style === 'height') { properties = ['border-top-width', 'padding-top', 'padding-bottom', 'border-bottom-width']; }
                    else { properties = ['border-left-width', 'padding-left', 'padding-right', 'border-right-width']; }
                    return properties.inject(dim, function(memo, property) { var val = proceed(element, property); return val === null ? memo : memo - parseInt(val, 10); }) + 'px'; default: return proceed(element, style);
            } 
        }); Element.Methods.readAttribute = Element.Methods.readAttribute.wrap(function(proceed, element, attribute) { if (attribute === 'title') return element.title; return proceed(element, attribute); });
    }
    else if (Prototype.Browser.IE)
    {
        Element.Methods.getOffsetParent = Element.Methods.getOffsetParent.wrap(function(proceed, element)
        {
            element = $(element); try { element.offsetParent }
            catch (e) { return $(document.body) }
            var position = element.getStyle('position'); if (position !== 'static') return proceed(element); element.setStyle({ position: 'relative' }); var value = proceed(element); element.setStyle({ position: position }); return value;
        }); $w('positionedOffset viewportOffset').each(function(method)
        {
            Element.Methods[method] = Element.Methods[method].wrap(function(proceed, element)
            {
                element = $(element); try { element.offsetParent }
                catch (e) { return Element._returnOffset(0, 0) }
                var position = element.getStyle('position'); if (position !== 'static') return proceed(element); var offsetParent = element.getOffsetParent(); if (offsetParent && offsetParent.getStyle('position') === 'fixed')
                    offsetParent.setStyle({ zoom: 1 }); element.setStyle({ position: 'relative' }); var value = proceed(element); element.setStyle({ position: position }); return value;
            });
        }); Element.Methods.cumulativeOffset = Element.Methods.cumulativeOffset.wrap(function(proceed, element)
        {
            try { element.offsetParent }
            catch (e) { return Element._returnOffset(0, 0) }
            return proceed(element);
        }); Element.Methods.getStyle = function(element, style)
        {
            element = $(element); style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize(); var value = element.style[style]; if (!value && element.currentStyle) value = element.currentStyle[style]; if (style == 'opacity')
            {
                if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/))
                    if (value[1]) return parseFloat(value[1]) / 100; return 1.0;
            }
            if (value == 'auto')
            {
                if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none'))
                    return element['offset' + style.capitalize()] + 'px'; return null;
            }
            return value;
        }; Element.Methods.setOpacity = function(element, value)
        {
            function stripAlpha(filter) { return filter.replace(/alpha\([^\)]*\)/gi, ''); }
            element = $(element); var currentStyle = element.currentStyle; if ((currentStyle && !currentStyle.hasLayout) || (!currentStyle && element.style.zoom == 'normal'))
                element.style.zoom = 1; var filter = element.getStyle('filter'), style = element.style; if (value == 1 || value === '') { (filter = stripAlpha(filter)) ? style.filter = filter : style.removeAttribute('filter'); return element; } else if (value < 0.00001) value = 0; style.filter = stripAlpha(filter) + 'alpha(opacity=' + (value * 100) + ')'; return element;
        }; Element._attributeTranslations = { read: { names: { 'class': 'className', 'for': 'htmlFor' }, values: { _getAttr: function(element, attribute) { return element.getAttribute(attribute, 2); }, _getAttrNode: function(element, attribute) { var node = element.getAttributeNode(attribute); return node ? node.value : ""; }, _getEv: function(element, attribute) { attribute = element.getAttribute(attribute); return attribute ? attribute.toString().slice(23, -2) : null; }, _flag: function(element, attribute) { return $(element).hasAttribute(attribute) ? attribute : null; }, style: function(element) { return element.style.cssText.toLowerCase(); }, title: function(element) { return element.title; } }} }; Element._attributeTranslations.write = { names: Object.extend({ cellpadding: 'cellPadding', cellspacing: 'cellSpacing' }, Element._attributeTranslations.read.names), values: { checked: function(element, value) { element.checked = !!value; }, style: function(element, value) { element.style.cssText = value ? value : ''; } } }; Element._attributeTranslations.has = {}; $w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' + 'encType maxLength readOnly longDesc frameBorder').each(function(attr) { Element._attributeTranslations.write.names[attr.toLowerCase()] = attr; Element._attributeTranslations.has[attr.toLowerCase()] = attr; }); (function(v) { Object.extend(v, { href: v._getAttr, src: v._getAttr, type: v._getAttr, action: v._getAttrNode, disabled: v._flag, checked: v._flag, readonly: v._flag, multiple: v._flag, onload: v._getEv, onunload: v._getEv, onclick: v._getEv, ondblclick: v._getEv, onmousedown: v._getEv, onmouseup: v._getEv, onmouseover: v._getEv, onmousemove: v._getEv, onmouseout: v._getEv, onfocus: v._getEv, onblur: v._getEv, onkeypress: v._getEv, onkeydown: v._getEv, onkeyup: v._getEv, onsubmit: v._getEv, onreset: v._getEv, onselect: v._getEv, onchange: v._getEv }); })(Element._attributeTranslations.read.values);
    }
    else if (Prototype.Browser.Gecko && /rv:1\.8\.0/.test(navigator.userAgent)) { Element.Methods.setOpacity = function(element, value) { element = $(element); element.style.opacity = (value == 1) ? 0.999999 : (value === '') ? '' : (value < 0.00001) ? 0 : value; return element; }; }
    else if (Prototype.Browser.WebKit)
    {
        Element.Methods.setOpacity = function(element, value)
        {
            element = $(element); element.style.opacity = (value == 1 || value === '') ? '' : (value < 0.00001) ? 0 : value; if (value == 1)
                if (element.tagName.toUpperCase() == 'IMG' && element.width) { element.width++; element.width--; } else try { var n = document.createTextNode(' '); element.appendChild(n); element.removeChild(n); } catch (e) { }
            return element;
        }; Element.Methods.cumulativeOffset = function(element)
        {
            var valueT = 0, valueL = 0; do
            {
                valueT += element.offsetTop || 0; valueL += element.offsetLeft || 0; if (element.offsetParent == document.body)
                    if (Element.getStyle(element, 'position') == 'absolute') break; element = element.offsetParent;
            } while (element); return Element._returnOffset(valueL, valueT);
        };
    }
    if (Prototype.Browser.IE || Prototype.Browser.Opera)
    {
        Element.Methods.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); var tagName = element.tagName.toUpperCase(); if (tagName in Element._insertionTranslations.tags) { $A(element.childNodes).each(function(node) { element.removeChild(node) }); Element._getContentFromAnonymousElement(tagName, content.stripScripts()).each(function(node) { element.appendChild(node) }); }
            else element.innerHTML = content.stripScripts(); content.evalScripts.bind(content).defer(); return element;
        };
    }
    if ('outerHTML' in document.createElement('div'))
    {
        Element.Methods.replace = function(element, content)
        {
            element = $(element); if (content && content.toElement) content = content.toElement(); if (Object.isElement(content)) { element.parentNode.replaceChild(content, element); return element; }
            content = Object.toHTML(content); var parent = element.parentNode, tagName = parent.tagName.toUpperCase(); if (Element._insertionTranslations.tags[tagName])
            {
                var nextSibling = element.next(); var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts()); parent.removeChild(element); if (nextSibling)
                    fragments.each(function(node) { parent.insertBefore(node, nextSibling) }); else
                    fragments.each(function(node) { parent.appendChild(node) });
            }
            else element.outerHTML = content.stripScripts(); content.evalScripts.bind(content).defer(); return element;
        };
    }
    Element._returnOffset = function(l, t) { var result = [l, t]; result.left = l; result.top = t; return result; }; Element._getContentFromAnonymousElement = function(tagName, html) { var div = new Element('div'), t = Element._insertionTranslations.tags[tagName]; if (t) { div.innerHTML = t[0] + html + t[1]; t[2].times(function() { div = div.firstChild }); } else div.innerHTML = html; return $A(div.childNodes); }; Element._insertionTranslations = { before: function(element, node) { element.parentNode.insertBefore(node, element); }, top: function(element, node) { element.insertBefore(node, element.firstChild); }, bottom: function(element, node) { element.appendChild(node); }, after: function(element, node) { element.parentNode.insertBefore(node, element.nextSibling); }, tags: { TABLE: ['<table>', '</table>', 1], TBODY: ['<table><tbody>', '</tbody></table>', 2], TR: ['<table><tbody><tr>', '</tr></tbody></table>', 3], TD: ['<table><tbody><tr><td>', '</td></tr></tbody></table>', 4], SELECT: ['<select>', '</select>', 1]} }; (function() { Object.extend(this.tags, { THEAD: this.tags.TBODY, TFOOT: this.tags.TBODY, TH: this.tags.TD }); }).call(Element._insertionTranslations); Element.Methods.Simulated = { hasAttribute: function(element, attribute) { attribute = Element._attributeTranslations.has[attribute] || attribute; var node = $(element).getAttributeNode(attribute); return !!(node && node.specified); } }; Element.Methods.ByTag = {}; Object.extend(Element, Element.Methods); if (!Prototype.BrowserFeatures.ElementExtensions && document.createElement('div')['__proto__']) { window.HTMLElement = {}; window.HTMLElement.prototype = document.createElement('div')['__proto__']; Prototype.BrowserFeatures.ElementExtensions = true; }
    Element.extend = (function()
    {
        if (Prototype.BrowserFeatures.SpecificElementExtensions)
            return Prototype.K; var Methods = {}, ByTag = Element.Methods.ByTag; var extend = Object.extend(function(element)
            {
                if (!element || element._extendedByPrototype || element.nodeType != 1 || element == window) return element; var methods = Object.clone(Methods), tagName = element.tagName.toUpperCase(), property, value; if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]); for (property in methods)
                {
                    value = methods[property]; if (Object.isFunction(value) && !(property in element))
                        element[property] = value.methodize();
                }
                element._extendedByPrototype = Prototype.emptyFunction; return element;
            }, { refresh: function() { if (!Prototype.BrowserFeatures.ElementExtensions) { Object.extend(Methods, Element.Methods); Object.extend(Methods, Element.Methods.Simulated); } } }); extend.refresh(); return extend;
    })(); Element.hasAttribute = function(element, attribute) { if (element.hasAttribute) return element.hasAttribute(attribute); return Element.Methods.Simulated.hasAttribute(element, attribute); }; Element.addMethods = function(methods)
    {
        var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag; if (!methods) { Object.extend(Form, Form.Methods); Object.extend(Form.Element, Form.Element.Methods); Object.extend(Element.Methods.ByTag, { "FORM": Object.clone(Form.Methods), "INPUT": Object.clone(Form.Element.Methods), "SELECT": Object.clone(Form.Element.Methods), "TEXTAREA": Object.clone(Form.Element.Methods) }); }
        if (arguments.length == 2) { var tagName = methods; methods = arguments[1]; }
        if (!tagName) Object.extend(Element.Methods, methods || {}); else { if (Object.isArray(tagName)) tagName.each(extend); else extend(tagName); }
        function extend(tagName)
        {
            tagName = tagName.toUpperCase(); if (!Element.Methods.ByTag[tagName])
                Element.Methods.ByTag[tagName] = {}; Object.extend(Element.Methods.ByTag[tagName], methods);
        }
        function copy(methods, destination, onlyIfAbsent)
        {
            onlyIfAbsent = onlyIfAbsent || false; for (var property in methods)
            {
                var value = methods[property]; if (!Object.isFunction(value)) continue; if (!onlyIfAbsent || !(property in destination))
                    destination[property] = value.methodize();
            } 
        }
        function findDOMClass(tagName) { var klass; var trans = { "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph", "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList", "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading", "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote", "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION": "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD": "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR": "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET": "FrameSet", "IFRAME": "IFrame" }; if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element'; if (window[klass]) return window[klass]; klass = 'HTML' + tagName + 'Element'; if (window[klass]) return window[klass]; klass = 'HTML' + tagName.capitalize() + 'Element'; if (window[klass]) return window[klass]; window[klass] = {}; window[klass].prototype = document.createElement(tagName)['__proto__']; return window[klass]; }
        if (F.ElementExtensions) { copy(Element.Methods, HTMLElement.prototype); copy(Element.Methods.Simulated, HTMLElement.prototype, true); }
        if (F.SpecificElementExtensions) { for (var tag in Element.Methods.ByTag) { var klass = findDOMClass(tag); if (Object.isUndefined(klass)) continue; copy(T[tag], klass.prototype); } }
        Object.extend(Element, Element.Methods); delete Element.ByTag; if (Element.extend.refresh) Element.extend.refresh(); Element.cache = {};
    }; document.viewport = { getDimensions: function() { var dimensions = {}, B = Prototype.Browser; $w('width height').each(function(d) { var D = d.capitalize(); if (B.WebKit && !document.evaluate) { dimensions[d] = self['inner' + D]; } else if (B.Opera && parseFloat(window.opera.version()) < 9.5) { dimensions[d] = document.body['client' + D] } else { dimensions[d] = document.documentElement['client' + D]; } }); return dimensions; }, getWidth: function() { return this.getDimensions().width; }, getHeight: function() { return this.getDimensions().height; }, getScrollOffsets: function() { return Element._returnOffset(window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft, window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop); } }; var Selector = Class.create({ initialize: function(expression) { this.expression = expression.strip(); if (this.shouldUseSelectorsAPI()) { this.mode = 'selectorsAPI'; } else if (this.shouldUseXPath()) { this.mode = 'xpath'; this.compileXPathMatcher(); } else { this.mode = "normal"; this.compileMatcher(); } }, shouldUseXPath: function()
    {
        if (!Prototype.BrowserFeatures.XPath) return false; var e = this.expression; if (Prototype.Browser.WebKit && (e.include("-of-type") || e.include(":empty")))
            return false; if ((/(\[[\w-]*?:|:checked)/).test(e))
            return false; return true;
    }, shouldUseSelectorsAPI: function()
    {
        if (!Prototype.BrowserFeatures.SelectorsAPI) return false; if (!Selector._div) Selector._div = new Element('div'); try { Selector._div.querySelector(this.expression); } catch (e) { return false; }
        return true;
    }, compileMatcher: function()
    {
        var e = this.expression, ps = Selector.patterns, h = Selector.handlers, c = Selector.criteria, le, p, m; if (Selector._cache[e]) { this.matcher = Selector._cache[e]; return; }
        this.matcher = ["this.matcher = function(root) {", "var r = root, h = Selector.handlers, c = false, n;"]; while (e && le != e && (/\S/).test(e)) { le = e; for (var i in ps) { p = ps[i]; if (m = e.match(p)) { this.matcher.push(Object.isFunction(c[i]) ? c[i](m) : new Template(c[i]).evaluate(m)); e = e.replace(m[0], ''); break; } } }
        this.matcher.push("return h.unique(n);\n}"); eval(this.matcher.join('\n')); Selector._cache[this.expression] = this.matcher;
    }, compileXPathMatcher: function()
    {
        var e = this.expression, ps = Selector.patterns, x = Selector.xpath, le, m; if (Selector._cache[e]) { this.xpath = Selector._cache[e]; return; }
        this.matcher = ['.//*']; while (e && le != e && (/\S/).test(e)) { le = e; for (var i in ps) { if (m = e.match(ps[i])) { this.matcher.push(Object.isFunction(x[i]) ? x[i](m) : new Template(x[i]).evaluate(m)); e = e.replace(m[0], ''); break; } } }
        this.xpath = this.matcher.join(''); Selector._cache[this.expression] = this.xpath;
    }, findElements: function(root)
    {
        root = root || document; var e = this.expression, results; switch (this.mode)
        {
            case 'selectorsAPI': if (root !== document) { var oldId = root.id, id = $(root).identify(); e = "#" + id + " " + e; }
                results = $A(root.querySelectorAll(e)).map(Element.extend); root.id = oldId; return results; case 'xpath': return document._getElementsByXPath(this.xpath, root); default: return this.matcher(root);
        } 
    }, match: function(element)
    {
        this.tokens = []; var e = this.expression, ps = Selector.patterns, as = Selector.assertions; var le, p, m; while (e && le !== e && (/\S/).test(e)) { le = e; for (var i in ps) { p = ps[i]; if (m = e.match(p)) { if (as[i]) { this.tokens.push([i, Object.clone(m)]); e = e.replace(m[0], ''); } else { return this.findElements(document).include(element); } } } }
        var match = true, name, matches; for (var i = 0, token; token = this.tokens[i]; i++) { name = token[0], matches = token[1]; if (!Selector.assertions[name](element, matches)) { match = false; break; } }
        return match;
    }, toString: function() { return this.expression; }, inspect: function() { return "#<Selector:" + this.expression.inspect() + ">"; } 
    }); Object.extend(Selector, { _cache: {}, xpath: { descendant: "//*", child: "/*", adjacent: "/following-sibling::*[1]", laterSibling: '/following-sibling::*', tagName: function(m) { if (m[1] == '*') return ''; return "[local-name()='" + m[1].toLowerCase() + "' or local-name()='" + m[1].toUpperCase() + "']"; }, className: "[contains(concat(' ', @class, ' '), ' #{1} ')]", id: "[@id='#{1}']", attrPresence: function(m) { m[1] = m[1].toLowerCase(); return new Template("[@#{1}]").evaluate(m); }, attr: function(m) { m[1] = m[1].toLowerCase(); m[3] = m[5] || m[6]; return new Template(Selector.xpath.operators[m[2]]).evaluate(m); }, pseudo: function(m) { var h = Selector.xpath.pseudos[m[1]]; if (!h) return ''; if (Object.isFunction(h)) return h(m); return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m); }, operators: { '=': "[@#{1}='#{3}']", '!=': "[@#{1}!='#{3}']", '^=': "[starts-with(@#{1}, '#{3}')]", '$=': "[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']", '*=': "[contains(@#{1}, '#{3}')]", '~=': "[contains(concat(' ', @#{1}, ' '), ' #{3} ')]", '|=': "[contains(concat('-', @#{1}, '-'), '-#{3}-')]" }, pseudos: { 'first-child': '[not(preceding-sibling::*)]', 'last-child': '[not(following-sibling::*)]', 'only-child': '[not(preceding-sibling::* or following-sibling::*)]', 'empty': "[count(*) = 0 and (count(text()) = 0)]", 'checked': "[@checked]", 'disabled': "[(@disabled) and (@type!='hidden')]", 'enabled': "[not(@disabled) and (@type!='hidden')]", 'not': function(m)
    {
        var e = m[6], p = Selector.patterns, x = Selector.xpath, le, v; var exclusion = []; while (e && le != e && (/\S/).test(e)) { le = e; for (var i in p) { if (m = e.match(p[i])) { v = Object.isFunction(x[i]) ? x[i](m) : new Template(x[i]).evaluate(m); exclusion.push("(" + v.substring(1, v.length - 1) + ")"); e = e.replace(m[0], ''); break; } } }
        return "[not(" + exclusion.join(" and ") + ")]";
    }, 'nth-child': function(m) { return Selector.xpath.pseudos.nth("(count(./preceding-sibling::*) + 1) ", m); }, 'nth-last-child': function(m) { return Selector.xpath.pseudos.nth("(count(./following-sibling::*) + 1) ", m); }, 'nth-of-type': function(m) { return Selector.xpath.pseudos.nth("position() ", m); }, 'nth-last-of-type': function(m) { return Selector.xpath.pseudos.nth("(last() + 1 - position()) ", m); }, 'first-of-type': function(m) { m[6] = "1"; return Selector.xpath.pseudos['nth-of-type'](m); }, 'last-of-type': function(m) { m[6] = "1"; return Selector.xpath.pseudos['nth-last-of-type'](m); }, 'only-of-type': function(m) { var p = Selector.xpath.pseudos; return p['first-of-type'](m) + p['last-of-type'](m); }, nth: function(fragment, m)
    {
        var mm, formula = m[6], predicate; if (formula == 'even') formula = '2n+0'; if (formula == 'odd') formula = '2n+1'; if (mm = formula.match(/^(\d+)$/))
            return '[' + fragment + "= " + mm[1] + ']'; if (mm = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { if (mm[1] == "-") mm[1] = -1; var a = mm[1] ? Number(mm[1]) : 1; var b = mm[2] ? Number(mm[2]) : 0; predicate = "[((#{fragment} - #{b}) mod #{a} = 0) and " + "((#{fragment} - #{b}) div #{a} >= 0)]"; return new Template(predicate).evaluate({ fragment: fragment, a: a, b: b }); } 
    } }
    }, criteria: { tagName: 'n = h.tagName(n, r, "#{1}", c);      c = false;', className: 'n = h.className(n, r, "#{1}", c);    c = false;', id: 'n = h.id(n, r, "#{1}", c);           c = false;', attrPresence: 'n = h.attrPresence(n, r, "#{1}", c); c = false;', attr: function(m) { m[3] = (m[5] || m[6]); return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}", c); c = false;').evaluate(m); }, pseudo: function(m) { if (m[6]) m[6] = m[6].replace(/"/g, '\\"'); return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m); }, descendant: 'c = "descendant";', child: 'c = "child";', adjacent: 'c = "adjacent";', laterSibling: 'c = "laterSibling";' }, patterns: { laterSibling: /^\s*~\s*/, child: /^\s*>\s*/, adjacent: /^\s*\+\s*/, descendant: /^\s/, tagName: /^\s*(\*|[\w\-]+)(\b|$)?/, id: /^#([\w\-\*]+)(\b|$)/, className: /^\.([\w\-\*]+)(\b|$)/, pseudo: /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s|[:+~>]))/, attrPresence: /^\[((?:[\w]+:)?[\w]+)\]/, attr: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/ }, assertions: { tagName: function(element, matches) { return matches[1].toUpperCase() == element.tagName.toUpperCase(); }, className: function(element, matches) { return Element.hasClassName(element, matches[1]); }, id: function(element, matches) { return element.id === matches[1]; }, attrPresence: function(element, matches) { return Element.hasAttribute(element, matches[1]); }, attr: function(element, matches) { var nodeValue = Element.readAttribute(element, matches[1]); return nodeValue && Selector.operators[matches[2]](nodeValue, matches[5] || matches[6]); } }, handlers: { concat: function(a, b)
    {
        for (var i = 0, node; node = b[i]; i++)
            a.push(node); return a;
    }, mark: function(nodes)
    {
        var _true = Prototype.emptyFunction; for (var i = 0, node; node = nodes[i]; i++)
            node._countedByPrototype = _true; return nodes;
    }, unmark: function(nodes)
    {
        for (var i = 0, node; node = nodes[i]; i++)
            node._countedByPrototype = undefined; return nodes;
    }, index: function(parentNode, reverse, ofType)
    {
        parentNode._countedByPrototype = Prototype.emptyFunction; if (reverse) { for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) { var node = nodes[i]; if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++; } } else
        {
            for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++)
                if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++;
        } 
    }, unique: function(nodes)
    {
        if (nodes.length == 0) return nodes; var results = [], n; for (var i = 0, l = nodes.length; i < l; i++)
            if (!(n = nodes[i])._countedByPrototype) { n._countedByPrototype = Prototype.emptyFunction; results.push(Element.extend(n)); }
        return Selector.handlers.unmark(results);
    }, descendant: function(nodes)
    {
        var h = Selector.handlers; for (var i = 0, results = [], node; node = nodes[i]; i++)
            h.concat(results, node.getElementsByTagName('*')); return results;
    }, child: function(nodes)
    {
        var h = Selector.handlers; for (var i = 0, results = [], node; node = nodes[i]; i++)
        {
            for (var j = 0, child; child = node.childNodes[j]; j++)
                if (child.nodeType == 1 && child.tagName != '!') results.push(child);
        }
        return results;
    }, adjacent: function(nodes)
    {
        for (var i = 0, results = [], node; node = nodes[i]; i++) { var next = this.nextElementSibling(node); if (next) results.push(next); }
        return results;
    }, laterSibling: function(nodes)
    {
        var h = Selector.handlers; for (var i = 0, results = [], node; node = nodes[i]; i++)
            h.concat(results, Element.nextSiblings(node)); return results;
    }, nextElementSibling: function(node)
    {
        while (node = node.nextSibling)
            if (node.nodeType == 1) return node; return null;
    }, previousElementSibling: function(node)
    {
        while (node = node.previousSibling)
            if (node.nodeType == 1) return node; return null;
    }, tagName: function(nodes, root, tagName, combinator)
    {
        var uTagName = tagName.toUpperCase(); var results = [], h = Selector.handlers; if (nodes)
        {
            if (combinator)
            {
                if (combinator == "descendant")
                {
                    for (var i = 0, node; node = nodes[i]; i++)
                        h.concat(results, node.getElementsByTagName(tagName)); return results;
                } else nodes = this[combinator](nodes); if (tagName == "*") return nodes;
            }
            for (var i = 0, node; node = nodes[i]; i++)
                if (node.tagName.toUpperCase() === uTagName) results.push(node); return results;
        } else return root.getElementsByTagName(tagName);
    }, id: function(nodes, root, id, combinator)
    {
        var targetNode = $(id), h = Selector.handlers; if (!targetNode) return []; if (!nodes && root == document) return [targetNode]; if (nodes)
        {
            if (combinator)
            {
                if (combinator == 'child')
                {
                    for (var i = 0, node; node = nodes[i]; i++)
                        if (targetNode.parentNode == node) return [targetNode];
                } else if (combinator == 'descendant')
                {
                    for (var i = 0, node; node = nodes[i]; i++)
                        if (Element.descendantOf(targetNode, node)) return [targetNode];
                } else if (combinator == 'adjacent')
                {
                    for (var i = 0, node; node = nodes[i]; i++)
                        if (Selector.handlers.previousElementSibling(targetNode) == node)
                        return [targetNode];
                } else nodes = h[combinator](nodes);
            }
            for (var i = 0, node; node = nodes[i]; i++)
                if (node == targetNode) return [targetNode]; return [];
        }
        return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : [];
    }, className: function(nodes, root, className, combinator) { if (nodes && combinator) nodes = this[combinator](nodes); return Selector.handlers.byClassName(nodes, root, className); }, byClassName: function(nodes, root, className)
    {
        if (!nodes) nodes = Selector.handlers.descendant([root]); var needle = ' ' + className + ' '; for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++)
        {
            nodeClassName = node.className; if (nodeClassName.length == 0) continue; if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle))
                results.push(node);
        }
        return results;
    }, attrPresence: function(nodes, root, attr, combinator)
    {
        if (!nodes) nodes = root.getElementsByTagName("*"); if (nodes && combinator) nodes = this[combinator](nodes); var results = []; for (var i = 0, node; node = nodes[i]; i++)
            if (Element.hasAttribute(node, attr)) results.push(node); return results;
    }, attr: function(nodes, root, attr, value, operator, combinator)
    {
        if (!nodes) nodes = root.getElementsByTagName("*"); if (nodes && combinator) nodes = this[combinator](nodes); var handler = Selector.operators[operator], results = []; for (var i = 0, node; node = nodes[i]; i++) { var nodeValue = Element.readAttribute(node, attr); if (nodeValue === null) continue; if (handler(nodeValue, value)) results.push(node); }
        return results;
    }, pseudo: function(nodes, name, value, root, combinator) { if (nodes && combinator) nodes = this[combinator](nodes); if (!nodes) nodes = root.getElementsByTagName("*"); return Selector.pseudos[name](nodes, value, root); } 
    }, pseudos: { 'first-child': function(nodes, value, root)
    {
        for (var i = 0, results = [], node; node = nodes[i]; i++) { if (Selector.handlers.previousElementSibling(node)) continue; results.push(node); }
        return results;
    }, 'last-child': function(nodes, value, root)
    {
        for (var i = 0, results = [], node; node = nodes[i]; i++) { if (Selector.handlers.nextElementSibling(node)) continue; results.push(node); }
        return results;
    }, 'only-child': function(nodes, value, root)
    {
        var h = Selector.handlers; for (var i = 0, results = [], node; node = nodes[i]; i++)
            if (!h.previousElementSibling(node) && !h.nextElementSibling(node))
            results.push(node); return results;
    }, 'nth-child': function(nodes, formula, root) { return Selector.pseudos.nth(nodes, formula, root); }, 'nth-last-child': function(nodes, formula, root) { return Selector.pseudos.nth(nodes, formula, root, true); }, 'nth-of-type': function(nodes, formula, root) { return Selector.pseudos.nth(nodes, formula, root, false, true); }, 'nth-last-of-type': function(nodes, formula, root) { return Selector.pseudos.nth(nodes, formula, root, true, true); }, 'first-of-type': function(nodes, formula, root) { return Selector.pseudos.nth(nodes, "1", root, false, true); }, 'last-of-type': function(nodes, formula, root) { return Selector.pseudos.nth(nodes, "1", root, true, true); }, 'only-of-type': function(nodes, formula, root) { var p = Selector.pseudos; return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root); }, getIndices: function(a, b, total) { if (a == 0) return b > 0 ? [b] : []; return $R(1, total).inject([], function(memo, i) { if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i); return memo; }); }, nth: function(nodes, formula, root, reverse, ofType)
    {
        if (nodes.length == 0) return []; if (formula == 'even') formula = '2n+0'; if (formula == 'odd') formula = '2n+1'; var h = Selector.handlers, results = [], indexed = [], m; h.mark(nodes); for (var i = 0, node; node = nodes[i]; i++) { if (!node.parentNode._countedByPrototype) { h.index(node.parentNode, reverse, ofType); indexed.push(node.parentNode); } }
        if (formula.match(/^\d+$/))
        {
            formula = Number(formula); for (var i = 0, node; node = nodes[i]; i++)
                if (node.nodeIndex == formula) results.push(node);
        } else if (m = formula.match(/^(-?\d*)?n(([+-])(\d+))?/))
        {
            if (m[1] == "-") m[1] = -1; var a = m[1] ? Number(m[1]) : 1; var b = m[2] ? Number(m[2]) : 0; var indices = Selector.pseudos.getIndices(a, b, nodes.length); for (var i = 0, node, l = indices.length; node = nodes[i]; i++)
            {
                for (var j = 0; j < l; j++)
                    if (node.nodeIndex == indices[j]) results.push(node);
            } 
        }
        h.unmark(nodes); h.unmark(indexed); return results;
    }, 'empty': function(nodes, value, root)
    {
        for (var i = 0, results = [], node; node = nodes[i]; i++) { if (node.tagName == '!' || node.firstChild) continue; results.push(node); }
        return results;
    }, 'not': function(nodes, selector, root)
    {
        var h = Selector.handlers, selectorType, m; var exclusions = new Selector(selector).findElements(root); h.mark(exclusions); for (var i = 0, results = [], node; node = nodes[i]; i++)
            if (!node._countedByPrototype) results.push(node); h.unmark(exclusions); return results;
    }, 'enabled': function(nodes, value, root)
    {
        for (var i = 0, results = [], node; node = nodes[i]; i++)
            if (!node.disabled && (!node.type || node.type !== 'hidden'))
            results.push(node); return results;
    }, 'disabled': function(nodes, value, root)
    {
        for (var i = 0, results = [], node; node = nodes[i]; i++)
            if (node.disabled) results.push(node); return results;
    }, 'checked': function(nodes, value, root)
    {
        for (var i = 0, results = [], node; node = nodes[i]; i++)
            if (node.checked) results.push(node); return results;
    } 
    }, operators: { '=': function(nv, v) { return nv == v; }, '!=': function(nv, v) { return nv != v; }, '^=': function(nv, v) { return nv == v || nv && nv.startsWith(v); }, '$=': function(nv, v) { return nv == v || nv && nv.endsWith(v); }, '*=': function(nv, v) { return nv == v || nv && nv.include(v); }, '$=': function(nv, v) { return nv.endsWith(v); }, '*=': function(nv, v) { return nv.include(v); }, '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); }, '|=': function(nv, v) { return ('-' + (nv || "").toUpperCase() + '-').include('-' + (v || "").toUpperCase() + '-'); } }, split: function(expression) { var expressions = []; expression.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) { expressions.push(m[1].strip()); }); return expressions; }, matchElements: function(elements, expression)
    {
        var matches = $$(expression), h = Selector.handlers; h.mark(matches); for (var i = 0, results = [], element; element = elements[i]; i++)
            if (element._countedByPrototype) results.push(element); h.unmark(matches); return results;
    }, findElement: function(elements, expression, index)
    {
        if (Object.isNumber(expression)) { index = expression; expression = false; }
        return Selector.matchElements(elements, expression || '*')[index || 0];
    }, findChildElements: function(element, expressions)
    {
        expressions = Selector.split(expressions.join(',')); var results = [], h = Selector.handlers; for (var i = 0, l = expressions.length, selector; i < l; i++) { selector = new Selector(expressions[i].strip()); h.concat(results, selector.findElements(element)); }
        return (l > 1) ? h.unique(results) : results;
    } 
    }); if (Prototype.Browser.IE)
    {
        Object.extend(Selector.handlers, { concat: function(a, b)
        {
            for (var i = 0, node; node = b[i]; i++)
                if (node.tagName !== "!") a.push(node); return a;
        }, unmark: function(nodes)
        {
            for (var i = 0, node; node = nodes[i]; i++)
                node.removeAttribute('_countedByPrototype'); return nodes;
        } 
        });
    }
    function $$() { return Selector.findChildElements(document, $A(arguments)); }
    var Form = { reset: function(form) { $(form).reset(); return form; }, serializeElements: function(elements, options)
    {
        if (typeof options != 'object') options = { hash: !!options }; else if (Object.isUndefined(options.hash)) options.hash = true; var key, value, submitted = false, submit = options.submit; var data = elements.inject({}, function(result, element)
        {
            if (!element.disabled && element.name)
            {
                key = element.name; value = $(element).getValue(); if (value != null && element.type != 'file' && (element.type != 'submit' || (!submitted && submit !== false && (!submit || key == submit) && (submitted = true))))
                {
                    if (key in result) { if (!Object.isArray(result[key])) result[key] = [result[key]]; result[key].push(value); }
                    else result[key] = value;
                } 
            }
            return result;
        }); return options.hash ? data : Object.toQueryString(data);
    } 
    }; Form.Methods = { serialize: function(form, options) { return Form.serializeElements(Form.getElements(form), options); }, getElements: function(form)
    {
        return $A($(form).getElementsByTagName('*')).inject([], function(elements, child)
        {
            if (Form.Element.Serializers[child.tagName.toLowerCase()])
                elements.push(Element.extend(child)); return elements;
        });
    }, getInputs: function(form, typeName, name)
    {
        form = $(form); var inputs = form.getElementsByTagName('input'); if (!typeName && !name) return $A(inputs).map(Element.extend); for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++)
        {
            var input = inputs[i]; if ((typeName && input.type != typeName) || (name && input.name != name))
                continue; matchingInputs.push(Element.extend(input));
        }
        return matchingInputs;
    }, disable: function(form) { form = $(form); Form.getElements(form).invoke('disable'); return form; }, enable: function(form) { form = $(form); Form.getElements(form).invoke('enable'); return form; }, findFirstElement: function(form) { var elements = $(form).getElements().findAll(function(element) { return 'hidden' != element.type && !element.disabled; }); var firstByIndex = elements.findAll(function(element) { return element.hasAttribute('tabIndex') && element.tabIndex >= 0; }).sortBy(function(element) { return element.tabIndex }).first(); return firstByIndex ? firstByIndex : elements.find(function(element) { return ['input', 'select', 'textarea'].include(element.tagName.toLowerCase()); }); }, focusFirstElement: function(form) { form = $(form); form.findFirstElement().activate(); return form; }, request: function(form, options)
    {
        form = $(form), options = Object.clone(options || {}); var params = options.parameters, action = form.readAttribute('action') || ''; if (action.blank()) action = window.location.href; options.parameters = form.serialize(true); if (params) { if (Object.isString(params)) params = params.toQueryParams(); Object.extend(options.parameters, params); }
        if (form.hasAttribute('method') && !options.method)
            options.method = form.method; return new Ajax.Request(action, options);
    } 
    }; Form.Element = { focus: function(element) { $(element).focus(); return element; }, select: function(element) { $(element).select(); return element; } }; Form.Element.Methods = { serialize: function(element)
    {
        element = $(element); if (!element.disabled && element.name) { var value = element.getValue(); if (value != undefined) { var pair = {}; pair[element.name] = value; return Object.toQueryString(pair); } }
        return '';
    }, getValue: function(element) { element = $(element); var method = element.tagName.toLowerCase(); return Form.Element.Serializers[method](element); }, setValue: function(element, value) { element = $(element); var method = element.tagName.toLowerCase(); Form.Element.Serializers[method](element, value); return element; }, clear: function(element) { $(element).value = ''; return element; }, present: function(element) { return $(element).value != ''; }, activate: function(element)
    {
        element = $(element); try
        {
            element.focus(); if (element.select && (element.tagName.toLowerCase() != 'input' || !['button', 'reset', 'submit'].include(element.type)))
                element.select();
        } catch (e) { }
        return element;
    }, disable: function(element) { element = $(element); element.disabled = true; return element; }, enable: function(element) { element = $(element); element.disabled = false; return element; } 
    }; var Field = Form.Element; var $F = Form.Element.Methods.getValue; Form.Element.Serializers = { input: function(element, value) { switch (element.type.toLowerCase()) { case 'checkbox': case 'radio': return Form.Element.Serializers.inputSelector(element, value); default: return Form.Element.Serializers.textarea(element, value); } }, inputSelector: function(element, value) { if (Object.isUndefined(value)) return element.checked ? element.value : null; else element.checked = !!value; }, textarea: function(element, value) { if (Object.isUndefined(value)) return element.value; else element.value = value; }, select: function(element, value)
    {
        if (Object.isUndefined(value))
            return this[element.type == 'select-one' ? 'selectOne' : 'selectMany'](element); else
        {
            var opt, currentValue, single = !Object.isArray(value); for (var i = 0, length = element.length; i < length; i++)
            {
                opt = element.options[i]; currentValue = this.optionValue(opt); if (single) { if (currentValue == value) { opt.selected = true; return; } }
                else opt.selected = value.include(currentValue);
            } 
        } 
    }, selectOne: function(element) { var index = element.selectedIndex; return index >= 0 ? this.optionValue(element.options[index]) : null; }, selectMany: function(element)
    {
        var values, length = element.length; if (!length) return null; for (var i = 0, values = []; i < length; i++) { var opt = element.options[i]; if (opt.selected) values.push(this.optionValue(opt)); }
        return values;
    }, optionValue: function(opt) { return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text; } 
    }; Abstract.TimedObserver = Class.create(PeriodicalExecuter, { initialize: function($super, element, frequency, callback) { $super(callback, frequency); this.element = $(element); this.lastValue = this.getValue(); }, execute: function() { var value = this.getValue(); if (Object.isString(this.lastValue) && Object.isString(value) ? this.lastValue != value : String(this.lastValue) != String(value)) { this.callback(this.element, value); this.lastValue = value; } } }); Form.Element.Observer = Class.create(Abstract.TimedObserver, { getValue: function() { return Form.Element.getValue(this.element); } }); Form.Observer = Class.create(Abstract.TimedObserver, { getValue: function() { return Form.serialize(this.element); } }); Abstract.EventObserver = Class.create({ initialize: function(element, callback)
    {
        this.element = $(element); this.callback = callback; this.lastValue = this.getValue(); if (this.element.tagName.toLowerCase() == 'form')
            this.registerFormCallbacks(); else
            this.registerCallback(this.element);
    }, onElementEvent: function() { var value = this.getValue(); if (this.lastValue != value) { this.callback(this.element, value); this.lastValue = value; } }, registerFormCallbacks: function() { Form.getElements(this.element).each(this.registerCallback, this); }, registerCallback: function(element) { if (element.type) { switch (element.type.toLowerCase()) { case 'checkbox': case 'radio': Event.observe(element, 'click', this.onElementEvent.bind(this)); break; default: Event.observe(element, 'change', this.onElementEvent.bind(this)); break; } } } 
    }); Form.Element.EventObserver = Class.create(Abstract.EventObserver, { getValue: function() { return Form.Element.getValue(this.element); } }); Form.EventObserver = Class.create(Abstract.EventObserver, { getValue: function() { return Form.serialize(this.element); } }); if (!window.Event) var Event = {}; Object.extend(Event, { KEY_BACKSPACE: 8, KEY_TAB: 9, KEY_RETURN: 13, KEY_ESC: 27, KEY_LEFT: 37, KEY_UP: 38, KEY_RIGHT: 39, KEY_DOWN: 40, KEY_DELETE: 46, KEY_HOME: 36, KEY_END: 35, KEY_PAGEUP: 33, KEY_PAGEDOWN: 34, KEY_INSERT: 45, cache: {}, relatedTarget: function(event)
    {
        var element; switch (event.type) { case 'mouseover': element = event.fromElement; break; case 'mouseout': element = event.toElement; break; default: return null; }
        return Element.extend(element);
    } 
    }); Event.Methods = (function()
    {
        var isButton; if (Prototype.Browser.IE) { var buttonMap = { 0: 1, 1: 4, 2: 2 }; isButton = function(event, code) { return event.button == buttonMap[code]; }; } else if (Prototype.Browser.WebKit) { isButton = function(event, code) { switch (code) { case 0: return event.which == 1 && !event.metaKey; case 1: return event.which == 1 && event.metaKey; default: return false; } }; } else { isButton = function(event, code) { return event.which ? (event.which === code + 1) : (event.button === code); }; }
        return { isLeftClick: function(event) { return isButton(event, 0) }, isMiddleClick: function(event) { return isButton(event, 1) }, isRightClick: function(event) { return isButton(event, 2) }, element: function(event)
        {
            event = Event.extend(event); var node = event.target, type = event.type, currentTarget = event.currentTarget; if (currentTarget && currentTarget.tagName)
            {
                if (type === 'load' || type === 'error' || (type === 'click' && currentTarget.tagName.toLowerCase() === 'input' && currentTarget.type === 'radio'))
                    node = currentTarget;
            }
            if (node.nodeType == Node.TEXT_NODE) node = node.parentNode; return Element.extend(node);
        }, findElement: function(event, expression) { var element = Event.element(event); if (!expression) return element; var elements = [element].concat(element.ancestors()); return Selector.findElement(elements, expression, 0); }, pointer: function(event)
        {
            var docElement = document.documentElement, body = document.body || { scrollLeft: 0, scrollTop: 0 }; return { x: event.pageX || (event.clientX +
(docElement.scrollLeft || body.scrollLeft) -
(docElement.clientLeft || 0)), y: event.pageY || (event.clientY +
(docElement.scrollTop || body.scrollTop) -
(docElement.clientTop || 0))
            };
        }, pointerX: function(event) { return Event.pointer(event).x }, pointerY: function(event) { return Event.pointer(event).y }, stop: function(event) { Event.extend(event); event.preventDefault(); event.stopPropagation(); event.stopped = true; } 
        };
    })(); Event.extend = (function() { var methods = Object.keys(Event.Methods).inject({}, function(m, name) { m[name] = Event.Methods[name].methodize(); return m; }); if (Prototype.Browser.IE) { Object.extend(methods, { stopPropagation: function() { this.cancelBubble = true }, preventDefault: function() { this.returnValue = false }, inspect: function() { return "[object Event]" } }); return function(event) { if (!event) return false; if (event._extendedByPrototype) return event; event._extendedByPrototype = Prototype.emptyFunction; var pointer = Event.pointer(event); Object.extend(event, { target: event.srcElement, relatedTarget: Event.relatedTarget(event), pageX: pointer.x, pageY: pointer.y }); return Object.extend(event, methods); }; } else { Event.prototype = Event.prototype || document.createEvent("HTMLEvents")['__proto__']; Object.extend(Event.prototype, methods); return Prototype.K; } })(); Object.extend(Event, (function()
    {
        var cache = Event.cache; function getEventID(element) { if (element._prototypeEventID) return element._prototypeEventID[0]; arguments.callee.id = arguments.callee.id || 1; return element._prototypeEventID = [++arguments.callee.id]; }
        function getDOMEventName(eventName) { if (eventName && eventName.include(':')) return "dataavailable"; return eventName; }
        function getCacheForID(id) { return cache[id] = cache[id] || {}; }
        function getWrappersForEventName(id, eventName) { var c = getCacheForID(id); return c[eventName] = c[eventName] || []; }
        function createWrapper(element, eventName, handler)
        {
            var id = getEventID(element); var c = getWrappersForEventName(id, eventName); if (c.pluck("handler").include(handler)) return false; var wrapper = function(event)
            {
                if (!Event || !Event.extend || (event.eventName && event.eventName != eventName))
                    return false; Event.extend(event); handler.call(element, event);
            }; wrapper.handler = handler; c.push(wrapper); return wrapper;
        }
        function findWrapper(id, eventName, handler) { var c = getWrappersForEventName(id, eventName); return c.find(function(wrapper) { return wrapper.handler == handler }); }
        function destroyWrapper(id, eventName, handler) { var c = getCacheForID(id); if (!c[eventName]) return false; c[eventName] = c[eventName].without(findWrapper(id, eventName, handler)); }
        function destroyCache()
        {
            for (var id in cache)
                for (var eventName in cache[id])
                cache[id][eventName] = null;
        }
        if (window.attachEvent) { window.attachEvent("onunload", destroyCache); }
        if (Prototype.Browser.WebKit) { window.addEventListener('unload', Prototype.emptyFunction, false); }
        return { observe: function(element, eventName, handler)
        {
            element = $(element); var name = getDOMEventName(eventName); var wrapper = createWrapper(element, eventName, handler); if (!wrapper) return element; if (element.addEventListener) { element.addEventListener(name, wrapper, false); } else { element.attachEvent("on" + name, wrapper); }
            return element;
        }, stopObserving: function(element, eventName, handler)
        {
            element = $(element); var id = getEventID(element), name = getDOMEventName(eventName); if (!handler && eventName) { getWrappersForEventName(id, eventName).each(function(wrapper) { element.stopObserving(eventName, wrapper.handler); }); return element; } else if (!eventName) { Object.keys(getCacheForID(id)).each(function(eventName) { element.stopObserving(eventName); }); return element; }
            var wrapper = findWrapper(id, eventName, handler); if (!wrapper) return element; if (element.removeEventListener) { element.removeEventListener(name, wrapper, false); } else { element.detachEvent("on" + name, wrapper); }
            destroyWrapper(id, eventName, handler); return element;
        }, fire: function(element, eventName, memo)
        {
            element = $(element); if (element == document && document.createEvent && !element.dispatchEvent)
                element = document.documentElement; var event; if (document.createEvent) { event = document.createEvent("HTMLEvents"); event.initEvent("dataavailable", true, true); } else { event = document.createEventObject(); event.eventType = "ondataavailable"; }
            event.eventName = eventName; event.memo = memo || {}; if (document.createEvent) { element.dispatchEvent(event); } else { element.fireEvent(event.eventType, event); }
            return Event.extend(event);
        } 
        };
    })()); Object.extend(Event, Event.Methods); Element.addMethods({ fire: Event.fire, observe: Event.observe, stopObserving: Event.stopObserving }); Object.extend(document, { fire: Element.Methods.fire.methodize(), observe: Element.Methods.observe.methodize(), stopObserving: Element.Methods.stopObserving.methodize(), loaded: false }); (function()
    {
        var timer; function fireContentLoadedEvent() { if (document.loaded) return; if (timer) window.clearInterval(timer); document.fire("dom:loaded"); document.loaded = true; }
        if (document.addEventListener)
        {
            if (Prototype.Browser.WebKit)
            {
                timer = window.setInterval(function()
                {
                    if (/loaded|complete/.test(document.readyState))
                        fireContentLoadedEvent();
                }, 0); Event.observe(window, "load", fireContentLoadedEvent);
            } else { document.addEventListener("DOMContentLoaded", fireContentLoadedEvent, false); } 
        } else { document.write("<script id=__onDOMContentLoaded defer src=//:><\/script>"); $("__onDOMContentLoaded").onreadystatechange = function() { if (this.readyState == "complete") { this.onreadystatechange = null; fireContentLoadedEvent(); } }; } 
    })(); Hash.toQueryString = Object.toQueryString; var Toggle = { display: Element.toggle }; Element.Methods.childOf = Element.Methods.descendantOf; var Insertion = { Before: function(element, content) { return Element.insert(element, { before: content }); }, Top: function(element, content) { return Element.insert(element, { top: content }); }, Bottom: function(element, content) { return Element.insert(element, { bottom: content }); }, After: function(element, content) { return Element.insert(element, { after: content }); } }; var $continue = new Error('"throw $continue" is deprecated, use "return" instead'); var Position = { includeScrollOffsets: false, prepare: function() { this.deltaX = window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft || 0; this.deltaY = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0; }, within: function(element, x, y)
    {
        if (this.includeScrollOffsets)
            return this.withinIncludingScrolloffsets(element, x, y); this.xcomp = x; this.ycomp = y; this.offset = Element.cumulativeOffset(element); return (y >= this.offset[1] && y < this.offset[1] + element.offsetHeight && x >= this.offset[0] && x < this.offset[0] + element.offsetWidth);
    }, withinIncludingScrolloffsets: function(element, x, y) { var offsetcache = Element.cumulativeScrollOffset(element); this.xcomp = x + offsetcache[0] - this.deltaX; this.ycomp = y + offsetcache[1] - this.deltaY; this.offset = Element.cumulativeOffset(element); return (this.ycomp >= this.offset[1] && this.ycomp < this.offset[1] + element.offsetHeight && this.xcomp >= this.offset[0] && this.xcomp < this.offset[0] + element.offsetWidth); }, overlap: function(mode, element)
    {
        if (!mode) return 0; if (mode == 'vertical')
            return ((this.offset[1] + element.offsetHeight) - this.ycomp) / element.offsetHeight; if (mode == 'horizontal')
            return ((this.offset[0] + element.offsetWidth) - this.xcomp) / element.offsetWidth;
    }, cumulativeOffset: Element.Methods.cumulativeOffset, positionedOffset: Element.Methods.positionedOffset, absolutize: function(element) { Position.prepare(); return Element.absolutize(element); }, relativize: function(element) { Position.prepare(); return Element.relativize(element); }, realOffset: Element.Methods.cumulativeScrollOffset, offsetParent: Element.Methods.getOffsetParent, page: Element.Methods.viewportOffset, clone: function(source, target, options) { options = options || {}; return Element.clonePosition(target, source, options); } 
    }; if (!document.getElementsByClassName) document.getElementsByClassName = function(instanceMethods)
    {
        function iter(name) { return name.blank() ? null : "[contains(concat(' ', @class, ' '), ' " + name + " ')]"; }
        instanceMethods.getElementsByClassName = Prototype.BrowserFeatures.XPath ? function(element, className) { className = className.toString().strip(); var cond = /\s/.test(className) ? $w(className).map(iter).join('') : iter(className); return cond ? document._getElementsByXPath('.//*' + cond, element) : []; } : function(element, className)
        {
            className = className.toString().strip(); var elements = [], classNames = (/\s/.test(className) ? $w(className) : null); if (!classNames && !className) return elements; var nodes = $(element).getElementsByTagName('*'); className = ' ' + className + ' '; for (var i = 0, child, cn; child = nodes[i]; i++)
            {
                if (child.className && (cn = ' ' + child.className + ' ') && (cn.include(className) || (classNames && classNames.all(function(name) { return !name.toString().blank() && cn.include(' ' + name + ' '); }))))
                    elements.push(Element.extend(child));
            }
            return elements;
        }; return function(className, parentElement) { return $(parentElement || document.body).getElementsByClassName(className); };
    } (Element.Methods); Element.ClassNames = Class.create(); Element.ClassNames.prototype = { initialize: function(element) { this.element = $(element); }, _each: function(iterator) { this.element.className.split(/\s+/).select(function(name) { return name.length > 0; })._each(iterator); }, set: function(className) { this.element.className = className; }, add: function(classNameToAdd) { if (this.include(classNameToAdd)) return; this.set($A(this).concat(classNameToAdd).join(' ')); }, remove: function(classNameToRemove) { if (!this.include(classNameToRemove)) return; this.set($A(this).without(classNameToRemove).join(' ')); }, toString: function() { return $A(this).join(' '); } }; Object.extend(Element.ClassNames.prototype, Enumerable); Element.addMethods(); String.prototype.parseColor = function()
    {
        var color = '#'; if (this.slice(0, 4) == 'rgb(') { var cols = this.slice(4, this.length - 1).split(','); var i = 0; do { color += parseInt(cols[i]).toColorPart() } while (++i < 3); } else { if (this.slice(0, 1) == '#') { if (this.length == 4) for (var i = 1; i < 4; i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase(); if (this.length == 7) color = this.toLowerCase(); } }
        return (color.length == 7 ? color : (arguments[0] || this));
    }; Element.collectTextNodes = function(element) { return $A($(element).childNodes).collect(function(node) { return (node.nodeType == 3 ? node.nodeValue : (node.hasChildNodes() ? Element.collectTextNodes(node) : '')); }).flatten().join(''); }; Element.collectTextNodesIgnoreClass = function(element, className) { return $A($(element).childNodes).collect(function(node) { return (node.nodeType == 3 ? node.nodeValue : ((node.hasChildNodes() && !Element.hasClassName(node, className)) ? Element.collectTextNodesIgnoreClass(node, className) : '')); }).flatten().join(''); }; Element.setContentZoom = function(element, percent) { element = $(element); element.setStyle({ fontSize: (percent / 100) + 'em' }); if (Prototype.Browser.WebKit) window.scrollBy(0, 0); return element; }; Element.getInlineOpacity = function(element) { return $(element).style.opacity || ''; }; Element.forceRerendering = function(element) { try { element = $(element); var n = document.createTextNode(' '); element.appendChild(n); element.removeChild(n); } catch (e) { } }; var Effect = { _elementDoesNotExistError: { name: 'ElementDoesNotExistError', message: 'The specified DOM element does not exist, but is required for this effect to operate' }, Transitions: { linear: Prototype.K, sinoidal: function(pos) { return (-Math.cos(pos * Math.PI) / 2) + .5; }, reverse: function(pos) { return 1 - pos; }, flicker: function(pos) { var pos = ((-Math.cos(pos * Math.PI) / 4) + .75) + Math.random() / 4; return pos > 1 ? 1 : pos; }, wobble: function(pos) { return (-Math.cos(pos * Math.PI * (9 * pos)) / 2) + .5; }, pulse: function(pos, pulses) { return (-Math.cos((pos * ((pulses || 5) - .5) * 2) * Math.PI) / 2) + .5; }, spring: function(pos) { return 1 - (Math.cos(pos * 4.5 * Math.PI) * Math.exp(-pos * 6)); }, none: function(pos) { return 0; }, full: function(pos) { return 1; } }, DefaultOptions: { duration: 1.0, fps: 100, sync: false, from: 0.0, to: 1.0, delay: 0.0, queue: 'parallel' }, tagifyText: function(element) { var tagifyStyle = 'position:relative'; if (Prototype.Browser.IE) tagifyStyle += ';zoom:1'; element = $(element); $A(element.childNodes).each(function(child) { if (child.nodeType == 3) { child.nodeValue.toArray().each(function(character) { element.insertBefore(new Element('span', { style: tagifyStyle }).update(character == ' ' ? String.fromCharCode(160) : character), child); }); Element.remove(child); } }); }, multiple: function(element, effect)
    {
        var elements; if (((typeof element == 'object') || Object.isFunction(element)) && (element.length))
            elements = element; else
            elements = $(element).childNodes; var options = Object.extend({ speed: 0.1, delay: 0.0 }, arguments[2] || {}); var masterDelay = options.delay; $A(elements).each(function(element, index) { new effect(element, Object.extend(options, { delay: index * options.speed + masterDelay })); });
    }, PAIRS: { 'slide': ['SlideDown', 'SlideUp'], 'blind': ['BlindDown', 'BlindUp'], 'appear': ['Appear', 'Fade'] }, toggle: function(element, effect) { element = $(element); effect = (effect || 'appear').toLowerCase(); var options = Object.extend({ queue: { position: 'end', scope: (element.id || 'global'), limit: 1} }, arguments[2] || {}); Effect[element.visible() ? Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options); } 
    }; Effect.DefaultOptions.transition = Effect.Transitions.sinoidal; Effect.ScopedQueue = Class.create(Enumerable, { initialize: function() { this.effects = []; this.interval = null; }, _each: function(iterator) { this.effects._each(iterator); }, add: function(effect)
    {
        var timestamp = new Date().getTime(); var position = Object.isString(effect.options.queue) ? effect.options.queue : effect.options.queue.position; switch (position) { case 'front': this.effects.findAll(function(e) { return e.state == 'idle' }).each(function(e) { e.startOn += effect.finishOn; e.finishOn += effect.finishOn; }); break; case 'with-last': timestamp = this.effects.pluck('startOn').max() || timestamp; break; case 'end': timestamp = this.effects.pluck('finishOn').max() || timestamp; break; }
        effect.startOn += timestamp; effect.finishOn += timestamp; if (!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit))
            this.effects.push(effect); if (!this.interval)
            this.interval = setInterval(this.loop.bind(this), 15);
    }, remove: function(effect) { this.effects = this.effects.reject(function(e) { return e == effect }); if (this.effects.length == 0) { clearInterval(this.interval); this.interval = null; } }, loop: function()
    {
        var timePos = new Date().getTime(); for (var i = 0, len = this.effects.length; i < len; i++)
            this.effects[i] && this.effects[i].loop(timePos);
    } 
    }); Effect.Queues = { instances: $H(), get: function(queueName) { if (!Object.isString(queueName)) return queueName; return this.instances.get(queueName) || this.instances.set(queueName, new Effect.ScopedQueue()); } }; Effect.Queue = Effect.Queues.get('global'); Effect.Base = Class.create({ position: null, start: function(options)
    {
        function codeForEvent(options, eventName)
        {
            return ((options[eventName + 'Internal'] ? 'this.options.' + eventName + 'Internal(this);' : '') +
(options[eventName] ? 'this.options.' + eventName + '(this);' : ''));
        }
        if (options && options.transition === false) options.transition = Effect.Transitions.linear; this.options = Object.extend(Object.extend({}, Effect.DefaultOptions), options || {}); this.currentFrame = 0; this.state = 'idle'; this.startOn = this.options.delay * 1000; this.finishOn = this.startOn + (this.options.duration * 1000); this.fromToDelta = this.options.to - this.options.from; this.totalTime = this.finishOn - this.startOn; this.totalFrames = this.options.fps * this.options.duration; this.render = (function()
        {
            function dispatch(effect, eventName)
            {
                if (effect.options[eventName + 'Internal'])
                    effect.options[eventName + 'Internal'](effect); if (effect.options[eventName])
                    effect.options[eventName](effect);
            }
            return function(pos)
            {
                if (this.state === "idle") { this.state = "running"; dispatch(this, 'beforeSetup'); if (this.setup) this.setup(); dispatch(this, 'afterSetup'); }
                if (this.state === "running") { pos = (this.options.transition(pos) * this.fromToDelta) + this.options.from; this.position = pos; dispatch(this, 'beforeUpdate'); if (this.update) this.update(pos); dispatch(this, 'afterUpdate'); } 
            };
        })(); this.event('beforeStart'); if (!this.options.sync)
            Effect.Queues.get(Object.isString(this.options.queue) ? 'global' : this.options.queue.scope).add(this);
    }, loop: function(timePos)
    {
        if (timePos >= this.startOn)
        {
            if (timePos >= this.finishOn) { this.render(1.0); this.cancel(); this.event('beforeFinish'); if (this.finish) this.finish(); this.event('afterFinish'); return; }
            var pos = (timePos - this.startOn) / this.totalTime, frame = (pos * this.totalFrames).round(); if (frame > this.currentFrame) { this.render(pos); this.currentFrame = frame; } 
        } 
    }, cancel: function()
    {
        if (!this.options.sync)
            Effect.Queues.get(Object.isString(this.options.queue) ? 'global' : this.options.queue.scope).remove(this); this.state = 'finished';
    }, event: function(eventName) { if (this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this); if (this.options[eventName]) this.options[eventName](this); }, inspect: function()
    {
        var data = $H(); for (property in this)
            if (!Object.isFunction(this[property])) data.set(property, this[property]); return '#<Effect:' + data.inspect() + ',options:' + $H(this.options).inspect() + '>';
    } 
    }); Effect.Parallel = Class.create(Effect.Base, { initialize: function(effects) { this.effects = effects || []; this.start(arguments[1]); }, update: function(position) { this.effects.invoke('render', position); }, finish: function(position) { this.effects.each(function(effect) { effect.render(1.0); effect.cancel(); effect.event('beforeFinish'); if (effect.finish) effect.finish(position); effect.event('afterFinish'); }); } }); Effect.Tween = Class.create(Effect.Base, { initialize: function(object, from, to) { object = Object.isString(object) ? $(object) : object; var args = $A(arguments), method = args.last(), options = args.length == 5 ? args[3] : null; this.method = Object.isFunction(method) ? method.bind(object) : Object.isFunction(object[method]) ? object[method].bind(object) : function(value) { object[method] = value }; this.start(Object.extend({ from: from, to: to }, options || {})); }, update: function(position) { this.method(position); } }); Effect.Event = Class.create(Effect.Base, { initialize: function() { this.start(Object.extend({ duration: 0 }, arguments[0] || {})); }, update: Prototype.emptyFunction }); Effect.Opacity = Class.create(Effect.Base, { initialize: function(element)
    {
        this.element = $(element); if (!this.element) throw (Effect._elementDoesNotExistError); if (Prototype.Browser.IE && (!this.element.currentStyle.hasLayout))
            this.element.setStyle({ zoom: 1 }); var options = Object.extend({ from: this.element.getOpacity() || 0.0, to: 1.0 }, arguments[1] || {}); this.start(options);
    }, update: function(position) { this.element.setOpacity(position); } 
    }); Effect.Move = Class.create(Effect.Base, { initialize: function(element) { this.element = $(element); if (!this.element) throw (Effect._elementDoesNotExistError); var options = Object.extend({ x: 0, y: 0, mode: 'relative' }, arguments[1] || {}); this.start(options); }, setup: function() { this.element.makePositioned(); this.originalLeft = parseFloat(this.element.getStyle('left') || '0'); this.originalTop = parseFloat(this.element.getStyle('top') || '0'); if (this.options.mode == 'absolute') { this.options.x = this.options.x - this.originalLeft; this.options.y = this.options.y - this.originalTop; } }, update: function(position) { this.element.setStyle({ left: (this.options.x * position + this.originalLeft).round() + 'px', top: (this.options.y * position + this.originalTop).round() + 'px' }); } }); Effect.MoveBy = function(element, toTop, toLeft) { return new Effect.Move(element, Object.extend({ x: toLeft, y: toTop }, arguments[3] || {})); }; Effect.Scale = Class.create(Effect.Base, { initialize: function(element, percent) { this.element = $(element); if (!this.element) throw (Effect._elementDoesNotExistError); var options = Object.extend({ scaleX: true, scaleY: true, scaleContent: true, scaleFromCenter: false, scaleMode: 'box', scaleFrom: 100.0, scaleTo: percent }, arguments[2] || {}); this.start(options); }, setup: function()
    {
        this.restoreAfterFinish = this.options.restoreAfterFinish || false; this.elementPositioning = this.element.getStyle('position'); this.originalStyle = {}; ['top', 'left', 'width', 'height', 'fontSize'].each(function(k) { this.originalStyle[k] = this.element.style[k]; } .bind(this)); this.originalTop = this.element.offsetTop; this.originalLeft = this.element.offsetLeft; var fontSize = this.element.getStyle('font-size') || '100%'; ['em', 'px', '%', 'pt'].each(function(fontSizeType) { if (fontSize.indexOf(fontSizeType) > 0) { this.fontSize = parseFloat(fontSize); this.fontSizeType = fontSizeType; } } .bind(this)); this.factor = (this.options.scaleTo - this.options.scaleFrom) / 100; this.dims = null; if (this.options.scaleMode == 'box')
            this.dims = [this.element.offsetHeight, this.element.offsetWidth]; if (/^content/.test(this.options.scaleMode))
            this.dims = [this.element.scrollHeight, this.element.scrollWidth]; if (!this.dims)
            this.dims = [this.options.scaleMode.originalHeight, this.options.scaleMode.originalWidth];
    }, update: function(position)
    {
        var currentScale = (this.options.scaleFrom / 100.0) + (this.factor * position); if (this.options.scaleContent && this.fontSize)
            this.element.setStyle({ fontSize: this.fontSize * currentScale + this.fontSizeType }); this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale);
    }, finish: function(position) { if (this.restoreAfterFinish) this.element.setStyle(this.originalStyle); }, setDimensions: function(height, width)
    {
        var d = {}; if (this.options.scaleX) d.width = width.round() + 'px'; if (this.options.scaleY) d.height = height.round() + 'px'; if (this.options.scaleFromCenter) { var topd = (height - this.dims[0]) / 2; var leftd = (width - this.dims[1]) / 2; if (this.elementPositioning == 'absolute') { if (this.options.scaleY) d.top = this.originalTop - topd + 'px'; if (this.options.scaleX) d.left = this.originalLeft - leftd + 'px'; } else { if (this.options.scaleY) d.top = -topd + 'px'; if (this.options.scaleX) d.left = -leftd + 'px'; } }
        this.element.setStyle(d);
    } 
    }); Effect.Highlight = Class.create(Effect.Base, { initialize: function(element) { this.element = $(element); if (!this.element) throw (Effect._elementDoesNotExistError); var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || {}); this.start(options); }, setup: function()
    {
        if (this.element.getStyle('display') == 'none') { this.cancel(); return; }
        this.oldStyle = {}; if (!this.options.keepBackgroundImage) { this.oldStyle.backgroundImage = this.element.getStyle('background-image'); this.element.setStyle({ backgroundImage: 'none' }); }
        if (!this.options.endcolor)
            this.options.endcolor = this.element.getStyle('background-color').parseColor('#ffffff'); if (!this.options.restorecolor)
            this.options.restorecolor = this.element.getStyle('background-color'); this._base = $R(0, 2).map(function(i) { return parseInt(this.options.startcolor.slice(i * 2 + 1, i * 2 + 3), 16) } .bind(this)); this._delta = $R(0, 2).map(function(i) { return parseInt(this.options.endcolor.slice(i * 2 + 1, i * 2 + 3), 16) - this._base[i] } .bind(this));
    }, update: function(position) { this.element.setStyle({ backgroundColor: $R(0, 2).inject('#', function(m, v, i) { return m + ((this._base[i] + (this._delta[i] * position)).round().toColorPart()); } .bind(this)) }); }, finish: function() { this.element.setStyle(Object.extend(this.oldStyle, { backgroundColor: this.options.restorecolor })); } 
    }); Effect.ScrollTo = function(element) { var options = arguments[1] || {}, scrollOffsets = document.viewport.getScrollOffsets(), elementOffsets = $(element).cumulativeOffset(); if (options.offset) elementOffsets[1] += options.offset; return new Effect.Tween(null, scrollOffsets.top, elementOffsets[1], options, function(p) { scrollTo(scrollOffsets.left, p.round()); }); }; Effect.Fade = function(element) { element = $(element); var oldOpacity = element.getInlineOpacity(); var options = Object.extend({ from: element.getOpacity() || 1.0, to: 0.0, afterFinishInternal: function(effect) { if (effect.options.to != 0) return; effect.element.hide().setStyle({ opacity: oldOpacity }); } }, arguments[1] || {}); return new Effect.Opacity(element, options); }; Effect.Appear = function(element) { element = $(element); var options = Object.extend({ from: (element.getStyle('display') == 'none' ? 0.0 : element.getOpacity() || 0.0), to: 1.0, afterFinishInternal: function(effect) { effect.element.forceRerendering(); }, beforeSetup: function(effect) { effect.element.setOpacity(effect.options.from).show(); } }, arguments[1] || {}); return new Effect.Opacity(element, options); }; Effect.Puff = function(element) { element = $(element); var oldStyle = { opacity: element.getInlineOpacity(), position: element.getStyle('position'), top: element.style.top, left: element.style.left, width: element.style.width, height: element.style.height }; return new Effect.Parallel([new Effect.Scale(element, 200, { sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }), new Effect.Opacity(element, { sync: true, to: 0.0 })], Object.extend({ duration: 1.0, beforeSetupInternal: function(effect) { Position.absolutize(effect.effects[0].element); }, afterFinishInternal: function(effect) { effect.effects[0].element.hide().setStyle(oldStyle); } }, arguments[1] || {})); }; Effect.BlindUp = function(element) { element = $(element); element.makeClipping(); return new Effect.Scale(element, 0, Object.extend({ scaleContent: false, scaleX: false, restoreAfterFinish: true, afterFinishInternal: function(effect) { effect.element.hide().undoClipping(); } }, arguments[1] || {})); }; Effect.BlindDown = function(element) { element = $(element); var elementDimensions = element.getDimensions(); return new Effect.Scale(element, 100, Object.extend({ scaleContent: false, scaleX: false, scaleFrom: 0, scaleMode: { originalHeight: elementDimensions.height, originalWidth: elementDimensions.width }, restoreAfterFinish: true, afterSetup: function(effect) { effect.element.makeClipping().setStyle({ height: '0px' }).show(); }, afterFinishInternal: function(effect) { effect.element.undoClipping(); } }, arguments[1] || {})); }; Effect.SwitchOff = function(element) { element = $(element); var oldOpacity = element.getInlineOpacity(); return new Effect.Appear(element, Object.extend({ duration: 0.4, from: 0, transition: Effect.Transitions.flicker, afterFinishInternal: function(effect) { new Effect.Scale(effect.element, 1, { duration: 0.3, scaleFromCenter: true, scaleX: false, scaleContent: false, restoreAfterFinish: true, beforeSetup: function(effect) { effect.element.makePositioned().makeClipping(); }, afterFinishInternal: function(effect) { effect.element.hide().undoClipping().undoPositioned().setStyle({ opacity: oldOpacity }); } }); } }, arguments[1] || {})); }; Effect.DropOut = function(element) { element = $(element); var oldStyle = { top: element.getStyle('top'), left: element.getStyle('left'), opacity: element.getInlineOpacity() }; return new Effect.Parallel([new Effect.Move(element, { x: 0, y: 100, sync: true }), new Effect.Opacity(element, { sync: true, to: 0.0 })], Object.extend({ duration: 0.5, beforeSetup: function(effect) { effect.effects[0].element.makePositioned(); }, afterFinishInternal: function(effect) { effect.effects[0].element.hide().undoPositioned().setStyle(oldStyle); } }, arguments[1] || {})); }; Effect.Shake = function(element) { element = $(element); var options = Object.extend({ distance: 20, duration: 0.5 }, arguments[1] || {}); var distance = parseFloat(options.distance); var split = parseFloat(options.duration) / 10.0; var oldStyle = { top: element.getStyle('top'), left: element.getStyle('left') }; return new Effect.Move(element, { x: distance, y: 0, duration: split, afterFinishInternal: function(effect) { new Effect.Move(effect.element, { x: -distance * 2, y: 0, duration: split * 2, afterFinishInternal: function(effect) { new Effect.Move(effect.element, { x: distance * 2, y: 0, duration: split * 2, afterFinishInternal: function(effect) { new Effect.Move(effect.element, { x: -distance * 2, y: 0, duration: split * 2, afterFinishInternal: function(effect) { new Effect.Move(effect.element, { x: distance * 2, y: 0, duration: split * 2, afterFinishInternal: function(effect) { new Effect.Move(effect.element, { x: -distance, y: 0, duration: split, afterFinishInternal: function(effect) { effect.element.undoPositioned().setStyle(oldStyle); } }); } }); } }); } }); } }); } }); }; Effect.SlideDown = function(element) { element = $(element).cleanWhitespace(); var oldInnerBottom = element.down().getStyle('bottom'); var elementDimensions = element.getDimensions(); return new Effect.Scale(element, 100, Object.extend({ scaleContent: false, scaleX: false, scaleFrom: window.opera ? 0 : 1, scaleMode: { originalHeight: elementDimensions.height, originalWidth: elementDimensions.width }, restoreAfterFinish: true, afterSetup: function(effect) { effect.element.makePositioned(); effect.element.down().makePositioned(); if (window.opera) effect.element.setStyle({ top: '' }); effect.element.makeClipping().setStyle({ height: '0px' }).show(); }, afterUpdateInternal: function(effect) { effect.element.down().setStyle({ bottom: (effect.dims[0] - effect.element.clientHeight) + 'px' }); }, afterFinishInternal: function(effect) { effect.element.undoClipping().undoPositioned(); effect.element.down().undoPositioned().setStyle({ bottom: oldInnerBottom }); } }, arguments[1] || {})); }; Effect.SlideUp = function(element) { element = $(element).cleanWhitespace(); var oldInnerBottom = element.down().getStyle('bottom'); var elementDimensions = element.getDimensions(); return new Effect.Scale(element, window.opera ? 0 : 1, Object.extend({ scaleContent: false, scaleX: false, scaleMode: 'box', scaleFrom: 100, scaleMode: { originalHeight: elementDimensions.height, originalWidth: elementDimensions.width }, restoreAfterFinish: true, afterSetup: function(effect) { effect.element.makePositioned(); effect.element.down().makePositioned(); if (window.opera) effect.element.setStyle({ top: '' }); effect.element.makeClipping().show(); }, afterUpdateInternal: function(effect) { effect.element.down().setStyle({ bottom: (effect.dims[0] - effect.element.clientHeight) + 'px' }); }, afterFinishInternal: function(effect) { effect.element.hide().undoClipping().undoPositioned(); effect.element.down().undoPositioned().setStyle({ bottom: oldInnerBottom }); } }, arguments[1] || {})); }; Effect.Squish = function(element) { return new Effect.Scale(element, window.opera ? 1 : 0, { restoreAfterFinish: true, beforeSetup: function(effect) { effect.element.makeClipping(); }, afterFinishInternal: function(effect) { effect.element.hide().undoClipping(); } }); }; Effect.Grow = function(element)
    {
        element = $(element); var options = Object.extend({ direction: 'center', moveTransition: Effect.Transitions.sinoidal, scaleTransition: Effect.Transitions.sinoidal, opacityTransition: Effect.Transitions.full }, arguments[1] || {}); var oldStyle = { top: element.style.top, left: element.style.left, height: element.style.height, width: element.style.width, opacity: element.getInlineOpacity() }; var dims = element.getDimensions(); var initialMoveX, initialMoveY; var moveX, moveY; switch (options.direction) { case 'top-left': initialMoveX = initialMoveY = moveX = moveY = 0; break; case 'top-right': initialMoveX = dims.width; initialMoveY = moveY = 0; moveX = -dims.width; break; case 'bottom-left': initialMoveX = moveX = 0; initialMoveY = dims.height; moveY = -dims.height; break; case 'bottom-right': initialMoveX = dims.width; initialMoveY = dims.height; moveX = -dims.width; moveY = -dims.height; break; case 'center': initialMoveX = dims.width / 2; initialMoveY = dims.height / 2; moveX = -dims.width / 2; moveY = -dims.height / 2; break; }
        return new Effect.Move(element, { x: initialMoveX, y: initialMoveY, duration: 0.01, beforeSetup: function(effect) { effect.element.hide().makeClipping().makePositioned(); }, afterFinishInternal: function(effect) { new Effect.Parallel([new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }), new Effect.Move(effect.element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }), new Effect.Scale(effect.element, 100, { scaleMode: { originalHeight: dims.height, originalWidth: dims.width }, sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true })], Object.extend({ beforeSetup: function(effect) { effect.effects[0].element.setStyle({ height: '0px' }).show(); }, afterFinishInternal: function(effect) { effect.effects[0].element.undoClipping().undoPositioned().setStyle(oldStyle); } }, options)); } });
    }; Effect.Shrink = function(element)
    {
        element = $(element); var options = Object.extend({ direction: 'center', moveTransition: Effect.Transitions.sinoidal, scaleTransition: Effect.Transitions.sinoidal, opacityTransition: Effect.Transitions.none }, arguments[1] || {}); var oldStyle = { top: element.style.top, left: element.style.left, height: element.style.height, width: element.style.width, opacity: element.getInlineOpacity() }; var dims = element.getDimensions(); var moveX, moveY; switch (options.direction) { case 'top-left': moveX = moveY = 0; break; case 'top-right': moveX = dims.width; moveY = 0; break; case 'bottom-left': moveX = 0; moveY = dims.height; break; case 'bottom-right': moveX = dims.width; moveY = dims.height; break; case 'center': moveX = dims.width / 2; moveY = dims.height / 2; break; }
        return new Effect.Parallel([new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }), new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true }), new Effect.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition })], Object.extend({ beforeStartInternal: function(effect) { effect.effects[0].element.makePositioned().makeClipping(); }, afterFinishInternal: function(effect) { effect.effects[0].element.hide().undoClipping().undoPositioned().setStyle(oldStyle); } }, options));
    }; Effect.Pulsate = function(element) { element = $(element); var options = arguments[1] || {}, oldOpacity = element.getInlineOpacity(), transition = options.transition || Effect.Transitions.linear, reverser = function(pos) { return 1 - transition((-Math.cos((pos * (options.pulses || 5) * 2) * Math.PI) / 2) + .5); }; return new Effect.Opacity(element, Object.extend(Object.extend({ duration: 2.0, from: 0, afterFinishInternal: function(effect) { effect.element.setStyle({ opacity: oldOpacity }); } }, options), { transition: reverser })); }; Effect.Fold = function(element) { element = $(element); var oldStyle = { top: element.style.top, left: element.style.left, width: element.style.width, height: element.style.height }; element.makeClipping(); return new Effect.Scale(element, 5, Object.extend({ scaleContent: false, scaleX: false, afterFinishInternal: function(effect) { new Effect.Scale(element, 1, { scaleContent: false, scaleY: false, afterFinishInternal: function(effect) { effect.element.hide().undoClipping().setStyle(oldStyle); } }); } }, arguments[1] || {})); }; Effect.Morph = Class.create(Effect.Base, { initialize: function(element)
    {
        this.element = $(element); if (!this.element) throw (Effect._elementDoesNotExistError); var options = Object.extend({ style: {} }, arguments[1] || {}); if (!Object.isString(options.style)) this.style = $H(options.style); else
        {
            if (options.style.include(':'))
                this.style = options.style.parseStyle(); else { this.element.addClassName(options.style); this.style = $H(this.element.getStyles()); this.element.removeClassName(options.style); var css = this.element.getStyles(); this.style = this.style.reject(function(style) { return style.value == css[style.key]; }); options.afterFinishInternal = function(effect) { effect.element.addClassName(effect.options.style); effect.transforms.each(function(transform) { effect.element.style[transform.style] = ''; }); }; } 
        }
        this.start(options);
    }, setup: function()
    {
        function parseColor(color) { if (!color || ['rgba(0, 0, 0, 0)', 'transparent'].include(color)) color = '#ffffff'; color = color.parseColor(); return $R(0, 2).map(function(i) { return parseInt(color.slice(i * 2 + 1, i * 2 + 3), 16); }); }
        this.transforms = this.style.map(function(pair)
        {
            var property = pair[0], value = pair[1], unit = null; if (value.parseColor('#zzzzzz') != '#zzzzzz') { value = value.parseColor(); unit = 'color'; } else if (property == 'opacity')
            {
                value = parseFloat(value); if (Prototype.Browser.IE && (!this.element.currentStyle.hasLayout))
                    this.element.setStyle({ zoom: 1 });
            } else if (Element.CSS_LENGTH.test(value)) { var components = value.match(/^([\+\-]?[0-9\.]+)(.*)$/); value = parseFloat(components[1]); unit = (components.length == 3) ? components[2] : null; }
            var originalValue = this.element.getStyle(property); return { style: property.camelize(), originalValue: unit == 'color' ? parseColor(originalValue) : parseFloat(originalValue || 0), targetValue: unit == 'color' ? parseColor(value) : value, unit: unit };
        } .bind(this)).reject(function(transform) { return ((transform.originalValue == transform.targetValue) || (transform.unit != 'color' && (isNaN(transform.originalValue) || isNaN(transform.targetValue)))); });
    }, update: function(position)
    {
        var style = {}, transform, i = this.transforms.length; while (i--)
            style[(transform = this.transforms[i]).style] = transform.unit == 'color' ? '#' +
(Math.round(transform.originalValue[0] +
(transform.targetValue[0] - transform.originalValue[0]) * position)).toColorPart() +
(Math.round(transform.originalValue[1] +
(transform.targetValue[1] - transform.originalValue[1]) * position)).toColorPart() +
(Math.round(transform.originalValue[2] +
(transform.targetValue[2] - transform.originalValue[2]) * position)).toColorPart() : (transform.originalValue +
(transform.targetValue - transform.originalValue) * position).toFixed(3) +
(transform.unit === null ? '' : transform.unit); this.element.setStyle(style, true);
    } 
    }); Effect.Transform = Class.create({ initialize: function(tracks) { this.tracks = []; this.options = arguments[1] || {}; this.addTracks(tracks); }, addTracks: function(tracks) { tracks.each(function(track) { track = $H(track); var data = track.values().first(); this.tracks.push($H({ ids: track.keys().first(), effect: Effect.Morph, options: { style: data} })); } .bind(this)); return this; }, play: function() { return new Effect.Parallel(this.tracks.map(function(track) { var ids = track.get('ids'), effect = track.get('effect'), options = track.get('options'); var elements = [$(ids) || $$(ids)].flatten(); return elements.map(function(e) { return new effect(e, Object.extend({ sync: true }, options)) }); }).flatten(), this.options); } }); Element.CSS_PROPERTIES = $w('backgroundColor backgroundPosition borderBottomColor borderBottomStyle ' + 'borderBottomWidth borderLeftColor borderLeftStyle borderLeftWidth ' + 'borderRightColor borderRightStyle borderRightWidth borderSpacing ' + 'borderTopColor borderTopStyle borderTopWidth bottom clip color ' + 'fontSize fontWeight height left letterSpacing lineHeight ' + 'marginBottom marginLeft marginRight marginTop markerOffset maxHeight ' + 'maxWidth minHeight minWidth opacity outlineColor outlineOffset ' + 'outlineWidth paddingBottom paddingLeft paddingRight paddingTop ' + 'right textIndent top width wordSpacing zIndex'); Element.CSS_LENGTH = /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/; String.__parseStyleElement = document.createElement('div'); String.prototype.parseStyle = function()
    {
        var style, styleRules = $H(); if (Prototype.Browser.WebKit)
            style = new Element('div', { style: this }).style; else { String.__parseStyleElement.innerHTML = '<div style="' + this + '"></div>'; style = String.__parseStyleElement.childNodes[0].style; }
        Element.CSS_PROPERTIES.each(function(property) { if (style[property]) styleRules.set(property, style[property]); }); if (Prototype.Browser.IE && this.include('opacity'))
            styleRules.set('opacity', this.match(/opacity:\s*((?:0|1)?(?:\.\d*)?)/)[1]); return styleRules;
    }; if (document.defaultView && document.defaultView.getComputedStyle) { Element.getStyles = function(element) { var css = document.defaultView.getComputedStyle($(element), null); return Element.CSS_PROPERTIES.inject({}, function(styles, property) { styles[property] = css[property]; return styles; }); }; } else { Element.getStyles = function(element) { element = $(element); var css = element.currentStyle, styles; styles = Element.CSS_PROPERTIES.inject({}, function(results, property) { results[property] = css[property]; return results; }); if (!styles.opacity) styles.opacity = element.getOpacity(); return styles; }; }
    Effect.Methods = { morph: function(element, style) { element = $(element); new Effect.Morph(element, Object.extend({ style: style }, arguments[2] || {})); return element; }, visualEffect: function(element, effect, options) { element = $(element); var s = effect.dasherize().camelize(), klass = s.charAt(0).toUpperCase() + s.substring(1); new Effect[klass](element, options); return element; }, highlight: function(element, options) { element = $(element); new Effect.Highlight(element, options); return element; } }; $w('fade appear grow shrink fold blindUp blindDown slideUp slideDown ' + 'pulsate shake puff squish switchOff dropOut').each(function(effect) { Effect.Methods[effect] = function(element, options) { element = $(element); Effect[effect.charAt(0).toUpperCase() + effect.substring(1)](element, options); return element; }; }); $w('getInlineOpacity forceRerendering setContentZoom collectTextNodes collectTextNodesIgnoreClass getStyles').each(function(f) { Effect.Methods[f] = Element[f]; }); Element.addMethods(Effect.Methods); if (typeof Effect == 'undefined')
        throw ("controls.js requires including script.aculo.us' effects.js library"); var Autocompleter = {}; Autocompleter.Base = Class.create({ baseInitialize: function(element, update, options)
        {
            element = $(element); this.element = element; this.update = $(update); this.hasFocus = false; this.changed = false; this.active = false; this.index = 0; this.entryCount = 0; this.oldElementValue = this.element.value; if (this.setOptions)
                this.setOptions(options); else
                this.options = options || {}; this.options.paramName = this.options.paramName || this.element.name; this.options.tokens = this.options.tokens || []; this.options.frequency = this.options.frequency || 0.4; this.options.minChars = this.options.minChars || 1; this.options.onShow = this.options.onShow || function(element, update)
                {
                    if (!update.style.position || update.style.position == 'absolute') { update.style.position = 'absolute'; Position.clone(element, update, { setHeight: false, offsetTop: element.offsetHeight }); }
                    Effect.Appear(update, { duration: 0.15 });
                }; this.options.onHide = this.options.onHide || function(element, update) { new Effect.Fade(update, { duration: 0.15 }) }; if (typeof (this.options.tokens) == 'string')
                this.options.tokens = new Array(this.options.tokens); if (!this.options.tokens.include('\n'))
                this.options.tokens.push('\n'); this.observer = null; this.element.setAttribute('autocomplete', 'off'); Element.hide(this.update); Event.observe(this.element, 'blur', this.onBlur.bindAsEventListener(this)); Event.observe(this.element, 'keydown', this.onKeyPress.bindAsEventListener(this));
        }, show: function()
        {
            if (Element.getStyle(this.update, 'display') == 'none') this.options.onShow(this.element, this.update); if (!this.iefix && (Prototype.Browser.IE) && (Element.getStyle(this.update, 'position') == 'absolute')) { new Insertion.After(this.update, '<iframe id="' + this.update.id + '_iefix" ' + 'style="display:none;position:absolute;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);" ' + 'src="javascript:false;" frameborder="0" scrolling="no"></iframe>'); this.iefix = $(this.update.id + '_iefix'); }
            if (this.iefix) setTimeout(this.fixIEOverlapping.bind(this), 50);
        }, fixIEOverlapping: function() { Position.clone(this.update, this.iefix, { setTop: (!this.update.style.height) }); this.iefix.style.zIndex = 1; this.update.style.zIndex = 2; Element.show(this.iefix); }, hide: function() { this.stopIndicator(); if (Element.getStyle(this.update, 'display') != 'none') this.options.onHide(this.element, this.update); if (this.iefix) Element.hide(this.iefix); }, startIndicator: function() { if (this.options.indicator) Element.show(this.options.indicator); }, stopIndicator: function() { if (this.options.indicator) Element.hide(this.options.indicator); }, onKeyPress: function(event)
        {
            if (this.active)
                switch (event.keyCode) { case Event.KEY_TAB: case Event.KEY_RETURN: this.selectEntry(); Event.stop(event); case Event.KEY_ESC: this.hide(); this.active = false; Event.stop(event); return; case Event.KEY_LEFT: case Event.KEY_RIGHT: return; case Event.KEY_UP: this.markPrevious(); this.render(); Event.stop(event); return; case Event.KEY_DOWN: this.markNext(); this.render(); Event.stop(event); return; }
            else
                if (event.keyCode == Event.KEY_TAB || event.keyCode == Event.KEY_RETURN || (Prototype.Browser.WebKit > 0 && event.keyCode == 0)) return; this.changed = true; this.hasFocus = true; if (this.observer) clearTimeout(this.observer); this.observer = setTimeout(this.onObserverEvent.bind(this), this.options.frequency * 1000);
        }, activate: function() { this.changed = false; this.hasFocus = true; this.getUpdatedChoices(); }, onHover: function(event)
        {
            var element = Event.findElement(event, 'LI'); if (this.index != element.autocompleteIndex)
            { this.index = element.autocompleteIndex; this.render(); }
            Event.stop(event);
        }, onClick: function(event) { var element = Event.findElement(event, 'LI'); this.index = element.autocompleteIndex; this.selectEntry(); this.hide(); }, onBlur: function(event) { setTimeout(this.hide.bind(this), 250); this.hasFocus = false; this.active = false; }, render: function()
        {
            if (this.entryCount > 0)
            {
                for (var i = 0; i < this.entryCount; i++)
                    this.index == i ? Element.addClassName(this.getEntry(i), "selected") : Element.removeClassName(this.getEntry(i), "selected"); if (this.hasFocus) { this.show(); this.active = true; } 
            } else { this.active = false; this.hide(); } 
        }, markPrevious: function() { if (this.index > 0) this.index--; else this.index = this.entryCount - 1; this.getEntry(this.index).scrollIntoView(true); }, markNext: function() { if (this.index < this.entryCount - 1) this.index++; else this.index = 0; this.getEntry(this.index).scrollIntoView(false); }, getEntry: function(index) { return this.update.firstChild.childNodes[index]; }, getCurrentEntry: function() { return this.getEntry(this.index); }, selectEntry: function() { this.active = false; this.updateElement(this.getCurrentEntry()); }, updateElement: function(selectedElement)
        {
            if (this.options.updateElement) { this.options.updateElement(selectedElement); return; }
            var value = ''; if (this.options.select) { var nodes = $(selectedElement).select('.' + this.options.select) || []; if (nodes.length > 0) value = Element.collectTextNodes(nodes[0], this.options.select); } else
                value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal'); var bounds = this.getTokenBounds(); if (bounds[0] != -1)
            {
                var newValue = this.element.value.substr(0, bounds[0]); var whitespace = this.element.value.substr(bounds[0]).match(/^\s+/); if (whitespace)
                    newValue += whitespace[0]; this.element.value = newValue + value + this.element.value.substr(bounds[1]);
            } else { this.element.value = value; }
            this.oldElementValue = this.element.value; this.element.focus(); if (this.options.afterUpdateElement)
                this.options.afterUpdateElement(this.element, selectedElement);
        }, updateChoices: function(choices)
        {
            if (!this.changed && this.hasFocus)
            {
                this.update.innerHTML = choices; Element.cleanWhitespace(this.update); Element.cleanWhitespace(this.update.down()); if (this.update.firstChild && this.update.down().childNodes) { this.entryCount = this.update.down().childNodes.length; for (var i = 0; i < this.entryCount; i++) { var entry = this.getEntry(i); entry.autocompleteIndex = i; this.addObservers(entry); } } else { this.entryCount = 0; }
                this.stopIndicator(); this.index = 0; if (this.entryCount == 1 && this.options.autoSelect) { this.selectEntry(); this.hide(); } else { this.render(); } 
            } 
        }, addObservers: function(element) { Event.observe(element, "mouseover", this.onHover.bindAsEventListener(this)); Event.observe(element, "click", this.onClick.bindAsEventListener(this)); }, onObserverEvent: function()
        {
            this.changed = false; this.tokenBounds = null; if (this.getToken().length >= this.options.minChars) { this.getUpdatedChoices(); } else { this.active = false; this.hide(); }
            this.oldElementValue = this.element.value;
        }, getToken: function() { var bounds = this.getTokenBounds(); return this.element.value.substring(bounds[0], bounds[1]).strip(); }, getTokenBounds: function()
        {
            if (null != this.tokenBounds) return this.tokenBounds; var value = this.element.value; if (value.strip().empty()) return [-1, 0]; var diff = arguments.callee.getFirstDifferencePos(value, this.oldElementValue); var offset = (diff == this.oldElementValue.length ? 1 : 0); var prevTokenPos = -1, nextTokenPos = value.length; var tp; for (var index = 0, l = this.options.tokens.length; index < l; ++index) { tp = value.lastIndexOf(this.options.tokens[index], diff + offset - 1); if (tp > prevTokenPos) prevTokenPos = tp; tp = value.indexOf(this.options.tokens[index], diff + offset); if (-1 != tp && tp < nextTokenPos) nextTokenPos = tp; }
            return (this.tokenBounds = [prevTokenPos + 1, nextTokenPos]);
        } 
        }); Autocompleter.Base.prototype.getTokenBounds.getFirstDifferencePos = function(newS, oldS)
        {
            var boundary = Math.min(newS.length, oldS.length); for (var index = 0; index < boundary; ++index)
                if (newS[index] != oldS[index])
                return index; return boundary;
        }; Ajax.Autocompleter = Class.create(Autocompleter.Base, { initialize: function(element, update, url, options) { this.baseInitialize(element, update, options); this.options.asynchronous = true; this.options.onComplete = this.onComplete.bind(this); this.options.defaultParams = this.options.parameters || null; this.url = url; }, getUpdatedChoices: function()
        {
            this.startIndicator(); var entry = encodeURIComponent(this.options.paramName) + '=' +
encodeURIComponent(this.getToken()); this.options.parameters = this.options.callback ? this.options.callback(this.element, entry) : entry; if (this.options.defaultParams)
                this.options.parameters += '&' + this.options.defaultParams; new Ajax.Request(this.url, this.options);
        }, onComplete: function(request) { this.updateChoices(request.responseText); } 
        }); Autocompleter.Local = Class.create(Autocompleter.Base, { initialize: function(element, update, array, options) { this.baseInitialize(element, update, options); this.options.array = array; }, getUpdatedChoices: function() { this.updateChoices(this.options.selector(this)); }, setOptions: function(options)
        {
            this.options = Object.extend({ choices: 10, partialSearch: true, partialChars: 2, ignoreCase: true, fullSearch: false, selector: function(instance)
            {
                var ret = []; var partial = []; var entry = instance.getToken(); var count = 0; for (var i = 0; i < instance.options.array.length && ret.length < instance.options.choices; i++)
                {
                    var elem = instance.options.array[i]; var foundPos = instance.options.ignoreCase ? elem.toLowerCase().indexOf(entry.toLowerCase()) : elem.indexOf(entry); while (foundPos != -1)
                    {
                        if (foundPos == 0 && elem.length != entry.length)
                        {
                            ret.push("<li><strong>" + elem.substr(0, entry.length) + "</strong>" +
elem.substr(entry.length) + "</li>"); break;
                        } else if (entry.length >= instance.options.partialChars && instance.options.partialSearch && foundPos != -1)
                        {
                            if (instance.options.fullSearch || /\s/.test(elem.substr(foundPos - 1, 1)))
                            {
                                partial.push("<li>" + elem.substr(0, foundPos) + "<strong>" +
elem.substr(foundPos, entry.length) + "</strong>" + elem.substr(foundPos + entry.length) + "</li>"); break;
                            } 
                        }
                        foundPos = instance.options.ignoreCase ? elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) : elem.indexOf(entry, foundPos + 1);
                    } 
                }
                if (partial.length)
                    ret = ret.concat(partial.slice(0, instance.options.choices - ret.length)); return "<ul>" + ret.join('') + "</ul>";
            } 
            }, options || {});
        } 
        }); Field.scrollFreeActivate = function(field) { setTimeout(function() { Field.activate(field); }, 1); }; Ajax.InPlaceEditor = Class.create({ initialize: function(element, url, options)
        {
            this.url = url; this.element = element = $(element); this.prepareOptions(); this._controls = {}; arguments.callee.dealWithDeprecatedOptions(options); Object.extend(this.options, options || {}); if (!this.options.formId && this.element.id)
            {
                this.options.formId = this.element.id + '-inplaceeditor'; if ($(this.options.formId))
                    this.options.formId = '';
            }
            if (this.options.externalControl)
                this.options.externalControl = $(this.options.externalControl); if (!this.options.externalControl)
                this.options.externalControlOnly = false; this._originalBackground = this.element.getStyle('background-color') || 'transparent'; this.element.title = this.options.clickToEditText; this._boundCancelHandler = this.handleFormCancellation.bind(this); this._boundComplete = (this.options.onComplete || Prototype.emptyFunction).bind(this); this._boundFailureHandler = this.handleAJAXFailure.bind(this); this._boundSubmitHandler = this.handleFormSubmission.bind(this); this._boundWrapperHandler = this.wrapUp.bind(this); this.registerListeners();
        }, checkForEscapeOrReturn: function(e)
        {
            if (!this._editing || e.ctrlKey || e.altKey || e.shiftKey) return; if (Event.KEY_ESC == e.keyCode)
                this.handleFormCancellation(e); else if (Event.KEY_RETURN == e.keyCode)
                this.handleFormSubmission(e);
        }, createControl: function(mode, handler, extraClasses)
        {
            var control = this.options[mode + 'Control']; var text = this.options[mode + 'Text']; if ('button' == control)
            {
                var btn = document.createElement('input'); btn.type = 'submit'; btn.value = text; btn.className = 'editor_' + mode + '_button'; if ('cancel' == mode)
                    btn.onclick = this._boundCancelHandler; this._form.appendChild(btn); this._controls[mode] = btn;
            } else if ('link' == control)
            {
                var link = document.createElement('a'); link.href = '#'; link.appendChild(document.createTextNode(text)); link.onclick = 'cancel' == mode ? this._boundCancelHandler : this._boundSubmitHandler; link.className = 'editor_' + mode + '_link'; if (extraClasses)
                    link.className += ' ' + extraClasses; this._form.appendChild(link); this._controls[mode] = link;
            } 
        }, createEditField: function()
        {
            var text = (this.options.loadTextURL ? this.options.loadingText : this.getText()); var fld; if (1 >= this.options.rows && !/\r|\n/.test(this.getText())) { fld = document.createElement('input'); fld.type = 'text'; var size = this.options.size || this.options.cols || 0; if (0 < size) fld.size = size; } else { fld = document.createElement('textarea'); fld.rows = (1 >= this.options.rows ? this.options.autoRows : this.options.rows); fld.cols = this.options.cols || 40; }
            fld.name = this.options.paramName; fld.value = text; fld.className = 'editor_field'; if (this.options.submitOnBlur)
                fld.onblur = this._boundSubmitHandler; this._controls.editor = fld; if (this.options.loadTextURL)
                this.loadExternalText(); this._form.appendChild(this._controls.editor);
        }, createForm: function()
        {
            var ipe = this; function addText(mode, condition) { var text = ipe.options['text' + mode + 'Controls']; if (!text || condition === false) return; ipe._form.appendChild(document.createTextNode(text)); }; this._form = $(document.createElement('form')); this._form.id = this.options.formId; this._form.addClassName(this.options.formClassName); this._form.onsubmit = this._boundSubmitHandler; this.createEditField(); if ('textarea' == this._controls.editor.tagName.toLowerCase())
                this._form.appendChild(document.createElement('br')); if (this.options.onFormCustomization)
                this.options.onFormCustomization(this, this._form); addText('Before', this.options.okControl || this.options.cancelControl); this.createControl('ok', this._boundSubmitHandler); addText('Between', this.options.okControl && this.options.cancelControl); this.createControl('cancel', this._boundCancelHandler, 'editor_cancel'); addText('After', this.options.okControl || this.options.cancelControl);
        }, destroy: function()
        {
            if (this._oldInnerHTML)
                this.element.innerHTML = this._oldInnerHTML; this.leaveEditMode(); this.unregisterListeners();
        }, enterEditMode: function(e)
        {
            if (this._saving || this._editing) return; this._editing = true; this.triggerCallback('onEnterEditMode'); if (this.options.externalControl)
                this.options.externalControl.hide(); this.element.hide(); this.createForm(); this.element.parentNode.insertBefore(this._form, this.element); if (!this.options.loadTextURL)
                this.postProcessEditField(); if (e) Event.stop(e);
        }, enterHover: function(e)
        {
            if (this.options.hoverClassName)
                this.element.addClassName(this.options.hoverClassName); if (this._saving) return; this.triggerCallback('onEnterHover');
        }, getText: function() { return this.element.innerHTML.unescapeHTML(); }, handleAJAXFailure: function(transport) { this.triggerCallback('onFailure', transport); if (this._oldInnerHTML) { this.element.innerHTML = this._oldInnerHTML; this._oldInnerHTML = null; } }, handleFormCancellation: function(e) { this.wrapUp(); if (e) Event.stop(e); }, handleFormSubmission: function(e)
        {
            var form = this._form; var value = $F(this._controls.editor); this.prepareSubmission(); var params = this.options.callback(form, value) || ''; if (Object.isString(params))
                params = params.toQueryParams(); params.editorId = this.element.id; if (this.options.htmlResponse) { var options = Object.extend({ evalScripts: true }, this.options.ajaxOptions); Object.extend(options, { parameters: params, onComplete: this._boundWrapperHandler, onFailure: this._boundFailureHandler }); new Ajax.Updater({ success: this.element }, this.url, options); } else { var options = Object.extend({ method: 'get' }, this.options.ajaxOptions); Object.extend(options, { parameters: params, onComplete: this._boundWrapperHandler, onFailure: this._boundFailureHandler }); new Ajax.Request(this.url, options); }
            if (e) Event.stop(e);
        }, leaveEditMode: function()
        {
            this.element.removeClassName(this.options.savingClassName); this.removeForm(); this.leaveHover(); this.element.style.backgroundColor = this._originalBackground; this.element.show(); if (this.options.externalControl)
                this.options.externalControl.show(); this._saving = false; this._editing = false; this._oldInnerHTML = null; this.triggerCallback('onLeaveEditMode');
        }, leaveHover: function(e)
        {
            if (this.options.hoverClassName)
                this.element.removeClassName(this.options.hoverClassName); if (this._saving) return; this.triggerCallback('onLeaveHover');
        }, loadExternalText: function()
        {
            this._form.addClassName(this.options.loadingClassName); this._controls.editor.disabled = true; var options = Object.extend({ method: 'get' }, this.options.ajaxOptions); Object.extend(options, { parameters: 'editorId=' + encodeURIComponent(this.element.id), onComplete: Prototype.emptyFunction, onSuccess: function(transport)
            {
                this._form.removeClassName(this.options.loadingClassName); var text = transport.responseText; if (this.options.stripLoadedTextTags)
                    text = text.stripTags(); this._controls.editor.value = text; this._controls.editor.disabled = false; this.postProcessEditField();
            } .bind(this), onFailure: this._boundFailureHandler
            }); new Ajax.Request(this.options.loadTextURL, options);
        }, postProcessEditField: function()
        {
            var fpc = this.options.fieldPostCreation; if (fpc)
                $(this._controls.editor)['focus' == fpc ? 'focus' : 'activate']();
        }, prepareOptions: function() { this.options = Object.clone(Ajax.InPlaceEditor.DefaultOptions); Object.extend(this.options, Ajax.InPlaceEditor.DefaultCallbacks); [this._extraDefaultOptions].flatten().compact().each(function(defs) { Object.extend(this.options, defs); } .bind(this)); }, prepareSubmission: function() { this._saving = true; this.removeForm(); this.leaveHover(); this.showSaving(); }, registerListeners: function()
        {
            this._listeners = {}; var listener; $H(Ajax.InPlaceEditor.Listeners).each(function(pair)
            {
                listener = this[pair.value].bind(this); this._listeners[pair.key] = listener; if (!this.options.externalControlOnly)
                    this.element.observe(pair.key, listener); if (this.options.externalControl)
                    this.options.externalControl.observe(pair.key, listener);
            } .bind(this));
        }, removeForm: function() { if (!this._form) return; this._form.remove(); this._form = null; this._controls = {}; }, showSaving: function() { this._oldInnerHTML = this.element.innerHTML; this.element.innerHTML = this.options.savingText; this.element.addClassName(this.options.savingClassName); this.element.style.backgroundColor = this._originalBackground; this.element.show(); }, triggerCallback: function(cbName, arg) { if ('function' == typeof this.options[cbName]) { this.options[cbName](this, arg); } }, unregisterListeners: function()
        {
            $H(this._listeners).each(function(pair)
            {
                if (!this.options.externalControlOnly)
                    this.element.stopObserving(pair.key, pair.value); if (this.options.externalControl)
                    this.options.externalControl.stopObserving(pair.key, pair.value);
            } .bind(this));
        }, wrapUp: function(transport) { this.leaveEditMode(); this._boundComplete(transport, this.element); } 
        }); Object.extend(Ajax.InPlaceEditor.prototype, { dispose: Ajax.InPlaceEditor.prototype.destroy }); Ajax.InPlaceCollectionEditor = Class.create(Ajax.InPlaceEditor, { initialize: function($super, element, url, options) { this._extraDefaultOptions = Ajax.InPlaceCollectionEditor.DefaultOptions; $super(element, url, options); }, createEditField: function()
        {
            var list = document.createElement('select'); list.name = this.options.paramName; list.size = 1; this._controls.editor = list; this._collection = this.options.collection || []; if (this.options.loadCollectionURL)
                this.loadCollection(); else
                this.checkForExternalText(); this._form.appendChild(this._controls.editor);
        }, loadCollection: function()
        {
            this._form.addClassName(this.options.loadingClassName); this.showLoadingText(this.options.loadingCollectionText); var options = Object.extend({ method: 'get' }, this.options.ajaxOptions); Object.extend(options, { parameters: 'editorId=' + encodeURIComponent(this.element.id), onComplete: Prototype.emptyFunction, onSuccess: function(transport)
            {
                var js = transport.responseText.strip(); if (!/^\[.*\]$/.test(js))
                    throw ('Server returned an invalid collection representation.'); this._collection = eval(js); this.checkForExternalText();
            } .bind(this), onFailure: this.onFailure
            }); new Ajax.Request(this.options.loadCollectionURL, options);
        }, showLoadingText: function(text)
        {
            this._controls.editor.disabled = true; var tempOption = this._controls.editor.firstChild; if (!tempOption) { tempOption = document.createElement('option'); tempOption.value = ''; this._controls.editor.appendChild(tempOption); tempOption.selected = true; }
            tempOption.update((text || '').stripScripts().stripTags());
        }, checkForExternalText: function()
        {
            this._text = this.getText(); if (this.options.loadTextURL)
                this.loadExternalText(); else
                this.buildOptionList();
        }, loadExternalText: function() { this.showLoadingText(this.options.loadingText); var options = Object.extend({ method: 'get' }, this.options.ajaxOptions); Object.extend(options, { parameters: 'editorId=' + encodeURIComponent(this.element.id), onComplete: Prototype.emptyFunction, onSuccess: function(transport) { this._text = transport.responseText.strip(); this.buildOptionList(); } .bind(this), onFailure: this.onFailure }); new Ajax.Request(this.options.loadTextURL, options); }, buildOptionList: function() { this._form.removeClassName(this.options.loadingClassName); this._collection = this._collection.map(function(entry) { return 2 === entry.length ? entry : [entry, entry].flatten(); }); var marker = ('value' in this.options) ? this.options.value : this._text; var textFound = this._collection.any(function(entry) { return entry[0] == marker; } .bind(this)); this._controls.editor.update(''); var option; this._collection.each(function(entry, index) { option = document.createElement('option'); option.value = entry[0]; option.selected = textFound ? entry[0] == marker : 0 == index; option.appendChild(document.createTextNode(entry[1])); this._controls.editor.appendChild(option); } .bind(this)); this._controls.editor.disabled = false; Field.scrollFreeActivate(this._controls.editor); } 
        }); Ajax.InPlaceEditor.prototype.initialize.dealWithDeprecatedOptions = function(options) { if (!options) return; function fallback(name, expr) { if (name in options || expr === undefined) return; options[name] = expr; }; fallback('cancelControl', (options.cancelLink ? 'link' : (options.cancelButton ? 'button' : options.cancelLink == options.cancelButton == false ? false : undefined))); fallback('okControl', (options.okLink ? 'link' : (options.okButton ? 'button' : options.okLink == options.okButton == false ? false : undefined))); fallback('highlightColor', options.highlightcolor); fallback('highlightEndColor', options.highlightendcolor); }; Object.extend(Ajax.InPlaceEditor, { DefaultOptions: { ajaxOptions: {}, autoRows: 3, cancelControl: 'link', cancelText: 'cancel', clickToEditText: 'Click to edit', externalControl: null, externalControlOnly: false, fieldPostCreation: 'activate', formClassName: 'inplaceeditor-form', formId: null, highlightColor: '#ffff99', highlightEndColor: '#ffffff', hoverClassName: '', htmlResponse: true, loadingClassName: 'inplaceeditor-loading', loadingText: 'Loading...', okControl: 'button', okText: 'ok', paramName: 'value', rows: 1, savingClassName: 'inplaceeditor-saving', savingText: 'Saving...', size: 0, stripLoadedTextTags: false, submitOnBlur: false, textAfterControls: '', textBeforeControls: '', textBetweenControls: '' }, DefaultCallbacks: { callback: function(form) { return Form.serialize(form); }, onComplete: function(transport, element) { new Effect.Highlight(element, { startcolor: this.options.highlightColor, keepBackgroundImage: true }); }, onEnterEditMode: null, onEnterHover: function(ipe)
        {
            ipe.element.style.backgroundColor = ipe.options.highlightColor; if (ipe._effect)
                ipe._effect.cancel();
        }, onFailure: function(transport, ipe) { alert('Error communication with the server: ' + transport.responseText.stripTags()); }, onFormCustomization: null, onLeaveEditMode: null, onLeaveHover: function(ipe) { ipe._effect = new Effect.Highlight(ipe.element, { startcolor: ipe.options.highlightColor, endcolor: ipe.options.highlightEndColor, restorecolor: ipe._originalBackground, keepBackgroundImage: true }); } 
        }, Listeners: { click: 'enterEditMode', keydown: 'checkForEscapeOrReturn', mouseover: 'enterHover', mouseout: 'leaveHover'}
        }); Ajax.InPlaceCollectionEditor.DefaultOptions = { loadingCollectionText: 'Loading options...' }; Form.Element.DelayedObserver = Class.create({ initialize: function(element, delay, callback) { this.delay = delay || 0.5; this.element = $(element); this.callback = callback; this.timer = null; this.lastValue = $F(this.element); Event.observe(this.element, 'keyup', this.delayedListener.bindAsEventListener(this)); }, delayedListener: function(event) { if (this.lastValue == $F(this.element)) return; if (this.timer) clearTimeout(this.timer); this.timer = setTimeout(this.onTimerEvent.bind(this), this.delay * 1000); this.lastValue = $F(this.element); }, onTimerEvent: function() { this.timer = null; this.callback(this.element, $F(this.element)); } }); if (Object.isUndefined(Effect))
        throw ("dragdrop.js requires including script.aculo.us' effects.js library"); var Droppables = { drops: [], remove: function(element) { this.drops = this.drops.reject(function(d) { return d.element == $(element) }); }, add: function(element)
        {
            element = $(element); var options = Object.extend({ greedy: true, hoverclass: null, tree: false }, arguments[1] || {}); if (options.containment) { options._containers = []; var containment = options.containment; if (Object.isArray(containment)) { containment.each(function(c) { options._containers.push($(c)) }); } else { options._containers.push($(containment)); } }
            if (options.accept) options.accept = [options.accept].flatten(); Element.makePositioned(element); options.element = element; this.drops.push(options);
        }, findDeepestChild: function(drops)
        {
            deepest = drops[0]; for (i = 1; i < drops.length; ++i)
                if (Element.isParent(drops[i].element, deepest.element))
                deepest = drops[i]; return deepest;
        }, isContained: function(element, drop)
        {
            var containmentNode; if (drop.tree) { containmentNode = element.treeNode; } else { containmentNode = element.parentNode; }
            return drop._containers.detect(function(c) { return containmentNode == c });
        }, isAffected: function(point, element, drop) { return ((drop.element != element) && ((!drop._containers) || this.isContained(element, drop)) && ((!drop.accept) || (Element.classNames(element).detect(function(v) { return drop.accept.include(v) }))) && Position.within(drop.element, point[0], point[1])); }, deactivate: function(drop)
        {
            if (drop.hoverclass)
                Element.removeClassName(drop.element, drop.hoverclass); this.last_active = null;
        }, activate: function(drop)
        {
            if (drop.hoverclass)
                Element.addClassName(drop.element, drop.hoverclass); this.last_active = drop;
        }, show: function(point, element)
        {
            if (!this.drops.length) return; var drop, affected = []; this.drops.each(function(drop)
            {
                if (Droppables.isAffected(point, element, drop))
                    affected.push(drop);
            }); if (affected.length > 0)
                drop = Droppables.findDeepestChild(affected); if (this.last_active && this.last_active != drop) this.deactivate(this.last_active); if (drop)
            {
                Position.within(drop.element, point[0], point[1]); if (drop.onHover)
                    drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element)); if (drop != this.last_active) Droppables.activate(drop);
            } 
        }, fire: function(event, element)
        {
            if (!this.last_active) return; Position.prepare(); if (this.isAffected([Event.pointerX(event), Event.pointerY(event)], element, this.last_active))
                if (this.last_active.onDrop) { this.last_active.onDrop(element, this.last_active.element, event); return true; } 
        }, reset: function()
        {
            if (this.last_active)
                this.deactivate(this.last_active);
        } 
        }; var Draggables = { drags: [], observers: [], register: function(draggable)
        {
            if (this.drags.length == 0) { this.eventMouseUp = this.endDrag.bindAsEventListener(this); this.eventMouseMove = this.updateDrag.bindAsEventListener(this); this.eventKeypress = this.keyPress.bindAsEventListener(this); Event.observe(document, "mouseup", this.eventMouseUp); Event.observe(document, "mousemove", this.eventMouseMove); Event.observe(document, "keypress", this.eventKeypress); }
            this.drags.push(draggable);
        }, unregister: function(draggable) { this.drags = this.drags.reject(function(d) { return d == draggable }); if (this.drags.length == 0) { Event.stopObserving(document, "mouseup", this.eventMouseUp); Event.stopObserving(document, "mousemove", this.eventMouseMove); Event.stopObserving(document, "keypress", this.eventKeypress); } }, activate: function(draggable) { if (draggable.options.delay) { this._timeout = setTimeout(function() { Draggables._timeout = null; window.focus(); Draggables.activeDraggable = draggable; } .bind(this), draggable.options.delay); } else { window.focus(); this.activeDraggable = draggable; } }, deactivate: function() { this.activeDraggable = null; }, updateDrag: function(event) { if (!this.activeDraggable) return; var pointer = [Event.pointerX(event), Event.pointerY(event)]; if (this._lastPointer && (this._lastPointer.inspect() == pointer.inspect())) return; this._lastPointer = pointer; this.activeDraggable.updateDrag(event, pointer); }, endDrag: function(event)
        {
            if (this._timeout) { clearTimeout(this._timeout); this._timeout = null; }
            if (!this.activeDraggable) return; this._lastPointer = null; this.activeDraggable.endDrag(event); this.activeDraggable = null;
        }, keyPress: function(event)
        {
            if (this.activeDraggable)
                this.activeDraggable.keyPress(event);
        }, addObserver: function(observer) { this.observers.push(observer); this._cacheObserverCallbacks(); }, removeObserver: function(element) { this.observers = this.observers.reject(function(o) { return o.element == element }); this._cacheObserverCallbacks(); }, notify: function(eventName, draggable, event)
        {
            if (this[eventName + 'Count'] > 0)
                this.observers.each(function(o) { if (o[eventName]) o[eventName](eventName, draggable, event); }); if (draggable.options[eventName]) draggable.options[eventName](draggable, event);
        }, _cacheObserverCallbacks: function() { ['onStart', 'onEnd', 'onDrag'].each(function(eventName) { Draggables[eventName + 'Count'] = Draggables.observers.select(function(o) { return o[eventName]; }).length; }); } 
        }; var Draggable = Class.create({ initialize: function(element)
        {
            var defaults = { handle: false, reverteffect: function(element, top_offset, left_offset) { var dur = Math.sqrt(Math.abs(top_offset ^ 2) + Math.abs(left_offset ^ 2)) * 0.02; new Effect.Move(element, { x: -left_offset, y: -top_offset, duration: dur, queue: { scope: '_draggable', position: 'end'} }); }, endeffect: function(element) { var toOpacity = Object.isNumber(element._opacity) ? element._opacity : 1.0; new Effect.Opacity(element, { duration: 0.2, from: 0.7, to: toOpacity, queue: { scope: '_draggable', position: 'end' }, afterFinish: function() { Draggable._dragging[element] = false } }); }, zindex: 1000, revert: false, quiet: false, scroll: false, scrollSensitivity: 20, scrollSpeed: 15, snap: false, delay: 0 }; if (!arguments[1] || Object.isUndefined(arguments[1].endeffect))
                Object.extend(defaults, { starteffect: function(element) { element._opacity = Element.getOpacity(element); Draggable._dragging[element] = true; new Effect.Opacity(element, { duration: 0.2, from: element._opacity, to: 0.7 }); } }); var options = Object.extend(defaults, arguments[1] || {}); this.element = $(element); if (options.handle && Object.isString(options.handle))
                this.handle = this.element.down('.' + options.handle, 0); if (!this.handle) this.handle = $(options.handle); if (!this.handle) this.handle = this.element; if (options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML) { options.scroll = $(options.scroll); this._isScrollChild = Element.childOf(this.element, options.scroll); }
            Element.makePositioned(this.element); this.options = options; this.dragging = false; this.eventMouseDown = this.initDrag.bindAsEventListener(this); Event.observe(this.handle, "mousedown", this.eventMouseDown); Draggables.register(this);
        }, destroy: function() { Event.stopObserving(this.handle, "mousedown", this.eventMouseDown); Draggables.unregister(this); }, currentDelta: function() { return ([parseInt(Element.getStyle(this.element, 'left') || '0'), parseInt(Element.getStyle(this.element, 'top') || '0')]); }, initDrag: function(event) { if (!Object.isUndefined(Draggable._dragging[this.element]) && Draggable._dragging[this.element]) return; if (Event.isLeftClick(event)) { var src = Event.element(event); if ((tag_name = src.tagName.toUpperCase()) && (tag_name == 'INPUT' || tag_name == 'SELECT' || tag_name == 'OPTION' || tag_name == 'BUTTON' || tag_name == 'TEXTAREA')) return; var pointer = [Event.pointerX(event), Event.pointerY(event)]; var pos = Position.cumulativeOffset(this.element); this.offset = [0, 1].map(function(i) { return (pointer[i] - pos[i]) }); Draggables.activate(this); Event.stop(event); } }, startDrag: function(event)
        {
            this.dragging = true; if (!this.delta)
                this.delta = this.currentDelta(); if (this.options.zindex) { this.originalZ = parseInt(Element.getStyle(this.element, 'z-index') || 0); this.element.style.zIndex = this.options.zindex; }
            if (this.options.ghosting)
            {
                this._clone = this.element.cloneNode(true); this._originallyAbsolute = (this.element.getStyle('position') == 'absolute'); if (!this._originallyAbsolute)
                    Position.absolutize(this.element); this.element.parentNode.insertBefore(this._clone, this.element);
            }
            if (this.options.scroll) { if (this.options.scroll == window) { var where = this._getWindowScroll(this.options.scroll); this.originalScrollLeft = where.left; this.originalScrollTop = where.top; } else { this.originalScrollLeft = this.options.scroll.scrollLeft; this.originalScrollTop = this.options.scroll.scrollTop; } }
            Draggables.notify('onStart', this, event); if (this.options.starteffect) this.options.starteffect(this.element);
        }, updateDrag: function(event, pointer)
        {
            if (!this.dragging) this.startDrag(event); if (!this.options.quiet) { Position.prepare(); Droppables.show(pointer, this.element); }
            Draggables.notify('onDrag', this, event); this.draw(pointer); if (this.options.change) this.options.change(this); if (this.options.scroll)
            {
                this.stopScrolling(); var p; if (this.options.scroll == window) { with (this._getWindowScroll(this.options.scroll)) { p = [left, top, left + width, top + height]; } } else { p = Position.page(this.options.scroll); p[0] += this.options.scroll.scrollLeft + Position.deltaX; p[1] += this.options.scroll.scrollTop + Position.deltaY; p.push(p[0] + this.options.scroll.offsetWidth); p.push(p[1] + this.options.scroll.offsetHeight); }
                var speed = [0, 0]; if (pointer[0] < (p[0] + this.options.scrollSensitivity)) speed[0] = pointer[0] - (p[0] + this.options.scrollSensitivity); if (pointer[1] < (p[1] + this.options.scrollSensitivity)) speed[1] = pointer[1] - (p[1] + this.options.scrollSensitivity); if (pointer[0] > (p[2] - this.options.scrollSensitivity)) speed[0] = pointer[0] - (p[2] - this.options.scrollSensitivity); if (pointer[1] > (p[3] - this.options.scrollSensitivity)) speed[1] = pointer[1] - (p[3] - this.options.scrollSensitivity); this.startScrolling(speed);
            }
            if (Prototype.Browser.WebKit) window.scrollBy(0, 0); Event.stop(event);
        }, finishDrag: function(event, success)
        {
            this.dragging = false; if (this.options.quiet) { Position.prepare(); var pointer = [Event.pointerX(event), Event.pointerY(event)]; Droppables.show(pointer, this.element); }
            if (this.options.ghosting)
            {
                if (!this._originallyAbsolute)
                    Position.relativize(this.element); delete this._originallyAbsolute; Element.remove(this._clone); this._clone = null;
            }
            var dropped = false; if (success) { dropped = Droppables.fire(event, this.element); if (!dropped) dropped = false; }
            if (dropped && this.options.onDropped) this.options.onDropped(this.element); Draggables.notify('onEnd', this, event); var revert = this.options.revert; if (revert && Object.isFunction(revert)) revert = revert(this.element); var d = this.currentDelta(); if (revert && this.options.reverteffect)
            {
                if (dropped == 0 || revert != 'failure')
                    this.options.reverteffect(this.element, d[1] - this.delta[1], d[0] - this.delta[0]);
            } else { this.delta = d; }
            if (this.options.zindex)
                this.element.style.zIndex = this.originalZ; if (this.options.endeffect)
                this.options.endeffect(this.element); Draggables.deactivate(this); Droppables.reset();
        }, keyPress: function(event) { if (event.keyCode != Event.KEY_ESC) return; this.finishDrag(event, false); Event.stop(event); }, endDrag: function(event) { if (!this.dragging) return; this.stopScrolling(); this.finishDrag(event, true); Event.stop(event); }, draw: function(point)
        {
            var pos = Position.cumulativeOffset(this.element); if (this.options.ghosting) { var r = Position.realOffset(this.element); pos[0] += r[0] - Position.deltaX; pos[1] += r[1] - Position.deltaY; }
            var d = this.currentDelta(); pos[0] -= d[0]; pos[1] -= d[1]; if (this.options.scroll && (this.options.scroll != window && this._isScrollChild)) { pos[0] -= this.options.scroll.scrollLeft - this.originalScrollLeft; pos[1] -= this.options.scroll.scrollTop - this.originalScrollTop; }
            var p = [0, 1].map(function(i) { return (point[i] - pos[i] - this.offset[i]) } .bind(this)); if (this.options.snap) { if (Object.isFunction(this.options.snap)) { p = this.options.snap(p[0], p[1], this); } else { if (Object.isArray(this.options.snap)) { p = p.map(function(v, i) { return (v / this.options.snap[i]).round() * this.options.snap[i] } .bind(this)); } else { p = p.map(function(v) { return (v / this.options.snap).round() * this.options.snap } .bind(this)); } } }
            var style = this.element.style; if ((!this.options.constraint) || (this.options.constraint == 'horizontal'))
                style.left = p[0] + "px"; if ((!this.options.constraint) || (this.options.constraint == 'vertical'))
                style.top = p[1] + "px"; if (style.visibility == "hidden") style.visibility = "";
        }, stopScrolling: function() { if (this.scrollInterval) { clearInterval(this.scrollInterval); this.scrollInterval = null; Draggables._lastScrollPointer = null; } }, startScrolling: function(speed) { if (!(speed[0] || speed[1])) return; this.scrollSpeed = [speed[0] * this.options.scrollSpeed, speed[1] * this.options.scrollSpeed]; this.lastScrolled = new Date(); this.scrollInterval = setInterval(this.scroll.bind(this), 10); }, scroll: function()
        {
            var current = new Date(); var delta = current - this.lastScrolled; this.lastScrolled = current; if (this.options.scroll == window) { with (this._getWindowScroll(this.options.scroll)) { if (this.scrollSpeed[0] || this.scrollSpeed[1]) { var d = delta / 1000; this.options.scroll.scrollTo(left + d * this.scrollSpeed[0], top + d * this.scrollSpeed[1]); } } } else { this.options.scroll.scrollLeft += this.scrollSpeed[0] * delta / 1000; this.options.scroll.scrollTop += this.scrollSpeed[1] * delta / 1000; }
            Position.prepare(); Droppables.show(Draggables._lastPointer, this.element); Draggables.notify('onDrag', this); if (this._isScrollChild)
            {
                Draggables._lastScrollPointer = Draggables._lastScrollPointer || $A(Draggables._lastPointer); Draggables._lastScrollPointer[0] += this.scrollSpeed[0] * delta / 1000; Draggables._lastScrollPointer[1] += this.scrollSpeed[1] * delta / 1000; if (Draggables._lastScrollPointer[0] < 0)
                    Draggables._lastScrollPointer[0] = 0; if (Draggables._lastScrollPointer[1] < 0)
                    Draggables._lastScrollPointer[1] = 0; this.draw(Draggables._lastScrollPointer);
            }
            if (this.options.change) this.options.change(this);
        }, _getWindowScroll: function(w)
        {
            var T, L, W, H; with (w.document)
            {
                if (w.document.documentElement && documentElement.scrollTop) { T = documentElement.scrollTop; L = documentElement.scrollLeft; } else if (w.document.body) { T = body.scrollTop; L = body.scrollLeft; }
                if (w.innerWidth) { W = w.innerWidth; H = w.innerHeight; } else if (w.document.documentElement && documentElement.clientWidth) { W = documentElement.clientWidth; H = documentElement.clientHeight; } else { W = body.offsetWidth; H = body.offsetHeight; } 
            }
            return { top: T, left: L, width: W, height: H };
        } 
        }); Draggable._dragging = {}; var SortableObserver = Class.create({ initialize: function(element, observer) { this.element = $(element); this.observer = observer; this.lastValue = Sortable.serialize(this.element); }, onStart: function() { this.lastValue = Sortable.serialize(this.element); }, onEnd: function()
        {
            Sortable.unmark(); if (this.lastValue != Sortable.serialize(this.element))
                this.observer(this.element)
        } 
        }); var Sortable = { SERIALIZE_RULE: /^[^_\-](?:[A-Za-z0-9\-\_]*)[_](.*)$/, sortables: {}, _findRootElement: function(element) { while (element.tagName.toUpperCase() != "BODY") { if (element.id && Sortable.sortables[element.id]) return element; element = element.parentNode; } }, options: function(element) { element = Sortable._findRootElement($(element)); if (!element) return; return Sortable.sortables[element.id]; }, destroy: function(element) { element = $(element); var s = Sortable.sortables[element.id]; if (s) { Draggables.removeObserver(s.element); s.droppables.each(function(d) { Droppables.remove(d) }); s.draggables.invoke('destroy'); delete Sortable.sortables[s.element.id]; } }, create: function(element)
        {
            element = $(element); var options = Object.extend({ element: element, tag: 'li', dropOnEmpty: false, tree: false, treeTag: 'ul', overlap: 'vertical', constraint: 'vertical', containment: element, handle: false, only: false, delay: 0, hoverclass: null, ghosting: false, quiet: false, scroll: false, scrollSensitivity: 20, scrollSpeed: 15, format: this.SERIALIZE_RULE, elements: false, handles: false, onChange: Prototype.emptyFunction, onUpdate: Prototype.emptyFunction }, arguments[1] || {}); this.destroy(element); var options_for_draggable = { revert: true, quiet: options.quiet, scroll: options.scroll, scrollSpeed: options.scrollSpeed, scrollSensitivity: options.scrollSensitivity, delay: options.delay, ghosting: options.ghosting, constraint: options.constraint, handle: options.handle }; if (options.starteffect)
                options_for_draggable.starteffect = options.starteffect; if (options.reverteffect)
                options_for_draggable.reverteffect = options.reverteffect; else
                if (options.ghosting) options_for_draggable.reverteffect = function(element) { element.style.top = 0; element.style.left = 0; }; if (options.endeffect)
                options_for_draggable.endeffect = options.endeffect; if (options.zindex)
                options_for_draggable.zindex = options.zindex; var options_for_droppable = { overlap: options.overlap, containment: options.containment, tree: options.tree, hoverclass: options.hoverclass, onHover: Sortable.onHover }; var options_for_tree = { onHover: Sortable.onEmptyHover, overlap: options.overlap, containment: options.containment, hoverclass: options.hoverclass }; Element.cleanWhitespace(element); options.draggables = []; options.droppables = []; if (options.dropOnEmpty || options.tree) { Droppables.add(element, options_for_tree); options.droppables.push(element); }
            (options.elements || this.findElements(element, options) || []).each(function(e, i) { var handle = options.handles ? $(options.handles[i]) : (options.handle ? $(e).select('.' + options.handle)[0] : e); options.draggables.push(new Draggable(e, Object.extend(options_for_draggable, { handle: handle }))); Droppables.add(e, options_for_droppable); if (options.tree) e.treeNode = element; options.droppables.push(e); }); if (options.tree) { (Sortable.findTreeElements(element, options) || []).each(function(e) { Droppables.add(e, options_for_tree); e.treeNode = element; options.droppables.push(e); }); }
            this.sortables[element.id] = options; Draggables.addObserver(new SortableObserver(element, options.onUpdate));
        }, findElements: function(element, options) { return Element.findChildren(element, options.only, options.tree ? true : false, options.tag); }, findTreeElements: function(element, options) { return Element.findChildren(element, options.only, options.tree ? true : false, options.treeTag); }, onHover: function(element, dropon, overlap)
        {
            if (Element.isParent(dropon, element)) return; if (overlap > .33 && overlap < .66 && Sortable.options(dropon).tree) { return; } else if (overlap > 0.5)
            {
                Sortable.mark(dropon, 'before'); if (dropon.previousSibling != element)
                {
                    var oldParentNode = element.parentNode; element.style.visibility = "hidden"; dropon.parentNode.insertBefore(element, dropon); if (dropon.parentNode != oldParentNode)
                        Sortable.options(oldParentNode).onChange(element); Sortable.options(dropon.parentNode).onChange(element);
                } 
            } else
            {
                Sortable.mark(dropon, 'after'); var nextElement = dropon.nextSibling || null; if (nextElement != element)
                {
                    var oldParentNode = element.parentNode; element.style.visibility = "hidden"; dropon.parentNode.insertBefore(element, nextElement); if (dropon.parentNode != oldParentNode)
                        Sortable.options(oldParentNode).onChange(element); Sortable.options(dropon.parentNode).onChange(element);
                } 
            } 
        }, onEmptyHover: function(element, dropon, overlap)
        {
            var oldParentNode = element.parentNode; var droponOptions = Sortable.options(dropon); if (!Element.isParent(dropon, element))
            {
                var index; var children = Sortable.findElements(dropon, { tag: droponOptions.tag, only: droponOptions.only }); var child = null; if (children) { var offset = Element.offsetSize(dropon, droponOptions.overlap) * (1.0 - overlap); for (index = 0; index < children.length; index += 1) { if (offset - Element.offsetSize(children[index], droponOptions.overlap) >= 0) { offset -= Element.offsetSize(children[index], droponOptions.overlap); } else if (offset - (Element.offsetSize(children[index], droponOptions.overlap) / 2) >= 0) { child = index + 1 < children.length ? children[index + 1] : null; break; } else { child = children[index]; break; } } }
                dropon.insertBefore(element, child); Sortable.options(oldParentNode).onChange(element); droponOptions.onChange(element);
            } 
        }, unmark: function() { if (Sortable._marker) Sortable._marker.hide(); }, mark: function(dropon, position)
        {
            var sortable = Sortable.options(dropon.parentNode); if (sortable && !sortable.ghosting) return; if (!Sortable._marker) { Sortable._marker = ($('dropmarker') || Element.extend(document.createElement('DIV'))).hide().addClassName('dropmarker').setStyle({ position: 'absolute' }); document.getElementsByTagName("body").item(0).appendChild(Sortable._marker); }
            var offsets = Position.cumulativeOffset(dropon); Sortable._marker.setStyle({ left: offsets[0] + 'px', top: offsets[1] + 'px' }); if (position == 'after')
                if (sortable.overlap == 'horizontal')
                Sortable._marker.setStyle({ left: (offsets[0] + dropon.clientWidth) + 'px' }); else
                Sortable._marker.setStyle({ top: (offsets[1] + dropon.clientHeight) + 'px' }); Sortable._marker.show();
        }, _tree: function(element, options, parent)
        {
            var children = Sortable.findElements(element, options) || []; for (var i = 0; i < children.length; ++i)
            {
                var match = children[i].id.match(options.format); if (!match) continue; var child = { id: encodeURIComponent(match ? match[1] : null), element: element, parent: parent, children: [], position: parent.children.length, container: $(children[i]).down(options.treeTag) }; if (child.container)
                    this._tree(child.container, options, child); parent.children.push(child);
            }
            return parent;
        }, tree: function(element) { element = $(element); var sortableOptions = this.options(element); var options = Object.extend({ tag: sortableOptions.tag, treeTag: sortableOptions.treeTag, only: sortableOptions.only, name: element.id, format: sortableOptions.format }, arguments[1] || {}); var root = { id: null, parent: null, children: [], container: element, position: 0 }; return Sortable._tree(element, options, root); }, _constructIndex: function(node) { var index = ''; do { if (node.id) index = '[' + node.position + ']' + index; } while ((node = node.parent) != null); return index; }, sequence: function(element) { element = $(element); var options = Object.extend(this.options(element), arguments[1] || {}); return $(this.findElements(element, options) || []).map(function(item) { return item.id.match(options.format) ? item.id.match(options.format)[1] : ''; }); }, setSequence: function(element, new_sequence)
        {
            element = $(element); var options = Object.extend(this.options(element), arguments[2] || {}); var nodeMap = {}; this.findElements(element, options).each(function(n)
            {
                if (n.id.match(options.format))
                    nodeMap[n.id.match(options.format)[1]] = [n, n.parentNode]; n.parentNode.removeChild(n);
            }); new_sequence.each(function(ident) { var n = nodeMap[ident]; if (n) { n[1].appendChild(n[0]); delete nodeMap[ident]; } });
        }, serialize: function(element)
        {
            element = $(element); var options = Object.extend(Sortable.options(element), arguments[1] || {}); var name = encodeURIComponent((arguments[1] && arguments[1].name) ? arguments[1].name : element.id); if (options.tree)
            {
                return Sortable.tree(element, arguments[1]).children.map(function(item)
                {
                    return [name + Sortable._constructIndex(item) + "[id]=" +
encodeURIComponent(item.id)].concat(item.children.map(arguments.callee));
                }).flatten().join('&');
            } else { return Sortable.sequence(element, arguments[1]).map(function(item) { return name + "[]=" + encodeURIComponent(item); }).join('&'); } 
        } 
        }; Element.isParent = function(child, element) { if (!child.parentNode || child == element) return false; if (child.parentNode == element) return true; return Element.isParent(child.parentNode, element); }; Element.findChildren = function(element, only, recursive, tagName)
        {
            if (!element.hasChildNodes()) return null; tagName = tagName.toUpperCase(); if (only) only = [only].flatten(); var elements = []; $A(element.childNodes).each(function(e)
            {
                if (e.tagName && e.tagName.toUpperCase() == tagName && (!only || (Element.classNames(e).detect(function(v) { return only.include(v) }))))
                    elements.push(e); if (recursive) { var grandchildren = Element.findChildren(e, only, recursive, tagName); if (grandchildren) elements.push(grandchildren); } 
            }); return (elements.length > 0 ? elements.flatten() : []);
        }; Element.offsetSize = function(element, type) { return element['offset' + ((type == 'vertical' || type == 'height') ? 'Height' : 'Width')]; }; if (!Control) var Control = {}; Control.Slider = Class.create({ initialize: function(handle, track, options)
        {
            var slider = this; if (Object.isArray(handle)) { this.handles = handle.collect(function(e) { return $(e) }); } else { this.handles = [$(handle)]; }
            this.track = $(track); this.options = options || {}; this.axis = this.options.axis || 'horizontal'; this.increment = this.options.increment || 1; this.step = parseInt(this.options.step || '1'); this.range = this.options.range || $R(0, 1); this.value = 0; this.values = this.handles.map(function() { return 0 }); this.spans = this.options.spans ? this.options.spans.map(function(s) { return $(s) }) : false; this.options.startSpan = $(this.options.startSpan || null); this.options.endSpan = $(this.options.endSpan || null); this.restricted = this.options.restricted || false; this.maximum = this.options.maximum || this.range.end; this.minimum = this.options.minimum || this.range.start; this.alignX = parseInt(this.options.alignX || '0'); this.alignY = parseInt(this.options.alignY || '0'); this.trackLength = this.maximumOffset() - this.minimumOffset(); this.handleLength = this.isVertical() ? (this.handles[0].offsetHeight != 0 ? this.handles[0].offsetHeight : this.handles[0].style.height.replace(/px$/, "")) : (this.handles[0].offsetWidth != 0 ? this.handles[0].offsetWidth : this.handles[0].style.width.replace(/px$/, "")); this.active = false; this.dragging = false; this.disabled = false; if (this.options.disabled) this.setDisabled(); this.allowedValues = this.options.values ? this.options.values.sortBy(Prototype.K) : false; if (this.allowedValues) { this.minimum = this.allowedValues.min(); this.maximum = this.allowedValues.max(); }
            this.eventMouseDown = this.startDrag.bindAsEventListener(this); this.eventMouseUp = this.endDrag.bindAsEventListener(this); this.eventMouseMove = this.update.bindAsEventListener(this); this.handles.each(function(h, i) { i = slider.handles.length - 1 - i; slider.setValue(parseFloat((Object.isArray(slider.options.sliderValue) ? slider.options.sliderValue[i] : slider.options.sliderValue) || slider.range.start), i); h.makePositioned().observe("mousedown", slider.eventMouseDown); }); this.track.observe("mousedown", this.eventMouseDown); document.observe("mouseup", this.eventMouseUp); document.observe("mousemove", this.eventMouseMove); this.initialized = true;
        }, dispose: function() { var slider = this; Event.stopObserving(this.track, "mousedown", this.eventMouseDown); Event.stopObserving(document, "mouseup", this.eventMouseUp); Event.stopObserving(document, "mousemove", this.eventMouseMove); this.handles.each(function(h) { Event.stopObserving(h, "mousedown", slider.eventMouseDown); }); }, setDisabled: function() { this.disabled = true; }, setEnabled: function() { this.disabled = false; }, getNearestValue: function(value)
        {
            if (this.allowedValues) { if (value >= this.allowedValues.max()) return (this.allowedValues.max()); if (value <= this.allowedValues.min()) return (this.allowedValues.min()); var offset = Math.abs(this.allowedValues[0] - value); var newValue = this.allowedValues[0]; this.allowedValues.each(function(v) { var currentOffset = Math.abs(v - value); if (currentOffset <= offset) { newValue = v; offset = currentOffset; } }); return newValue; }
            if (value > this.range.end) return this.range.end; if (value < this.range.start) return this.range.start; return value;
        }, setValue: function(sliderValue, handleIdx)
        {
            if (!this.active) { this.activeHandleIdx = handleIdx || 0; this.activeHandle = this.handles[this.activeHandleIdx]; this.updateStyles(); }
            handleIdx = handleIdx || this.activeHandleIdx || 0; if (this.initialized && this.restricted)
            {
                if ((handleIdx > 0) && (sliderValue < this.values[handleIdx - 1]))
                    sliderValue = this.values[handleIdx - 1]; if ((handleIdx < (this.handles.length - 1)) && (sliderValue > this.values[handleIdx + 1]))
                    sliderValue = this.values[handleIdx + 1];
            }
            sliderValue = this.getNearestValue(sliderValue); this.values[handleIdx] = sliderValue; this.value = this.values[0]; this.handles[handleIdx].style[this.isVertical() ? 'top' : 'left'] = this.translateToPx(sliderValue); this.drawSpans(); if (!this.dragging || !this.event) this.updateFinished();
        }, setValueBy: function(delta, handleIdx) { this.setValue(this.values[handleIdx || this.activeHandleIdx || 0] + delta, handleIdx || this.activeHandleIdx || 0); }, translateToPx: function(value) { return Math.round(((this.trackLength - this.handleLength) / (this.range.end - this.range.start)) * (value - this.range.start)) + "px"; }, translateToValue: function(offset) { return ((offset / (this.trackLength - this.handleLength) * (this.range.end - this.range.start)) + this.range.start); }, getRange: function(range) { var v = this.values.sortBy(Prototype.K); range = range || 0; return $R(v[range], v[range + 1]); }, minimumOffset: function() { return (this.isVertical() ? this.alignY : this.alignX); }, maximumOffset: function() { return (this.isVertical() ? (this.track.offsetHeight != 0 ? this.track.offsetHeight : this.track.style.height.replace(/px$/, "")) - this.alignY : (this.track.offsetWidth != 0 ? this.track.offsetWidth : this.track.style.width.replace(/px$/, "")) - this.alignX); }, isVertical: function() { return (this.axis == 'vertical'); }, drawSpans: function()
        {
            var slider = this; if (this.spans)
                $R(0, this.spans.length - 1).each(function(r) { slider.setSpan(slider.spans[r], slider.getRange(r)) }); if (this.options.startSpan)
                this.setSpan(this.options.startSpan, $R(0, this.values.length > 1 ? this.getRange(0).min() : this.value)); if (this.options.endSpan)
                this.setSpan(this.options.endSpan, $R(this.values.length > 1 ? this.getRange(this.spans.length - 1).max() : this.value, this.maximum));
        }, setSpan: function(span, range) { if (this.isVertical()) { span.style.top = this.translateToPx(range.start); span.style.height = this.translateToPx(range.end - range.start + this.range.start); } else { span.style.left = this.translateToPx(range.start); span.style.width = this.translateToPx(range.end - range.start + this.range.start); } }, updateStyles: function() { this.handles.each(function(h) { Element.removeClassName(h, 'selected') }); Element.addClassName(this.activeHandle, 'selected'); }, startDrag: function(event)
        {
            if (Event.isLeftClick(event))
            {
                if (!this.disabled)
                {
                    this.active = true; var handle = Event.element(event); var pointer = [Event.pointerX(event), Event.pointerY(event)]; var track = handle; if (track == this.track) { var offsets = Position.cumulativeOffset(this.track); this.event = event; this.setValue(this.translateToValue((this.isVertical() ? pointer[1] - offsets[1] : pointer[0] - offsets[0]) - (this.handleLength / 2))); var offsets = Position.cumulativeOffset(this.activeHandle); this.offsetX = (pointer[0] - offsets[0]); this.offsetY = (pointer[1] - offsets[1]); } else
                    {
                        while ((this.handles.indexOf(handle) == -1) && handle.parentNode)
                            handle = handle.parentNode; if (this.handles.indexOf(handle) != -1) { this.activeHandle = handle; this.activeHandleIdx = this.handles.indexOf(this.activeHandle); this.updateStyles(); var offsets = Position.cumulativeOffset(this.activeHandle); this.offsetX = (pointer[0] - offsets[0]); this.offsetY = (pointer[1] - offsets[1]); } 
                    } 
                }
                Event.stop(event);
            } 
        }, update: function(event) { if (this.active) { if (!this.dragging) this.dragging = true; this.draw(event); if (Prototype.Browser.WebKit) window.scrollBy(0, 0); Event.stop(event); } }, draw: function(event)
        {
            var pointer = [Event.pointerX(event), Event.pointerY(event)]; var offsets = Position.cumulativeOffset(this.track); pointer[0] -= this.offsetX + offsets[0]; pointer[1] -= this.offsetY + offsets[1]; this.event = event; this.setValue(this.translateToValue(this.isVertical() ? pointer[1] : pointer[0])); if (this.initialized && this.options.onSlide)
                this.options.onSlide(this.values.length > 1 ? this.values : this.value, this);
        }, endDrag: function(event)
        {
            if (this.active && this.dragging) { this.finishDrag(event, true); Event.stop(event); }
            this.active = false; this.dragging = false;
        }, finishDrag: function(event, success) { this.active = false; this.dragging = false; this.updateFinished(); }, updateFinished: function()
        {
            if (this.initialized && this.options.onChange)
                this.options.onChange(this.values.length > 1 ? this.values : this.value, this); this.event = null;
        } 
        }); var Resizables = { instances: [], observers: [], register: function(resizable)
        {
            if (this.instances.length == 0) { this.eventMouseUp = this.endResize.bindAsEventListener(this); this.eventMouseMove = this.updateResize.bindAsEventListener(this); Event.observe(document, "mouseup", this.eventMouseUp); Event.observe(document, "mousemove", this.eventMouseMove); }
            this.instances.push(resizable);
        }, unregister: function(resizable) { this.instances = this.instances.reject(function(d) { return d == resizable }); if (this.instances.length == 0) { Event.stopObserving(document, "mouseup", this.eventMouseUp); Event.stopObserving(document, "mousemove", this.eventMouseMove); } }, activate: function(resizable) { if (resizable.options.delay) { this._timeout = setTimeout(function() { Resizables._timeout = null; Resizables.activeResizable = resizable; } .bind(this), resizable.options.delay); } else { this.activeResizable = resizable; } }, deactivate: function() { this.activeResizable = null; }, updateResize: function(event) { if (!this.activeResizable) return; var pointer = [Event.pointerX(event), Event.pointerY(event)]; if (this._lastPointer && (this._lastPointer.inspect() == pointer.inspect())) return; this._lastPointer = pointer; this.activeResizable.updateResize(event, pointer); }, endResize: function(event)
        {
            if (this._timeout) { clearTimeout(this._timeout); this._timeout = null; }
            if (!this.activeResizable) return; this._lastPointer = null; this.activeResizable.endResize(event); this.activeResizable = null;
        }, addObserver: function(observer) { this.observers.push(observer); this._cacheObserverCallbacks(); }, removeObserver: function(element) { this.observers = this.observers.reject(function(o) { return o.element == element }); this._cacheObserverCallbacks(); }, notify: function(eventName, resizable, event)
        {
            if (this[eventName + 'Count'] > 0)
                this.observers.each(function(o) { if (o[eventName]) o[eventName](eventName, resizable, event); }); if (resizable.options[eventName]) resizable.options[eventName](resizable, event);
        }, _cacheObserverCallbacks: function() { ['onStart', 'onEnd', 'onResize'].each(function(eventName) { Resizables[eventName + 'Count'] = Resizables.observers.select(function(o) { return o[eventName]; }).length; }); } 
        }
    var Resizable = Class.create(); Resizable._resizing = {}; Resizable.prototype = { initialize: function(element)
    {
        var defaults = { handle: false, snap: false, delay: 0, minHeight: false, minwidth: false, maxHeight: false, maxWidth: false }
        this.element = $(element); var options = Object.extend(defaults, arguments[1] || {}); if (options.handle && typeof options.handle == 'string')
            this.handle = $(options.handle); else if (options.handle)
            this.handle = options.handle; if (!this.handle) this.handle = this.element; this.options = options; this.dragging = false; this.eventMouseDown = this.initResize.bindAsEventListener(this); Event.observe(this.handle, "mousedown", this.eventMouseDown); Resizables.register(this);
    }, destroy: function() { Event.stopObserving(this.handle, "mousedown", this.eventMouseDown); }, currentDelta: function() { return ([parseInt(Element.getStyle(this.element, 'width') || '0'), parseInt(Element.getStyle(this.element, 'height') || '0')]); }, initResize: function(event) { if (typeof Resizable._resizing[this.element] != 'undefined' && Resizable._resizing[this.element]) return; if (Event.isLeftClick(event)) { var src = Event.element(event); if ((tag_name = src.tagName.toUpperCase()) && (tag_name == 'INPUT' || tag_name == 'SELECT' || tag_name == 'OPTION' || tag_name == 'BUTTON' || tag_name == 'TEXTAREA')) return; this.pointer = [Event.pointerX(event), Event.pointerY(event)]; this.size = [parseInt(this.element.getStyle('width')) || 0, parseInt(this.element.getStyle('height')) || 0]; Resizables.activate(this); Event.stop(event); } }, startResize: function(event)
    {
        this.resizing = true; if (this.options.zindex) { this.originalZ = parseInt(Element.getStyle(this.element, 'z-index') || 0); this.element.style.zIndex = this.options.zindex; }
        Resizables.notify('onStart', this, event); Resizable._resizing[this.element] = true;
    }, updateResize: function(event, pointer) { if (!this.resizing) this.startResize(event); Resizables.notify('onResize', this, event); this.draw(pointer); if (this.options.change) this.options.change(this); if (Prototype.Browser.WebKit) window.scrollBy(0, 0); Event.stop(event); }, finishResize: function(event, success) { this.resizing = false; Resizables.notify('onEnd', this, event); if (this.options.zindex) this.element.style.zIndex = this.originalZ; Resizable._resizing[this.element] = false; Resizables.deactivate(this); }, endResize: function(event) { if (!this.resizing) return; this.finishResize(event, true); Event.stop(event); }, draw: function(point)
    {
        var p = [0, 1].map(function(i) { return (this.size[i] + point[i] - this.pointer[i]); } .bind(this)); if (this.options.snap) { if (typeof this.options.snap == 'function') { p = this.options.snap(p[0], p[1], this); } else { if (this.options.snap instanceof Array) { p = p.map(function(v, i) { return Math.round(v / this.options.snap[i]) * this.options.snap[i] } .bind(this)) } else { p = p.map(function(v) { return Math.round(v / this.options.snap) * this.options.snap } .bind(this)) } } }
        var minWidth = (typeof (this.options.minWidth) == 'function') ? this.options.minWidth(this.element) : this.options.minWidth; var maxWidth = (typeof (this.options.maxWidth) == 'function') ? this.options.maxWidth(this.element) : this.options.maxWidth; var minHeight = (typeof (this.options.minHeight) == 'function') ? this.options.minHeight(this.element) : this.options.minHeight; var maxHeight = (typeof (this.options.maxHeight) == 'function') ? this.options.maxHeight(this.element) : this.options.maxHeight; if (minWidth && p[0] <= minWidth) p[0] = minWidth; if (maxWidth && p[0] >= maxWidth) p[0] = maxWidth; if (minHeight && p[1] <= minHeight) p[1] = minHeight; if (maxHeight && p[1] >= maxHeight) p[1] = maxHeight; var style = this.element.style; if ((!this.options.constraint) || (this.options.constraint == 'horizontal')) { style.width = p[0] + "px"; }
        if ((!this.options.constraint) || (this.options.constraint == 'vertical')) { style.height = p[1] + "px"; }
        if (style.visibility == "hidden") style.visibility = "";
    } 
    }; if (typeof (Control) == 'undefined')
        Control = {}; var $proc = function(proc) { return typeof (proc) == 'function' ? proc : function() { return proc }; }; var $value = function(value) { return typeof (value) == 'function' ? value() : value; }; Object.Event = { extend: function(object)
        {
            object._objectEventSetup = function(event_name) { this._observers = this._observers || {}; this._observers[event_name] = this._observers[event_name] || []; }; object.observe = function(event_name, observer)
            {
                if (typeof (event_name) == 'string' && typeof (observer) != 'undefined')
                {
                    this._objectEventSetup(event_name); if (!this._observers[event_name].include(observer))
                        this._observers[event_name].push(observer);
                } else
                    for (var e in event_name)
                    this.observe(e, event_name[e]);
            }; object.stopObserving = function(event_name, observer)
            {
                this._objectEventSetup(event_name); if (event_name && observer)
                    this._observers[event_name] = this._observers[event_name].without(observer); else if (event_name)
                    this._observers[event_name] = []; else
                    this._observers = {};
            }; object.observeOnce = function(event_name, outer_observer) { var inner_observer = function() { outer_observer.apply(this, arguments); this.stopObserving(event_name, inner_observer); } .bind(this); this._objectEventSetup(event_name); this._observers[event_name].push(inner_observer); }; object.notify = function(event_name)
            {
                this._objectEventSetup(event_name); var collected_return_values = []; var args = $A(arguments).slice(1); try
                {
                    for (var i = 0; i < this._observers[event_name].length; ++i)
                        collected_return_values.push(this._observers[event_name][i].apply(this._observers[event_name][i], args) || null);
                } catch (e)
                {
                    if (e == $break)
                        return false; else
                        throw e;
                }
                return collected_return_values;
            }; if (object.prototype)
            {
                object.prototype._objectEventSetup = object._objectEventSetup; object.prototype.observe = object.observe; object.prototype.stopObserving = object.stopObserving; object.prototype.observeOnce = object.observeOnce; object.prototype.notify = function(event_name)
                {
                    if (object.notify) { var args = $A(arguments).slice(1); args.unshift(this); args.unshift(event_name); object.notify.apply(object, args); }
                    this._objectEventSetup(event_name); var args = $A(arguments).slice(1); var collected_return_values = []; try
                    {
                        if (this.options && this.options[event_name] && typeof (this.options[event_name]) == 'function')
                            collected_return_values.push(this.options[event_name].apply(this, args) || null); for (var i = 0; i < this._observers[event_name].length; ++i)
                            collected_return_values.push(this._observers[event_name][i].apply(this._observers[event_name][i], args) || null);
                    } catch (e)
                    {
                        if (e == $break)
                            return false; else
                            throw e;
                    }
                    return collected_return_values;
                };
            } 
        } 
        }; Element.addMethods({ observeOnce: function(element, event_name, outer_callback) { var inner_callback = function() { outer_callback.apply(this, arguments); Element.stopObserving(element, event_name, inner_callback); }; Element.observe(element, event_name, inner_callback); } }); Object.extend(Event, (function()
        {
            var cache = Event.cache; function getEventID(element) { if (element._prototypeEventID) return element._prototypeEventID[0]; arguments.callee.id = arguments.callee.id || 1; return element._prototypeEventID = [++arguments.callee.id]; }
            function getDOMEventName(eventName)
            {
                if (eventName && eventName.include(':')) return "dataavailable"; if (!Prototype.Browser.IE) { eventName = { mouseenter: 'mouseover', mouseleave: 'mouseout'}[eventName] || eventName; }
                return eventName;
            }
            function getCacheForID(id) { return cache[id] = cache[id] || {}; }
            function getWrappersForEventName(id, eventName) { var c = getCacheForID(id); return c[eventName] = c[eventName] || []; }
            function createWrapper(element, eventName, handler)
            {
                var id = getEventID(element); var c = getWrappersForEventName(id, eventName); if (c.pluck("handler").include(handler)) return false; var wrapper = function(event)
                {
                    if (!Event || !Event.extend || (event.eventName && event.eventName != eventName))
                        return false; Event.extend(event); handler.call(element, event);
                }; if (!(Prototype.Browser.IE) && ['mouseenter', 'mouseleave'].include(eventName))
                {
                    wrapper = wrapper.wrap(function(proceed, event)
                    {
                        var rel = event.relatedTarget; var cur = event.currentTarget; if (rel && rel.nodeType == Node.TEXT_NODE)
                            rel = rel.parentNode; if (rel && rel != cur && !rel.descendantOf(cur))
                            return proceed(event);
                    });
                }
                wrapper.handler = handler; c.push(wrapper); return wrapper;
            }
            function findWrapper(id, eventName, handler) { var c = getWrappersForEventName(id, eventName); return c.find(function(wrapper) { return wrapper.handler == handler }); }
            function destroyWrapper(id, eventName, handler) { var c = getCacheForID(id); if (!c[eventName]) return false; c[eventName] = c[eventName].without(findWrapper(id, eventName, handler)); }
            function destroyCache()
            {
                for (var id in cache)
                    for (var eventName in cache[id])
                    cache[id][eventName] = null;
            }
            if (window.attachEvent) { window.attachEvent("onunload", destroyCache); }
            return { observe: function(element, eventName, handler)
            {
                element = $(element); var name = getDOMEventName(eventName); var wrapper = createWrapper(element, eventName, handler); if (!wrapper) return element; if (element.addEventListener) { element.addEventListener(name, wrapper, false); } else { element.attachEvent("on" + name, wrapper); }
                return element;
            }, stopObserving: function(element, eventName, handler)
            {
                element = $(element); var id = getEventID(element), name = getDOMEventName(eventName); if (!handler && eventName) { getWrappersForEventName(id, eventName).each(function(wrapper) { element.stopObserving(eventName, wrapper.handler); }); return element; } else if (!eventName) { Object.keys(getCacheForID(id)).each(function(eventName) { element.stopObserving(eventName); }); return element; }
                var wrapper = findWrapper(id, eventName, handler); if (!wrapper) return element; if (element.removeEventListener) { element.removeEventListener(name, wrapper, false); } else { element.detachEvent("on" + name, wrapper); }
                destroyWrapper(id, eventName, handler); return element;
            }, fire: function(element, eventName, memo)
            {
                element = $(element); if (element == document && document.createEvent && !element.dispatchEvent)
                    element = document.documentElement; var event; if (document.createEvent) { event = document.createEvent("HTMLEvents"); event.initEvent("dataavailable", true, true); } else { event = document.createEventObject(); event.eventType = "ondataavailable"; }
                event.eventName = eventName; event.memo = memo || {}; if (document.createEvent) { element.dispatchEvent(event); } else { element.fireEvent(event.eventType, event); }
                return Event.extend(event);
            } 
            };
        })()); Object.extend(Event, Event.Methods); Element.addMethods({ fire: Event.fire, observe: Event.observe, stopObserving: Event.stopObserving }); Object.extend(document, { fire: Element.Methods.fire.methodize(), observe: Element.Methods.observe.methodize(), stopObserving: Element.Methods.stopObserving.methodize() }); (function()
        {
            function wheel(event)
            {
                var delta; if (event.wheelDelta)
                    delta = event.wheelDelta / 120; else if (event.detail)
                    delta = -event.detail / 3; if (!delta)
                    return; var custom_event = Event.element(event).fire('mouse:wheel', { delta: delta }); if (custom_event.stopped) { Event.stop(event); return false; } 
            }
            document.observe('mousewheel', wheel); document.observe('DOMMouseScroll', wheel);
        })(); var IframeShim = Class.create({ initialize: function() { this.element = new Element('iframe', { style: 'position:absolute;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);display:none', src: 'javascript:void(0);', frameborder: 0 }); $(document.body).insert(this.element); }, hide: function() { this.element.hide(); return this; }, show: function() { this.element.show(); return this; }, positionUnder: function(element) { var element = $(element); var offset = element.cumulativeOffset(); var dimensions = element.getDimensions(); this.element.setStyle({ left: offset[0] + 'px', top: offset[1] + 'px', width: dimensions.width + 'px', height: dimensions.height + 'px', zIndex: element.getStyle('zIndex') - 1 }).show(); return this; }, setBounds: function(bounds)
        {
            for (prop in bounds)
                bounds[prop] += 'px'; this.element.setStyle(bounds); return this;
        }, destroy: function()
        {
            if (this.element)
                this.element.remove(); return this;
        } 
        }); if (typeof (Prototype) == "undefined") { throw "Control.ContextMenu requires Prototype to be loaded."; }
    if (typeof (Object.Event) == "undefined") { throw "Control.ContextMenu requires Object.Event to be loaded."; }
    Control.ContextMenu = Class.create({ initialize: function(container, options)
    {
        Control.ContextMenu.load(); this.options = Object.extend({ leftClick: false, disableOnShiftKey: true, disableOnAltKey: true, selectedClassName: 'selected', activatedClassName: 'activated', animation: true, animationCycles: 2, animationLength: 300, delayCallback: true }, options || {}); this.activated = false; this.items = this.options.items || []; this.container = $(container); this.container.observe(this.options.leftClick ? 'click' : (Prototype.Browser.Opera ? 'click' : 'contextmenu'), function(event)
        {
            if (!Control.ContextMenu.enabled || Prototype.Browser.Opera && !event.ctrlKey) { return; }
            this.open(event);
        } .bindAsEventListener(this));
    }, open: function(event)
    {
        if (Control.ContextMenu.current && !Control.ContextMenu.current.close()) { return; }
        if (this.notify('beforeOpen', event) === false) { return false; }
        this.buildMenu(); if (this.items.length === 0) { this.close(event); return false; }
        Control.ContextMenu.current = this; Control.ContextMenu.positionContainer(event); Control.ContextMenu.container.show(); if (this.notify('afterOpen', event) === false) { return false; }
        event.stop(); return true;
    }, close: function(event)
    {
        if (event) { event.stop(); }
        if (this.notify('beforeClose') === false) { return false; }
        Control.ContextMenu.current = false; this.activated = false; Control.ContextMenu.container.removeClassName(this.options.activatedClassName); Control.ContextMenu.container.select('li').invoke('stopObserving'); Control.ContextMenu.container.hide(); Control.ContextMenu.container.update(''); if (this.notify('afterClose') === false) { return false; }
        return true;
    }, buildMenu: function()
    {
        var list = document.createElement('ul'); Control.ContextMenu.container.appendChild(list); this.items.each(function(item)
        {
            if (!(!item.condition || item.condition && item.condition() !== false)) { return; }
            var item_container = $(document.createElement('li')); item_container.update($value(item.label)); list.appendChild(item_container); item_container[$value(item.enabled) ? 'removeClassName' : 'addClassName']('disabled'); item_container.observe('mousedown', function(event, item)
            {
                if (!$value(item.enabled)) { return event.stop(); }
                this.activated = $value(item.label);
            } .bindAsEventListener(this, item)); item_container.observe('click', this.selectMenuItem.bindAsEventListener(this, item, item_container)); item_container.observe('contextmenu', this.selectMenuItem.bindAsEventListener(this, item, item_container));
        } .bind(this));
    }, addItem: function(params)
    {
        if (!('enabled' in params)) { params.enabled = true; }
        this.items.push(params); return this;
    }, destroy: function() { this.container.stopObserving(Prototype.Browser.Opera || this.options.leftClick ? 'click' : 'contextmenu'); this.items = []; }, selectMenuItem: function(event, item, item_container)
    {
        if (!$value(item.enabled)) { return event.stop(); }
        if (!this.activated || this.activated == $value(item.label)) { if (this.options.animation) { Control.ContextMenu.container.addClassName(this.options.activatedClassName); $A($R(0, this.options.animationCycles * 2)).each(function(i) { window.setTimeout(function() { item_container.toggleClassName(this.options.selectedClassName); } .bind(this), i * parseInt(this.options.animationLength / (this.options.animationCycles * 2), 10)); } .bind(this)); window.setTimeout(function() { if (this.close() && this.options.delayCallback) { item.callback(); } } .bind(this), this.options.animationLength); if (!this.options.delayCallback) { item.callback(); } } else if (this.close()) { item.callback(); } }
        event.stop(); return false;
    } 
    }); Object.extend(Control.ContextMenu, { loaded: false, capture_all: false, menus: [], current: false, enabled: false, offset: 4, load: function(capture_all)
    {
        if (Control.ContextMenu.loaded) { return; }
        Control.ContextMenu.loaded = true; if (typeof (capture_all) == 'undefined') { capture_all = false; }
        Control.ContextMenu.capture_all = capture_all; Control.ContextMenu.container = $(document.createElement('div')); Control.ContextMenu.container.id = 'control_contextmenu'; Control.ContextMenu.container.style.position = 'absolute'; Control.ContextMenu.container.style.zIndex = 99999; Control.ContextMenu.container.hide(); document.body.appendChild(Control.ContextMenu.container); Control.ContextMenu.enable();
    }, enable: function() { Control.ContextMenu.enabled = true; Event.observe(document.body, 'click', Control.ContextMenu.onClick); if (Control.ContextMenu.capture_all) { Event.observe(document.body, 'contextmenu', Control.ContextMenu.onContextMenu); } }, disable: function() { Event.stopObserving(document.body, 'click', Control.ContextMenu.onClick); if (Control.ContextMenu.capture_all) { Event.stopObserving(document.body, 'contextmenu', Control.ContextMenu.onContextMenu); } }, onContextMenu: function(event) { event.stop(); return false; }, onClick: function() { if (Control.ContextMenu.current) { Control.ContextMenu.current.close(); } }, positionContainer: function(event)
    {
        var dimensions = Control.ContextMenu.container.getDimensions(); var top = Event.pointerY(event); var left = Event.pointerX(event); var bottom = dimensions.height + top; var right = dimensions.width + left; var viewport_dimensions = document.viewport.getDimensions(); var viewport_scroll_offsets = document.viewport.getScrollOffsets(); if (bottom > viewport_dimensions.height + viewport_scroll_offsets.top) { top -= bottom - ((viewport_dimensions.height + viewport_scroll_offsets.top) - Control.ContextMenu.offset); }
        if (right > viewport_dimensions.width + viewport_scroll_offsets.left) { left -= right - ((viewport_dimensions.width + viewport_scroll_offsets.left) - Control.ContextMenu.offset); }
        Control.ContextMenu.container.setStyle({ top: top + 'px', left: left + 'px' });
    } 
    }); Object.Event.extend(Control.ContextMenu); if (typeof (Prototype) == "undefined")
        throw "Cookie requires Prototype to be loaded."
    if (typeof (Object.Event) == "undefined")
        throw "Cookie requires Object.Event to be loaded."; var Cookie = { build: function() { return $A(arguments).compact().join("; "); }, secondsFromNow: function(seconds) { var d = new Date(); d.setTime(d.getTime() + (seconds * 1000)); return d.toGMTString(); }, set: function(name, value, seconds) { Cookie.notify('set', name, value); var expiry = seconds ? 'expires=' + Cookie.secondsFromNow(seconds) : null; document.cookie = Cookie.build(name + "=" + value, expiry, "path=/"); }, get: function(name) { Cookie.notify('get', name); var valueMatch = new RegExp(name + "=([^;]+)").exec(document.cookie); return valueMatch ? valueMatch[1] : null; }, unset: function(name) { Cookie.notify('unset', name); Cookie.set(name, '', -1); } }; Object.Event.extend(Cookie); if (typeof (Prototype) == "undefined")
        throw "Event.Behavior requires Prototype to be loaded."; if (typeof (Object.Event) == "undefined")
        throw "Event.Behavior requires Object.Event to be loaded."; Event.Behavior = { addVerbs: function(verbs) { for (name in verbs) { v = new Event.Behavior.Verb(verbs[name]); Event.Behavior.Verbs[name] = v; Event.Behavior[name.underscore()] = Event.Behavior[name] = v.getCallbackForStack.bind(v); } }, addEvents: function(events) { $H(events).each(function(event_type) { Event.Behavior.Adjective.prototype[event_type.key.underscore()] = Event.Behavior.Adjective.prototype[event_type.key] = function() { this.nextConditionType = 'and'; this.events.push(event_type.value); this.attachObserver(false); return this; }; }); }, invokeElementMethod: function(element, action, args)
        {
            if (typeof (element) == 'function')
            {
                return $A(element()).each(function(e)
                {
                    if (typeof (args[0]) == 'function') { return $A(args[0]).each(function(a) { return $(e)[action].apply($(e), (a ? [a] : [])); }); } else
                        return $(e)[action].apply($(e), args || []);
                });
            } else
                return $(element)[action].apply($(element), args || []);
        } 
        }; Event.Behavior.Verbs = $H({}); Event.Behavior.Verb = Class.create(); Object.extend(Event.Behavior.Verb.prototype, { originalAction: false, execute: false, executeOpposite: false, target: false, initialize: function(action) { this.originalAction = action; this.execute = function(action, target, argument) { return (argument) ? action(target, argument) : action(target); } .bind(this, action); }, setOpposite: function(opposite_verb) { opposite_action = opposite_verb.originalAction; this.executeOpposite = function(opposite_action, target, argument) { return (argument) ? opposite_action(target, argument) : opposite_action(target); } .bind(this, opposite_action); }, getCallbackForStack: function(argument) { return new Event.Behavior.Noun(this, argument); } }); Event.Behavior.addVerbs({ call: function(callback) { callback(); }, show: function(element) { return Event.Behavior.invokeElementMethod(element, 'show'); }, hide: function(element) { return Event.Behavior.invokeElementMethod(element, 'hide'); }, remove: function(element) { return Event.Behavior.invokeElementMethod(element, 'remove'); }, setStyle: function(element, styles) { return Event.Behavior.invokeElementMethod(element, 'setStyle', [(typeof (styles) == 'function' ? styles() : styles)]); }, addClassName: function(element, class_name) { return Event.Behavior.invokeElementMethod(element, 'addClassName', [(typeof (class_name) == 'function' ? class_name() : class_name)]); }, removeClassName: function(element, class_name) { return Event.Behavior.invokeElementMethod(element, 'removeClassName', [(typeof (class_name) == 'function' ? class_name() : class_name)]); }, setClassName: function(element, class_name)
        {
            c = (typeof (class_name) == 'function') ? class_name() : class_name; if (typeof (element) == 'function') { return $A(element()).each(function(e) { $(e).className = c; }); } else
                return $(element).className = c;
        }, update: function(content, element) { return Event.Behavior.invokeElementMethod(element, 'update', [(typeof (content) == 'function' ? content() : content)]); }, replace: function(content, element) { return Event.Behavior.invokeElementMethod(element, 'replace', [(typeof (content) == 'function' ? content() : content)]); } 
        }); Event.Behavior.Verbs.show.setOpposite(Event.Behavior.Verbs.hide); Event.Behavior.Verbs.hide.setOpposite(Event.Behavior.Verbs.show); Event.Behavior.Verbs.addClassName.setOpposite(Event.Behavior.Verbs.removeClassName); Event.Behavior.Verbs.removeClassName.setOpposite(Event.Behavior.Verbs.addClassName); Event.Behavior.Noun = Class.create(); Object.extend(Event.Behavior.Noun.prototype, { verbs: false, verb: false, argument: false, subject: false, target: false, initialize: function(verb, argument) { this.verb = verb; this.argument = argument; }, execute: function() { return (this.target) ? this.verb.execute(this.target, this.argument) : this.verb.execute(this.argument); }, executeOpposite: function() { return (this.target) ? this.verb.executeOpposite(this.target, this.argument) : this.verb.executeOpposite(this.argument); }, when: function(subject) { this.subject = subject; return new Event.Behavior.Adjective(this); }, getValue: function() { return Try.these(function() { return $(this.subject).getValue(); } .bind(this), function() { return $(this.subject).options[$(this.subject).options.selectedIndex].value; } .bind(this), function() { return $(this.subject).value; } .bind(this), function() { return $(this.subject).innerHTML; } .bind(this)); }, containsValue: function(match)
        {
            value = this.getValue(); if (typeof (match) == 'function') { return $A(match()).include(value); } else
                return value.match(match);
        }, setTarget: function(target) { this.target = target; return this; }, and: function() { } 
        }); Event.Behavior.Noun.prototype._with = Event.Behavior.Noun.prototype.setTarget; Event.Behavior.Noun.prototype.on = Event.Behavior.Noun.prototype.setTarget; Event.Behavior.Noun.prototype.of = Event.Behavior.Noun.prototype.setTarget; Event.Behavior.Noun.prototype.to = Event.Behavior.Noun.prototype.setTarget; Event.Behavior.Noun.prototype.from = Event.Behavior.Noun.prototype.setTarget; Event.Behavior.Adjective = Class.create(); Object.extend(Event.Behavior.Adjective.prototype, { noun: false, lastConditionName: '', nextConditionType: 'and', conditions: $A([]), events: $A([]), attached: false, initialize: function(noun) { this.conditions = $A([]); this.events = $A([]); this.noun = noun; }, attachObserver: function(execute_on_load)
        {
            if (this.attached)
            {
                if (execute_on_load)
                    this.execute(); return;
            }
            this.attached = true; if (typeof (this.noun.subject) == 'function') { $A(this.noun.subject()).each(function(subject) { (this.events.length > 0 ? this.events : $A(['change'])).each(function(event_name) { (subject.observe ? subject : $(subject)).observe(event_name, function() { this.execute(); } .bind(this)); } .bind(this)); } .bind(this)); } else { (this.events.length > 0 ? this.events : $A(['change'])).each(function(event_name) { $(this.noun.subject).observe(event_name, function() { this.execute(); } .bind(this)); } .bind(this)); }
            if (execute_on_load)
                this.execute();
        }, execute: function()
        {
            if (this.match())
                return this.noun.execute(); else if (this.noun.verb.executeOpposite)
                this.noun.executeOpposite();
        }, attachCondition: function(callback) { this.conditions.push([this.nextConditionType, callback.bind(this)]); }, match: function()
        {
            if (this.conditions.length == 0)
                return true; else { return this.conditions.inject(new Boolean(), function(bool, condition) { return (condition[0] == 'and') ? (bool && condition[1]()) : (bool || condition[1]()); }); } 
        }, is: function(item) { this.lastConditionName = 'is'; this.attachCondition(function(item) { return (typeof (item) == 'function' ? item() : item) == this.noun.getValue(); } .bind(this, item)); this.attachObserver(true); return this; }, isNot: function(item) { this.lastConditionName = 'isNot'; this.attachCondition(function(item) { return (typeof (item) == 'function' ? item() : item) != this.noun.getValue(); } .bind(this, item)); this.attachObserver(true); return this; }, contains: function(item) { this.lastConditionName = 'contains'; this.attachCondition(function(item) { return this.noun.containsValue(item); } .bind(this, item)); this.attachObserver(true); return this; }, within: function(item) { this.lastConditionName = 'within'; this.attachCondition(function(item) { } .bind(this, item)); this.attachObserver(true); return this; }, change: function() { this.nextConditionType = 'and'; this.attachObserver(true); return this; }, and: function(condition)
        {
            this.attached = false; this.nextConditionType = 'and'; if (condition)
                this[this.lastConditionName](condition); return this;
        }, or: function(condition)
        {
            this.attached = false; this.nextConditionType = 'or'; if (condition)
                this[this.lastConditionName](condition); return this;
        } 
        }); Event.Behavior.addEvents({ losesFocus: 'blur', gainsFocus: 'focus', isClicked: 'click', isDoubleClicked: 'dblclick', keyPressed: 'keypress' }); Event.Behavior.Adjective.prototype.is_not = Event.Behavior.Adjective.prototype.isNot; Event.Behavior.Adjective.prototype.include = Event.Behavior.Adjective.prototype.contains; Event.Behavior.Adjective.prototype.includes = Event.Behavior.Adjective.prototype.contains; Event.Behavior.Adjective.prototype.are = Event.Behavior.Adjective.prototype.is; Event.Behavior.Adjective.prototype.areNot = Event.Behavior.Adjective.prototype.isNot; Event.Behavior.Adjective.prototype.are_not = Event.Behavior.Adjective.prototype.isNot; Event.Behavior.Adjective.prototype.changes = Event.Behavior.Adjective.prototype.change; if (typeof (Prototype) == "undefined") { throw "HotKey requires Prototype to be loaded."; }
    if (typeof (Object.Event) == "undefined") { throw "HotKey requires Object.Event to be loaded."; }
    var HotKey = Class.create({ initialize: function(letter, callback, options)
    {
        letter = letter.toUpperCase(); HotKey.hotkeys.push(this); this.options = Object.extend({ element: false, shiftKey: false, altKey: false, ctrlKey: true }, options || {}); this.letter = letter; this.callback = callback; this.element = $(this.options.element || document); this.handler = function(event)
        {
            if (!event || ((Event['KEY_' + this.letter] || this.letter.charCodeAt(0)) == event.keyCode && ((!this.options.shiftKey || (this.options.shiftKey && event.shiftKey)) && (!this.options.altKey || (this.options.altKey && event.altKey)) && (!this.options.ctrlKey || (this.options.ctrlKey && event.ctrlKey)))))
            {
                if (this.notify('beforeCallback', event) === false) { return; }
                this.callback(event); this.notify('afterCallback', event);
            } 
        } .bind(this); this.enable();
    }, trigger: function() { this.handler(); }, enable: function() { this.element.observe('keydown', this.handler); }, disable: function() { this.element.stopObserving('keydown', this.handler); }, destroy: function() { this.disable(); HotKey.hotkeys = HotKey.hotkeys.without(this); } 
    }); Object.extend(HotKey, { hotkeys: [] }); Object.Event.extend(HotKey); if (typeof (Control) == "undefined")
        Control = {}; if (typeof (Object.Event) == "undefined")
        throw "Control.Pagination requires Object.Event to be loaded."; Control.Paginator = Class.create({ initialize: function(items, options) { this.items = items; this.options = Object.extend({ size: 10, onPageChange: Prototype.emptyFunction, onItemChange: Prototype.emptyFunction }, options || {}); this.setSize(this.options.size); this.page_index = 1; this.item_index = 0; }, setSize: function(size) { this.options.size = size; this.number_of_pages = Math.ceil(this.items.length / this.options.size); }, pageIndexFromItemIndex: function(item_index) { return Math.floor(((item_index || this.item_index) / this.options.size) + 1); }, goToPage: function(page_index) { this.page_index = page_index; this.triggerOnPageChange(); }, triggerOnPageChange: function() { this.notify('onPageChange', this.items.slice((this.page_index - 1) * this.options.size, ((this.page_index - 1) * this.options.size) + this.options.size), this.page_index); }, goToItem: function(item_index)
        {
            this.item_index = item_index; this.notify('onItemChange', this.items[this.item_index], this.item_index); var new_page_index = this.pageIndexFromItemIndex(this.item_index); if (new_page_index != this.page_index)
                this.goToPage(new_page_index);
        }, hasNextItem: function() { return this.item_index < this.items.length - 1; }, hasPreviousItem: function() { return this.item_index >= 1; }, nextItem: function()
        {
            if (!this.hasNextItem())
                return false; this.goToItem(this.item_index + 1); return true;
        }, previousItem: function()
        {
            if (!this.hasPreviousItem())
                return false; this.goToItem(this.item_index - 1); return true;
        }, hasNextPage: function() { return this.page_index < this.number_of_pages; }, hasPreviousPage: function() { return this.page_index >= 2; }, nextPage: function()
        {
            if (!this.hasNextPage())
                return false; this.goToPage(this.page_index + 1); return true;
        }, previousPage: function()
        {
            if (!this.hasPreviousPage())
                return false; this.goToPage(this.page_index - 1); return true;
        } 
        }); Object.Event.extend(Control.Paginator); if (typeof (Prototype) == "undefined")
        throw "Control.ProgressBar requires Prototype to be loaded."; if (typeof (Object.Event) == "undefined")
        throw "Control.ProgressBar requires Object.Event to be loaded."; Control.ProgressBar = Class.create({ initialize: function(container, options) { this.progress = 0; this.executer = false; this.active = false; this.poller = false; this.container = $(container); this.containerWidth = this.container.getDimensions().width - (parseInt(this.container.getStyle('border-right-width').replace(/px/, '')) + parseInt(this.container.getStyle('border-left-width').replace(/px/, ''))); this.progressContainer = $(document.createElement('div')); this.progressContainer.setStyle({ width: this.containerWidth + 'px', height: '100%', position: 'absolute', top: '0px', right: '0px' }); this.container.appendChild(this.progressContainer); this.options = { afterChange: Prototype.emptyFunction, interval: 0.25, step: 1, classNames: { active: 'progress_bar_active', inactive: 'progress_bar_inactive'} }; Object.extend(this.options, options || {}); this.container.addClassName(this.options.classNames.inactive); this.active = false; }, setProgress: function(value)
        {
            this.progress = value; this.draw(); if (this.progress >= 100)
                this.stop(false); this.notify('afterChange', this.progress, this.active);
        }, poll: function(url, interval)
        {
            this.active = true; this.poller = new PeriodicalExecuter(function()
            {
                new Ajax.Request(url, { onSuccess: function(request)
                {
                    this.setProgress(parseInt(request.responseText)); if (!this.active)
                        this.poller.stop();
                } .bind(this)
                });
            } .bind(this), interval || 3);
        }, start: function() { this.active = true; this.container.removeClassName(this.options.classNames.inactive); this.container.addClassName(this.options.classNames.active); this.executer = new PeriodicalExecuter(this.step.bind(this, this.options.step), this.options.interval); }, stop: function(reset)
        {
            this.active = false; if (this.executer)
                this.executer.stop(); this.container.removeClassName(this.options.classNames.active); this.container.addClassName(this.options.classNames.inactive); if (typeof (reset) == 'undefined' || reset == true)
                this.reset();
        }, step: function(amount) { this.active = true; this.setProgress(Math.min(100, this.progress + amount)); }, reset: function() { this.active = false; this.setProgress(0); }, draw: function() { this.progressContainer.setStyle({ width: (this.containerWidth - Math.floor((parseInt(this.progress) / 100) * this.containerWidth)) + 'px' }); }, notify: function(event_name)
        {
            if (this.options[event_name])
                return [this.options[event_name].apply(this.options[event_name], $A(arguments).slice(1))];
        } 
        }); Object.Event.extend(Control.ProgressBar); if (typeof (Prototype) == "undefined") { throw "Control.Rating requires Prototype to be loaded."; }
    if (typeof (Object.Event) == "undefined") { throw "Control.Rating requires Object.Event to be loaded."; }
    Control.Rating = Class.create({ initialize: function(container, options)
    {
        Control.Rating.instances.push(this); this.value = false; this.links = []; this.container = $(container); this.container.update(''); this.options = { min: 1, max: 5, rated: false, input: false, reverse: false, capture: true, multiple: false, classNames: { off: 'rating_off', half: 'rating_half', on: 'rating_on', selected: 'rating_selected' }, updateUrl: false, updateParameterName: 'value', afterChange: Prototype.emptyFunction }; Object.extend(this.options, options || {}); if (this.options.value) { this.value = this.options.value; delete this.options.value; }
        if (this.options.input) { this.options.input = $(this.options.input); this.options.input.observe('change', function(input) { this.setValueFromInput(input); } .bind(this, this.options.input)); this.setValueFromInput(this.options.input, true); }
        var range = $R(this.options.min, this.options.max); (this.options.reverse ? $A(range).reverse() : range).each(function(i) { var link = this.buildLink(i); this.container.appendChild(link); this.links.push(link); } .bind(this)); this.setValue(this.value || this.options.min - 1, false, true);
    }, buildLink: function(rating)
    {
        var link = $(document.createElement('a')); link.value = rating; if (this.options.multiple || (!this.options.rated && !this.options.multiple)) { link.href = ''; link.onmouseover = this.mouseOver.bind(this, link); link.onmouseout = this.mouseOut.bind(this, link); link.onclick = this.click.bindAsEventListener(this, link); } else { link.style.cursor = 'default'; link.observe('click', function(event) { Event.stop(event); return false; } .bindAsEventListener(this)); }
        link.addClassName(this.options.classNames.off); return link;
    }, disable: function() { this.links.each(function(link) { link.onmouseover = Prototype.emptyFunction; link.onmouseout = Prototype.emptyFunction; link.onclick = Prototype.emptyFunction; link.observe('click', function(event) { Event.stop(event); return false; } .bindAsEventListener(this)); link.style.cursor = 'default'; } .bind(this)); }, setValueFromInput: function(input, prevent_callbacks) { this.setValue($F(input), true, prevent_callbacks); }, setValue: function(value, force_selected, prevent_callbacks)
    {
        this.value = value; if (this.options.input) { if (this.options.input.options) { $A(this.options.input.options).each(function(option, i) { if (option.value == this.value) { this.options.input.options.selectedIndex = i; throw $break; } } .bind(this)); } else { this.options.input.value = this.value; } }
        this.render(this.value, force_selected); if (!prevent_callbacks)
        {
            if (this.options.updateUrl) { var params = {}, a; params[this.options.updateParameterName] = this.value; a = new Ajax.Request(this.options.updateUrl, { parameters: params }); }
            this.notify('afterChange', this.value);
        } 
    }, render: function(rating, force_selected) { (this.options.reverse ? this.links.reverse() : this.links).each(function(link, i) { if (link.value <= Math.ceil(rating)) { link.className = this.options.classNames[link.value <= rating ? 'on' : 'half']; if (this.options.rated || force_selected) { link.addClassName(this.options.classNames.selected); } } else { link.className = this.options.classNames.off; } } .bind(this)); }, mouseOver: function(link) { this.render(link.value, true); }, mouseOut: function(link) { this.render(this.value); }, click: function(event, link)
    {
        this.options.rated = true; this.setValue((link.value ? link.value : link), true); if (!this.options.multiple) { this.disable(); }
        if (this.options.capture) { Event.stop(event); return false; } 
    } 
    }); Object.extend(Control.Rating, { instances: [], findByElementId: function(id) { return Control.Rating.instances.find(function(instance) { return (instance.container.id && instance.container.id == id); }); } }); Object.Event.extend(Control.Rating); if (typeof (Prototype) == "undefined")
        throw "Control.ScrollBar requires Prototype to be loaded."; if (typeof (Control.Slider) == "undefined")
        throw "Control.ScrollBar requires Control.Slider to be loaded."; if (typeof (Object.Event) == "undefined")
        throw "Control.ScrollBar requires Object.Event to be loaded."; Control.ScrollBar = Class.create({ initialize: function(container, track, options)
        {
            this.enabled = false; this.notificationTimeout = false; this.container = $(container); this.boundMouseWheelEvent = this.onMouseWheel.bindAsEventListener(this); this.boundResizeObserver = this.onWindowResize.bind(this); this.track = $(track); this.handle = this.track.firstDescendant(); this.options = Object.extend({ active_class_name: 'scrolling', apply_active_class_name_to: this.container, notification_timeout_length: 125, handle_minimum_height: 25, scroll_to_smoothing: 0.01, scroll_to_steps: 15, proportional: true, slider_options: {} }, options || {}); this.slider = new Control.Slider(this.handle, this.track, Object.extend({ axis: 'vertical', onSlide: this.onChange.bind(this), onChange: this.onChange.bind(this) }, this.options.slider_options)); this.recalculateLayout(); Event.observe(window, 'resize', this.boundResizeObserver); this.handle.observe('mousedown', function()
            {
                if (this.auto_sliding_executer)
                    this.auto_sliding_executer.stop();
            } .bind(this));
        }, destroy: function() { Event.stopObserving(window, 'resize', this.boundResizeObserver); }, enable: function()
        {
            this.enabled = true; this.container.observe('mouse:wheel', this.boundMouseWheelEvent); this.slider.setEnabled(); this.track.show(); if (this.options.active_class_name)
                $(this.options.apply_active_class_name_to).addClassName(this.options.active_class_name); this.notify('enabled');
        }, disable: function()
        {
            this.enabled = false; this.container.stopObserving('mouse:wheel', this.boundMouseWheelEvent); this.slider.setDisabled(); this.track.hide(); if (this.options.active_class_name)
                $(this.options.apply_active_class_name_to).removeClassName(this.options.active_class_name); this.notify('disabled'); this.reset();
        }, reset: function() { this.slider.setValue(0); }, recalculateLayout: function()
        {
            if (this.container.scrollHeight <= this.container.offsetHeight)
                this.disable(); else
            {
                this.slider.trackLength = this.slider.maximumOffset() - this.slider.minimumOffset(); if (this.options.proportional) { this.handle.style.height = Math.max(this.container.offsetHeight * (this.container.offsetHeight / this.container.scrollHeight), this.options.handle_minimum_height) + 'px'; this.slider.handleLength = this.handle.style.height.replace(/px/, ''); }
                this.enable();
            } 
        }, onWindowResize: function() { this.recalculateLayout(); this.scrollBy(0); }, onMouseWheel: function(event)
        {
            if (this.auto_sliding_executer)
                this.auto_sliding_executer.stop(); this.slider.setValueBy(-(event.memo.delta / 20)); event.stop(); return false;
        }, onChange: function(value)
        {
            this.container.scrollTop = Math.round(value / this.slider.maximum * (this.container.scrollHeight - this.container.offsetHeight)); if (this.notification_timeout)
                window.clearTimeout(this.notificationTimeout); this.notificationTimeout = window.setTimeout(function() { this.notify('change', value); } .bind(this), this.options.notification_timeout_length);
        }, getCurrentMaximumDelta: function() { return this.slider.maximum * (this.container.scrollHeight - this.container.offsetHeight); }, getDeltaToElement: function(element) { return this.slider.maximum * ((element.positionedOffset().top + (element.getHeight() / 2)) - (this.container.getHeight() / 2)); }, scrollTo: function(y, animate)
        {
            var current_maximum_delta = this.getCurrentMaximumDelta(); if (y == 'top')
                y = 0; else if (y == 'bottom')
                y = current_maximum_delta; else if (typeof (y) != "number")
                y = this.getDeltaToElement($(y)); if (this.enabled)
            {
                y = Math.max(0, Math.min(y, current_maximum_delta)); if (this.auto_sliding_executer)
                    this.auto_sliding_executer.stop(); var target_value = y / current_maximum_delta; var original_slider_value = this.slider.value; var delta = (target_value - original_slider_value) * current_maximum_delta; if (animate)
                {
                    this.auto_sliding_executer = new PeriodicalExecuter(function()
                    {
                        if (Math.round(this.slider.value * 100) / 100 < Math.round(target_value * 100) / 100 || Math.round(this.slider.value * 100) / 100 > Math.round(target_value * 100) / 100) { this.scrollBy(delta / this.options.scroll_to_steps); } else
                        {
                            this.auto_sliding_executer.stop(); this.auto_sliding_executer = null; if (typeof (animate) == "function")
                                animate();
                        } 
                    } .bind(this), this.options.scroll_to_smoothing);
                } else
                    this.scrollBy(delta);
            } else if (typeof (animate) == "function")
                animate();
        }, scrollBy: function(y)
        {
            if (!this.enabled)
                return false; this.slider.setValueBy(y / this.getCurrentMaximumDelta());
        } 
        }); Object.Event.extend(Control.ScrollBar); if (typeof (Prototype) == "undefined")
        throw "Control.Selection requires Prototype to be loaded."; if (typeof (Object.Event) == "undefined")
        throw "Control.Selection requires Object.Event to be loaded."; Control.Selection = { options: { resize_layout_timeout: 125, selected: Prototype.emptyFunction, deselected: Prototype.emptyFunction, change: Prototype.emptyFunction, selection_id: 'control_selection', selection_style: { zIndex: 999, cursor: 'default', border: '1px dotted #000' }, filter: function(element) { return true; }, drag_proxy: false, drag_proxy_threshold: 1, drag_proxy_options: {} }, selectableElements: [], elements: [], selectableObjects: [], objects: [], active: false, container: false, resizeTimeout: false, load: function(options)
        {
            Control.Selection.options = Object.extend(Control.Selection.options, options || {}); Control.Selection.selection_div = $(document.createElement('div')); Control.Selection.selection_div.id = Control.Selection.options.selection_id; Control.Selection.selection_div.style.display = 'none'; Control.Selection.selection_div.setStyle(Control.Selection.options.selection_style); Control.Selection.border_width = parseInt(Control.Selection.selection_div.getStyle('border-top-width')) * 2; Control.Selection.container = Prototype.Browser.IE ? window.container : window; $(document.body).insert(Control.Selection.selection_div); Control.Selection.enable(); if (Control.Selection.options.drag_proxy && typeof (Draggable) != 'undefined')
                Control.Selection.DragProxy.load(); Event.observe(window, 'resize', function()
                {
                    if (Control.Selection.resizeTimeout)
                        window.clearTimeout(Control.Selection.resizeTimeout); Control.Selection.resizeTimeout = window.setTimeout(Control.Selection.recalculateLayout, Control.Selection.options.resize_layout_timeout);
                }); if (Prototype.Browser.IE) { var body = $$('body').first(); body.observe('mouseleave', Control.Selection.stop); body.observe('mouseup', Control.Selection.stop); } 
        }, enable: function()
        {
            if (Prototype.Browser.IE) { document.onselectstart = function() { return false; } }
            Event.observe(Control.Selection.container, 'mousedown', Control.Selection.start); Event.observe(Control.Selection.container, 'mouseup', Control.Selection.stop);
        }, disable: function()
        {
            if (Prototype.Browser.IE) { document.onselectstart = function() { return true; } }
            Event.stopObserving(Control.Selection.container, 'mousedown', Control.Selection.start); Event.stopObserving(Control.Selection.container, 'mouseup', Control.Selection.stop);
        }, recalculateLayout: function()
        {
            Control.Selection.selectableElements.each(function(element)
            {
                var dimensions = element.getDimensions(); var offset = element.cumulativeOffset(); var scroll_offset = element.cumulativeScrollOffset(); if (!element._control_selection)
                    element._control_selection = {}; element._control_selection.top = offset[1] - scroll_offset[1]; element._control_selection.left = offset[0] - scroll_offset[0]; element._control_selection.width = dimensions.width; element._control_selection.height = dimensions.height;
            });
        }, addSelectable: function(element, object, activation_targets, activation_target_callback)
        {
            element = $(element); if (activation_targets)
                activation_targets = activation_targets.each ? activation_targets : [activation_targets]; var dimensions = element.getDimensions(); var offset = Position.cumulativeOffset(element); element._control_selection = { activation_targets: activation_targets, is_selected: false, top: offset[1], left: offset[0], width: dimensions.width, height: dimensions.height, activationTargetMouseMove: function()
                {
                    Control.Selection.notify('activationTargetMouseMove', element); if (activation_targets) { activation_targets.each(function(activation_target) { activation_target.stopObserving('mousemove', element._control_selection.activationTargetMouseMove); }); }
                    Control.Selection.DragProxy.container.stopObserving('mousemove', element._control_selection.activationTargetMouseMove);
                }, activationTargetMouseDown: function(event)
                {
                    if (!Control.Selection.elements.include(element))
                        Control.Selection.select(element); Control.Selection.DragProxy.start(event); Control.Selection.DragProxy.container.hide(); if (activation_targets) { activation_targets.each(function(activation_target) { activation_target.observe('mousemove', element._control_selection.activationTargetMouseMove); }); }
                    Control.Selection.DragProxy.container.observe('mousemove', element._control_selection.activationTargetMouseMove);
                }, activationTargetClick: function()
                {
                    Control.Selection.select(element); if (typeof (activation_target_callback) == "function")
                        activation_target_callback(); if (activation_targets) { activation_targets.each(function(activation_target) { activation_target.stopObserving('mousemove', element._control_selection.activationTargetMouseMove); }); }
                    Control.Selection.DragProxy.container.stopObserving('mousemove', element._control_selection.activationTargetMouseMove);
                } 
                }; element.onselectstart = function() { return false; }; element.unselectable = 'on'; element.style.MozUserSelect = 'none'; if (activation_targets) { activation_targets.each(function(activation_target) { activation_target.observe('mousedown', element._control_selection.activationTargetMouseDown); activation_target.observe('click', element._control_selection.activationTargetClick); }); }
            Control.Selection.selectableElements.push(element); Control.Selection.selectableObjects.push(object);
        }, removeSelectable: function(element)
        {
            element = $(element); if (element._control_selection.activation_targets) { element._control_selection.activation_targets.each(function(activation_target) { activation_target.stopObserving('mousedown', element._control_selection.activationTargetMouseDown); }); element._control_selection.activation_targets.each(function(activation_target) { activation_target.stopObserving('click', element._control_selection.activationTargetClick); }); }
            element._control_selection = null; element.onselectstart = function() { return true; }; element.unselectable = 'off'; element.style.MozUserSelect = ''; var position = 0; Control.Selection.selectableElements.each(function(selectable_element, i) { if (selectable_element == element) { position = i; throw $break; } }); Control.Selection.selectableElements = Control.Selection.selectableElements.without(element); Control.Selection.selectableObjects = Control.Selection.selectableObjects.slice(0, position).concat(Control.Selection.selectableObjects.slice(position + 1))
        }, select: function(selected_elements)
        {
            if (typeof (selected_elements) == "undefined" || !selected_elements)
                selected_elements = []; if (!selected_elements.each && !selected_elements._each)
                selected_elements = [selected_elements]; var selected_items_have_changed = !(Control.Selection.elements.length == selected_elements.length && Control.Selection.elements.all(function(item, i) { return selected_elements[i] == item; })); if (!selected_items_have_changed)
                return; var selected_objects_indexed_by_element = {}; var selected_objects = selected_elements.collect(function(selected_element) { var selected_object = Control.Selection.selectableObjects[Control.Selection.selectableElements.indexOf(selected_element)]; selected_objects_indexed_by_element[selected_element] = selected_object; return selected_object; }); if (Control.Selection.elements.length == 0 && selected_elements.length != 0) { selected_elements.each(function(element) { Control.Selection.notify('selected', element, selected_objects_indexed_by_element[element]); }); } else { Control.Selection.elements.each(function(element) { if (!selected_elements.include(element)) { Control.Selection.notify('deselected', element, selected_objects_indexed_by_element[element]); } }); selected_elements.each(function(element) { if (!Control.Selection.elements.include(element)) { Control.Selection.notify('selected', element, selected_objects_indexed_by_element[element]); } }); }
            Control.Selection.elements = selected_elements; Control.Selection.objects = selected_objects; Control.Selection.notify('change', Control.Selection.elements, Control.Selection.objects);
        }, deselect: function()
        {
            if (Control.Selection.notify('deselect') === false)
                return false; Control.Selection.elements.each(function(element) { Control.Selection.notify('deselected', element, Control.Selection.selectableObjects[Control.Selection.selectableElements.indexOf(element)]); }); Control.Selection.objects = []; Control.Selection.elements = []; Control.Selection.notify('change', Control.Selection.objects, Control.Selection.elements); return true;
        }, start: function(event)
        {
            if (!event.isLeftClick() || Control.Selection.notify('start', event) === false)
                return false; if (!event.shiftKey && !event.altKey)
                Control.Selection.deselect(); Event.observe(Control.Selection.container, 'mousemove', Control.Selection.onMouseMove); Event.stop(event); return false;
        }, stop: function() { Event.stopObserving(Control.Selection.container, 'mousemove', Control.Selection.onMouseMove); Control.Selection.active = false; Control.Selection.selection_div.setStyle({ display: 'none', top: null, left: null, width: null, height: null }); Control.Selection.start_mouse_coordinates = {}; Control.Selection.current_mouse_coordinates = {}; }, mouseCoordinatesFromEvent: function(event) { return { x: Event.pointerX(event), y: Event.pointerY(event) }; }, onClick: function(event, element, source)
        {
            var selection = []; if (event.shiftKey)
            {
                selection = Control.Selection.elements.clone(); if (!selection.include(element))
                    selection.push(element);
            } else if (event.altKey)
            {
                selection = Control.Selection.elements.clone(); if (selection.include(element))
                    selection = selection.without(element);
            } else { selection = [element]; }
            Control.Selection.select(selection); if (source == 'click')
                Event.stop(event);
        }, onMouseMove: function(event)
        {
            if (!Control.Selection.active) { Control.Selection.active = true; Control.Selection.start_mouse_coordinates = Control.Selection.mouseCoordinatesFromEvent(event); } else
            {
                Control.Selection.current_mouse_coordinates = Control.Selection.mouseCoordinatesFromEvent(event); Control.Selection.drawSelectionDiv(); var current_selection = Control.Selection.selectableElements.findAll(function(element) { return Control.Selection.options.filter(element) && Control.Selection.elementWithinSelection(element); }); if (event.shiftKey && !event.altKey)
                {
                    Control.Selection.elements.each(function(element)
                    {
                        if (!current_selection.include(element))
                            current_selection.push(element);
                    });
                } else if (event.altKey && !event.shiftKey) { current_selection = Control.Selection.elements.findAll(function(element) { return !current_selection.include(element); }); }
                Control.Selection.select(current_selection);
            } 
        }, drawSelectionDiv: function() { if (Control.Selection.start_mouse_coordinates == Control.Selection.current_mouse_coordinates) { Control.Selection.selection_div.style.display = 'none'; } else { Control.Selection.viewport = document.viewport.getDimensions(); Control.Selection.selection_div.style.position = 'absolute'; Control.Selection.current_direction = (Control.Selection.start_mouse_coordinates.y > Control.Selection.current_mouse_coordinates.y ? 'N' : 'S') + (Control.Selection.start_mouse_coordinates.x < Control.Selection.current_mouse_coordinates.x ? 'E' : 'W'); Control.Selection.selection_div.setStyle(Control.Selection['dimensionsFor' + Control.Selection.current_direction]()); Control.Selection.selection_div.style.display = 'block'; } }, dimensionsForNW: function() { return { top: (Control.Selection.start_mouse_coordinates.y - (Control.Selection.start_mouse_coordinates.y - Control.Selection.current_mouse_coordinates.y)) + 'px', left: (Control.Selection.start_mouse_coordinates.x - (Control.Selection.start_mouse_coordinates.x - Control.Selection.current_mouse_coordinates.x)) + 'px', width: (Control.Selection.start_mouse_coordinates.x - Control.Selection.current_mouse_coordinates.x) + 'px', height: (Control.Selection.start_mouse_coordinates.y - Control.Selection.current_mouse_coordinates.y) + 'px' }; }, dimensionsForNE: function() { return { top: (Control.Selection.start_mouse_coordinates.y - (Control.Selection.start_mouse_coordinates.y - Control.Selection.current_mouse_coordinates.y)) + 'px', left: Control.Selection.start_mouse_coordinates.x + 'px', width: Math.min((Control.Selection.viewport.width - Control.Selection.start_mouse_coordinates.x) - Control.Selection.border_width, Control.Selection.current_mouse_coordinates.x - Control.Selection.start_mouse_coordinates.x) + 'px', height: (Control.Selection.start_mouse_coordinates.y - Control.Selection.current_mouse_coordinates.y) + 'px' }; }, dimensionsForSE: function() { return { top: Control.Selection.start_mouse_coordinates.y + 'px', left: Control.Selection.start_mouse_coordinates.x + 'px', width: Math.min((Control.Selection.viewport.width - Control.Selection.start_mouse_coordinates.x) - Control.Selection.border_width, Control.Selection.current_mouse_coordinates.x - Control.Selection.start_mouse_coordinates.x) + 'px', height: Math.min((Control.Selection.viewport.height - Control.Selection.start_mouse_coordinates.y) - Control.Selection.border_width, Control.Selection.current_mouse_coordinates.y - Control.Selection.start_mouse_coordinates.y) + 'px' }; }, dimensionsForSW: function() { return { top: Control.Selection.start_mouse_coordinates.y + 'px', left: (Control.Selection.start_mouse_coordinates.x - (Control.Selection.start_mouse_coordinates.x - Control.Selection.current_mouse_coordinates.x)) + 'px', width: (Control.Selection.start_mouse_coordinates.x - Control.Selection.current_mouse_coordinates.x) + 'px', height: Math.min((Control.Selection.viewport.height - Control.Selection.start_mouse_coordinates.y) - Control.Selection.border_width, Control.Selection.current_mouse_coordinates.y - Control.Selection.start_mouse_coordinates.y) + 'px' }; }, inBoundsForNW: function(element, selection) { return (((element.left > selection.left || element.right > selection.left) && selection.right > element.left) && ((element.top > selection.top || element.bottom > selection.top) && selection.bottom > element.top)); }, inBoundsForNE: function(element, selection) { return (((element.left < selection.right || element.left < selection.right) && selection.left < element.right) && ((element.top > selection.top || element.bottom > selection.top) && selection.bottom > element.top)); }, inBoundsForSE: function(element, selection) { return (((element.left < selection.right || element.left < selection.right) && selection.left < element.right) && ((element.bottom < selection.bottom || element.top < selection.bottom) && selection.top < element.bottom)); }, inBoundsForSW: function(element, selection) { return (((element.left > selection.left || element.right > selection.left) && selection.right > element.left) && ((element.bottom < selection.bottom || element.top < selection.bottom) && selection.top < element.bottom)); }, elementWithinSelection: function(element) { if (Control.Selection['inBoundsFor' + Control.Selection.current_direction]({ top: element._control_selection.top, left: element._control_selection.left, bottom: element._control_selection.top + element._control_selection.height, right: element._control_selection.left + element._control_selection.width }, { top: parseInt(Control.Selection.selection_div.style.top), left: parseInt(Control.Selection.selection_div.style.left), bottom: parseInt(Control.Selection.selection_div.style.top) + parseInt(Control.Selection.selection_div.style.height), right: parseInt(Control.Selection.selection_div.style.left) + parseInt(Control.Selection.selection_div.style.width) })) { element._control_selection.is_selected = true; return true; } else { element._control_selection.is_selected = false; return false; } }, DragProxy: { active: false, xorigin: 0, yorigin: 0, load: function() { Control.Selection.DragProxy.container = $(document.createElement('div')); Control.Selection.DragProxy.container.id = 'control_selection_drag_proxy'; Control.Selection.DragProxy.container.setStyle({ position: 'absolute', top: '1px', left: '1px', zIndex: 99999 }); Control.Selection.DragProxy.container.hide(); document.body.appendChild(Control.Selection.DragProxy.container); Control.Selection.observe('selected', Control.Selection.DragProxy.selected); Control.Selection.observe('deselected', Control.Selection.DragProxy.deselected); }, start: function(event)
        {
            if (event.isRightClick()) { Control.Selection.DragProxy.container.hide(); return; }
            if (Control.Selection.DragProxy.xorigin == Event.pointerX(event) && Control.Selection.DragProxy.yorigin == Event.pointerY(event))
                return; Control.Selection.DragProxy.active = true; Control.Selection.DragProxy.container.setStyle({ position: 'absolute', top: Event.pointerY(event) + 'px', left: Event.pointerX(event) + 'px' }); Control.Selection.DragProxy.container.observe('mouseup', Control.Selection.DragProxy.onMouseUp); Control.Selection.DragProxy.container.show(); Control.Selection.DragProxy.container._draggable = new Draggable(Control.Selection.DragProxy.container, Object.extend({ onEnd: Control.Selection.DragProxy.stop }, Control.Selection.options.drag_proxy_options)); Control.Selection.DragProxy.container._draggable.eventMouseDown(event); Control.Selection.DragProxy.notify('start', Control.Selection.DragProxy.container, Control.Selection.elements);
        }, stop: function()
        {
            window.setTimeout(function()
            {
                Control.Selection.DragProxy.active = false; Control.Selection.DragProxy.container.hide(); if (Control.Selection.DragProxy.container._draggable) { Control.Selection.DragProxy.container._draggable.destroy(); Control.Selection.DragProxy.container._draggable = null; }
                Control.Selection.DragProxy.notify('stop');
            }, 1);
        }, onClick: function(event)
        {
            Control.Selection.DragProxy.xorigin = Event.pointerX(event); Control.Selection.DragProxy.yorigin = Event.pointerY(event); if (event.isRightClick())
                Control.Selection.DragProxy.container.hide(); if (Control.Selection.elements.length >= Control.Selection.options.drag_proxy_threshold && !(event.shiftKey || event.altKey) && (Control.Selection.DragProxy.xorigin != Event.pointerX(event) || Control.Selection.DragProxy.yorigin != Event.pointerY(event))) { Control.Selection.DragProxy.start(event); Event.stop(event); } 
        }, onMouseUp: function(event) { Control.Selection.DragProxy.stop(); Control.Selection.DragProxy.container.stopObserving('mouseup', Control.Selection.DragProxy.onMouseUp); }, selected: function(element) { element.observe('mousedown', Control.Selection.DragProxy.onClick); }, deselected: function(element) { element.stopObserving('mousedown', Control.Selection.DragProxy.onClick); } }
        }; Object.Event.extend(Control.Selection); Object.Event.extend(Control.Selection.DragProxy); if (typeof (Prototype) == "undefined") { throw "Control.SelectMultiple requires Prototype to be loaded."; }
    if (typeof (Object.Event) == "undefined") { throw "Control.SelectMultiple requires Object.Event to be loaded."; }
    Control.SelectMultiple = Class.create({ select: false, container: false, numberOfCheckedBoxes: 0, checkboxes: [], hasExtraOption: false, initialize: function(select, container, options)
    {
        this.options = { checkboxSelector: 'input[type=checkbox]', nameSelector: 'span.name', labelSeparator: ', ', valueSeparator: ',', afterChange: Prototype.emptyFunction, overflowString: function(str) { return str.truncate(); }, overflowLength: 30 }; Object.extend(this.options, options || {}); this.select = $(select); this.container = $(container); this.checkboxes = (typeof (this.options.checkboxSelector) == 'function') ? this.options.checkboxSelector.bind(this)() : this.container.getElementsBySelector(this.options.checkboxSelector); var value_was_set = false; if (this.options.value) { value_was_set = true; this.setValue(this.options.value); delete this.options.value; }
        this.hasExtraOption = false; this.checkboxes.each(function(checkbox) { checkbox.observe('click', this.checkboxOnClick.bind(this, checkbox)); } .bind(this)); this.select.observe('change', this.selectOnChange.bind(this)); this.countAndCheckCheckBoxes(); if (!value_was_set) { this.scanCheckBoxes(); }
        this.notify('afterChange', this.select.options[this.select.options.selectedIndex].value);
    }, countAndCheckCheckBoxes: function()
    {
        this.numberOfCheckedBoxes = this.checkboxes.inject(0, function(number, checkbox)
        {
            checkbox.checked = (this.select.options[this.select.options.selectedIndex].value == checkbox.value); var value_string = this.select.options[this.select.options.selectedIndex].value; var value_collection = $A(value_string.split ? value_string.split(this.options.valueSeparator) : value_string); var should_check = value_collection.any(function(value) { if (!should_check && checkbox.value == value) { return true; } } .bind(this)); checkbox.checked = should_check; if (checkbox.checked) { ++number; }
            return number;
        } .bind(this));
    }, setValue: function(value_string) { this.numberOfCheckedBoxes = 0; var value_collection = $A(value_string.split ? value_string.split(this.options.valueSeparator) : value_string); this.checkboxes.each(function(checkbox) { checkbox.checked = false; value_collection.each(function(value) { if (checkbox.value == value) { ++this.numberOfCheckedBoxes; checkbox.checked = true; } } .bind(this)); } .bind(this)); this.scanCheckBoxes(); }, selectOnChange: function() { this.removeExtraOption(); this.countAndCheckCheckBoxes(); this.notify('afterChange', this.select.options[this.select.options.selectedIndex].value); }, checkboxOnClick: function(checkbox) { this.numberOfCheckedBoxes = this.checkboxes.findAll(function(c) { return c.checked; }).length; this.scanCheckBoxes(); this.notify('afterChange', this.numberOfCheckedBoxes === 0 ? "" : this.select.options[this.select.options.selectedIndex].value); }, scanCheckBoxes: function() { switch (this.numberOfCheckedBoxes) { case 1: this.checkboxes.each(function(checkbox) { if (checkbox.checked) { $A(this.select.options).each(function(option, i) { if (option.value == checkbox.value) { this.select.options.selectedIndex = i; throw $break; } } .bind(this)); throw $break; } } .bind(this)); break; case 0: this.removeExtraOption(); break; default: this.addExtraOption(); break; } }, getLabelForExtraOption: function()
    {
        var label = (typeof (this.options.nameSelector) == 'function' ? this.options.nameSelector.bind(this)() : this.container.getElementsBySelector(this.options.nameSelector).inject([], function(labels, name_element, i)
        {
            if (this.checkboxes[i].checked) { labels.push(name_element.innerHTML); }
            return labels;
        } .bind(this))).join(this.options.labelSeparator); return (label.length >= this.options.overflowLength && this.options.overflowLength > 0) ? (typeof (this.options.overflowString) == 'function' ? this.options.overflowString(label) : this.options.overflowString) : label;
    }, getValueForExtraOption: function()
    {
        return this.checkboxes.inject([], function(values, checkbox)
        {
            if (checkbox.checked) { values.push(checkbox.value); }
            return values;
        }).join(this.options.valueSeparator);
    }, addExtraOption: function() { this.removeExtraOption(); this.hasExtraOption = true; this.select.options[this.select.options.length] = new Option(this.getLabelForExtraOption(), this.getValueForExtraOption()); this.select.options.selectedIndex = this.select.options.length - 1; }, removeExtraOption: function() { if (this.hasExtraOption) { this.select.remove(this.select.options.length - 1); this.hasExtraOption = false; } } 
    }); Object.Event.extend(Control.SelectMultiple); if (typeof (Prototype) == "undefined")
        throw "Control.Tabs requires Prototype to be loaded."; if (typeof (Object.Event) == "undefined")
        throw "Control.Tabs requires Object.Event to be loaded."; Control.Tabs = Class.create({ initialize: function(tab_list_container, options)
        {
            if (!$(tab_list_container))
                throw "Control.Tabs could not find the element: " + tab_list_container; this.activeContainer = false; this.activeLink = false; this.containers = $H({}); this.links = []; Control.Tabs.instances.push(this); this.options = { beforeChange: Prototype.emptyFunction, afterChange: Prototype.emptyFunction, hover: false, linkSelector: 'li a', setClassOnContainer: false, activeClassName: 'active', defaultTab: 'first', autoLinkExternal: true, targetRegExp: /#(.+)$/, showFunction: Element.show, hideFunction: Element.hide }; Object.extend(this.options, options || {}); (typeof (this.options.linkSelector == 'string') ? $(tab_list_container).select(this.options.linkSelector) : this.options.linkSelector($(tab_list_container))).findAll(function(link) { return (/^#/).exec((Prototype.Browser.WebKit ? decodeURIComponent(link.href) : link.href).replace(window.location.href.split('#')[0], '')); }).each(function(link) { this.addTab(link); } .bind(this)); this.containers.values().each(Element.hide); if (this.options.defaultTab == 'first')
                this.setActiveTab(this.links.first()); else if (this.options.defaultTab == 'last')
                this.setActiveTab(this.links.last()); else
                this.setActiveTab(this.options.defaultTab); var targets = this.options.targetRegExp.exec(window.location); if (targets && targets[1]) { targets[1].split(',').each(function(target) { this.setActiveTab(this.links.find(function(link) { return link.key == target; })); } .bind(this)); }
            if (this.options.autoLinkExternal) { $A(document.getElementsByTagName('a')).each(function(a) { if (!this.links.include(a)) { var clean_href = a.href.replace(window.location.href.split('#')[0], ''); if (clean_href.substring(0, 1) == '#') { if (this.containers.keys().include(clean_href.substring(1))) { $(a).observe('click', function(event, clean_href) { this.setActiveTab(clean_href.substring(1)); } .bindAsEventListener(this, clean_href)); } } } } .bind(this)); } 
        }, addTab: function(link)
        {
            this.links.push(link); link.key = link.getAttribute('href').replace(window.location.href.split('#')[0], '').split('#').last().replace(/#/, ''); var container = $(link.key); if (!container)
                throw "Control.Tabs: #" + link.key + " was not found on the page."
            this.containers.set(link.key, container); link[this.options.hover ? 'onmouseover' : 'onclick'] = function(link)
            {
                if (window.event)
                    Event.stop(window.event); this.setActiveTab(link); return false;
            } .bind(this, link);
        }, setActiveTab: function(link)
        {
            if (!link && typeof (link) == 'undefined')
                return; if (typeof (link) == 'string') { this.setActiveTab(this.links.find(function(_link) { return _link.key == link; })); } else if (typeof (link) == 'number') { this.setActiveTab(this.links[link]); } else
            {
                if (this.notify('beforeChange', this.activeContainer, this.containers.get(link.key)) === false)
                    return; if (this.activeContainer)
                    this.options.hideFunction(this.activeContainer); this.links.each(function(item) { (this.options.setClassOnContainer ? $(item.parentNode) : item).removeClassName(this.options.activeClassName); } .bind(this)); (this.options.setClassOnContainer ? $(link.parentNode) : link).addClassName(this.options.activeClassName); this.activeContainer = this.containers.get(link.key); this.activeLink = link; this.options.showFunction(this.containers.get(link.key)); this.notify('afterChange', this.containers.get(link.key));
            } 
        }, next: function() { this.links.each(function(link, i) { if (this.activeLink == link && this.links[i + 1]) { this.setActiveTab(this.links[i + 1]); throw $break; } } .bind(this)); }, previous: function() { this.links.each(function(link, i) { if (this.activeLink == link && this.links[i - 1]) { this.setActiveTab(this.links[i - 1]); throw $break; } } .bind(this)); }, first: function() { this.setActiveTab(this.links.first()); }, last: function() { this.setActiveTab(this.links.last()); } 
        }); Object.extend(Control.Tabs, { instances: [], findByTabId: function(id) { return Control.Tabs.instances.find(function(tab) { return tab.links.find(function(link) { return link.key == id; }); }); } }); Object.Event.extend(Control.Tabs); if (typeof (Prototype) == "undefined") { throw "Control.TextArea requires Prototype to be loaded."; }
    if (typeof (Object.Event) == "undefined") { throw "Control.TextArea requires Object.Event to be loaded."; }
    Control.TextArea = Class.create({ initialize: function(textarea) { this.onChangeTimeout = false; this.element = $(textarea); $(this.element).observe('keyup', this.doOnChange.bindAsEventListener(this)); $(this.element).observe('paste', this.doOnChange.bindAsEventListener(this)); $(this.element).observe('input', this.doOnChange.bindAsEventListener(this)); if (!!document.selection) { $(this.element).observe('mouseup', this.saveRange.bindAsEventListener(this)); $(this.element).observe('keyup', this.saveRange.bindAsEventListener(this)); } }, doOnChange: function(event)
    {
        if (this.onChangeTimeout) { window.clearTimeout(this.onChangeTimeout); }
        this.onChangeTimeout = window.setTimeout(function() { this.notify('change', this.getValue()); } .bind(this), Control.TextArea.onChangeTimeoutLength);
    }, saveRange: function() { this.range = document.selection.createRange(); }, getValue: function() { return this.element.value; }, getSelection: function()
    {
        if (!!document.selection) { return document.selection.createRange().text; }
        else if (!!this.element.setSelectionRange) { return this.element.value.substring(this.element.selectionStart, this.element.selectionEnd); }
        else { return false; } 
    }, replaceSelection: function(text)
    {
        var scroll_top = this.element.scrollTop; if (!!document.selection) { this.element.focus(); var range = (this.range) ? this.range : document.selection.createRange(); range.text = text; range.select(); } else if (!!this.element.setSelectionRange) { var selection_start = this.element.selectionStart; this.element.value = this.element.value.substring(0, selection_start) + text + this.element.value.substring(this.element.selectionEnd); this.element.setSelectionRange(selection_start + text.length, selection_start + text.length); }
        this.doOnChange(); this.element.focus(); this.element.scrollTop = scroll_top;
    }, wrapSelection: function(before, after) { var sel = this.getSelection(); if (sel.indexOf(before) === 0 && sel.lastIndexOf(after) === (sel.length - after.length)) { this.replaceSelection(sel.substring(before.length, sel.length - after.length)); } else { this.replaceSelection(before + sel + after); } }, insertBeforeSelection: function(text) { this.replaceSelection(text + this.getSelection()); }, insertAfterSelection: function(text) { this.replaceSelection(this.getSelection() + text); }, collectFromEachSelectedLine: function(callback, before, after) { this.replaceSelection((before || '') + $A(this.getSelection().split("\n")).collect(callback).join("\n") + (after || '')); }, insertBeforeEachSelectedLine: function(text, before, after) { this.collectFromEachSelectedLine(function(line) { }, before, after); } 
    }); Object.extend(Control.TextArea, { onChangeTimeoutLength: 500 }); Object.Event.extend(Control.TextArea); Control.TextArea.ToolBar = Class.create({ initialize: function(textarea, toolbar)
    {
        this.textarea = textarea; if (toolbar) { this.container = $(toolbar); }
        else { this.container = $(document.createElement('ul')); this.textarea.element.parentNode.insertBefore(this.container, this.textarea.element); } 
    }, attachButton: function(node, callback) { node.onclick = function() { return false; }; $(node).observe('click', callback.bindAsEventListener(this.textarea)); }, addButton: function(link_text, callback, attrs)
    {
        var li = document.createElement('li'); var a = document.createElement('a'); a.href = '#'; this.attachButton(a, callback); li.appendChild(a); Object.extend(a, attrs || {}); if (link_text) { var span = document.createElement('span'); span.innerHTML = link_text; a.appendChild(span); }
        this.container.appendChild(li);
    } 
    }); if (typeof (Draggable) != 'undefined')
    {
        Draggable.prototype.draw = function(point)
        {
            var pos = Position.cumulativeOffset(this.element); if (this.options.ghosting) { var r = Position.realOffset(this.element); pos[0] += r[0] - Position.deltaX; pos[1] += r[1] - Position.deltaY; }
            var d = this.currentDelta(); pos[0] -= d[0]; pos[1] -= d[1]; if (this.options.scroll && (this.options.scroll != window && this._isScrollChild)) { pos[0] -= this.options.scroll.scrollLeft - this.originalScrollLeft; pos[1] -= this.options.scroll.scrollTop - this.originalScrollTop; }
            var p = [0, 1].map(function(i) { return (point[i] - pos[i] - this.offset[i]) } .bind(this)); if (this.options.snap) { if (typeof this.options.snap == 'function') { p = this.options.snap(p[0], p[1], this); } else { if (this.options.snap instanceof Array) { p = p.map(function(v, i) { return Math.round(v / this.options.snap[i]) * this.options.snap[i] } .bind(this)) } else { p = p.map(function(v) { return Math.round(v / this.options.snap) * this.options.snap } .bind(this)) } } }
            if (this.options.onDraw)
                this.options.onDraw.bind(this)(p); else
            {
                var style = this.element.style; if (this.options.constrainToViewport)
                {
                    var viewport_dimensions = document.viewport.getDimensions(); var container_dimensions = this.element.getDimensions(); var margin_top = parseInt(this.element.getStyle('margin-top')); var margin_left = parseInt(this.element.getStyle('margin-left')); var boundary = [[0 - margin_left, 0 - margin_top], [(viewport_dimensions.width - container_dimensions.width) - margin_left, (viewport_dimensions.height - container_dimensions.height) - margin_top]]; if ((!this.options.constraint) || (this.options.constraint == 'horizontal'))
                    {
                        if ((p[0] >= boundary[0][0]) && (p[0] <= boundary[1][0]))
                            this.element.style.left = p[0] + "px"; else
                            this.element.style.left = ((p[0] < boundary[0][0]) ? boundary[0][0] : boundary[1][0]) + "px";
                    }
                    if ((!this.options.constraint) || (this.options.constraint == 'vertical'))
                    {
                        if ((p[1] >= boundary[0][1]) && (p[1] <= boundary[1][1]))
                            this.element.style.top = p[1] + "px"; else
                            this.element.style.top = ((p[1] <= boundary[0][1]) ? boundary[0][1] : boundary[1][1]) + "px";
                    } 
                } else
                {
                    if ((!this.options.constraint) || (this.options.constraint == 'horizontal'))
                        style.left = p[0] + "px"; if ((!this.options.constraint) || (this.options.constraint == 'vertical'))
                        style.top = p[1] + "px";
                }
                if (style.visibility == "hidden")
                    style.visibility = "";
            } 
        };
    }
    if (typeof (Prototype) == "undefined")
        throw "Control.Window requires Prototype to be loaded."; if (typeof (IframeShim) == "undefined")
        throw "Control.Window requires IframeShim to be loaded."; if (typeof (Object.Event) == "undefined")
        throw "Control.Window requires Object.Event to be loaded."; Control.Window = Class.create({ initialize: function(container, options)
        {
            Control.Window.windows.push(this); this.container = false; this.isOpen = false; this.href = false; this.sourceContainer = false; this.ajaxRequest = false; this.remoteContentLoaded = false; this.numberInSequence = Control.Window.windows.length + 1; this.indicator = false; this.effects = { fade: false, appear: false }; this.indicatorEffects = { fade: false, appear: false }; this.options = Object.extend({ beforeOpen: Prototype.emptyFunction, afterOpen: Prototype.emptyFunction, beforeClose: Prototype.emptyFunction, afterClose: Prototype.emptyFunction, height: null, width: null, className: false, position: 'center', offsetLeft: 0, offsetTop: 0, iframe: false, hover: false, indicator: false, closeOnClick: false, iframeshim: true, fade: false, fadeDuration: 0.75, draggable: false, onDrag: Prototype.emptyFunction, resizable: false, minHeight: false, minWidth: false, maxHeight: false, maxWidth: false, onResize: Prototype.emptyFunction, constrainToViewport: false, method: 'post', parameters: {}, onComplete: Prototype.emptyFunction, onSuccess: Prototype.emptyFunction, onFailure: Prototype.emptyFunction, onException: Prototype.emptyFunction, onRemoteContentLoaded: Prototype.emptyFunction, insertRemoteContentAt: false }, options || {}); this.indicator = this.options.indicator ? $(this.options.indicator) : false; if (container)
            {
                if (typeof (container) == "string" && container.match(Control.Window.uriRegex))
                    this.href = container; else
                {
                    this.container = $(container); this.createDefaultContainer(container); if (this.container && ((this.container.readAttribute('href') && this.container.readAttribute('href') != '') || (this.options.hover && this.options.hover !== true)))
                    {
                        if (this.options.hover && this.options.hover !== true)
                            this.sourceContainer = $(this.options.hover); else
                        {
                            this.sourceContainer = this.container; this.href = this.container.readAttribute('href'); var rel = this.href.match(/^#(.+)$/); if (rel && rel[1]) { this.container = $(rel[1]); this.href = false; } else
                                this.container = false;
                        }
                        this.sourceContainerOpenHandler = function(event) { this.open(event); event.stop(); return false; } .bindAsEventListener(this); this.sourceContainerCloseHandler = function(event) { this.close(event); } .bindAsEventListener(this); this.sourceContainerMouseMoveHandler = function(event) { this.position(event); } .bindAsEventListener(this); if (this.options.hover)
                        {
                            this.sourceContainer.observe('mouseenter', this.sourceContainerOpenHandler); this.sourceContainer.observe('mouseleave', this.sourceContainerCloseHandler); if (this.options.position == 'mouse')
                                this.sourceContainer.observe('mousemove', this.sourceContainerMouseMoveHandler);
                        } else
                            this.sourceContainer.observe('click', this.sourceContainerOpenHandler);
                    } 
                } 
            }
            this.createDefaultContainer(container); if (this.options.insertRemoteContentAt === false)
                this.options.insertRemoteContentAt = this.container; var styles = { margin: 0, position: 'absolute', zIndex: Control.Window.initialZIndexForWindow() }; if (this.options.width)
                styles.width = $value(this.options.width) + 'px'; if (this.options.height)
                styles.height = $value(this.options.height) + 'px'; this.container.setStyle(styles); if (this.options.className)
                this.container.addClassName(this.options.className); this.positionHandler = this.position.bindAsEventListener(this); this.outOfBoundsPositionHandler = this.ensureInBounds.bindAsEventListener(this); this.bringToFrontHandler = this.bringToFront.bindAsEventListener(this); this.container.observe('mousedown', this.bringToFrontHandler); this.container.hide(); this.closeHandler = this.close.bindAsEventListener(this); if (this.options.iframeshim) { this.iFrameShim = new IframeShim(); this.iFrameShim.hide(); }
            this.applyResizable(); this.applyDraggable(); Event.observe(window, 'resize', this.outOfBoundsPositionHandler); this.notify('afterInitialize');
        }, open: function(event)
        {
            if (this.isOpen) { this.bringToFront(); return false; }
            if (this.notify('beforeOpen') === false)
                return false; if (this.options.closeOnClick)
            {
                if (this.options.closeOnClick === true)
                    this.closeOnClickContainer = $(document.body); else if (this.options.closeOnClick == 'container')
                    this.closeOnClickContainer = this.container; else if (this.options.closeOnClick == 'overlay') { Control.Overlay.load(); this.closeOnClickContainer = Control.Overlay.container; } else
                    this.closeOnClickContainer = $(this.options.closeOnClick); this.closeOnClickContainer.observe('click', this.closeHandler);
            }
            if (this.href && !this.options.iframe && !this.remoteContentLoaded)
            {
                this.remoteContentLoaded = true; if (this.href.match(/\.(jpe?g|gif|png|tiff?)$/i))
                {
                    var img = new Element('img'); img.observe('load', function(img)
                    {
                        this.getRemoteContentInsertionTarget().insert(img); this.position(); if (this.notify('onRemoteContentLoaded') !== false)
                        {
                            if (this.options.indicator)
                                this.hideIndicator(); this.finishOpen();
                        } 
                    } .bind(this, img)); img.writeAttribute('src', this.href);
                } else
                {
                    if (!this.ajaxRequest)
                    {
                        if (this.options.indicator)
                            this.showIndicator(); this.ajaxRequest = new Ajax.Request(this.href, { method: this.options.method, parameters: this.options.parameters, onComplete: function(request) { this.notify('onComplete', request); this.ajaxRequest = false; } .bind(this), onSuccess: function(request)
                            {
                                this.getRemoteContentInsertionTarget().insert(request.responseText); this.notify('onSuccess', request); if (this.notify('onRemoteContentLoaded') !== false)
                                {
                                    if (this.options.indicator)
                                        this.hideIndicator(); this.finishOpen();
                                } 
                            } .bind(this), onFailure: function(request)
                            {
                                this.notify('onFailure', request); if (this.options.indicator)
                                    this.hideIndicator();
                            } .bind(this), onException: function(request, e)
                            {
                                this.notify('onException', request, e); if (this.options.indicator)
                                    this.hideIndicator();
                            } .bind(this)
                            });
                    } 
                }
                return true;
            } else if (this.options.iframe && !this.remoteContentLoaded)
            {
                this.remoteContentLoaded = true; if (this.options.indicator)
                    this.showIndicator(); this.getRemoteContentInsertionTarget().insert(Control.Window.iframeTemplate.evaluate({ href: this.href })); var iframe = this.container.down('iframe'); iframe.onload = function()
                    {
                        this.notify('onRemoteContentLoaded'); if (this.options.indicator)
                            this.hideIndicator(); iframe.onload = null;
                    } .bind(this);
            }
            this.finishOpen(event); return true
        }, close: function(event)
        {
            if (!this.isOpen || this.notify('beforeClose', event) === false)
                return false; if (this.options.closeOnClick)
                this.closeOnClickContainer.stopObserving('click', this.closeHandler); if (this.options.fade)
            {
                this.effects.fade = new Effect.Fade(this.container, { queue: { position: 'front', scope: 'Control.Window' + this.numberInSequence }, from: 1, to: 0, duration: this.options.fadeDuration / 2, afterFinish: function()
                {
                    if (this.iFrameShim)
                        this.iFrameShim.hide(); this.isOpen = false; this.notify('afterClose');
                } .bind(this)
                });
            } else
            {
                this.container.hide(); if (this.iFrameShim)
                    this.iFrameShim.hide();
            }
            if (this.ajaxRequest)
                this.ajaxRequest.transport.abort(); if (!(this.options.draggable || this.options.resizable) && this.options.position == 'center')
                Event.stopObserving(window, 'resize', this.positionHandler); if (!this.options.draggable && this.options.position == 'center')
                Event.stopObserving(window, 'scroll', this.positionHandler); if (this.options.indicator)
                this.hideIndicator(); if (!this.options.fade) { this.isOpen = false; this.notify('afterClose'); }
            return true;
        }, position: function(event)
        {
            if (this.options.position == 'mouse') { var xy = [Event.pointerX(event), Event.pointerY(event)]; this.container.setStyle({ top: xy[1] + $value(this.options.offsetTop) + 'px', left: xy[0] + $value(this.options.offsetLeft) + 'px' }); return; }
            var container_dimensions = this.container.getDimensions(); var viewport_dimensions = document.viewport.getDimensions(); Position.prepare(); var offset_left = (Position.deltaX + Math.floor((viewport_dimensions.width - container_dimensions.width) / 2)); var offset_top = (Position.deltaY + ((viewport_dimensions.height > container_dimensions.height) ? Math.floor((viewport_dimensions.height - container_dimensions.height) / 2) : 0)); if (this.options.position == 'center') { this.container.setStyle({ top: (container_dimensions.height <= viewport_dimensions.height) ? ((offset_top != null && offset_top > 0) ? offset_top : 0) + 'px' : 0, left: (container_dimensions.width <= viewport_dimensions.width) ? ((offset_left != null && offset_left > 0) ? offset_left : 0) + 'px' : 0 }); } else if (this.options.position == 'relative') { var xy = this.sourceContainer.cumulativeOffset(); var top = xy[1] + $value(this.options.offsetTop); var left = xy[0] + $value(this.options.offsetLeft); this.container.setStyle({ top: (container_dimensions.height <= viewport_dimensions.height) ? (this.options.constrainToViewport ? Math.max(0, Math.min(viewport_dimensions.height - (container_dimensions.height), top)) : top) + 'px' : 0, left: (container_dimensions.width <= viewport_dimensions.width) ? (this.options.constrainToViewport ? Math.max(0, Math.min(viewport_dimensions.width - (container_dimensions.width), left)) : left) + 'px' : 0 }); } else if (this.options.position.length) { var top = $value(this.options.position[1]) + $value(this.options.offsetTop); var left = $value(this.options.position[0]) + $value(this.options.offsetLeft); this.container.setStyle({ top: (container_dimensions.height <= viewport_dimensions.height) ? (this.options.constrainToViewport ? Math.max(0, Math.min(viewport_dimensions.height - (container_dimensions.height), top)) : top) + 'px' : 0, left: (container_dimensions.width <= viewport_dimensions.width) ? (this.options.constrainToViewport ? Math.max(0, Math.min(viewport_dimensions.width - (container_dimensions.width), left)) : left) + 'px' : 0 }); }
            if (this.iFrameShim)
                this.updateIFrameShimZIndex();
        }, ensureInBounds: function()
        {
            if (!this.isOpen)
                return; var viewport_dimensions = document.viewport.getDimensions(); var container_offset = this.container.cumulativeOffset(); var container_dimensions = this.container.getDimensions(); if (container_offset.left + container_dimensions.width > viewport_dimensions.width) { this.container.setStyle({ left: (Math.max(0, viewport_dimensions.width - container_dimensions.width)) + 'px' }); }
            if (container_offset.top + container_dimensions.height > viewport_dimensions.height) { this.container.setStyle({ top: (Math.max(0, viewport_dimensions.height - container_dimensions.height)) + 'px' }); } 
        }, bringToFront: function() { Control.Window.bringToFront(this); this.notify('bringToFront'); }, destroy: function()
        {
            this.container.stopObserving('mousedown', this.bringToFrontHandler); if (this.draggable) { Draggables.removeObserver(this.container); this.draggable.handle.stopObserving('mousedown', this.bringToFrontHandler); this.draggable.destroy(); }
            if (this.resizable) { Resizables.removeObserver(this.container); this.resizable.handle.stopObserving('mousedown', this.bringToFrontHandler); this.resizable.destroy(); }
            if (this.container && !this.sourceContainer)
                this.container.remove(); if (this.sourceContainer)
            {
                if (this.options.hover)
                {
                    this.sourceContainer.stopObserving('mouseenter', this.sourceContainerOpenHandler); this.sourceContainer.stopObserving('mouseleave', this.sourceContainerCloseHandler); if (this.options.position == 'mouse')
                        this.sourceContainer.stopObserving('mousemove', this.sourceContainerMouseMoveHandler);
                } else
                    this.sourceContainer.stopObserving('click', this.sourceContainerOpenHandler);
            }
            if (this.iFrameShim)
                this.iFrameShim.destroy(); Event.stopObserving(window, 'resize', this.outOfBoundsPositionHandler); Control.Window.windows = Control.Window.windows.without(this); this.notify('afterDestroy');
        }, applyResizable: function()
        {
            if (this.options.resizable)
            {
                if (typeof (Resizable) == "undefined")
                    throw "Control.Window requires resizable.js to be loaded."; var resizable_handle = null; if (this.options.resizable === true) { resizable_handle = new Element('div', { className: 'resizable_handle' }); this.container.insert(resizable_handle); } else
                    resizable_handle = $(this.options.resziable); this.resizable = new Resizable(this.container, { handle: resizable_handle, minHeight: this.options.minHeight, minWidth: this.options.minWidth, maxHeight: this.options.constrainToViewport ? function(element) { return (document.viewport.getDimensions().height - parseInt(element.style.top || 0)) - (element.getHeight() - parseInt(element.style.height || 0)); } : this.options.maxHeight, maxWidth: this.options.constrainToViewport ? function(element) { return (document.viewport.getDimensions().width - parseInt(element.style.left || 0)) - (element.getWidth() - parseInt(element.style.width || 0)); } : this.options.maxWidth }); this.resizable.handle.observe('mousedown', this.bringToFrontHandler); Resizables.addObserver(new Control.Window.LayoutUpdateObserver(this, function()
                    {
                        if (this.iFrameShim)
                            this.updateIFrameShimZIndex(); this.notify('onResize');
                    } .bind(this)));
            } 
        }, applyDraggable: function()
        {
            if (this.options.draggable)
            {
                if (typeof (Draggables) == "undefined")
                    throw "Control.Window requires dragdrop.js to be loaded."; var draggable_handle = null; if (this.options.draggable === true) { draggable_handle = new Element('div', { className: 'draggable_handle' }); this.container.insert(draggable_handle); } else
                    draggable_handle = $(this.options.draggable); this.draggable = new Draggable(this.container, { handle: draggable_handle, constrainToViewport: this.options.constrainToViewport, zindex: this.container.getStyle('z-index'), starteffect: function() { if (Prototype.Browser.IE) { this.old_onselectstart = document.onselectstart; document.onselectstart = function() { return false; }; } } .bind(this), endeffect: function() { document.onselectstart = this.old_onselectstart; } .bind(this) }); this.draggable.handle.observe('mousedown', this.bringToFrontHandler); Draggables.addObserver(new Control.Window.LayoutUpdateObserver(this, function()
                    {
                        if (this.iFrameShim)
                            this.updateIFrameShimZIndex(); this.notify('onDrag');
                    } .bind(this)));
            } 
        }, createDefaultContainer: function(container)
        {
            if (!this.container)
            {
                this.container = new Element('div', { id: 'control_window_' + this.numberInSequence }); $(document.body).insert(this.container); if (typeof (container) == "string" && $(container) == null && !container.match(/^#(.+)$/) && !container.match(Control.Window.uriRegex))
                    this.container.update(container);
            } 
        }, finishOpen: function(event)
        {
            this.bringToFront(); if (this.options.fade)
            {
                if (typeof (Effect) == "undefined")
                    throw "Control.Window requires effects.js to be loaded."
                if (this.effects.fade)
                    this.effects.fade.cancel(); this.effects.appear = new Effect.Appear(this.container, { queue: { position: 'end', scope: 'Control.Window.' + this.numberInSequence }, from: 0, to: 1, duration: this.options.fadeDuration / 2, afterFinish: function()
                    {
                        if (this.iFrameShim)
                            this.updateIFrameShimZIndex(); this.isOpen = true; this.notify('afterOpen');
                    } .bind(this)
                    });
            } else
                this.container.show(); this.position(event); if (!(this.options.draggable || this.options.resizable) && this.options.position == 'center')
                Event.observe(window, 'resize', this.positionHandler, false); if (!this.options.draggable && this.options.position == 'center')
                Event.observe(window, 'scroll', this.positionHandler, false); if (!this.options.fade) { this.isOpen = true; this.notify('afterOpen'); }
            return true;
        }, showIndicator: function()
        {
            this.showIndicatorTimeout = window.setTimeout(function()
            {
                if (this.options.fade) { this.indicatorEffects.appear = new Effect.Appear(this.indicator, { queue: { position: 'front', scope: 'Control.Window.indicator.' + this.numberInSequence }, from: 0, to: 1, duration: this.options.fadeDuration / 2 }); } else
                    this.indicator.show();
            } .bind(this), Control.Window.indicatorTimeout);
        }, hideIndicator: function()
        {
            if (this.showIndicatorTimeout)
                window.clearTimeout(this.showIndicatorTimeout); this.indicator.hide();
        }, getRemoteContentInsertionTarget: function() { return typeof (this.options.insertRemoteContentAt) == "string" ? this.container.down(this.options.insertRemoteContentAt) : $(this.options.insertRemoteContentAt); }, updateIFrameShimZIndex: function()
        {
            if (this.iFrameShim)
                this.iFrameShim.positionUnder(this.container);
        } 
        }); Object.extend(Control.Window, { windows: [], baseZIndex: 9999, indicatorTimeout: 250, iframeTemplate: new Template('<iframe src="#{href}" width="100%" height="100%" frameborder="0"></iframe>'), uriRegex: /^(\/|\#|https?\:\/\/|[\w]+\/)/, bringToFront: function(w)
        {
            Control.Window.windows = Control.Window.windows.without(w); Control.Window.windows.push(w); Control.Window.windows.each(function(w, i)
            {
                var z_index = Control.Window.baseZIndex + i; w.container.setStyle({ zIndex: z_index }); if (w.isOpen)
                {
                    if (w.iFrameShim)
                        w.updateIFrameShimZIndex();
                }
                if (w.options.draggable)
                    w.draggable.options.zindex = z_index;
            });
        }, open: function(container, options) { var w = new Control.Window(container, options); w.open(); return w; }, initialZIndexForWindow: function(w) { return Control.Window.baseZIndex + (Control.Window.windows.length - 1); } 
        }); Object.Event.extend(Control.Window); Control.Window.LayoutUpdateObserver = Class.create({ initialize: function(w, observer) { this.w = w; this.element = $(w.container); this.observer = observer; }, onStart: Prototype.emptyFunction, onEnd: function(event_name, instance)
        {
            if (instance.element == this.element && this.iFrameShim)
                this.w.updateIFrameShimZIndex();
        }, onResize: function(event_name, instance)
        {
            if (instance.element == this.element)
                this.observer(this.element);
        }, onDrag: function(event_name, instance)
        {
            if (instance.element == this.element)
                this.observer(this.element);
        } 
        }); Control.Overlay = { id: 'control_overlay', loaded: false, container: false, lastOpacity: 0, styles: { position: 'fixed', top: 0, left: 0, width: '100%', height: '100%', zIndex: 9998 }, ieStyles: { position: 'absolute', top: 0, left: 0, zIndex: 9998 }, effects: { fade: false, appear: false }, load: function()
        {
            if (Control.Overlay.loaded)
                return false; Control.Overlay.loaded = true; Control.Overlay.container = new Element('div', { id: Control.Overlay.id }); $(document.body).insert(Control.Overlay.container); if (Prototype.Browser.IE) { Control.Overlay.container.setStyle(Control.Overlay.ieStyles); Event.observe(window, 'scroll', Control.Overlay.positionOverlay); Event.observe(window, 'resize', Control.Overlay.positionOverlay); Control.Overlay.observe('beforeShow', Control.Overlay.positionOverlay); } else
                Control.Overlay.container.setStyle(Control.Overlay.styles); Control.Overlay.iFrameShim = new IframeShim(); Control.Overlay.iFrameShim.hide(); Event.observe(window, 'resize', Control.Overlay.positionIFrameShim); Control.Overlay.container.hide(); return true;
        }, unload: function()
        {
            if (!Control.Overlay.loaded)
                return false; Event.stopObserving(window, 'resize', Control.Overlay.positionOverlay); Control.Overlay.stopObserving('beforeShow', Control.Overlay.positionOverlay); Event.stopObserving(window, 'resize', Control.Overlay.positionIFrameShim); Control.Overlay.iFrameShim.destroy(); Control.Overlay.container.remove(); Control.Overlay.loaded = false; return true;
        }, show: function(opacity, fade)
        {
            if (Control.Overlay.notify('beforeShow') === false)
                return false; Control.Overlay.lastOpacity = opacity; Control.Overlay.positionIFrameShim(); Control.Overlay.iFrameShim.show(); if (fade)
            {
                if (typeof (Effect) == "undefined")
                    throw "Control.Window requires effects.js to be loaded."
                if (Control.Overlay.effects.fade)
                    Control.Overlay.effects.fade.cancel(); Control.Overlay.effects.appear = new Effect.Appear(Control.Overlay.container, { queue: { position: 'end', scope: 'Control.Overlay' }, afterFinish: function() { Control.Overlay.notify('afterShow'); }, from: 0, to: Control.Overlay.lastOpacity, duration: (fade === true ? 0.75 : fade) / 2 });
            } else { Control.Overlay.container.setStyle({ opacity: opacity || 1 }); Control.Overlay.container.show(); Control.Overlay.notify('afterShow'); }
            return true;
        }, hide: function(fade)
        {
            if (Control.Overlay.notify('beforeHide') === false)
                return false; if (Control.Overlay.effects.appear)
                Control.Overlay.effects.appear.cancel(); Control.Overlay.iFrameShim.hide(); if (fade) { Control.Overlay.effects.fade = new Effect.Fade(Control.Overlay.container, { queue: { position: 'front', scope: 'Control.Overlay' }, afterFinish: function() { Control.Overlay.notify('afterHide'); }, from: Control.Overlay.lastOpacity, to: 0, duration: (fade === true ? 0.75 : fade) / 2 }); } else { Control.Overlay.container.hide(); Control.Overlay.notify('afterHide'); }
            return true;
        }, positionIFrameShim: function()
        {
            if (Control.Overlay.container.visible())
                Control.Overlay.iFrameShim.positionUnder(Control.Overlay.container);
        }, positionOverlay: function() { Control.Overlay.container.setStyle({ width: document.body.clientWidth + 'px', height: document.body.clientHeight + 'px' }); } 
        }; Object.Event.extend(Control.Overlay); Control.ToolTip = Class.create(Control.Window, { initialize: function($super, container, tooltip, options) { $super(tooltip, Object.extend(Object.extend(Object.clone(Control.ToolTip.defaultOptions), options || {}), { position: 'mouse', hover: container })); } }); Object.extend(Control.ToolTip, { defaultOptions: { offsetLeft: 10} }); Control.Modal = Class.create(Control.Window, { initialize: function($super, container, options) { Control.Modal.InstanceMethods.beforeInitialize.bind(this)(); $super(container, Object.extend(Object.clone(Control.Modal.defaultOptions), options || {})); } }); Object.extend(Control.Modal, { defaultOptions: { overlayOpacity: 0.5, closeOnClick: 'overlay' }, current: false, open: function(container, options) { var modal = new Control.Modal(container, options); modal.open(); return modal; }, close: function()
        {
            if (Control.Modal.current)
                Control.Modal.current.close();
        }, InstanceMethods: { beforeInitialize: function() { Control.Overlay.load(); this.overlayFinishedOpening = false; this.observe('beforeOpen', Control.Modal.Observers.beforeOpen.bind(this)); this.observe('afterOpen', Control.Modal.Observers.afterOpen.bind(this)); this.observe('afterClose', Control.Modal.Observers.afterClose.bind(this)); } }, Observers: { beforeOpen: function()
        {
            if (!this.overlayFinishedOpening) { Control.Overlay.observeOnce('afterShow', function() { this.overlayFinishedOpening = true; this.open(); } .bind(this)); Control.Overlay.show(this.options.overlayOpacity, this.options.fade ? this.options.fadeDuration : false); throw $break; } else
                Control.Window.windows.without(this).invoke('close');
        }, afterOpen: function() { Control.Modal.current = this; }, afterClose: function() { Control.Overlay.hide(this.options.fade ? this.options.fadeDuration : false); Control.Modal.current = false; this.overlayFinishedOpening = false; } }
        }); Control.LightBox = Class.create(Control.Window, { initialize: function($super, container, options)
        {
            this.allImagesLoaded = false; if (options.modal) { var options = Object.extend(Object.clone(Control.LightBox.defaultOptions), options || {}); options = Object.extend(Object.clone(Control.Modal.defaultOptions), options); options = Control.Modal.InstanceMethods.beforeInitialize.bind(this)(options); $super(container, options); } else
                $super(container, Object.extend(Object.clone(Control.LightBox.defaultOptions), options || {})); this.hasRemoteContent = this.href && !this.options.iframe; if (this.hasRemoteContent)
                this.observe('onRemoteContentLoaded', Control.LightBox.Observers.onRemoteContentLoaded.bind(this)); else
                this.applyImageObservers(); this.observe('beforeOpen', Control.LightBox.Observers.beforeOpen.bind(this));
        }, applyImageObservers: function() { var images = this.getImages(); this.numberImagesToLoad = images.length; this.numberofImagesLoaded = 0; images.each(function(image) { image.observe('load', function(image) { ++this.numberofImagesLoaded; if (this.numberImagesToLoad == this.numberofImagesLoaded) { this.allImagesLoaded = true; this.onAllImagesLoaded(); } } .bind(this, image)); image.hide(); } .bind(this)); }, onAllImagesLoaded: function()
        {
            this.getImages().each(function(image) { this.showImage(image); } .bind(this)); if (this.hasRemoteContent)
            {
                if (this.options.indicator)
                    this.hideIndicator(); this.finishOpen();
            } else
                this.open();
        }, getImages: function() { return this.container.select(Control.LightBox.imageSelector); }, showImage: function(image) { image.show(); } 
        }); Object.extend(Control.LightBox, { imageSelector: 'img', defaultOptions: {}, Observers: { beforeOpen: function()
        {
            if (!this.hasRemoteContent && !this.allImagesLoaded)
                throw $break;
        }, onRemoteContentLoaded: function()
        {
            this.applyImageObservers(); if (!this.allImagesLoaded)
                throw $break;
        } }
        }); var dp = { sh: { Toolbar: {}, Utils: {}, RegexLib: {}, Brushes: {}, Strings: { AboutDialog: '<html><head><title>About...</title></head><body class="dp-about"><table cellspacing="0"><tr><td class="copy"><p class="title">dp.SyntaxHighlighter</div><div class="para">Version: {V}</p><p><a href="http://www.dreamprojections.com/syntaxhighlighter/?ref=about" target="_blank">http://www.dreamprojections.com/syntaxhighlighter</a></p>&copy;2004-2007 Alex Gorbatchev.</td></tr><tr><td class="footer"><input type="button" class="close" value="OK" onClick="window.close()"/></td></tr></table></body></html>' }, ClipboardSwf: null, Version: '1.5'} }; dp.SyntaxHighlighter = dp.sh; dp.sh.Toolbar.Commands = { ExpandSource: { label: '+ expand source', check: function(highlighter) { return highlighter.collapse; }, func: function(sender, highlighter)
        { sender.parentNode.removeChild(sender); highlighter.div.className = highlighter.div.className.replace('collapsed', ''); } 
        }, ViewSource: { label: 'view plain', func: function(sender, highlighter)
        { var code = highlighter.originalCode.replace(/</g, '&lt;'); var wnd = window.open('', '_blank', 'width=750, height=400, location=0, resizable=1, menubar=0, scrollbars=0'); wnd.document.write('<textarea style="width:99%;height:99%">' + code + '</textarea>'); wnd.document.close(); } 
        }, CopyToClipboard: { label: 'copy to clipboard', check: function() { return window.clipboardData != null || dp.sh.ClipboardSwf != null; }, func: function(sender, highlighter)
        {
            var code = highlighter.originalCode; if (window.clipboardData)
            { window.clipboardData.setData('text', code); }
            else if (dp.sh.ClipboardSwf != null)
            {
                var flashcopier = highlighter.flashCopier; if (flashcopier == null)
                { flashcopier = document.createElement('div'); highlighter.flashCopier = flashcopier; highlighter.div.appendChild(flashcopier); }
                flashcopier.innerHTML = '<embed src="' + dp.sh.ClipboardSwf + '" FlashVars="clipboard=' + encodeURIComponent(code) + '" width="0" height="0" type="application/x-shockwave-flash"></embed>';
            }
            alert('The code is in your clipboard now');
        } 
        }, PrintSource: { label: 'print', func: function(sender, highlighter)
        { var iframe = document.createElement('IFRAME'); var doc = null; iframe.style.cssText = 'position:absolute;width:0px;height:0px;left:-500px;top:-500px;'; document.body.appendChild(iframe); doc = iframe.contentWindow.document; dp.sh.Utils.CopyStyles(doc, window.document); doc.write('<div class="' + highlighter.div.className.replace('collapsed', '') + ' printing">' + highlighter.div.innerHTML + '</div>'); doc.close(); iframe.contentWindow.focus(); iframe.contentWindow.print(); alert('Printing...'); document.body.removeChild(iframe); } 
        }, About: { label: '?', func: function(highlighter)
        { var wnd = window.open('', '_blank', 'dialog,width=300,height=150,scrollbars=0'); var doc = wnd.document; dp.sh.Utils.CopyStyles(doc, window.document); doc.write(dp.sh.Strings.AboutDialog.replace('{V}', dp.sh.Version)); doc.close(); wnd.focus(); } }
        }; dp.sh.Toolbar.Create = function(highlighter)
        {
            var div = document.createElement('DIV'); div.className = 'tools'; for (var name in dp.sh.Toolbar.Commands)
            {
                var cmd = dp.sh.Toolbar.Commands[name]; if (cmd.check != null && !cmd.check(highlighter))
                    continue; div.innerHTML += '<a href="#" onclick="dp.sh.Toolbar.Command(\'' + name + '\',this);return false;">' + cmd.label + '</a>';
            }
            return div;
        }
    dp.sh.Toolbar.Command = function(name, sender)
    {
        var n = sender; while (n != null && n.className.indexOf('dp-highlighter') == -1)
            n = n.parentNode; if (n != null)
            dp.sh.Toolbar.Commands[name].func(sender, n.highlighter);
    }
    dp.sh.Utils.CopyStyles = function(destDoc, sourceDoc)
    {
        var links = sourceDoc.getElementsByTagName('link'); for (var i = 0; i < links.length; i++)
            if (links[i].rel.toLowerCase() == 'stylesheet')
            destDoc.write('<link type="text/css" rel="stylesheet" href="' + links[i].href + '"></link>');
    }
    dp.sh.RegexLib = { MultiLineCComments: new RegExp('/\\*[\\s\\S]*?\\*/', 'gm'), SingleLineCComments: new RegExp('//.*$', 'gm'), SingleLinePerlComments: new RegExp('#.*$', 'gm'), DoubleQuotedString: new RegExp('"(?:\\.|(\\\\\\")|[^\\""])*"', 'g'), SingleQuotedString: new RegExp("'(?:\\.|(\\\\\\')|[^\\''])*'", 'g') }; dp.sh.Match = function(value, index, css)
    { this.value = value; this.index = index; this.length = value.length; this.css = css; }
    dp.sh.Highlighter = function()
    { this.noGutter = false; this.addControls = true; this.collapse = false; this.tabsToSpaces = true; this.wrapColumn = 80; this.showColumns = true; }
    dp.sh.Highlighter.SortCallback = function(m1, m2)
    {
        if (m1.index < m2.index)
            return -1; else if (m1.index > m2.index)
            return 1; else
        {
            if (m1.length < m2.length)
                return -1; else if (m1.length > m2.length)
                return 1;
        }
        return 0;
    }
    dp.sh.Highlighter.prototype.CreateElement = function(name)
    { var result = document.createElement(name); result.highlighter = this; return result; }
    dp.sh.Highlighter.prototype.GetMatches = function(regex, css)
    {
        var index = 0; var match = null; while ((match = regex.exec(this.code)) != null)
            this.matches[this.matches.length] = new dp.sh.Match(match[0], match.index, css);
    }
    dp.sh.Highlighter.prototype.AddBit = function(str, css)
    {
        if (str == null || str.length == 0)
            return; var span = this.CreateElement('SPAN'); str = str.replace(/ /g, '&nbsp;'); str = str.replace(/</g, '&lt;'); str = str.replace(/\n/gm, '&nbsp;<br>'); if (css != null)
        {
            if ((/br/gi).test(str))
            {
                var lines = str.split('&nbsp;<br>'); for (var i = 0; i < lines.length; i++)
                {
                    span = this.CreateElement('SPAN'); span.className = css; span.innerHTML = lines[i]; this.div.appendChild(span); if (i + 1 < lines.length)
                        this.div.appendChild(this.CreateElement('BR'));
                } 
            }
            else
            { span.className = css; span.innerHTML = str; this.div.appendChild(span); } 
        }
        else
        { span.innerHTML = str; this.div.appendChild(span); } 
    }
    dp.sh.Highlighter.prototype.IsInside = function(match)
    {
        if (match == null || match.length == 0)
            return false; for (var i = 0; i < this.matches.length; i++)
        {
            var c = this.matches[i]; if (c == null)
                continue; if ((match.index > c.index) && (match.index < c.index + c.length))
                return true;
        }
        return false;
    }
    dp.sh.Highlighter.prototype.ProcessRegexList = function()
    {
        for (var i = 0; i < this.regexList.length; i++)
            this.GetMatches(this.regexList[i].regex, this.regexList[i].css);
    }
    dp.sh.Highlighter.prototype.ProcessSmartTabs = function(code)
    {
        var lines = code.split('\n'); var result = ''; var tabSize = 4; var tab = '\t'; function InsertSpaces(line, pos, count)
        {
            var left = line.substr(0, pos); var right = line.substr(pos + 1, line.length); var spaces = ''; for (var i = 0; i < count; i++)
                spaces += ' '; return left + spaces + right;
        }
        function ProcessLine(line, tabSize)
        {
            if (line.indexOf(tab) == -1)
                return line; var pos = 0; while ((pos = line.indexOf(tab)) != -1)
            { var spaces = tabSize - pos % tabSize; line = InsertSpaces(line, pos, spaces); }
            return line;
        }
        for (var i = 0; i < lines.length; i++)
            result += ProcessLine(lines[i], tabSize) + '\n'; return result;
    }
    dp.sh.Highlighter.prototype.SwitchToList = function()
    {
        var html = this.div.innerHTML.replace(/<(br)\/?>/gi, '\n'); var lines = html.split('\n'); if (this.addControls == true)
            this.bar.appendChild(dp.sh.Toolbar.Create(this)); if (this.showColumns)
        {
            var div = this.CreateElement('div'); var columns = this.CreateElement('div'); var showEvery = 10; var i = 1; while (i <= 150)
            {
                if (i % showEvery == 0)
                { div.innerHTML += i; i += (i + '').length; }
                else
                { div.innerHTML += '&middot;'; i++; } 
            }
            columns.className = 'columns'; columns.appendChild(div); this.bar.appendChild(columns);
        }
        for (var i = 0, lineIndex = this.firstLine; i < lines.length - 1; i++, lineIndex++)
        { var li = this.CreateElement('LI'); var span = this.CreateElement('SPAN'); li.className = (i % 2 == 0) ? 'alt' : ''; span.innerHTML = lines[i] + '&nbsp;'; li.appendChild(span); this.ol.appendChild(li); }
        this.div.innerHTML = '';
    }
    dp.sh.Highlighter.prototype.Highlight = function(code)
    {
        function Trim(str)
        { return str.replace(/^\s*(.*?)[\s\n]*$/g, '$1'); }
        function Chop(str)
        { return str.replace(/\n*$/, '').replace(/^\n*/, ''); }
        function Unindent(str)
        {
            var lines = str.split('\n'); var indents = new Array(); var regex = new RegExp('^\\s*', 'g'); var min = 1000; for (var i = 0; i < lines.length && min > 0; i++)
            {
                if (Trim(lines[i]).length == 0)
                    continue; var matches = regex.exec(lines[i]); if (matches != null && matches.length > 0)
                    min = Math.min(matches[0].length, min);
            }
            if (min > 0)
                for (var i = 0; i < lines.length; i++)
                lines[i] = lines[i].substr(min); return lines.join('\n');
        }
        function Copy(string, pos1, pos2)
        { return string.substr(pos1, pos2 - pos1); }
        var pos = 0; if (code == null)
            code = ''; this.originalCode = code; this.code = Chop(Unindent(code)); this.div = this.CreateElement('DIV'); this.bar = this.CreateElement('DIV'); this.ol = this.CreateElement('OL'); this.matches = new Array(); this.div.className = 'dp-highlighter'; this.div.highlighter = this; this.bar.className = 'bar'; this.ol.start = this.firstLine; if (this.CssClass != null)
            this.ol.className = this.CssClass; if (this.collapse)
            this.div.className += ' collapsed'; if (this.noGutter)
            this.div.className += ' nogutter'; if (this.tabsToSpaces == true)
            this.code = this.ProcessSmartTabs(this.code); this.ProcessRegexList(); if (this.matches.length == 0)
        { this.AddBit(this.code, null); this.SwitchToList(); this.div.appendChild(this.ol); return; }
        this.matches = this.matches.sort(dp.sh.Highlighter.SortCallback); for (var i = 0; i < this.matches.length; i++)
            if (this.IsInside(this.matches[i]))
            this.matches[i] = null; for (var i = 0; i < this.matches.length; i++)
        {
            var match = this.matches[i]; if (match == null || match.length == 0)
                continue; this.AddBit(Copy(this.code, pos, match.index), null); this.AddBit(match.value, match.css); pos = match.index + match.length;
        }
        this.AddBit(this.code.substr(pos), null); this.SwitchToList(); this.div.appendChild(this.bar); this.div.appendChild(this.ol);
    }
    dp.sh.Highlighter.prototype.GetKeywords = function(str)
    { return '\\b' + str.replace(/ /g, '\\b|\\b') + '\\b'; }
    dp.sh.HighlightAll = function(name, showGutter, showControls, collapseAll, firstLine, showColumns)
    {
        function FindValue()
        {
            var a = arguments; for (var i = 0; i < a.length; i++)
            {
                if (a[i] == null)
                    continue; if (typeof (a[i]) == 'string' && a[i] != '')
                    return a[i] + ''; if (typeof (a[i]) == 'object' && a[i].value != '')
                    return a[i].value + '';
            }
            return null;
        }
        function IsOptionSet(value, list)
        {
            for (var i = 0; i < list.length; i++)
                if (list[i] == value)
                return true; return false;
        }
        function GetOptionValue(name, list, defaultValue)
        {
            var regex = new RegExp('^' + name + '\\[(\\w+)\\]$', 'gi'); var matches = null; for (var i = 0; i < list.length; i++)
                if ((matches = regex.exec(list[i])) != null)
                return matches[1]; return defaultValue;
        }
        function FindTagsByName(list, name, tagName)
        {
            var tags = document.getElementsByTagName(tagName); for (var i = 0; i < tags.length; i++)
                if (tags[i].getAttribute('class') == name)
                list.push(tags[i]);
        }
        var elements = []; var highlighter = null; var registered = {}; var propertyName = 'innerHTML'; FindTagsByName(elements, name, 'code'); if (elements.length == 0)
            return; for (var brush in dp.sh.Brushes)
        {
            var aliases = dp.sh.Brushes[brush].Aliases; if (aliases == null)
                continue; for (var i = 0; i < aliases.length; i++)
                registered[aliases[i]] = brush;
        }
        for (var i = 0; i < elements.length; i++)
        {
            var element = elements[i]; var options = FindValue(element.attributes['class'], element.className, element.attributes['language'], element.language); var language = ''; if (options == null)
                continue; options = options.split(':'); language = options[0].toLowerCase(); if (registered[language] == null)
                continue; highlighter = new dp.sh.Brushes[registered[language]](); element.style.display = 'none'; highlighter.noGutter = (showGutter == null) ? IsOptionSet('nogutter', options) : !showGutter; highlighter.addControls = (showControls == null) ? !IsOptionSet('nocontrols', options) : showControls; highlighter.collapse = (collapseAll == null) ? IsOptionSet('collapse', options) : collapseAll; highlighter.showColumns = (showColumns == null) ? IsOptionSet('showcolumns', options) : showColumns; highlighter.firstLine = (firstLine == null) ? parseInt(GetOptionValue('firstline', options, 1)) : firstLine; highlighter.Highlight(element[propertyName]); highlighter.source = element; element.parentNode.insertBefore(highlighter.div, element);
        } 
    }
    dp.sh.Brushes.JScript = function()
    { var keywords = '\\$ abstract boolean break byte case catch char class const continue debugger ' + 'default delete do double else enum export extends final finally float ' + 'for function goto if implements import in instanceof int interface long native ' + 'new package private protected public return short static super switch ' + 'synchronized throw throws transient try typeof var void volatile while with'; var constants = 'true false null TRUE FALSE NULL [0-9]+'; var builtin = 'window document event Object Function Math Array Hash String Date RegExp'; this.regexList = [{ regex: dp.sh.RegexLib.SingleLineCComments, css: 'comment' }, { regex: dp.sh.RegexLib.MultiLineCComments, css: 'comment' }, { regex: dp.sh.RegexLib.DoubleQuotedString, css: 'string' }, { regex: dp.sh.RegexLib.SingleQuotedString, css: 'string' }, { regex: new RegExp('^\\s*#.*', 'gm'), css: 'preprocessor' }, { regex: new RegExp(this.GetKeywords(keywords), 'gm'), css: 'keyword' }, { regex: new RegExp(this.GetKeywords(builtin), 'gm'), css: 'builtin' }, { regex: new RegExp(this.GetKeywords(constants), 'g'), css: 'constants' }, { regex: new RegExp('this(?=(\\.|\\,|\\)))', 'g'), css: '_this' }, { regex: new RegExp('(\\s|\\{|\\,)[a-zA-Z0-9_]+(?=\\s?:\\s?function)', 'gm'), css: 'func_dec' }, { regex: new RegExp('on(R(ow(s(inserted|delete)|e(nter|xit))|e(s(ize(start|end)?|et)|adystatechange))|Mouse(o(ut|ver)|down|up|move)|B(efore(cut|deactivate|u(nload|pdate)|p(aste|rint)|editfocus|activate)|lur)|S(croll|top|ubmit|elect(start|ionchange)?)|H(over|elp)|C(hange|ont(extmenu|rolselect)|ut|ellchange|l(ick|ose))|D(eactivate|ata(setc(hanged|omplete)|available)|r(op|ag(start|over|drop|en(ter|d)|leave)?)|blclick)|Unload|P(aste|ropertychange)|Error(update)?|Key(down|up|press)|Focus|Load|A(ctivate|fter(update|print)|bort))', 'g'), css: 'support_property' }, { regex: new RegExp('(s(h(ift|ow(Mod(elessDialog|alDialog)|Help))|croll(X|By(Pages|Lines)?|Y|To)?|t(op|rike)|i(n|zeToContent|debar|gnText)|ort|u(p|b(str(ing)?)?)|pli(ce|t)|e(nd|t(Re(sizable|questHeader)|M(i(nutes|lliseconds)|onth)|Seconds|Ho(tKeys|urs)|Year|Cursor|Time(out)?|Interval|ZOptions|Date|UTC(M(i(nutes|lliseconds)|onth)|Seconds|Hours|Date|FullYear)|FullYear|Active)|arch)|qrt|lice|avePreferences|mall)|h(ome|andleEvent)|navigate|c(har(CodeAt|At)|o(s|n(cat|textual|firm)|mpile)|eil|lear(Timeout|Interval)?|a(ptureEvents|ll)|reate(StyleSheet|Popup|EventObject))|t(o(GMTString|S(tring|ource)|U(TCString|pperCase)|Lo(caleString|werCase))|est|a(n|int(Enabled)?))|i(s(NaN|Finite)|ndexOf|talics)|d(isableExternalCapture|ump|etachEvent)|u(n(shift|taint|escape|watch)|pdateCommands)|j(oin|avaEnabled)|p(o(p|w)|ush|lugins.refresh|a(ddings|rse(Int|Float)?)|r(int|ompt|eference))|e(scape|nableExternalCapture|val|lementFromPoint|x(p|ec(Script|Command)?))|valueOf|UTC|queryCommand(State|Indeterm|Enabled|Value)|f(i(nd|le(ModifiedDate|Size|CreatedDate|UpdatedDate)|xed)|o(nt(size|color)|rward)|loor|romCharCode)|watch|l(ink|o(ad|g)|astIndexOf)|a(sin|nchor|cos|t(tachEvent|ob|an(2)?)|pply|lert|b(s|ort))|r(ou(nd|teEvents)|e(size(By|To)|calc|turnValue|place|verse|l(oad|ease(Capture|Events)))|andom)|g(o|et(ResponseHeader|M(i(nutes|lliseconds)|onth)|Se(conds|lection)|Hours|Year|Time(zoneOffset)?|Da(y|te)|UTC(M(i(nutes|lliseconds)|onth)|Seconds|Hours|Da(y|te)|FullYear)|FullYear|A(ttention|llResponseHeaders)))|m(in|ove(B(y|elow)|To(Absolute)?|Above)|ergeAttributes|a(tch|rgins|x))|b(toa|ig|o(ld|rderWidths)|link|ack))(?=\\()', 'g'), css: 'support_method' }, { regex: new RegExp('(s(ub(stringData|mit)|plitText|e(t(NamedItem|Attribute(Node)?)|lect))|has(ChildNodes|Feature)|namedItem|c(l(ick|o(se|neNode))|reate(C(omment|DATASection|aption)|T(Head|extNode|Foot)|DocumentFragment|ProcessingInstruction|E(ntityReference|lement)|Attribute))|tabIndex|i(nsert(Row|Before|Cell|Data)|tem)|open|delete(Row|C(ell|aption)|T(Head|Foot)|Data)|focus|write(ln)?|a(dd|ppend(Child|Data))|re(set|place(Child|Data)|move(NamedItem|Child|Attribute(Node)?)?)|get(NamedItem|Element(sBy(Name|TagName)|ById)|Attribute(Node)?)|blur)(?=\\()', 'g'), css: 'support_method' }, { regex: new RegExp('on(R(ow(s(inserted|delete)|e(nter|xit))|e(s(ize(start|end)?|et)|adystatechange))|Mouse(o(ut|ver)|down|up|move)|B(efore(cut|deactivate|u(nload|pdate)|p(aste|rint)|editfocus|activate)|lur)|S(croll|top|ubmit|elect(start|ionchange)?)|H(over|elp)|C(hange|ont(extmenu|rolselect)|ut|ellchange|l(ick|ose))|D(eactivate|ata(setc(hanged|omplete)|available)|r(op|ag(start|over|drop|en(ter|d)|leave)?)|blclick)|Unload|P(aste|ropertychange)|Error(update)?|Key(down|up|press)|Focus|Load|A(ctivate|fter(update|print)|bort))', 'g'), css: 'support_property' }, { regex: new RegExp('\\.(s(ystemLanguage|cr(ipts|ollbars|een(X|Y|Top|Left))|t(yle(Sheets)?|atus(Text|bar)?)|ibling(Below|Above)|ource|uffixes|e(curity(Policy)?|l(ection|f)))|h(istory|ost(name)?|as(h|Focus))|y|X(MLDocument|SLDocument)|n(ext|ame(space(s|URI)|Prop))|M(IN_VALUE|AX_VALUE)|c(haracterSet|o(n(structor|trollers)|okieEnabled|lorDepth|mp(onents|lete))|urrent|puClass|l(i(p(boardData)?|entInformation)|osed|asses)|alle(e|r)|rypto)|t(o(olbar|p)|ext(Transform|Indent|Decoration|Align)|ags)|SQRT(1_2|2)|i(n(ner(Height|Width)|put)|ds|gnoreCase)|zIndex|o(scpu|n(readystatechange|Line)|uter(Height|Width)|p(sProfile|ener)|ffscreenBuffering)|NEGATIVE_INFINITY|d(i(splay|alog(Height|Top|Width|Left|Arguments)|rectories)|e(scription|fault(Status|Ch(ecked|arset)|View)))|u(ser(Profile|Language|Agent)|n(iqueID|defined)|pdateInterval)|_content|p(ixelDepth|ort|ersonalbar|kcs11|l(ugins|atform)|a(thname|dding(Right|Bottom|Top|Left)|rent(Window|Layer)?|ge(X(Offset)?|Y(Offset)?))|r(o(to(col|type)|duct(Sub)?|mpter)|e(vious|fix)))|e(n(coding|abledPlugin)|x(ternal|pando)|mbeds)|v(isibility|endor(Sub)?|Linkcolor)|URLUnencoded|P(I|OSITIVE_INFINITY)|f(ilename|o(nt(Size|Family|Weight)|rmName)|rame(s|Element)|gColor)|E|whiteSpace|l(i(stStyleType|n(eHeight|kColor))|o(ca(tion(bar)?|lName)|wsrc)|e(ngth|ft(Context)?)|a(st(M(odified|atch)|Index|Paren)|yer(s|X)|nguage))|a(pp(MinorVersion|Name|Co(deName|re)|Version)|vail(Height|Top|Width|Left)|ll|r(ity|guments)|Linkcolor|bove)|r(ight(Context)?|e(sponse(XML|Text)|adyState))|global|x|m(imeTypes|ultiline|enubar|argin(Right|Bottom|Top|Left))|L(N(10|2)|OG(10E|2E))|b(o(ttom|rder(RightWidth|BottomWidth|Style|Color|TopWidth|LeftWidth))|ufferDepth|elow|ackground(Color|Image)))', 'g'), css: 'support_property'}]; this.CssClass = 'javascript'; }
    dp.sh.Brushes.JScript.prototype = new dp.sh.Highlighter(); dp.sh.Brushes.JScript.Aliases = ['js', 'jscript', 'javascript']; dp.sh.Brushes.CSS = function()
    { var keywords = 'ascent azimuth background-attachment background-color background-image background-position ' + 'background-repeat background baseline bbox border-collapse border-color border-spacing border-style border-top ' + 'border-right border-bottom border-left border-top-color border-right-color border-bottom-color border-left-color ' + 'border-top-style border-right-style border-bottom-style border-left-style border-top-width border-right-width ' + 'border-bottom-width border-left-width border-width border bottom cap-height caption-side centerline clear clip color ' + 'content counter-increment counter-reset cue-after cue-before cue cursor definition-src descent direction display ' + 'elevation empty-cells float font-size-adjust font-family font-size font-stretch font-style font-variant font-weight font ' + 'height letter-spacing line-height list-style-image list-style-position list-style-type list-style margin-top ' + 'margin-right margin-bottom margin-left margin marker-offset marks mathline max-height max-width min-height min-width orphans ' + 'outline-color outline-style outline-width outline overflow padding-top padding-right padding-bottom padding-left padding page ' + 'page-break-after page-break-before page-break-inside pause pause-after pause-before pitch pitch-range play-during position ' + 'quotes richness right size slope src speak-header speak-numeral speak-punctuation speak speech-rate stemh stemv stress ' + 'table-layout text-align text-decoration text-indent text-shadow text-transform unicode-bidi unicode-range units-per-em ' + 'vertical-align visibility voice-family volume white-space widows width widths word-spacing x-height z-index important'; var values = 'above absolute all always aqua armenian attr aural auto avoid baseline behind below bidi-override black blink block blue bold bolder ' + 'both bottom braille capitalize caption center center-left center-right circle close-quote code collapse compact condensed ' + 'continuous counter counters crop cross crosshair cursive dashed decimal decimal-leading-zero default digits disc dotted double ' + 'embed embossed e-resize expanded extra-condensed extra-expanded fantasy far-left far-right fast faster fixed format fuchsia ' + 'gray green groove hand handheld hebrew help hidden hide high higher icon inline-table inline inset inside invert italic ' + 'justify landscape large larger left-side left leftwards level lighter lime line-through list-item local loud lower-alpha ' + 'lowercase lower-greek lower-latin lower-roman lower low ltr marker maroon medium message-box middle mix move narrower ' + 'navy ne-resize no-close-quote none no-open-quote no-repeat normal nowrap n-resize nw-resize oblique olive once open-quote outset ' + 'outside overline pointer portrait pre print projection purple red relative repeat repeat-x repeat-y rgb ridge right right-side ' + 'rightwards rtl run-in screen scroll semi-condensed semi-expanded separate se-resize show silent silver slower slow ' + 'small small-caps small-caption smaller soft solid speech spell-out square s-resize static status-bar sub super sw-resize ' + 'table-caption table-cell table-column table-column-group table-footer-group table-header-group table-row table-row-group teal ' + 'text-bottom text-top thick thin top transparent tty tv ultra-condensed ultra-expanded underline upper-alpha uppercase upper-latin ' + 'upper-roman url visible wait white wider w-resize x-fast x-high x-large x-loud x-low x-slow x-small x-soft xx-large xx-small yellow'; var fonts = '[mM]onospace [tT]ahoma [vV]erdana [aA]rial [hH]elvetica [sS]ans-serif [sS]erif'; this.regexList = [{ regex: dp.sh.RegexLib.MultiLineCComments, css: 'comment' }, { regex: dp.sh.RegexLib.DoubleQuotedString, css: 'string' }, { regex: dp.sh.RegexLib.SingleQuotedString, css: 'string' }, { regex: new RegExp('\\#[a-fA-F0-9]{3,6}', 'g'), css: 'color' }, { regex: new RegExp('-?(\\d+)(px|pt|\:|\\s)?', 'g'), css: 'size' }, { regex: new RegExp(this.GetKeywords(keywords), 'gm'), css: 'keyword' }, { regex: new RegExp(this.GetKeywords(values), 'g'), css: 'value' }, { regex: new RegExp(this.GetKeywords(fonts), 'g'), css: 'fonts' }, { regex: new RegExp('(^|\n)[\\s\\#\\._\\-a-zA-Z0-9\\:\\,\\*]+[\\s\\n]*(?=\\{)', 'gm'), css: 'rule'}]; this.CssClass = 'css'; }
    dp.sh.Brushes.CSS.prototype = new dp.sh.Highlighter(); dp.sh.Brushes.CSS.Aliases = ['css']; dp.sh.Brushes.Xml = function()
    { this.CssClass = 'xml'; }
    dp.sh.Brushes.Xml.prototype = new dp.sh.Highlighter(); dp.sh.Brushes.Xml.Aliases = ['xml', 'xhtml', 'xslt', 'html', 'xhtml']; dp.sh.Brushes.Xml.prototype.ProcessRegexList = function()
    {
        function push(array, value)
        { array[array.length] = value; }
        var index = 0; var match = null; var regex = null; this.GetMatches(new RegExp('(\&lt;|<)\\!\\[[\\w\\s]*?\\[(.|\\s)*?\\]\\](\&gt;|>)', 'gm'), 'cdata'); this.GetMatches(new RegExp('(\&lt;|<)!--\\s*.*?\\s*--(\&gt;|>)', 'gm'), 'comments'); regex = new RegExp('([:\\w-\.]+)\\s*=\\s*(".*?"|\'.*?\'|\\w+)*|(\\w+)', 'gm'); while ((match = regex.exec(this.code)) != null)
        {
            if (match[1] == null)
            { continue; }
            push(this.matches, new dp.sh.Match(match[1], match.index, 'attribute')); if (match[2] != undefined)
            { push(this.matches, new dp.sh.Match(match[2], match.index + match[0].indexOf(match[2]), 'attribute-value')); } 
        }
        this.GetMatches(new RegExp('(\&lt;|<)/*\\?*(?!\\!)|/*\\?*(\&gt;|>)', 'gm'), 'tag'); regex = new RegExp('(?:\&lt;|<)/*\\?*\\s*([:\\w-\.]+)', 'gm'); while ((match = regex.exec(this.code)) != null)
        { push(this.matches, new dp.sh.Match(match[1], match.index + match[0].indexOf(match[1]), 'tag-name')); } 
    }
    Event.observe(window, 'load', function() { dp.sh.HighlightAll('javascript', false, false, false, true, false); dp.sh.HighlightAll('css', false, false, false, true, false); dp.sh.HighlightAll('xml', false, false, false, true, false); }); var Showdown = {}; Showdown.converter = function()
    {
        var g_urls; var g_titles; var g_html_blocks; var g_list_level = 0; this.makeHtml = function(text) { g_urls = new Array(); g_titles = new Array(); g_html_blocks = new Array(); text = text.replace(/~/g, "~T"); text = text.replace(/\$/g, "~D"); text = text.replace(/\r\n/g, "\n"); text = text.replace(/\r/g, "\n"); text = "\n\n" + text + "\n\n"; text = _Detab(text); text = text.replace(/^[ \t]+$/mg, ""); text = _HashHTMLBlocks(text); text = _StripLinkDefinitions(text); text = _RunBlockGamut(text); text = _UnescapeSpecialChars(text); text = text.replace(/~D/g, "$$"); text = text.replace(/~T/g, "~"); return text; }
        var _StripLinkDefinitions = function(text)
        {
            var text = text.replace(/^[ ]{0,3}\[(.+)\]:[ \t]*\n?[ \t]*<?(\S+?)>?[ \t]*\n?[ \t]*(?:(\n*)["(](.+?)[")][ \t]*)?(?:\n+|\Z)/gm, function(wholeMatch, m1, m2, m3, m4)
            {
                m1 = m1.toLowerCase(); g_urls[m1] = _EncodeAmpsAndAngles(m2); if (m3) { return m3 + m4; } else if (m4) { g_titles[m1] = m4.replace(/"/g, "&quot;"); }
                return "";
            }); return text;
        }
        var _HashHTMLBlocks = function(text)
        {
            text = text.replace(/\n/g, "\n\n"); var block_tags_a = "p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del"
            var block_tags_b = "p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math"
            text = text.replace(/^(<(p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del)\b[^\r]*?\n<\/\2>[ \t]*(?=\n+))/gm, hashElement); text = text.replace(/^(<(p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math)\b[^\r]*?.*<\/\2>[ \t]*(?=\n+)\n)/gm, hashElement); text = text.replace(/(\n[ ]{0,3}(<(hr)\b([^<>])*?\/?>)[ \t]*(?=\n{2,}))/g, hashElement); text = text.replace(/(\n\n[ ]{0,3}<!(--[^\r]*?--\s*)+>[ \t]*(?=\n{2,}))/g, hashElement); text = text.replace(/(?:\n\n)([ ]{0,3}(?:<([?%])[^\r]*?\2>)[ \t]*(?=\n{2,}))/g, hashElement); text = text.replace(/\n\n/g, "\n"); return text;
        }
        var hashElement = function(wholeMatch, m1) { var blockText = m1; blockText = blockText.replace(/\n\n/g, "\n"); blockText = blockText.replace(/^\n/, ""); blockText = blockText.replace(/\n+$/g, ""); blockText = "\n\n~K" + (g_html_blocks.push(blockText) - 1) + "K\n\n"; return blockText; }; var _RunBlockGamut = function(text) { text = _DoHeaders(text); var key = hashBlock("<hr />"); text = text.replace(/^[ ]{0,2}([ ]?\*[ ]?){3,}[ \t]*$/gm, key); text = text.replace(/^[ ]{0,2}([ ]?\-[ ]?){3,}[ \t]*$/gm, key); text = text.replace(/^[ ]{0,2}([ ]?\_[ ]?){3,}[ \t]*$/gm, key); text = _DoLists(text); text = _DoCodeBlocks(text); text = _DoBlockQuotes(text); text = _HashHTMLBlocks(text); text = _FormParagraphs(text); return text; }
        var _RunSpanGamut = function(text) { text = _DoCodeSpans(text); text = _EscapeSpecialCharsWithinTagAttributes(text); text = _EncodeBackslashEscapes(text); text = _DoImages(text); text = _DoAnchors(text); text = _DoAutoLinks(text); text = _EncodeAmpsAndAngles(text); text = _DoItalicsAndBold(text); text = text.replace(/  +\n/g, " <br />\n"); return text; }
        var _EscapeSpecialCharsWithinTagAttributes = function(text) { var regex = /(<[a-z\/!$]("[^"]*"|'[^']*'|[^'">])*>|<!(--.*?--\s*)+>)/gi; text = text.replace(regex, function(wholeMatch) { var tag = wholeMatch.replace(/(.)<\/?code>(?=.)/g, "$1`"); tag = escapeCharacters(tag, "\\`*_"); return tag; }); return text; }
        var _DoAnchors = function(text) { text = text.replace(/(\[((?:\[[^\]]*\]|[^\[\]])*)\][ ]?(?:\n[ ]*)?\[(.*?)\])()()()()/g, writeAnchorTag); text = text.replace(/(\[((?:\[[^\]]*\]|[^\[\]])*)\]\([ \t]*()<?(.*?)>?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g, writeAnchorTag); text = text.replace(/(\[([^\[\]]+)\])()()()()()/g, writeAnchorTag); return text; }
        var writeAnchorTag = function(wholeMatch, m1, m2, m3, m4, m5, m6, m7)
        {
            if (m7 == undefined) m7 = ""; var whole_match = m1; var link_text = m2; var link_id = m3.toLowerCase(); var url = m4; var title = m7; if (url == "")
            {
                if (link_id == "") { link_id = link_text.toLowerCase().replace(/ ?\n/g, " "); }
                url = "#" + link_id; if (g_urls[link_id] != undefined) { url = g_urls[link_id]; if (g_titles[link_id] != undefined) { title = g_titles[link_id]; } }
                else { if (whole_match.search(/\(\s*\)$/m) > -1) { url = ""; } else { return whole_match; } } 
            }
            url = escapeCharacters(url, "*_"); var result = "<a href=\"" + url + "\""; if (title != "") { title = title.replace(/"/g, "&quot;"); title = escapeCharacters(title, "*_"); result += " title=\"" + title + "\""; }
            result += ">" + link_text + "</a>"; return result;
        }
        var _DoImages = function(text) { text = text.replace(/(!\[(.*?)\][ ]?(?:\n[ ]*)?\[(.*?)\])()()()()/g, writeImageTag); text = text.replace(/(!\[(.*?)\]\s?\([ \t]*()<?(\S+?)>?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g, writeImageTag); return text; }
        var writeImageTag = function(wholeMatch, m1, m2, m3, m4, m5, m6, m7)
        {
            var whole_match = m1; var alt_text = m2; var link_id = m3.toLowerCase(); var url = m4; var title = m7; if (!title) title = ""; if (url == "")
            {
                if (link_id == "") { link_id = alt_text.toLowerCase().replace(/ ?\n/g, " "); }
                url = "#" + link_id; if (g_urls[link_id] != undefined) { url = g_urls[link_id]; if (g_titles[link_id] != undefined) { title = g_titles[link_id]; } }
                else { return whole_match; } 
            }
            alt_text = alt_text.replace(/"/g, "&quot;"); url = escapeCharacters(url, "*_"); var result = "<img src=\"" + url + "\" alt=\"" + alt_text + "\""; title = title.replace(/"/g, "&quot;"); title = escapeCharacters(title, "*_"); result += " title=\"" + title + "\""; result += " />"; return result;
        }
        var _DoHeaders = function(text) { text = text.replace(/^(.+)[ \t]*\n=+[ \t]*\n+/gm, function(wholeMatch, m1) { return hashBlock("<h1>" + _RunSpanGamut(m1) + "</h1>"); }); text = text.replace(/^(.+)[ \t]*\n-+[ \t]*\n+/gm, function(matchFound, m1) { return hashBlock("<h2>" + _RunSpanGamut(m1) + "</h2>"); }); text = text.replace(/^(\#{1,6})[ \t]*(.+?)[ \t]*\#*\n+/gm, function(wholeMatch, m1, m2) { var h_level = m1.length; return hashBlock("<h" + h_level + ">" + _RunSpanGamut(m2) + "</h" + h_level + ">"); }); return text; }
        var _ProcessListItems; var _DoLists = function(text)
        {
            text += "~0"; var whole_list = /^(([ ]{0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm; if (g_list_level) { text = text.replace(whole_list, function(wholeMatch, m1, m2) { var list = m1; var list_type = (m2.search(/[*+-]/g) > -1) ? "ul" : "ol"; list = list.replace(/\n{2,}/g, "\n\n\n"); ; var result = _ProcessListItems(list); result = result.replace(/\s+$/, ""); result = "<" + list_type + ">" + result + "</" + list_type + ">\n"; return result; }); } else { whole_list = /(\n\n|^\n?)(([ ]{0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/g; text = text.replace(whole_list, function(wholeMatch, m1, m2, m3) { var runup = m1; var list = m2; var list_type = (m3.search(/[*+-]/g) > -1) ? "ul" : "ol"; var list = list.replace(/\n{2,}/g, "\n\n\n"); ; var result = _ProcessListItems(list); result = runup + "<" + list_type + ">\n" + result + "</" + list_type + ">\n"; return result; }); }
            text = text.replace(/~0/, ""); return text;
        }
        _ProcessListItems = function(list_str)
        {
            g_list_level++; list_str = list_str.replace(/\n{2,}$/, "\n"); list_str += "~0"; list_str = list_str.replace(/(\n)?(^[ \t]*)([*+-]|\d+[.])[ \t]+([^\r]+?(\n{1,2}))(?=\n*(~0|\2([*+-]|\d+[.])[ \t]+))/gm, function(wholeMatch, m1, m2, m3, m4)
            {
                var item = m4; var leading_line = m1; var leading_space = m2; if (leading_line || (item.search(/\n{2,}/) > -1)) { item = _RunBlockGamut(_Outdent(item)); }
                else { item = _DoLists(_Outdent(item)); item = item.replace(/\n$/, ""); item = _RunSpanGamut(item); }
                return "<li>" + item + "</li>\n";
            }); list_str = list_str.replace(/~0/g, ""); g_list_level--; return list_str;
        }
        var _DoCodeBlocks = function(text) { text += "~0"; text = text.replace(/(?:\n\n|^)((?:(?:[ ]{4}|\t).*\n+)+)(\n*[ ]{0,3}[^ \t\n]|(?=~0))/g, function(wholeMatch, m1, m2) { var codeblock = m1; var nextChar = m2; codeblock = _EncodeCode(_Outdent(codeblock)); codeblock = _Detab(codeblock); codeblock = codeblock.replace(/^\n+/g, ""); codeblock = codeblock.replace(/\n+$/g, ""); codeblock = "<pre><code>" + codeblock + "\n</code></pre>"; return hashBlock(codeblock) + nextChar; }); text = text.replace(/~0/, ""); return text; }
        var hashBlock = function(text) { text = text.replace(/(^\n+|\n+$)/g, ""); return "\n\n~K" + (g_html_blocks.push(text) - 1) + "K\n\n"; }
        var _DoCodeSpans = function(text) { text = text.replace(/(^|[^\\])(`+)([^\r]*?[^`])\2(?!`)/gm, function(wholeMatch, m1, m2, m3, m4) { var c = m3; c = c.replace(/^([ \t]*)/g, ""); c = c.replace(/[ \t]*$/g, ""); c = _EncodeCode(c); return m1 + "<code>" + c + "</code>"; }); return text; }
        var _EncodeCode = function(text) { text = text.replace(/&/g, "&amp;"); text = text.replace(/</g, "&lt;"); text = text.replace(/>/g, "&gt;"); text = escapeCharacters(text, "\*_{}[]\\", false); return text; }
        var _DoItalicsAndBold = function(text) { text = text.replace(/(\*\*|__)(?=\S)([^\r]*?\S[*_]*)\1/g, "<strong>$2</strong>"); text = text.replace(/(\*|_)(?=\S)([^\r]*?\S)\1/g, "<em>$2</em>"); return text; }
        var _DoBlockQuotes = function(text) { text = text.replace(/((^[ \t]*>[ \t]?.+\n(.+\n)*\n*)+)/gm, function(wholeMatch, m1) { var bq = m1; bq = bq.replace(/^[ \t]*>[ \t]?/gm, "~0"); bq = bq.replace(/~0/g, ""); bq = bq.replace(/^[ \t]+$/gm, ""); bq = _RunBlockGamut(bq); bq = bq.replace(/(^|\n)/g, "$1  "); bq = bq.replace(/(\s*<pre>[^\r]+?<\/pre>)/gm, function(wholeMatch, m1) { var pre = m1; pre = pre.replace(/^  /mg, "~0"); pre = pre.replace(/~0/g, ""); return pre; }); return hashBlock("<blockquote>\n" + bq + "\n</blockquote>"); }); return text; }
        var _FormParagraphs = function(text)
        {
            text = text.replace(/^\n+/g, ""); text = text.replace(/\n+$/g, ""); var grafs = text.split(/\n{2,}/g); var grafsOut = new Array(); var end = grafs.length; for (var i = 0; i < end; i++)
            {
                var str = grafs[i]; if (str.search(/~K(\d+)K/g) >= 0) { grafsOut.push(str); }
                else if (str.search(/\S/) >= 0)
                {
                    str = _RunSpanGamut(str); str = str.replace(/^([ \t]*)/g, "<p>"); str += "</p>"
                    grafsOut.push(str);
                } 
            }
            end = grafsOut.length; for (var i = 0; i < end; i++) { while (grafsOut[i].search(/~K(\d+)K/) >= 0) { var blockText = g_html_blocks[RegExp.$1]; blockText = blockText.replace(/\$/g, "$$$$"); grafsOut[i] = grafsOut[i].replace(/~K\d+K/, blockText); } }
            return grafsOut.join("\n\n");
        }
        var _EncodeAmpsAndAngles = function(text) { text = text.replace(/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/g, "&amp;"); text = text.replace(/<(?![a-z\/?\$!])/gi, "&lt;"); return text; }
        var _EncodeBackslashEscapes = function(text) { text = text.replace(/\\(\\)/g, escapeCharacters_callback); text = text.replace(/\\([`*_{}\[\]()>#+-.!])/g, escapeCharacters_callback); return text; }
        var _DoAutoLinks = function(text) { text = text.replace(/<((https?|ftp|dict):[^'">\s]+)>/gi, "<a href=\"$1\">$1</a>"); text = text.replace(/<(?:mailto:)?([-.\w]+\@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)>/gi, function(wholeMatch, m1) { return _EncodeEmailAddress(_UnescapeSpecialChars(m1)); }); return text; }
        var _EncodeEmailAddress = function(addr)
        {
            function char2hex(ch) { var hexDigits = '0123456789ABCDEF'; var dec = ch.charCodeAt(0); return (hexDigits.charAt(dec >> 4) + hexDigits.charAt(dec & 15)); }
            var encode = [function(ch) { return "&#" + ch.charCodeAt(0) + ";"; }, function(ch) { return "&#x" + char2hex(ch) + ";"; }, function(ch) { return ch; } ]; addr = "mailto:" + addr; addr = addr.replace(/./g, function(ch)
            {
                if (ch == "@") { ch = encode[Math.floor(Math.random() * 2)](ch); } else if (ch != ":") { var r = Math.random(); ch = (r > .9 ? encode[2](ch) : r > .45 ? encode[1](ch) : encode[0](ch)); }
                return ch;
            }); addr = "<a href=\"" + addr + "\">" + addr + "</a>"; addr = addr.replace(/">.+:/g, "\">"); return addr;
        }
        var _UnescapeSpecialChars = function(text) { text = text.replace(/~E(\d+)E/g, function(wholeMatch, m1) { var charCodeToReplace = parseInt(m1); return String.fromCharCode(charCodeToReplace); }); return text; }
        var _Outdent = function(text)
        {
            text = text.replace(/^(\t|[ ]{1,4})/gm, "~0"); text = text.replace(/~0/g, "")
            return text;
        }
        var _Detab = function(text) { text = text.replace(/\t(?=\t)/g, "    "); text = text.replace(/\t/g, "~A~B"); text = text.replace(/~B(.+?)~A/g, function(wholeMatch, m1, m2) { var leadingText = m1; var numSpaces = 4 - leadingText.length % 4; for (var i = 0; i < numSpaces; i++) leadingText += " "; return leadingText; }); text = text.replace(/~A/g, "    "); text = text.replace(/~B/g, ""); return text; }
        var escapeCharacters = function(text, charsToEscape, afterBackslash)
        {
            var regexString = "([" + charsToEscape.replace(/([\[\]\\])/g, "\\$1") + "])"; if (afterBackslash) { regexString = "\\\\" + regexString; }
            var regex = new RegExp(regexString, "g"); text = text.replace(regex, escapeCharacters_callback); return text;
        }
        var escapeCharacters_callback = function(wholeMatch, m1) { var charCodeToEscape = m1.charCodeAt(0); return "~E" + charCodeToEscape + "E"; } 
    }