
//---IMPORTANT---(start)
/*

This file is a consolidation of complete and partial, often modified, open-source,
3rd-party code.  The license files for the original files immediately follows.
The code has been commented with credits (of the form "//---CREDIT---") when a
different source is used.

Note: Some 3rd pary code has also been replaced since the license were included.
Because a license is here there is no guarentee that any code from that source is
still in use.

NOTE: The licenses here, while similiar in nature, are NOT the same.  IF you
choose to use this file as is then you are solely responsible for adhering to and
honoring the licenses that cover this and these works.

 */
//---IMPORTANT---(end)


/*
TableBrain-Public-Domain

Code marked as TableBrain-Public-Domain is made available by TableBrain to the
public domain.  You may use code marked as such for any purpose you see fit AS
LONG AS you acknowledge and agree to the following three conditions:

 (1) TableBrain and its associates are NOT responsible for any resulting action
     or inaction that may come from using or including this code

 (2) TableBrain and its associates make NO claim to the fitness of this code
     for any purpose whatsoever

 (3) You will be using this code at your own risk
*/


/*
    json2.js
    2008-02-14

    Public Domain

    No warranty expressed or implied. Use at your own risk.

    See http://www.JSON.org/js.html

    This file creates a global JSON object containing two methods:

        JSON.stringify(value, whitelist)
            value       any JavaScript value, usually an object or array.

            whitelist   an optional array parameter that determines how object
                        values are stringified.

            This method produces a JSON text from a JavaScript value.
            There are three possible ways to stringify an object, depending
            on the optional whitelist parameter.

            If an object has a toJSON method, then the toJSON() method will be
            called. The value returned from the toJSON method will be
            stringified.

            Otherwise, if the optional whitelist parameter is an array, then
            the elements of the array will be used to select members of the
            object for stringification.

            Otherwise, if there is no whitelist parameter, then all of the
            members of the object will be stringified.

            Values that do not have JSON representaions, such as undefined or
            functions, will not be serialized. Such values in objects will be
            dropped; in arrays will be replaced with null.
            JSON.stringify(undefined) returns undefined. Dates will be
            stringified as quoted ISO dates.

            Example:

            var text = JSON.stringify(['e', {pluribus: 'unum'}]);
            // text is '["e",{"pluribus":"unum"}]'

        JSON.parse(text, filter)
            This method parses a JSON text to produce an object or
            array. It can throw a SyntaxError exception.

            The optional filter parameter is a function that can filter and
            transform the results. It receives each of the keys and values, and
            its return value is used instead of the original value. If it
            returns what it received, then structure is not modified. If it
            returns undefined then the member is deleted.

            Example:

            // Parse the text. If a key contains the string 'date' then
            // convert the value to a date.

            myData = JSON.parse(text, function (key, value) {
                return key.indexOf('date') >= 0 ? new Date(value) : value;
            });

    This is a reference implementation. You are free to copy, modify, or
    redistribute.

    Use your own copy. It is extremely unwise to load third party
    code into your pages.
*/


// the following license is included with behaviour.js
/*
   The following code is Copyright (C) Simon Willison 2004.

   document.getElementsBySelector(selector)
   - returns an array of element objects from the current document
     matching the CSS selector. Selectors can contain element names, 
     class names and ids and can be nested. For example:
     
       elements = document.getElementsBySelect('div#main p a.external')
     
     Will return an array of all 'a' elements with 'external' in their 
     class attribute that are contained inside 'p' elements that are 
     contained inside the 'div' element which has id="main"

   New in version 0.4: Support for CSS2 and CSS3 attribute selectors:
   See http://www.w3.org/TR/css3-selectors/#attribute-selectors

   Version 0.4 - Simon Willison, March 25th 2003
   -- Works in Phoenix 0.5, Mozilla 1.3, Opera 7, Internet Explorer 6, Internet Explorer 5 on Windows
   -- Opera 7 fails 
*/


/*
The Ultimate getElementsByClassName
Published on Monday, November 7th, 2005
//http://www.robertnyman.com/2005/11/07/the-ultimate-getelementsbyclassname/

Please try it out. Our hope is that it will help you develop unobtrusive JavaScripts
and that it will make it easier for you to maintain your web sites. Any problems with
the function, please let us know.

Go crazy now!
*/


/*  Prototype JavaScript framework, version 1.6.0.2
 *  (c) 2005-2008 Sam Stephenson
 *
 *  Prototype is freely distributable under the terms of an MIT-style license.
 *  For details, see the Prototype web site: http://www.prototypejs.org/
 *
 *--------------------------------------------------------------------------*/


// script.aculo.us scriptaculous.js v1.8.1, Thu Jan 03 22:07:12 -0500 2008

// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
// 
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
// 
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// For details, see the script.aculo.us web site: http://script.aculo.us/


//---CREDIT--- TableBrain-Public-Domain
if (window.addProgress) window.addProgress(5);

if ( ! TableBrain) var TableBrain = {};

TableBrain.initPD = function() {
    if (window.addProgress) window.addProgress(15);
};

TableBrain.elBlocking = {
    BODY: 1,
    DIV: 1,
    H1: 1, H2: 1, H3: 1, H4: 1, H5: 1, H6: 1,
    P: 1,
    TABLE: 1, TBODY: 1, TR: 1,
    IFRAME: 1
};

//---CREDIT--- Behaviour
var Behaviour = {
    list : new Array(),
    loadEvents : new Array(),
	
    register : function(sheet){
	Behaviour.list.push(sheet);
    },
    
    statePoller : false,
    pollState : function() {
    	if(document.readyState == "loaded" || document.readyState == "complete") {
    		clearTimeout(Behaviour.statePoller);
				var i, loadEvent;
				for(i=0;i < Behaviour.loadEvents.length; i++){
					var loadEvent = Behaviour.loadEvents[i];
					loadEvent();
				}
    	} else {
    		Behaviour.statePoller = setTimeout(Behaviour.pollState, 25);
    	}
    },
    
    start : function() {
    	if(typeof document.readyState != "undefined") {
    		Behaviour.statePoller = setTimeout(Behaviour.pollState, 25);
    	} else {
				var onload = function() {
					var i, loadEvent;
					for(i=0;i < Behaviour.loadEvents.length; i++){
						var loadEvent = Behaviour.loadEvents[i];
						loadEvent();
					}
				}
				window.onload = onload;
    	}
			Behaviour.addLoadEvent(Behaviour.apply);
    },

    apply : function(){
	var h, i, sheet, element, list;
	for (h = 0; sheet = Behaviour.list[h]; h++){
	    for (selector in sheet){
		if (sheet.hasOwnProperty(selector)) {
		    list = document.getElementsBySelector(selector);
		    if (list) {
			for (i = 0; element = list[i]; i++){
			    sheet[selector](element);
			}
		    }
		}
	    }
	}
    },
    
    addLoadEvent : function(func){
	Behaviour.loadEvents.push(func);
    }
}
Behaviour.start();

//---CREDIT--- document.getElementsBySelector(selector)
function getAllChildren(e) {
  // Returns all children of element. Workaround required for IE5/Windows. Ugh.
  return e.all ? e.all : e.getElementsByTagName('*');
}

document.getElementsBySelector = function(selector) {
  // Attempt to fail gracefully in lesser browsers
  if (!document.getElementsByTagName) {
    return new Array();
  }
  // Split selector in to tokens
  var tokens = selector.split(' ');
  var currentContext = new Array(document);
  for (var i = 0; i < tokens.length; i++) {
    token = tokens[i].replace(/^\s+/,'').replace(/\s+$/,'');;
    if (token.indexOf('#') > -1) {
      // Token is an ID selector
      var bits = token.split('#');
      var tagName = bits[0];
      var id = bits[1];
      var element = document.getElementById(id);
      if ( ! element) return new Array(); // TableBrain FIX
      if (tagName && element.nodeName.toLowerCase() != tagName) {
        // tag with that ID not found, return false
        return new Array();
      }
      // Set currentContext to contain just this element
      currentContext = new Array(element);
      continue; // Skip to next token
    }
    if (token.indexOf('.') > -1) {
      // Token contains a class selector
      var bits = token.split('.');
      var tagName = bits[0];
      var className = bits[1];
      if (!tagName) {
        tagName = '*';
      }
      // Get elements matching tag, filter them for class selector
      var found = new Array;
      var foundCount = 0;
      for (var h = 0; h < currentContext.length; h++) {
        var elements;
        if (tagName == '*') {
            elements = getAllChildren(currentContext[h]);
        } else {
            elements = currentContext[h].getElementsByTagName(tagName);
        }
        for (var j = 0; j < elements.length; j++) {
          found[foundCount++] = elements[j];
        }
      }
      currentContext = new Array;
      var currentContextIndex = 0;
      for (var k = 0; k < found.length; k++) {
        if (found[k].className && found[k].className.match(new RegExp('\\b'+className+'\\b'))) {
          currentContext[currentContextIndex++] = found[k];
        }
      }
      continue; // Skip to next token
    }
    // Code to deal with attribute selectors
    if (token.match(/^(\w*)\[(\w+)([=~\|\^\$\*]?)=?"?([^\]"]*)"?\]$/)) {
      var tagName = RegExp.$1;
      var attrName = RegExp.$2;
      var attrOperator = RegExp.$3;
      var attrValue = RegExp.$4;
      if (!tagName) {
        tagName = '*';
      }
      // Grab all of the tagName elements within current context
      var found = new Array;
      var foundCount = 0;
      for (var h = 0; h < currentContext.length; h++) {
        var elements;
        if (tagName == '*') {
            elements = getAllChildren(currentContext[h]);
        } else {
            elements = currentContext[h].getElementsByTagName(tagName);
        }
        for (var j = 0; j < elements.length; j++) {
          found[foundCount++] = elements[j];
        }
      }
      currentContext = new Array;
      var currentContextIndex = 0;
      var checkFunction; // This function will be used to filter the elements
      switch (attrOperator) {
        case '=': // Equality
          checkFunction = function(e) { return (e.getAttribute(attrName) == attrValue); };
          break;
        case '~': // Match one of space seperated words
          checkFunction = function(e) { return (e.getAttribute(attrName).match(new RegExp('\\b'+attrValue+'\\b'))); };
          break;
        case '|': // Match start with value followed by optional hyphen
          checkFunction = function(e) { return (e.getAttribute(attrName).match(new RegExp('^'+attrValue+'-?'))); };
          break;
        case '^': // Match starts with value
          checkFunction = function(e) { return (e.getAttribute(attrName).indexOf(attrValue) == 0); };
          break;
        case '$': // Match ends with value - fails with "Warning" in Opera 7
          checkFunction = function(e) { return (e.getAttribute(attrName).lastIndexOf(attrValue) == e.getAttribute(attrName).length - attrValue.length); };
          break;
        case '*': // Match ends with value
          checkFunction = function(e) { return (e.getAttribute(attrName).indexOf(attrValue) > -1); };
          break;
        default :
          // Just test for existence of attribute
          checkFunction = function(e) { return e.getAttribute(attrName); };
      }
      currentContext = new Array;
      var currentContextIndex = 0;
      for (var k = 0; k < found.length; k++) {
        if (checkFunction(found[k])) {
          currentContext[currentContextIndex++] = found[k];
        }
      }
      // alert('Attribute Selector: '+tagName+' '+attrName+' '+attrOperator+' '+attrValue);
      continue; // Skip to next token
    }
    
    if (!currentContext[0]){
    	return;
    }
    
    // If we get here, token is JUST an element (not a class or ID selector)
    tagName = token;
    var found = new Array;
    var foundCount = 0;
    for (var h = 0; h < currentContext.length; h++) {
      var elements = currentContext[h].getElementsByTagName(tagName);
      for (var j = 0; j < elements.length; j++) {
        found[foundCount++] = elements[j];
      }
    }
    currentContext = found;
  }
  return currentContext;
}

/* That revolting regular expression explained 
/^(\w+)\[(\w+)([=~\|\^\$\*]?)=?"?([^\]"]*)"?\]$/
  \---/  \---/\-------------/    \-------/
    |      |         |               |
    |      |         |           The value
    |      |    ~,|,^,$,* or =
    |   Attribute 
   Tag
*/


//---CREDIT--- json2
/*jslint evil: true */

/*global JSON */

/*members "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
    charCodeAt, floor, getUTCDate, getUTCFullYear, getUTCHours,
    getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join, length,
    parse, propertyIsEnumerable, prototype, push, replace, stringify, test,
    toJSON, toString
*/

if (!this.JSON) {

    JSON = function () {

        function f(n) {    // Format integers to have at least two digits.
            return n < 10 ? '0' + n : n;
        }

        Date.prototype.toJSON = function () {

// Eventually, this method will be based on the date.toISOString method.

            return this.getUTCFullYear()   + '-' +
                 f(this.getUTCMonth() + 1) + '-' +
                 f(this.getUTCDate())      + 'T' +
                 f(this.getUTCHours())     + ':' +
                 f(this.getUTCMinutes())   + ':' +
                 f(this.getUTCSeconds())   + 'Z';
        };


        var m = {    // table of character substitutions
            '\b': '\\b',
            '\t': '\\t',
            '\n': '\\n',
            '\f': '\\f',
            '\r': '\\r',
            '"' : '\\"',
            '\\': '\\\\'
        };

        function stringify(value, whitelist) {
            var a,          // The array holding the partial texts.
                i,          // The loop counter.
                k,          // The member key.
                l,          // Length.
                r = /["\\\x00-\x1f\x7f-\x9f]/g,
                v;          // The member value.

            switch (typeof value) {
            case 'string':

// If the string contains no control characters, no quote characters, and no
// backslash characters, then we can safely slap some quotes around it.
// Otherwise we must also replace the offending characters with safe sequences.

                return r.test(value) ?
                    '"' + value.replace(r, function (a) {
                        var c = m[a];
                        if (c) {
                            return c;
                        }
                        c = a.charCodeAt();
                        return '\\u00' + Math.floor(c / 16).toString(16) +
                                                   (c % 16).toString(16);
                    }) + '"' :
                    '"' + value + '"';

            case 'number':

// JSON numbers must be finite. Encode non-finite numbers as null.

                return isFinite(value) ? String(value) : 'null';

            case 'boolean':
            case 'null':
                return String(value);

            case 'object':

// Due to a specification blunder in ECMAScript,
// typeof null is 'object', so watch out for that case.

                if (!value) {
                    return 'null';
                }

// If the object has a toJSON method, call it, and stringify the result.

                if (typeof value.toJSON === 'function') {
                    return stringify(value.toJSON());
                }
                a = [];
                if (typeof value.length === 'number' &&
                        !(value.propertyIsEnumerable('length'))) {

// The object is an array. Stringify every element. Use null as a placeholder
// for non-JSON values.

                    l = value.length;
                    for (i = 0; i < l; i += 1) {
                        a.push(stringify(value[i], whitelist) || 'null');
                    }

// Join all of the elements together and wrap them in brackets.

                    return '[' + a.join(',') + ']';
                }
                if (whitelist) {

// If a whitelist (array of keys) is provided, use it to select the components
// of the object.

                    l = whitelist.length;
                    for (i = 0; i < l; i += 1) {
                        k = whitelist[i];
                        if (typeof k === 'string') {
                            v = stringify(value[k], whitelist);
                            if (v) {
                                a.push(stringify(k) + ':' + v);
                            }
                        }
                    }
                } else {

// Otherwise, iterate through all of the keys in the object.

                    for (k in value) {
                        if (typeof k === 'string') {
                            v = stringify(value[k], whitelist);
                            if (v) {
                                a.push(stringify(k) + ':' + v);
                            }
                        }
                    }
                }

// Join all of the member texts together and wrap them in braces.

                return '{' + a.join(',') + '}';
            }
        }

        return {
            stringify: stringify,
            parse: function (text, filter) {
                var j;

                function walk(k, v) {
                    var i, n;
                    if (v && typeof v === 'object') {
                        for (i in v) {
                            if (Object.prototype.hasOwnProperty.apply(v, [i])) {
                                n = walk(i, v[i]);
                                if (n !== undefined) {
                                    v[i] = n;
                                } else {
                                    delete v[i];
                                }
                            }
                        }
                    }
                    return filter(k, v);
                }


// Parsing happens in three stages. In the first stage, we run the text against
// regular expressions that look for non-JSON patterns. We are especially
// concerned with '()' and 'new' because they can cause invocation, and '='
// because it can cause mutation. But just to be safe, we want to reject all
// unexpected forms.

// We split the first stage into 4 regexp operations in order to work around
// crippling inefficiencies in IE's and Safari's regexp engines. First we
// replace all backslash pairs with '@' (a non-JSON character). Second, we
// replace all simple value tokens with ']' characters. Third, we delete all
// open brackets that follow a colon or comma or that begin the text. Finally,
// we look to see that the remaining characters are only whitespace or ']' or
// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.

                if (/^[\],:{}\s]*$/.test(text.replace(/\\./g, '@').
replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {

// In the second stage we use the eval function to compile the text into a
// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
// in JavaScript: it can begin a block or an object literal. We wrap the text
// in parens to eliminate the ambiguity.

                    j = eval('(' + text + ')');

// In the optional third stage, we recursively walk the new structure, passing
// each name/value pair to a filter function for possible transformation.

                    return typeof filter === 'function' ? walk('', j) : j;
                }

// If the text is not JSON parseable, then a SyntaxError is thrown.

                throw new SyntaxError('parseJSON');
            }
        };
    }();
}

//---CREDIT--- TableBrain-Public-Domain
if (window.addProgress) window.addProgress(5);

//---CREDIT--- Prototype
var Prototype = {
  // BASED ON Version: '1.6.0.2',

  Browser: {
    IE:     !!(window.attachEvent && !window.opera),
    Opera:  !!window.opera,
    WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1,
    Gecko:  navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1,
    MobileSafari: !!navigator.userAgent.match(/Apple.*Mobile.*Safari/)
  },
  
  BrowserFeatures: {
    XPath: !!document.evaluate,
    ElementExtensions: !!window.HTMLElement,
    SpecificElementExtensions:
      document.createElement('div').__proto__ &&
      document.createElement('div').__proto__ !==
        document.createElement('form').__proto__
  },
  
  ScriptFragment: '<script[^>]*>([\\S\\s]*?)<\/script>',
  JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/,
  
  emptyFunction: function() { },
  K: function(x) { return x }
};

if (Prototype.Browser.MobileSafari)
  Prototype.BrowserFeatures.SpecificElementExtensions = false;

/* Prototype comment: Based on Alex Arnell's inheritance implementation. */
var Class = {
  create: function() {
    var parent = null, properties = $A(arguments);
    if (Object.isFunction(properties[0]))
      parent = properties.shift();

    function klass() {
      this.initialize.apply(this, arguments);
    }

    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 = Object.extend((function(m) {
          return function() { return ancestor[m].apply(this, arguments) };
        })(property).wrap(method), {
          valueOf:  function() { return method },
          toString: function() { return method.toString() }
        });
      }
      this.prototype[property] = value;
    }

    return this;
  }
};

function $(element) {
    if (arguments.length > 1) {
	for (var i = 0, elements = [], length = arguments.length; i < length; i++)
	    elements.push($(arguments[i]));
	return elements;
    }
    if (typeof element == "string")
	element = document.getElementById(element);
    return Element.extend(element);
}

//---CREDIT--- TableBrain-Public-Domain
function $$(selector){
    var i, l, e;
    var list = document.getElementsBySelector(selector);
    if ( ! list) return [];
    l = list.length;
    for (i = 0; i < l; ++i) {
	Element.extend(list[i]);
    }
    return list;
}

//---CREDIT--- Prototype
if (Prototype.Browser.WebKit) {
    function $A(iterable) {
        if (!iterable) return [];
	if ( ! (typeof iterable == 'function' && iterable == '[object NodeList]') && iterable.toArray)
	    return iterable.toArray();
	var length = iterable.length || 0, results = new Array(length);
	while (length--) results[length] = iterable[length];
	return results;
    }
} else {
    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;
    }
}

function $w(string) {
    if (typeof string != 'string') return [];
    string = string.strip();
    return string ? string.split(/\s+/) : [];
}

Object.extend = function(destination, source) {
    for (var property in source)
	destination[property] = source[property];
    return destination;
};

Object.extend(Object, {
    clone: function(object) {
	return Object.extend({ }, object);
    },

    keys: function(object) {
        var keys = [];
        for (var property in object)
            keys.push(property);
        return keys;
    },

    toQueryString: function(object) {
        return $H(object).toQueryString();
    },

    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].split(",").invoke("strip");
	/*
	var v1 = this.toString();
	var v2 = v1.match(/^[\s\(]*function[^(]*\((.*?)\)/);
	var v3 = v2[1];
        var v4 = v3.split(",");
	var v5 = v4.invoke("strip");
	*/
        return names.length == 1 && !names[0] ? [] : names;
    },

    bind: function() {
	if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this;
	var __method = this, args = $A(arguments), object = args.shift();
	return function() {
	    return __method.apply(object, args.concat($A(arguments)));
	}
    },

    bindAsEventListener: function() {
	var __method = this, args = $A(arguments), object = args.shift();
	return function(event) {
	    return __method.apply(object, [event || window.event].concat(args));
	}
    },

    curry: function() {
        if (!arguments.length) return this;
        var __method = this, args = $A(arguments);
        return function() {
            return __method.apply(this, args.concat($A(arguments)));
        }
    },

    delay: function() {
        var __method = this, args = $A(arguments), timeout = args.shift() * 1000;
        return window.setTimeout(function() {
            return __method.apply(__method, args);
        }, timeout);
    },

    wrap: function(wrapper) {
        var __method = this;
        return function() {
            return wrapper.apply(this, [__method.bind(this)].concat($A(arguments)));
        };
    },

    methodize: function() {
        if (this._methodized) return this._methodized;
	var __method = this;
	return this._methodized = function() {
	    //return __method.apply(null, [this].concat($A(arguments)));
	    return __method.apply(this, arguments);
	};
    }
});

Function.prototype.defer = Function.prototype.delay.curry(0.01);

Object.extend(String, {
    interpret: function(value) {
        return value == null ? '' : String(value);
    }
});

Object.extend(String.prototype, {
    strip: function() {
        return this.replace(/^\s+/, '').replace(/\s+$/, '');
    },

    include: function(pattern) {
        return this.indexOf(pattern) > -1;
    },

    blank: function() {
        return /^\s*$/.test(this);
    },

    interpolate: function(object, pattern) {
        return new Template(this, pattern).evaluate(object);
    },

//---CREDIT--- TableBrain-Public-Domain
    unfilterJSON: function() {
	// ^/*-secure-(.*)*/___$
        //return this.sub(filter || Prototype.JSONFilter, '#{1}');
	return this.replace(Prototype.JSONFilter, '$1');
    },

//---CREDIT--- Prototype
    isJSON: function() {
	var str = this;
	if (str.blank()) return false;
	str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, '');  //" (for emacs)
	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);  // this.inspect());
    },

    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;
        });
    },

    stripScripts: function() {
        return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
    },

    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();
    }
});

if ( ! this.Element) Element = {};

Element.Methods = {
    identify: function() {
	var element = this;
	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;
    },
    
    writeAttribute: function(name, value) {
	var element = this;
	var attributes = { }, t = Element._attributeTranslations.write;
	
	if (typeof name === 'object')
	    attributes = name;
	else
	    attributes[name] = typeof value == "undefined" ? 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;
    },

    getOffsetParent: function() {
	var element = this;
	if (element.offsetParent) return Element.extend(element.offsetParent);
	if (element == document.body) return Element.extend(element);
	
	while ((element = element.parentNode) && element != document.body)
	    if (Element.getStyle(element, 'position') != 'static')
		return Element.extend(element);
	
	return Element.extend(document.body);
    },

    viewportOffset: function() {
	var valueT = 0, valueL = 0;

	var element = this;
	do {
	    valueT += element.offsetTop  || 0;
	    valueL += element.offsetLeft || 0;
	    
	    // Safari fix
	    if (element.offsetParent == document.body) {
		if ( ! element._stuffSet) element = Element.extend(element);
		if (element.getStyle('position') == 'absolute') break;
	    }
	} while (element = element.offsetParent);

	var element = this;
	do {
	    if (!Prototype.Browser.Opera || element.tagName == 'BODY') {
		valueT -= element.scrollTop  || 0;
		valueL -= element.scrollLeft || 0;
	    }
	} while (element = element.parentNode);
	
	var result = [valueL, valueT];
	result.left = valueL;
	result.top = valueT;
	return result;
    },

    getOffsetParent: function() {
	var element = this;

	if (element.offsetParent) return $(element.offsetParent);
	if (element == document.body) return $(element);
	
	while ((element = element.parentNode) && element != document.body) {
	    if ( ! element._stuffSet) element = Element.extend(element);
	    if (element.getStyle('position') != 'static')
		return $(element);
	}
	
	return $(document.body);
    },

    clonePosition: function(source) {
	var options = Object.extend({
		setLeft:    true,
		setTop:     true,
		setWidth:   true,
		setHeight:  true,
		offsetTop:  0,
		offsetLeft: 0
	    }, arguments[1] || { });
	
	// find page position of source
	source = $(source);
	var p = source.viewportOffset();

	// find coordinate system to use
	var element = this;
	var delta = [0, 0];
	var parent = null;
	// delta [0,0] will do fine with position: fixed elements,
	// position:absolute needs offsetParent deltas
	if (element.getStyle('position') == 'absolute') {
	    parent = element.getOffsetParent();
	    delta = parent.viewportOffset();
	}

	// correct by body offsets (fixes Safari)
	if (parent == document.body) {
	    delta[0] -= document.body.offsetLeft;
	    delta[1] -= document.body.offsetTop;
	}

	// set position
	var style = element.style;
	if (options.setLeft)   style.left  = (p[0] - delta[0] + options.offsetLeft) + 'px';
	if (options.setTop)    style.top   = (p[1] - delta[1] + options.offsetTop) + 'px';
	if (options.setWidth)  style.width = source.offsetWidth + 'px';
	if (options.setHeight) style.height = source.offsetHeight + 'px';
	return element;
    },

    identify: function() {
	var element = this;
	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;
    },

//---CREDIT--- TableBrain-Public-Domain
    _progress: (window.addProgress ? window.addProgress(5) : 0),

    readAttribute: function(name) {
	if (name === 'title' && this.title) return this.title;
	return this.getAttribute(name);
    },

    observe: function(eventName, handler) {
	if ( ! eventName) alert('Oops... Element.observe() eventName is missing!');
	if ( ! handler) alert('Oops... Element.observe() handler is null!');

	if (typeof eventName != 'string') alert('observe eventName="' + eventName + '"');

	this['on' + eventName] = function(event) {
	    var myEvent = this.normalizeEvent(event);
	    return handler.call(this, myEvent);
	};
	return this;
    },

    stopObserving: function(eventName, handler) {
	this['on' + eventName] = '';
	return this;
    },

    normalizeEvent: function(event) {
	var src = event || window.event;
	var myEvent = {};
	var target = src.target || src.srcElement;
	if (target.nodeType == 3) target = target.parentNode;  // stupid Safari
	myEvent.target = target.nodeType == 1 ? Element.extend(target) : null;
	var which = src.which;
	myEvent.keyCode = src.keyCode || which;
	myEvent.button = 0; // use the Microsoft model - it is the only one that makes any sense
	if (which) {
	    myEvent.button = which <= 1 ? which : (which == 2 ? 4 : 2);
	} else if (src.button) {
	    myEvent.button = src.button;
	}
	myEvent.isRightClick = (myEvent.button == 2);
	myEvent.animationName = src.animationName; // LEON
	if (src.pageX || src.pageY) {
	    myEvent.clientX = src.pageX;
	    myEvent.clientY = src.pageY;
	} else if (src.clientX || src.clientY) {
	    myEvent.clientX = src.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
	    myEvent.clientY = src.clientY + document.body.scrollTop + document.documentElement.scrollTop;
	} else {
	    myEvent.clientX = undefined;
	    myEvent.clientY = undefined;
	}
	myEvent.observee = this;
	return myEvent;
    },

    show: function() {
	//if (display && display.animate) {
	//    BrainEffect.show(this);
	//} else {
	    this.style.display = this._displayAs;
	//}
	return this;
    },

    hide: function() {
	//if (display && display.animate) {
	//    BrainEffect.hide(this);
	//} else {
	    this.style.display = 'none';
	//}
	return this;
    },
    
    addClassName: function(cls) {
    	var origClass = this.className;
    	var newClass = origClass.replace(cls, "");
    	newClass += " " + cls;
    	this.className = newClass;
    },
    removeClassName: function(cls) {
    	var origClass = this.className;
    	var newClass = origClass.replace(cls, "");
    	this.className = newClass;
    },

    getOpacity: function() {
	return this.getStyle('opacity');
    },

    _stuffSet: true
};

//---CREDIT--- Prototype (with fixes by TableBrain-Public-Domain)
if (Prototype.Browser.IE) {
    Element.Methods.getStyle = function(style) {
	var element = this;
	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(value) {
	this.style.filter = 'alpha(opacity=' + (value * 100) + ')';
	return this;
    };
} else {
    Element.Methods.getStyle = function(style) {
	element = this;
	style = style == 'float' ? 'cssFloat' : style.camelize();
	var value = element.style[style];
	if (( ! value) && window.getComputedStyle) {
	    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;
    };
    Element.Methods.setOpacity = function(value) {
	this.style.opacity = value;
	return this;
    };
}

Element._errorCount = 0;
Element.extend = function(element) {
    if (( ! element) || element._stuffSet) return element;
    var display = null;
    try {
	display = element.style.display;
    } catch(e) {
	Element._errorCount++;
	if (Element._errorCount <= 3)
	    alert('Element.extend() element=' + (element ? element.id : '*unknown*') + ', ' + e.message);
    }
    element._displayAs = (display == 'inline' || display == 'block') ? display :
        (TableBrain.elBlocking[element.tagName] ? 'block' : 'inline');
    return Object.extend(element, Element.Methods);
};

Element._returnOffset = function(l, t) {
  var result = [l, t];
  result.left = l;
  result.top = t;
  return result;
};

Object.extend(document, {
  normalizeEvent: Element.Methods.normalizeEvent.methodize(),
  observe:        Element.Methods.observe.methodize(),
  stopObserving:  Element.Methods.stopObserving.methodize()
});

document.viewport = {
    getWidth: function() {
	var B = Prototype.Browser;
	return (B.WebKit && !document.evaluate) ? self['innerWidth'] :
	       (B.Opera) ? document.body['clientWidth'] : document.documentElement['clientWidth'];
    },

    getHeight: function() {
	var B = Prototype.Browser;
	return (B.WebKit && !document.evaluate) ? self['innerHeight'] :
	       (B.Opera) ? document.body['clientHeight'] : document.documentElement['clientHeight'];
    },

    getDimensions: function() {
        return {
	    width: this.getWidth(),
	    height: this.getHeight()
	};
    },

    getScrollOffsets: function() {
	return Element._returnOffset(
	    window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft,
            window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop);
    }
};

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 > 0 ? this.length - 1 : 0)];
    },

    without: function() {
        var values = $A(arguments);
        return this.select(function(value) {
            return !values.include(value);
        });
    }
});

var $break = { };

var Enumerable = {
    each: function(iterator, context) {
        var index = 0;
        iterator = iterator.bind(context);
        try {
            this._each(function(value) {
                iterator(value, index++);
            });
        } catch (e) {
            if (e != $break) throw e;
        }
        return this;
    },

    collect: function(iterator, context) {
        iterator = iterator ? iterator.bind(context) : Prototype.K;
        var results = [];
        this.each(function(value, index) {
            results.push(iterator(value, index));
        });
        return results;
    },

    findAll: function(iterator, context) {
        iterator = iterator.bind(context);
        var results = [];
        this.each(function(value, index) {
            if (iterator(value, index))
            results.push(value);
        });
        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;
    },

    inject: function(memo, iterator, context) {
        iterator = iterator.bind(context);
        this.each(function(value, index) {
            memo = iterator(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);
        });
    }
};

Object.extend(Enumerable, {
    select:  Enumerable.findAll,
    map:     Enumerable.collect,
    member:  Enumerable.include
});

Object.extend(Array.prototype, Enumerable);

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) {
      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);
    },

    toQueryString: function() {
      return this.map(function(pair) {
        var key = encodeURIComponent(pair.key), values = pair.value;

        if (values && typeof values == 'object') {
          if (Object.isArray(values))
            return values.map(toQueryPair.curry(key)).join('&');
        }
        return toQueryPair(key, values);
      }).join('&');
    },

    clone: function() {
      return new Hash(this);
    }
  }
})());

//---CREDIT--- script.aculo.us

var Effect = {
    _elementDoesNotExistError: {
	name: 'ElementDoesNotExistError',
	message: 'The specified DOM element does not exist, but is required for this effect to operate'
    },
    Transitions: {
	linear: function(pos) { return pos; },
	sinoidal: function(pos) {
	    return (-Math.cos(pos*Math.PI)/2) + 0.5;
	},
	reverse: function(pos) {
	    return 1-pos;
	},
	flicker: function(pos) {
	    var pos = ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4;
	    return pos > 1 ? 1 : pos;
	},
	wobble: function(pos) {
	    return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5;
	},
	pulse: function(pos, pulses) { 
	    pulses = pulses || 5; 
	    return (
		    Math.round((pos % (1/pulses)) * pulses) == 0 ? 
		    Math.floor((pos * pulses * 2) - (pos * pulses * 2)) : 
		    1 - ((pos * pulses * 2) - Math.floor(pos * pulses * 2))
		    );
	},
	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;
	}
    }
};

//---CREDIT--- TableBrain-Public-Domain

if (window.addProgress) window.addProgress(5);

TableBrain.initPD();
