﻿var BrowserDetect = {
    init: function() {
        this.browser = this.searchString(this.dataBrowser) || "An unknown browser";
        this.version = this.searchVersion(navigator.userAgent)
|| this.searchVersion(navigator.appVersion)
|| "an unknown version";
        this.OS = this.searchString(this.dataOS) || "an unknown OS";
    },
    searchString: function(data) {
        for (var i = 0; i < data.length; i++) {
            var dataString = data[i].string;
            var dataProp = data[i].prop;
            this.versionSearchString = data[i].versionSearch || data[i].identity;
            if (dataString) {
                if (dataString.indexOf(data[i].subString) != -1)
                    return data[i].identity;
            }
            else if (dataProp)
                return data[i].identity;
        }
    },
    searchVersion: function(dataString) {
        var index = dataString.indexOf(this.versionSearchString);
        if (index == -1) return;
        return parseFloat(dataString.substring(index + this.versionSearchString.length + 1));
    },
    dataBrowser: [
{
    string: navigator.userAgent,
    subString: "Chrome",
    identity: "Chrome"
},
{ string: navigator.userAgent,
    subString: "OmniWeb",
    versionSearch: "OmniWeb/",
    identity: "OmniWeb"
},
{
    string: navigator.vendor,
    subString: "Apple",
    identity: "Safari"
},
{
    prop: window.opera,
    identity: "Opera"
},
{
    string: navigator.vendor,
    subString: "iCab",
    identity: "iCab"
},
{
    string: navigator.vendor,
    subString: "KDE",
    identity: "Konqueror"
},
{
    string: navigator.userAgent,
    subString: "Firefox",
    identity: "Firefox"
},
{
    string: navigator.vendor,
    subString: "Camino",
    identity: "Camino"
},
{		// for newer Netscapes (6+)
    string: navigator.userAgent,
    subString: "Netscape",
    identity: "Netscape"
},
{
    string: navigator.userAgent,
    subString: "MSIE",
    identity: "Explorer",
    versionSearch: "MSIE"
},
{
    string: navigator.userAgent,
    subString: "Gecko",
    identity: "Mozilla",
    versionSearch: "rv"
},
{ 		// for older Netscapes (4-)
    string: navigator.userAgent,
    subString: "Mozilla",
    identity: "Netscape",
    versionSearch: "Mozilla"
}
],
    dataOS: [
{
    string: navigator.platform,
    subString: "Win",
    identity: "Windows"
},
{
    string: navigator.platform,
    subString: "Mac",
    identity: "Mac"
},
{
    string: navigator.platform,
    subString: "Linux",
    identity: "Linux"
}
]
};
/*  Prototype JavaScript framework, version 1.5.0
*  (c) 2005-2007 Sam Stephenson
*
*  Prototype is freely distributable under the terms of an MIT-style license.
*  For details, see the Prototype web site: http://prototype.conio.net/
*
/*--------------------------------------------------------------------------*/
var Prototype = {
    Version: '1.5.0',
    BrowserFeatures: {
        XPath: !!document.evaluate
    },
    ScriptFragment: '(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)',
    emptyFunction: function() { },
    K: function(x) { return x }
}
var Class = {
    create: function() {
        return function() {
            this.initialize.apply(this, arguments);
        }
    }
}
var Abstract = new Object();
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 === undefined) return 'undefined';
            if (object === null) return 'null';
            return object.inspect ? object.inspect() : object.toString();
        } catch (e) {
            if (e instanceof RangeError) return '...';
            throw e;
        }
    },
    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);
    }
});
Function.prototype.bind = function() {
    var __method = this, args = $A(arguments), object = args.shift();
    return function() {
        return __method.apply(object, args.concat($A(arguments)));
    }
}
Function.prototype.bindAsEventListener = function(object) {
    var __method = this, args = $A(arguments), object = args.shift();
    return function(event) {
        return __method.apply(object, [(event || window.event)].concat(args).concat($A(arguments)));
    }
}
Object.extend(Number.prototype, {
    toColorPart: function() {
        var digits = this.toString(16);
        if (this < 16) return '0' + digits;
        return digits;
    },
    succ: function() {
        return this + 1;
    },
    times: function(iterator) {
        $R(0, this, true).each(iterator);
        return this;
    }
});
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;
    }
}
/*--------------------------------------------------------------------------*/
var PeriodicalExecuter = Class.create();
PeriodicalExecuter.prototype = {
    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);
    },
    stop: function() {
        if (!this.timer) return;
        clearInterval(this.timer);
        this.timer = null;
    },
    onTimerEvent: function() {
        if (!this.currentlyExecuting) {
            try {
                this.currentlyExecuting = true;
                this.callback(this);
            } finally {
                this.currentlyExecuting = false;
            }
        }
    }
}
String.interpret = function(value) {
    return value == null ? '' : String(value);
}
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 = count === undefined ? 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 this;
    },
    truncate: function(length, truncation) {
        length = length || 30;
        truncation = truncation === undefined ? '...' : truncation;
        return this.length > length ?
this.slice(0, length - truncation.length) + truncation : 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 div = document.createElement('div');
        var text = document.createTextNode(this);
        div.appendChild(text);
        return div.innerHTML;
    },
    unescapeHTML: function() {
        var div = document.createElement('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 name = decodeURIComponent(pair[0]);
                var value = pair[1] ? decodeURIComponent(pair[1]) : undefined;
                if (hash[name] !== undefined) {
                    if (hash[name].constructor != Array)
                        hash[name] = [hash[name]];
                    if (value) hash[name].push(value);
                }
                else hash[name] = 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);
    },
    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.replace(/\\/g, '\\\\');
        if (useDoubleQuotes)
            return '"' + escapedString.replace(/"/g, '\\"') + '"';
        else
            return "'" + escapedString.replace(/'/g, '\\\'') + "'";
    }
});
String.prototype.gsub.prepareReplacement = function(replacement) {
    if (typeof replacement == 'function') return replacement;
    var template = new Template(replacement);
    return function(match) { return template.evaluate(match) };
}
String.prototype.parseQuery = String.prototype.toQueryParams;
var Template = Class.create();
Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
Template.prototype = {
    initialize: function(template, pattern) {
        this.template = template.toString();
        this.pattern = pattern || Template.Pattern;
    },
    evaluate: function(object) {
        return this.template.gsub(this.pattern, function(match) {
            var before = match[1];
            if (before == '\\') return match[2];
            return before + String.interpret(object[match[3]]);
        });
    }
}
var $break = new Object();
var $continue = new Object();
var Enumerable = {
    each: function(iterator) {
        var index = 0;
        try {
            this._each(function(value) {
                try {
                    iterator(value, index++);
                } catch (e) {
                    if (e != $continue) throw e;
                }
            });
        } catch (e) {
            if (e != $break) throw e;
        }
        return this;
    },
    eachSlice: function(number, iterator) {
        var index = -number, slices = [], array = this.toArray();
        while ((index += number) < array.length)
            slices.push(array.slice(index, index + number));
        return slices.map(iterator);
    },
    all: function(iterator) {
        var result = true;
        this.each(function(value, index) {
            result = result && !!(iterator || Prototype.K)(value, index);
            if (!result) throw $break;
        });
        return result;
    },
    any: function(iterator) {
        var result = false;
        this.each(function(value, index) {
            if (result = !!(iterator || Prototype.K)(value, index))
                throw $break;
        });
        return result;
    },
    collect: function(iterator) {
        var results = [];
        this.each(function(value, index) {
            results.push((iterator || Prototype.K)(value, index));
        });
        return results;
    },
    detect: function(iterator) {
        var result;
        this.each(function(value, index) {
            if (iterator(value, index)) {
                result = value;
                throw $break;
            }
        });
        return result;
    },
    findAll: function(iterator) {
        var results = [];
        this.each(function(value, index) {
            if (iterator(value, index))
                results.push(value);
        });
        return results;
    },
    grep: function(pattern, iterator) {
        var results = [];
        this.each(function(value, index) {
            var stringValue = value.toString();
            if (stringValue.match(pattern))
                results.push((iterator || Prototype.K)(value, index));
        })
        return results;
    },
    include: function(object) {
        var found = false;
        this.each(function(value) {
            if (value == object) {
                found = true;
                throw $break;
            }
        });
        return found;
    },
    inGroupsOf: function(number, fillWith) {
        fillWith = fillWith === undefined ? null : fillWith;
        return this.eachSlice(number, function(slice) {
            while (slice.length < number) slice.push(fillWith);
            return slice;
        });
    },
    inject: function(memo, iterator) {
        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);
        });
    },
    max: function(iterator) {
        var result;
        this.each(function(value, index) {
            value = (iterator || Prototype.K)(value, index);
            if (result == undefined || value >= result)
                result = value;
        });
        return result;
    },
    min: function(iterator) {
        var result;
        this.each(function(value, index) {
            value = (iterator || Prototype.K)(value, index);
            if (result == undefined || value < result)
                result = value;
        });
        return result;
    },
    partition: function(iterator) {
        var trues = [], falses = [];
        this.each(function(value, index) {
            ((iterator || Prototype.K)(value, index) ?
trues : falses).push(value);
        });
        return [trues, falses];
    },
    pluck: function(property) {
        var results = [];
        this.each(function(value, index) {
            results.push(value[property]);
        });
        return results;
    },
    reject: function(iterator) {
        var results = [];
        this.each(function(value, index) {
            if (!iterator(value, index))
                results.push(value);
        });
        return results;
    },
    sortBy: function(iterator) {
        return this.map(function(value, index) {
            return { value: value, criteria: iterator(value, index) };
        }).sort(function(left, right) {
            var a = left.criteria, b = right.criteria;
            return a < b ? -1 : a > b ? 1 : 0;
        }).pluck('value');
    },
    toArray: function() {
        return this.map();
    },
    zip: function() {
        var iterator = Prototype.K, args = $A(arguments);
        if (typeof args.last() == 'function')
            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,
    member: Enumerable.include,
    entries: Enumerable.toArray
});
var $A = Array.from = function(iterable) {
    if (!iterable) return [];
    if (iterable.toArray) {
        return iterable.toArray();
    } else {
        var results = [];
        for (var i = 0, length = iterable.length; i < length; i++)
            results.push(iterable[i]);
        return results;
    }
}
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(value && value.constructor == Array ?
value.flatten() : [value]);
        });
    },
    without: function() {
        var values = $A(arguments);
        return this.select(function(value) {
            return !values.include(value);
        });
    },
    indexOf: function(object) {
        for (var i = 0, length = this.length; i < length; i++)
            if (this[i] == object) return i;
        return -1;
    },
    reverse: function(inline) {
        return (inline !== false ? this : this.toArray())._reverse();
    },
    reduce: function() {
        return this.length > 1 ? this : this[0];
    },
    uniq: function() {
        return this.inject([], function(array, value) {
            return array.include(value) ? array : array.concat([value]);
        });
    },
    clone: function() {
        return [].concat(this);
    },
    size: function() {
        return this.length;
    },
    inspect: function() {
        return '[' + this.map(Object.inspect).join(', ') + ']';
    }
});
Array.prototype.toArray = Array.prototype.clone;
function $w(string) {
    string = string.strip();
    return string ? string.split(/\s+/) : [];
}
if (window.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 (arguments[i].constructor == Array) {
                for (var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++)
                    array.push(arguments[i][j]);
            } else {
                array.push(arguments[i]);
            }
        }
        return array;
    }
}
var Hash = function(obj) {
    Object.extend(this, obj || {});
};
Object.extend(Hash, {
    toQueryString: function(obj) {
        var parts = [];
        this.prototype._each.call(obj, function(pair) {
            if (!pair.key) return;
            if (pair.value && pair.value.constructor == Array) {
                var values = pair.value.compact();
                if (values.length < 2) pair.value = values.reduce();
                else {
                    key = encodeURIComponent(pair.key);
                    values.each(function(value) {
                        value = value != undefined ? encodeURIComponent(value) : '';
                        parts.push(key + '=' + encodeURIComponent(value));
                    });
                    return;
                }
            }
            if (pair.value == undefined) pair[1] = '';
            parts.push(pair.map(encodeURIComponent).join('='));
        });
        return parts.join('&');
    }
});
Object.extend(Hash.prototype, Enumerable);
Object.extend(Hash.prototype, {
    _each: function(iterator) {
        for (var key in this) {
            var value = this[key];
            if (value && value == Hash.prototype[key]) continue;
            var pair = [key, value];
            pair.key = key;
            pair.value = value;
            iterator(pair);
        }
    },
    keys: function() {
        return this.pluck('key');
    },
    values: function() {
        return this.pluck('value');
    },
    merge: function(hash) {
        return $H(hash).inject(this, function(mergedHash, pair) {
            mergedHash[pair.key] = pair.value;
            return mergedHash;
        });
    },
    remove: function() {
        var result;
        for (var i = 0, length = arguments.length; i < length; i++) {
            var value = this[arguments[i]];
            if (value !== undefined) {
                if (result === undefined) result = value;
                else {
                    if (result.constructor != Array) result = [result];
                    result.push(value)
                }
            }
            delete this[arguments[i]];
        }
        return result;
    },
    toQueryString: function() {
        return Hash.toQueryString(this);
    },
    inspect: function() {
        return '#<Hash:{' + this.map(function(pair) {
            return pair.map(Object.inspect).join(': ');
        }).join(', ') + '}>';
    }
});
function $H(object) {
    if (object && object.constructor == Hash) return object;
    return new Hash(object);
};
ObjectRange = Class.create();
Object.extend(ObjectRange.prototype, Enumerable);
Object.extend(ObjectRange.prototype, {
    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 (typeof responder[callback] == 'function') {
                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 = function() { };
Ajax.Base.prototype = {
    setOptions: function(options) {
        this.options = {
            method: 'post',
            asynchronous: true,
            contentType: 'application/x-www-form-urlencoded',
            encoding: 'UTF-8',
            parameters: ''
        }
        Object.extend(this.options, options || {});
        this.options.method = this.options.method.toLowerCase();
        if (typeof this.options.parameters == 'string')
            this.options.parameters = this.options.parameters.toQueryParams();
    }
}
Ajax.Request = Class.create();
Ajax.Request.Events =
['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
    _complete: false,
    initialize: function(url, options) {
        this.transport = Ajax.getTransport();
        this.setOptions(options);
        this.request(url);
    },
    request: function(url) {
        this.url = url;
        this.method = this.options.method;
        var params = this.options.parameters;
        if (!['get', 'post'].include(this.method)) {
            // simulate other verbs over post
            params['_method'] = this.method;
            this.method = 'post';
        }
        params = Hash.toQueryString(params);
        if (params && /Konqueror|Safari|KHTML/.test(navigator.userAgent)) params += '&_='
        // when GET, append parameters to URL
        if (this.method == 'get' && params)
            this.url += (this.url.indexOf('?') > -1 ? '&' : '?') + params;
        try {
            Ajax.Responders.dispatch('onCreate', this, this.transport);
            this.transport.open(this.method.toUpperCase(), this.url,
this.options.asynchronous);
            if (this.options.asynchronous)
                setTimeout(function() { this.respondToReadyState(1) } .bind(this), 10);
            this.transport.onreadystatechange = this.onStateChange.bind(this);
            this.setRequestHeaders();
            var body = this.method == 'post' ? (this.options.postBody || params) : null;
            this.transport.send(body);
            /* Force Firefox to handle ready state 4 for synchronous requests */
            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 : '');
            /* Force "Connection: close" for older Mozilla browsers to work
            * around a bug where XMLHttpRequest sends an incorrect
            * Content-length header. See Mozilla Bugzilla #246651.
            */
            if (this.transport.overrideMimeType &&
(navigator.userAgent.match(/Gecko\/(\d{4})/) || [0, 2005])[1] < 2005)
                headers['Connection'] = 'close';
        }
        // user-defined headers
        if (typeof this.options.requestHeaders == 'object') {
            var extras = this.options.requestHeaders;
            if (typeof extras.push == 'function')
                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() {
        return !this.transport.status
|| (this.transport.status >= 200 && this.transport.status < 300);
    },
    respondToReadyState: function(readyState) {
        var state = Ajax.Request.Events[readyState];
        var transport = this.transport, json = this.evalJSON();
        if (state == 'Complete') {
            try {
                this._complete = true;
                (this.options['on' + this.transport.status]
|| this.options['on' + (this.success() ? 'Success' : 'Failure')]
|| Prototype.emptyFunction)(transport, json);
            } catch (e) {
                this.dispatchException(e);
            }
            if ((this.getHeader('Content-type') || 'text/javascript').strip().
match(/^(text|application)\/(x-)?(java|ecma)script(;.*)?$/i))
                this.evalResponse();
        }
        try {
            (this.options['on' + state] || Prototype.emptyFunction)(transport, json);
            Ajax.Responders.dispatch('on' + state, this, transport, json);
        } catch (e) {
            this.dispatchException(e);
        }
        if (state == 'Complete') {
            // avoid memory leak in MSIE: clean up
            this.transport.onreadystatechange = Prototype.emptyFunction;
        }
    },
    getHeader: function(name) {
        try {
            return this.transport.getResponseHeader(name);
        } catch (e) { return null }
    },
    evalJSON: function() {
        try {
            var json = this.getHeader('X-JSON');
            return json ? eval('(' + json + ')') : null;
        } catch (e) { return null }
    },
    evalResponse: function() {
        try {
            return eval(this.transport.responseText);
        } catch (e) {
            this.dispatchException(e);
        }
    },
    dispatchException: function(exception) {
        (this.options.onException || Prototype.emptyFunction)(this, exception);
        Ajax.Responders.dispatch('onException', this, exception);
    }
});
Ajax.Updater = Class.create();
Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {
    initialize: function(container, url, options) {
        this.container = {
            success: (container.success || container),
            failure: (container.failure || (container.success ? null : container))
        }
        this.transport = Ajax.getTransport();
        this.setOptions(options);
        var onComplete = this.options.onComplete || Prototype.emptyFunction;
        this.options.onComplete = (function(transport, param) {
            this.updateContent();
            onComplete(transport, param);
        }).bind(this);
        this.request(url);
    },
    updateContent: function() {
        var receiver = this.container[this.success() ? 'success' : 'failure'];
        var response = this.transport.responseText;
        if (!this.options.evalScripts) response = response.stripScripts();
        if (receiver = $(receiver)) {
            if (this.options.insertion)
                new this.options.insertion(receiver, response);
            else
                receiver.update(response);
        }
        if (this.success()) {
            if (this.onComplete)
                setTimeout(this.onComplete.bind(this), 10);
        }
    }
});
Ajax.PeriodicalUpdater = Class.create();
Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), {
    initialize: function(container, url, options) {
        this.setOptions(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(request) {
        if (this.options.decay) {
            this.decay = (request.responseText == this.lastText ?
this.decay * this.options.decay : 1);
            this.lastText = request.responseText;
        }
        this.timer = setTimeout(this.onTimerEvent.bind(this),
this.decay * this.frequency * 1000);
    },
    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 (typeof element == 'string')
        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(query.snapshotItem(i));
        return results;
    };
}
document.getElementsByClassName = function(className, parentElement) {
    if (Prototype.BrowserFeatures.XPath) {
        var q = ".//*[contains(concat(' ', @class, ' '), ' " + className + " ')]";
        return document._getElementsByXPath(q, parentElement);
    } else {
        var children = ($(parentElement) || document.body).getElementsByTagName('*');
        var elements = [], child;
        for (var i = 0, length = children.length; i < length; i++) {
            child = children[i];
            if (Element.hasClassName(child, className))
                elements.push(Element.extend(child));
        }
        return elements;
    }
};
/*--------------------------------------------------------------------------*/
if (!window.Element)
    var Element = new Object();
Element.extend = function(element) {
    if (!element || _nativeExtensions || element.nodeType == 3) return element;
    if (!element._extended && element.tagName && element != window) {
        var methods = Object.clone(Element.Methods), cache = Element.extend.cache;
        if (element.tagName == 'FORM')
            Object.extend(methods, Form.Methods);
        if (['INPUT', 'TEXTAREA', 'SELECT'].include(element.tagName))
            Object.extend(methods, Form.Element.Methods);
        Object.extend(methods, Element.Methods.Simulated);
        for (var property in methods) {
            var value = methods[property];
            if (typeof value == 'function' && !(property in element))
                element[property] = cache.findOrStore(value);
        }
    }
    element._extended = true;
    return element;
};
Element.extend.cache = {
    findOrStore: function(value) {
        return this[value] = this[value] || function() {
            return value.apply(null, [this].concat($A(arguments)));
        }
    }
};
Element.Methods = {
    visible: function(element) {
        return $(element).style.display != 'none';
    },
    toggle: function(element) {
        element = $(element);
        Element[Element.visible(element) ? 'hide' : 'show'](element);
        return element;
    },
    hide: function(element) {
        $(element).style.display = 'none';
        return element;
    },
    show: function(element) {
        if (element.style) {
            $(element).style.display = '';
        }
        return element;
    },
    remove: function(element) {
        element = $(element);
        element.parentNode.removeChild(element);
        return element;
    },
    update: function(element, html) {
        html = typeof html == 'undefined' ? '' : html.toString();
        $(element).innerHTML = html.stripScripts();
        setTimeout(function() { html.evalScripts() }, 10);
        return element;
    },
    replace: function(element, html) {
        element = $(element);
        html = typeof html == 'undefined' ? '' : html.toString();
        if (element.outerHTML) {
            element.outerHTML = html.stripScripts();
        } else {
            var range = element.ownerDocument.createRange();
            range.selectNodeContents(element);
            element.parentNode.replaceChild(
range.createContextualFragment(html.stripScripts()), element);
        }
        setTimeout(function() { html.evalScripts() }, 10);
        return element;
    },
    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 $A($(element).getElementsByTagName('*'));
    },
    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 (typeof selector == 'string')
            selector = new Selector(selector);
        return selector.match($(element));
    },
    up: function(element, expression, index) {
        return Selector.findElement($(element).ancestors(), expression, index);
    },
    down: function(element, expression, index) {
        return Selector.findElement($(element).descendants(), expression, index);
    },
    previous: function(element, expression, index) {
        return Selector.findElement($(element).previousSiblings(), expression, index);
    },
    next: function(element, expression, index) {
        return Selector.findElement($(element).nextSiblings(), expression, index);
    },
    getElementsBySelector: function() {
        var args = $A(arguments), element = $(args.shift());
        return Selector.findChildElements(element, args);
    },
    getElementsByClassName: function(element, className) {
        return document.getElementsByClassName(className, element);
    },
    readAttribute: function(element, name) {
        element = $(element);
        if (document.all && !window.opera) {
            var t = Element._attributeTranslations;
            if (t.values[name]) return t.values[name](element, name);
            if (t.names[name]) name = t.names[name];
            var attribute = element.attributes[name];
            if (attribute) return attribute.nodeValue;
        }
        return element.getAttribute(name);
    },
    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;
        if (elementClassName.length == 0) return false;
        if (elementClassName == className ||
elementClassName.match(new RegExp("(^|\\s)" + className + "(\\s|$)")))
            return true;
        return false;
    },
    addClassName: function(element, className) {
        if (!(element = $(element))) return;
        Element.classNames(element).add(className);
        return element;
    },
    removeClassName: function(element, className) {
        if (!(element = $(element))) return;
        Element.classNames(element).remove(className);
        return element;
    },
    toggleClassName: function(element, className) {
        if (!(element = $(element))) return;
        Element.classNames(element)[element.hasClassName(className) ? 'remove' : 'add'](className);
        return element;
    },
    observe: function() {
        Event.observe.apply(Event, arguments);
        return $A(arguments).first();
    },
    stopObserving: function() {
        Event.stopObserving.apply(Event, arguments);
        return $A(arguments).first();
    },
    // removes whitespace-only text node children
    cleanWhitespace: function(element) {
        element = $(element);
        var node = element.firstChild;
        while (node) {
            var nextNode = node.nextSibling;
            if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
                element.removeChild(node);
            node = nextNode;
        }
        return element;
    },
    empty: function(element) {
        return $(element).innerHTML.match(/^\s*$/);
    },
    descendantOf: function(element, ancestor) {
        element = $(element), ancestor = $(ancestor);
        while (element = element.parentNode)
            if (element == ancestor) return true;
        return false;
    },
    scrollTo: function(element) {
        element = $(element);
        var pos = Position.cumulativeOffset(element);
        window.scrollTo(pos[0], pos[1]);
        return element;
    },
    getStyle: function(element, style) {
        element = $(element);
        if (['float', 'cssFloat'].include(style))
            style = (typeof element.style.styleFloat != 'undefined' ? 'styleFloat' : 'cssFloat');
        style = style.camelize();
        var value = element.style[style];
        if (!value) {
            if (document.defaultView && document.defaultView.getComputedStyle) {
                var css = document.defaultView.getComputedStyle(element, null);
                value = css ? css[style] : null;
            } else if (element.currentStyle) {
                value = element.currentStyle[style];
            }
        }
        if ((value == 'auto') && ['width', 'height'].include(style) && (element.getStyle('display') != 'none'))
            value = element['offset' + style.capitalize()] + 'px';
        if (window.opera && ['left', 'top', 'right', 'bottom'].include(style))
            if (Element.getStyle(element, 'position') == 'static') value = 'auto';
        if (style == 'opacity') {
            if (value) return parseFloat(value);
            if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/))
                if (value[1]) return parseFloat(value[1]) / 100;
            return 1.0;
        }
        return value == 'auto' ? null : value;
    },
    setStyle: function(element, style) {
        element = $(element);
        for (var name in style) {
            var value = style[name];
            if (name == 'opacity') {
                if (value == 1) {
                    value = (/Gecko/.test(navigator.userAgent) &&
!/Konqueror|Safari|KHTML/.test(navigator.userAgent)) ? 0.999999 : 1.0;
                    if (/MSIE/.test(navigator.userAgent) && !window.opera)
                        element.style.filter = element.getStyle('filter').replace(/alpha\([^\)]*\)/gi, '');
                } else if (value == '') {
                    if (/MSIE/.test(navigator.userAgent) && !window.opera)
                        element.style.filter = element.getStyle('filter').replace(/alpha\([^\)]*\)/gi, '');
                } else {
                    if (value < 0.00001) value = 0;
                    if (/MSIE/.test(navigator.userAgent) && !window.opera)
                        element.style.filter = element.getStyle('filter').replace(/alpha\([^\)]*\)/gi, '') +
'alpha(opacity=' + value * 100 + ')';
                }
            } else if (['float', 'cssFloat'].include(name)) name = (typeof element.style.styleFloat != 'undefined') ? 'styleFloat' : 'cssFloat';
            element.style[name.camelize()] = value;
        }
        return element;
    },
    getDimensions: function(element) {
        element = $(element);
        var display = $(element).getStyle('display');
        if (display != 'none' && display != null) // Safari bug
            return { width: element.offsetWidth, height: element.offsetHeight };
        // All *Width and *Height properties give 0 on elements with display none,
        // so enable the element temporarily
        var els = element.style;
        var originalVisibility = els.visibility;
        var originalPosition = els.position;
        var originalDisplay = els.display;
        els.visibility = 'hidden';
        els.position = 'absolute';
        els.display = 'block';
        var originalWidth = element.clientWidth;
        var originalHeight = element.clientHeight;
        els.display = originalDisplay;
        els.position = originalPosition;
        els.visibility = originalVisibility;
        return { width: originalWidth, height: originalHeight };
    },
    makePositioned: function(element) {
        element = $(element);
        var pos = Element.getStyle(element, 'position');
        if (pos == 'static' || !pos) {
            element._madePositioned = true;
            element.style.position = 'relative';
            // Opera returns the offset relative to the positioning context, when an
            // element is position relative but top and left have not been defined
            if (window.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.style.overflow || 'auto';
        if ((Element.getStyle(element, 'overflow') || 'visible') != '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;
    }
};
Object.extend(Element.Methods, { childOf: Element.Methods.descendantOf });
Element._attributeTranslations = {};
Element._attributeTranslations.names = {
    colspan: "colSpan",
    rowspan: "rowSpan",
    valign: "vAlign",
    datetime: "dateTime",
    accesskey: "accessKey",
    tabindex: "tabIndex",
    enctype: "encType",
    maxlength: "maxLength",
    readonly: "readOnly",
    longdesc: "longDesc"
};
Element._attributeTranslations.values = {
    _getAttr: function(element, attribute) {
        return element.getAttribute(attribute, 2);
    },
    _flag: function(element, attribute) {
        return $(element).hasAttribute(attribute) ? attribute : null;
    },
    style: function(element) {
        return element.style.cssText.toLowerCase();
    },
    title: function(element) {
        var node = element.getAttributeNode('title');
        return node.specified ? node.nodeValue : null;
    }
};
Object.extend(Element._attributeTranslations.values, {
    href: Element._attributeTranslations.values._getAttr,
    src: Element._attributeTranslations.values._getAttr,
    disabled: Element._attributeTranslations.values._flag,
    checked: Element._attributeTranslations.values._flag,
    readonly: Element._attributeTranslations.values._flag,
    multiple: Element._attributeTranslations.values._flag
});
Element.Methods.Simulated = {
    hasAttribute: function(element, attribute) {
        var t = Element._attributeTranslations;
        attribute = t.names[attribute] || attribute;
        return $(element).getAttributeNode(attribute).specified;
    }
};
// IE is missing .innerHTML support for TABLE-related elements
if (document.all && !window.opera) {
    Element.Methods.update = function(element, html) {
        element = $(element);
        html = typeof html == 'undefined' ? '' : html.toString();
        var tagName = element.tagName.toUpperCase();
        if (['THEAD', 'TBODY', 'TR', 'TD'].include(tagName)) {
            var div = document.createElement('div');
            switch (tagName) {
                case 'THEAD':
                case 'TBODY':
                    div.innerHTML = '<table><tbody>' + html.stripScripts() + '</tbody></table>';
                    depth = 2;
                    break;
                case 'TR':
                    div.innerHTML = '<table><tbody><tr>' + html.stripScripts() + '</tr></tbody></table>';
                    depth = 3;
                    break;
                case 'TD':
                    div.innerHTML = '<table><tbody><tr><td>' + html.stripScripts() + '</td></tr></tbody></table>';
                    depth = 4;
            }
            $A(element.childNodes).each(function(node) {
                element.removeChild(node)
            });
            depth.times(function() { div = div.firstChild });
            $A(div.childNodes).each(
function(node) { element.appendChild(node) });
        } else {
            element.innerHTML = html.stripScripts();
        }
        setTimeout(function() { html.evalScripts() }, 10);
        return element;
    }
};
Object.extend(Element, Element.Methods);
var _nativeExtensions = false;
if (/Konqueror|Safari|KHTML/.test(navigator.userAgent))
    ['', 'Form', 'Input', 'TextArea', 'Select'].each(function(tag) {
        var className = 'HTML' + tag + 'Element';
        if (window[className]) return;
        var klass = window[className] = {};
        klass.prototype = document.createElement(tag ? tag.toLowerCase() : 'div').__proto__;
    });
Element.addMethods = function(methods) {
    Object.extend(Element.Methods, methods || {});
    function copy(methods, destination, onlyIfAbsent) {
        onlyIfAbsent = onlyIfAbsent || false;
        var cache = Element.extend.cache;
        for (var property in methods) {
            var value = methods[property];
            if (!onlyIfAbsent || !(property in destination))
                destination[property] = cache.findOrStore(value);
        }
    }
    if (typeof HTMLElement != 'undefined') {
        copy(Element.Methods, HTMLElement.prototype);
        copy(Element.Methods.Simulated, HTMLElement.prototype, true);
        copy(Form.Methods, HTMLFormElement.prototype);
        [HTMLInputElement, HTMLTextAreaElement, HTMLSelectElement].each(function(klass) {
            copy(Form.Element.Methods, klass.prototype);
        });
        _nativeExtensions = true;
    }
}
var Toggle = new Object();
Toggle.display = Element.toggle;
/*--------------------------------------------------------------------------*/
Abstract.Insertion = function(adjacency) {
    this.adjacency = adjacency;
}
Abstract.Insertion.prototype = {
    initialize: function(element, content) {
        this.element = $(element);
        this.content = content.stripScripts();
        if (this.adjacency && this.element.insertAdjacentHTML) {
            try {
                this.element.insertAdjacentHTML(this.adjacency, this.content);
            } catch (e) {
                var tagName = this.element.tagName.toUpperCase();
                if (['TBODY', 'TR'].include(tagName)) {
                    this.insertContent(this.contentFromAnonymousTable());
                } else {
                    throw e;
                }
            }
        } else {
            this.range = this.element.ownerDocument.createRange();
            if (this.initializeRange) this.initializeRange();
            this.insertContent([this.range.createContextualFragment(this.content)]);
        }
        setTimeout(function() { content.evalScripts() }, 10);
    },
    contentFromAnonymousTable: function() {
        var div = document.createElement('div');
        div.innerHTML = '<table><tbody>' + this.content + '</tbody></table>';
        return $A(div.childNodes[0].childNodes[0].childNodes);
    }
}
var Insertion = new Object();
Insertion.Before = Class.create();
Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), {
    initializeRange: function() {
        this.range.setStartBefore(this.element);
    },
    insertContent: function(fragments) {
        fragments.each((function(fragment) {
            this.element.parentNode.insertBefore(fragment, this.element);
        }).bind(this));
    }
});
Insertion.Top = Class.create();
Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), {
    initializeRange: function() {
        this.range.selectNodeContents(this.element);
        this.range.collapse(true);
    },
    insertContent: function(fragments) {
        fragments.reverse(false).each((function(fragment) {
            this.element.insertBefore(fragment, this.element.firstChild);
        }).bind(this));
    }
});
Insertion.Bottom = Class.create();
Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), {
    initializeRange: function() {
        this.range.selectNodeContents(this.element);
        this.range.collapse(this.element);
    },
    insertContent: function(fragments) {
        fragments.each((function(fragment) {
            this.element.appendChild(fragment);
        }).bind(this));
    }
});
Insertion.After = Class.create();
Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), {
    initializeRange: function() {
        this.range.setStartAfter(this.element);
    },
    insertContent: function(fragments) {
        fragments.each((function(fragment) {
            this.element.parentNode.insertBefore(fragment,
this.element.nextSibling);
        }).bind(this));
    }
});
/*--------------------------------------------------------------------------*/
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);
var Selector = Class.create();
Selector.prototype = {
    initialize: function(expression) {
        this.params = { classNames: [] };
        this.expression = expression.toString().strip();
        this.parseExpression();
        this.compileMatcher();
    },
    parseExpression: function() {
        function abort(message) { throw 'Parse error in selector: ' + message; }
        if (this.expression == '') abort('empty expression');
        var params = this.params, expr = this.expression, match, modifier, clause, rest;
        while (match = expr.match(/^(.*)\[([a-z0-9_:-]+?)(?:([~\|!]?=)(?:"([^"]*)"|([^\]\s]*)))?\]$/i)) {
            params.attributes = params.attributes || [];
            params.attributes.push({ name: match[2], operator: match[3], value: match[4] || match[5] || '' });
            expr = match[1];
        }
        if (expr == '*') return this.params.wildcard = true;
        while (match = expr.match(/^([^a-z0-9_-])?([a-z0-9_-]+)(.*)/i)) {
            modifier = match[1], clause = match[2], rest = match[3];
            switch (modifier) {
                case '#': params.id = clause; break;
                case '.': params.classNames.push(clause); break;
                case '':
                case undefined: params.tagName = clause.toUpperCase(); break;
                default: abort(expr.inspect());
            }
            expr = rest;
        }
        if (expr.length > 0) abort(expr.inspect());
    },
    buildMatchExpression: function() {
        var params = this.params, conditions = [], clause;
        if (params.wildcard)
            conditions.push('true');
        if (clause = params.id)
            conditions.push('element.readAttribute("id") == ' + clause.inspect());
        if (clause = params.tagName)
            conditions.push('element.tagName.toUpperCase() == ' + clause.inspect());
        if ((clause = params.classNames).length > 0)
            for (var i = 0, length = clause.length; i < length; i++)
            conditions.push('element.hasClassName(' + clause[i].inspect() + ')');
        if (clause = params.attributes) {
            clause.each(function(attribute) {
                var value = 'element.readAttribute(' + attribute.name.inspect() + ')';
                var splitValueBy = function(delimiter) {
                    return value + ' && ' + value + '.split(' + delimiter.inspect() + ')';
                }
                switch (attribute.operator) {
                    case '=': conditions.push(value + ' == ' + attribute.value.inspect()); break;
                    case '~=': conditions.push(splitValueBy(' ') + '.include(' + attribute.value.inspect() + ')'); break;
                    case '|=': conditions.push(
splitValueBy('-') + '.first().toUpperCase() == ' + attribute.value.toUpperCase().inspect()
); break;
                    case '!=': conditions.push(value + ' != ' + attribute.value.inspect()); break;
                    case '':
                    case undefined: conditions.push('element.hasAttribute(' + attribute.name.inspect() + ')'); break;
                    default: throw 'Unknown operator ' + attribute.operator + ' in selector';
                }
            });
        }
        return conditions.join(' && ');
    },
    compileMatcher: function() {
        this.match = new Function('element', 'if (!element.tagName) return false; \
element = $(element); \
return ' + this.buildMatchExpression());
    },
    findElements: function(scope) {
        var element;
        if (element = $(this.params.id))
            if (this.match(element))
            if (!scope || Element.childOf(element, scope))
            return [element];
        scope = (scope || document).getElementsByTagName(this.params.tagName || '*');
        var results = [];
        for (var i = 0, length = scope.length; i < length; i++)
            if (this.match(element = scope[i]))
            results.push(Element.extend(element));
        return results;
    },
    toString: function() {
        return this.expression;
    }
}
Object.extend(Selector, {
    matchElements: function(elements, expression) {
        var selector = new Selector(expression);
        return elements.select(selector.match.bind(selector)).map(Element.extend);
    },
    findElement: function(elements, expression, index) {
        if (typeof expression == 'number') index = expression, expression = false;
        return Selector.matchElements(elements, expression || '*')[index || 0];
    },
    findChildElements: function(element, expressions) {
        return expressions.map(function(expression) {
            return expression.match(/[^\s"]+(?:"[^"]*"[^\s"]+)*/g).inject([null], function(results, expr) {
                var selector = new Selector(expr);
                return results.inject([], function(elements, result) {
                    return elements.concat(selector.findElements(result || element));
                });
            });
        }).flatten();
    }
});
function $$() {
    return Selector.findChildElements(document, $A(arguments));
}
var Form = {
    reset: function(form) {
        $(form).reset();
        return form;
    },
    serializeElements: function(elements, getHash) {
        var data = elements.inject({}, function(result, element) {
            if (!element.disabled && element.name) {
                var key = element.name, value = $(element).getValue();
                if (value != undefined) {
                    if (result[key]) {
                        if (result[key].constructor != Array) result[key] = [result[key]];
                        result[key].push(value);
                    }
                    else result[key] = value;
                }
            }
            return result;
        });
        return getHash ? data : Hash.toQueryString(data);
    }
};
Form.Methods = {
    serialize: function(form, getHash) {
        return Form.serializeElements(Form.getElements(form), getHash);
    },
    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().each(function(element) {
            element.blur();
            element.disabled = 'true';
        });
        return form;
    },
    enable: function(form) {
        form = $(form);
        form.getElements().each(function(element) {
            element.disabled = '';
        });
        return form;
    },
    findFirstElement: function(form) {
        return $(form).getElements().find(function(element) {
            return element.type != 'hidden' && !element.disabled &&
['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
        });
    },
    focusFirstElement: function(form) {
        form = $(form);
        form.findFirstElement().activate();
        return form;
    }
}
Object.extend(Form, Form.Methods);
/*--------------------------------------------------------------------------*/
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 Hash.toQueryString(pair);
            }
        }
        return '';
    },
    getValue: function(element) {
        element = $(element);
        var method = element.tagName.toLowerCase();
        return Form.Element.Serializers[method](element);
    },
    clear: function(element) {
        $(element).value = '';
        return element;
    },
    present: function(element) {
        return $(element).value != '';
    },
    activate: function(element) {
        element = $(element);
        element.focus();
        if (element.select && (element.tagName.toLowerCase() != 'input' ||
!['button', 'reset', 'submit'].include(element.type)))
            element.select();
        return element;
    },
    disable: function(element) {
        element = $(element);
        element.disabled = true;
        return element;
    },
    enable: function(element) {
        element = $(element);
        element.blur();
        element.disabled = false;
        return element;
    }
}
Object.extend(Form.Element, Form.Element.Methods);
var Field = Form.Element;
var $F = Form.Element.getValue;
/*--------------------------------------------------------------------------*/
Form.Element.Serializers = {
    input: function(element) {
        switch (element.type.toLowerCase()) {
            case 'checkbox':
            case 'radio':
                return Form.Element.Serializers.inputSelector(element);
            default:
                return Form.Element.Serializers.textarea(element);
        }
    },
    inputSelector: function(element) {
        return element.checked ? element.value : null;
    },
    textarea: function(element) {
        return element.value;
    },
    select: function(element) {
        return this[element.type == 'select-one' ?
'selectOne' : 'selectMany'](element);
    },
    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) {
        // extend element because hasAttribute may not be native
        return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text;
    }
}
/*--------------------------------------------------------------------------*/
Abstract.TimedObserver = function() { }
Abstract.TimedObserver.prototype = {
    initialize: function(element, frequency, callback) {
        this.frequency = frequency;
        this.element = $(element);
        this.callback = callback;
        this.lastValue = this.getValue();
        this.registerCallback();
    },
    registerCallback: function() {
        setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
    },
    onTimerEvent: function() {
        var value = this.getValue();
        var changed = ('string' == typeof this.lastValue && 'string' == typeof value
? this.lastValue != value : String(this.lastValue) != String(value));
        if (changed) {
            this.callback(this.element, value);
            this.lastValue = value;
        }
    }
}
Form.Element.Observer = Class.create();
Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
    getValue: function() {
        return Form.Element.getValue(this.element);
    }
});
Form.Observer = Class.create();
Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
    getValue: function() {
        return Form.serialize(this.element);
    }
});
/*--------------------------------------------------------------------------*/
Abstract.EventObserver = function() { }
Abstract.EventObserver.prototype = {
    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.bind(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();
Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
    getValue: function() {
        return Form.Element.getValue(this.element);
    }
});
Form.EventObserver = Class.create();
Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
    getValue: function() {
        return Form.serialize(this.element);
    }
});
if (!window.Event) {
    var Event = new Object();
}
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,
    element: function(event) {
        return event.target || event.srcElement;
    },
    isLeftClick: function(event) {
        return (((event.which) && (event.which == 1)) ||
((event.button) && (event.button == 1)));
    },
    pointerX: function(event) {
        return event.pageX || (event.clientX +
(document.documentElement.scrollLeft || document.body.scrollLeft));
    },
    pointerY: function(event) {
        return event.pageY || (event.clientY +
(document.documentElement.scrollTop || document.body.scrollTop));
    },
    stop: function(event) {
        if (event.preventDefault) {
            event.preventDefault();
            event.stopPropagation();
        } else {
            event.returnValue = false;
            event.cancelBubble = true;
        }
    },
    // find the first node with the given tagName, starting from the
    // node the event was triggered on; traverses the DOM upwards
    findElement: function(event, tagName) {
        var element = Event.element(event);
        while (element.parentNode && (!element.tagName ||
(element.tagName.toUpperCase() != tagName.toUpperCase())))
            element = element.parentNode;
        return element;
    },
    observers: false,
    _observeAndCache: function(element, name, observer, useCapture) {
        if (!this.observers) this.observers = [];
        if (element.addEventListener) {
            this.observers.push([element, name, observer, useCapture]);
            element.addEventListener(name, observer, useCapture);
        } else if (element.attachEvent) {
            this.observers.push([element, name, observer, useCapture]);
            element.attachEvent('on' + name, observer);
        }
    },
    unloadCache: function() {
        if (!Event.observers) return;
        for (var i = 0, length = Event.observers.length; i < length; i++) {
            Event.stopObserving.apply(this, Event.observers[i]);
            Event.observers[i][0] = null;
        }
        Event.observers = false;
    },
    observe: function(element, name, observer, useCapture) {
        element = $(element);
        useCapture = useCapture || false;
        if (name == 'keypress' &&
(navigator.appVersion.match(/Konqueror|Safari|KHTML/)
|| element.attachEvent))
            name = 'keydown';
        Event._observeAndCache(element, name, observer, useCapture);
    },
    stopObserving: function(element, name, observer, useCapture) {
        element = $(element);
        useCapture = useCapture || false;
        if (name == 'keypress' &&
(navigator.appVersion.match(/Konqueror|Safari|KHTML/)
|| element.detachEvent))
            name = 'keydown';
        if (element.removeEventListener) {
            element.removeEventListener(name, observer, useCapture);
        } else if (element.detachEvent) {
            try {
                element.detachEvent('on' + name, observer);
            } catch (e) { }
        }
    }
});
/* prevent memory leaks in IE */
if (navigator.appVersion.match(/\bMSIE\b/))
    Event.observe(window, 'unload', Event.unloadCache, false);
var Position = {
    // set to true if needed, warning: firefox performance problems
    // NOT neeeded for page scrolling, only if draggable contained in
    // scrollable elements
    includeScrollOffsets: false,
    // must be called before calling withinIncludingScrolloffset, every time the
    // page is scrolled
    prepare: function() {
        this.deltaX = window.pageXOffset
|| document.documentElement.scrollLeft
|| document.body.scrollLeft
|| 0;
        this.deltaY = window.pageYOffset
|| document.documentElement.scrollTop
|| document.body.scrollTop
|| 0;
    },
    realOffset: function(element) {
        var valueT = 0, valueL = 0;
        do {
            valueT += element.scrollTop || 0;
            valueL += element.scrollLeft || 0;
            element = element.parentNode;
        } while (element);
        return [valueL, valueT];
    },
    cumulativeOffset: function(element) {
        var valueT = 0, valueL = 0;
        do {
            valueT += element.offsetTop || 0;
            valueL += element.offsetLeft || 0;
            element = element.offsetParent;
        } while (element);
        return [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 == 'BODY') break;
                var p = Element.getStyle(element, 'position');
                if (p == 'relative' || p == 'absolute') break;
            }
        } while (element);
        return [valueL, valueT];
    },
    offsetParent: 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;
    },
    // caches x/y coordinate pair to use with overlap
    within: function(element, x, y) {
        if (this.includeScrollOffsets)
            return this.withinIncludingScrolloffsets(element, x, y);
        this.xcomp = x;
        this.ycomp = y;
        this.offset = this.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 = this.realOffset(element);
        this.xcomp = x + offsetcache[0] - this.deltaX;
        this.ycomp = y + offsetcache[1] - this.deltaY;
        this.offset = this.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);
    },
    // within must be called directly before
    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;
    },
    page: function(forElement) {
        var valueT = 0, valueL = 0;
        var element = forElement;
        do {
            valueT += element.offsetTop || 0;
            valueL += element.offsetLeft || 0;
            // Safari fix
            if (element.offsetParent == document.body)
                if (Element.getStyle(element, 'position') == 'absolute') break;
        } while (element = element.offsetParent);
        element = forElement;
        do {
            if (!window.opera || element.tagName == 'BODY') {
                valueT -= element.scrollTop || 0;
                valueL -= element.scrollLeft || 0;
            }
        } while (element = element.parentNode);
        return [valueL, valueT];
    },
    clone: function(source, target) {
        var options = Object.extend({
            setLeft: true,
            setTop: true,
            setWidth: true,
            setHeight: true,
            offsetTop: 0,
            offsetLeft: 0
        }, arguments[2] || {})
        // find page position of source
        source = $(source);
        var p = Position.page(source);
        // find coordinate system to use
        target = $(target);
        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(target, 'position') == 'absolute') {
            parent = Position.offsetParent(target);
            delta = Position.page(parent);
        }
        // correct by body offsets (fixes Safari)
        if (parent == document.body) {
            delta[0] -= document.body.offsetLeft;
            delta[1] -= document.body.offsetTop;
        }
        // set position
        if (options.setLeft) target.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px';
        if (options.setTop) target.style.top = (p[1] - delta[1] + options.offsetTop) + 'px';
        if (options.setWidth) target.style.width = source.offsetWidth + 'px';
        if (options.setHeight) target.style.height = source.offsetHeight + 'px';
    },
    absolutize: function(element) {
        element = $(element);
        if (element.style.position == 'absolute') return;
        Position.prepare();
        var offsets = Position.positionedOffset(element);
        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';
    },
    relativize: function(element) {
        element = $(element);
        if (element.style.position == 'relative') return;
        Position.prepare();
        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;
    }
}
// Safari returns margins on body which is incorrect if the child is absolutely
// positioned.  For performance reasons, redefine Position.cumulativeOffset for
// KHTML/WebKit only.
if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) {
    Position.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 [valueL, valueT];
    }
}
Element.addMethods();
// script.aculo.us scriptaculous.js v1.7.0, Fri Jan 19 19:16:36 CET 2007
// Copyright (c) 2005, 2006 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/
var Scriptaculous = {
    Version: '1.7.0',
    require: function(libraryName) {
        // inserting via DOM fails in Safari 2.0, so brute force approach
        document.write('<script type="text/javascript" src="' + libraryName + '"></script>');
    },
    load: function() {
        if ((typeof Prototype == 'undefined') ||
(typeof Element == 'undefined') ||
(typeof Element.Methods == 'undefined') ||
parseFloat(Prototype.Version.split(".")[0] + "." +
Prototype.Version.split(".")[1]) < 1.5)
            throw ("script.aculo.us requires the Prototype JavaScript framework >= 1.5.0");
        $A(document.getElementsByTagName("script")).findAll(function(s) {
            return (s.src && s.src.match(/scriptaculous\.js(\?.*)?$/))
        }).each(function(s) {
            var path = s.src.replace(/scriptaculous\.js(\?.*)?$/, '');
            var includes = s.src.match(/\?.*load=([a-z,]*)/);
            (includes ? includes[1] : 'builder,effects,dragdrop,controls,slider').split(',').each(
function(include) { Scriptaculous.require(path + include + '.js') });
        });
    }
}
Scriptaculous.load();
// script.aculo.us effects.js v1.7.0, Fri Jan 19 19:16:36 CET 2007
// Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
// Contributors:
//  Justin Palmer (http://encytemedia.com/)
//  Mark Pilgrim (http://diveintomark.org/)
//  Martin Bialasinki
//
// script.aculo.us is freely distributable under the terms of an MIT-style license.
// For details, see the script.aculo.us web site: http://script.aculo.us/
// converts rgb() and #xxx to #xxxxxx format,
// returns self (or first argument) if not convertable
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 (navigator.appVersion.indexOf('AppleWebKit') > 0) window.scrollBy(0, 0);
    return element;
}
Element.getOpacity = function(element) {
    return $(element).getStyle('opacity');
}
Element.setOpacity = function(element, value) {
    return $(element).setStyle({ opacity: value });
}
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) { }
    */
};
/*--------------------------------------------------------------------------*/
Array.prototype.call = function() {
    var args = arguments;
    this.each(function(f) { f.apply(this, args) });
}
/*--------------------------------------------------------------------------*/
var Effect = {
    _elementDoesNotExistError: {
        name: 'ElementDoesNotExistError',
        message: 'The specified DOM element does not exist, but is required for this effect to operate'
    },
    tagifyText: function(element) {
        if (typeof Builder == 'undefined')
            throw ("Effect.tagifyText requires including script.aculo.us' builder.js library");
        var tagifyStyle = 'position:relative';
        if (/MSIE/.test(navigator.userAgent) && !window.opera) tagifyStyle += ';zoom:1';
        element = $(element);
        $A(element.childNodes).each(function(child) {
            if (child.nodeType == 3) {
                child.nodeValue.toArray().each(function(character) {
                    element.insertBefore(
Builder.node('span', { style: tagifyStyle },
character == ' ' ? String.fromCharCode(160) : character),
child);
                });
                Element.remove(child);
            }
        });
    },
    multiple: function(element, effect) {
        var elements;
        if (((typeof element == 'object') ||
(typeof element == 'function')) &&
(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);
    }
};
var Effect2 = Effect; // deprecated
/* ------------- transitions ------------- */
Effect.Transitions = {
    linear: Prototype.K,
    sinoidal: function(pos) {
        return (-Math.cos(pos * Math.PI) / 2) + 0.5;
    },
    reverse: function(pos) {
        return 1 - pos;
    },
    flicker: function(pos) {
        return ((-Math.cos(pos * Math.PI) / 4) + 0.75) + Math.random() / 4;
    },
    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 ?
((pos * pulses * 2) - Math.floor(pos * pulses * 2)) :
1 - ((pos * pulses * 2) - Math.floor(pos * pulses * 2))
);
    },
    none: function(pos) {
        return 0;
    },
    full: function(pos) {
        return 1;
    }
};
/* ------------- core effects ------------- */
Effect.ScopedQueue = Class.create();
Object.extend(Object.extend(Effect.ScopedQueue.prototype, 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 = (typeof effect.options.queue == 'string') ?
effect.options.queue : effect.options.queue.position;
        switch (position) {
            case 'front':
                // move unstarted effects after this effect
                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':
                // start effect after last queued effect has finished
                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++)
            if (this.effects[i]) this.effects[i].loop(timePos);
    }
});
Effect.Queues = {
    instances: $H(),
    get: function(queueName) {
        if (typeof queueName != 'string') return queueName;
        if (!this.instances[queueName])
            this.instances[queueName] = new Effect.ScopedQueue();
        return this.instances[queueName];
    }
}
Effect.Queue = Effect.Queues.get('global');
Effect.DefaultOptions = {
    transition: Effect.Transitions.sinoidal,
    duration: 1.0,   // seconds
    fps: 60.0,  // max. 60fps due to Effect.Queue implementation
    sync: false, // true for combining
    from: 0.0,
    to: 1.0,
    delay: 0.0,
    queue: 'parallel'
}
Effect.Base = function() { };
Effect.Base.prototype = {
    position: null,
    start: function(options) {
        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.event('beforeStart');
        if (!this.options.sync)
            Effect.Queues.get(typeof this.options.queue == 'string' ?
'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.finishOn - this.startOn);
            var frame = Math.round(pos * this.options.fps * this.options.duration);
            if (frame > this.currentFrame) {
                this.render(pos);
                this.currentFrame = frame;
            }
        }
    },
    render: function(pos) {
        if (this.state == 'idle') {
            this.state = 'running';
            this.event('beforeSetup');
            if (this.setup) this.setup();
            this.event('afterSetup');
        }
        if (this.state == 'running') {
            if (this.options.transition) pos = this.options.transition(pos);
            pos *= (this.options.to - this.options.from);
            pos += this.options.from;
            this.position = pos;
            this.event('beforeUpdate');
            if (this.update) this.update(pos);
            this.event('afterUpdate');
        }
    },
    cancel: function() {
        if (!this.options.sync)
            Effect.Queues.get(typeof this.options.queue == 'string' ?
'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 (typeof this[property] != 'function') data[property] = this[property];
        return '#<Effect:' + data.inspect() + ',options:' + $H(this.options).inspect() + '>';
    }
}
Effect.Parallel = Class.create();
Object.extend(Object.extend(Effect.Parallel.prototype, Effect.Base.prototype), {
    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.Event = Class.create();
Object.extend(Object.extend(Effect.Event.prototype, Effect.Base.prototype), {
    initialize: function() {
        var options = Object.extend({
            duration: 0
        }, arguments[0] || {});
        this.start(options);
    },
    update: Prototype.emptyFunction
});
Effect.Opacity = Class.create();
Object.extend(Object.extend(Effect.Opacity.prototype, Effect.Base.prototype), {
    initialize: function(element) {
        this.element = $(element);
        if (!this.element) throw (Effect._elementDoesNotExistError);
        // make this work on IE on elements without 'layout'
        if (/MSIE/.test(navigator.userAgent) && !window.opera && (!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();
Object.extend(Object.extend(Effect.Move.prototype, Effect.Base.prototype), {
    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() {
        // Bug in Opera: Opera returns the "real" position of a static element or
        // relative element that does not have top/left explicitly set.
        // ==> Always set top and left for position relative elements in your stylesheets
        // (to 0 if you do not need them)
        this.element.makePositioned();
        this.originalLeft = parseFloat(this.element.getStyle('left') || '0');
        this.originalTop = parseFloat(this.element.getStyle('top') || '0');
        if (this.options.mode == 'absolute') {
            // absolute movement, so we need to calc deltaX and deltaY
            this.options.x = this.options.x - this.originalLeft;
            this.options.y = this.options.y - this.originalTop;
        }
    },
    update: function(position) {
        this.element.setStyle({
            left: Math.round(this.options.x * position + this.originalLeft) + 'px',
            top: Math.round(this.options.y * position + this.originalTop) + 'px'
        });
    }
});
// for backwards compatibility
Effect.MoveBy = function(element, toTop, toLeft) {
    return new Effect.Move(element,
Object.extend({ x: toLeft, y: toTop }, arguments[3] || {}));
};
Effect.Scale = Class.create();
Object.extend(Object.extend(Effect.Scale.prototype, Effect.Base.prototype), {
    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',        // 'box' or 'contents' or {} with provided values
            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 = Math.round(width) + 'px';
        if (this.options.scaleY) d.height = Math.round(height) + '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();
Object.extend(Object.extend(Effect.Highlight.prototype, Effect.Base.prototype), {
    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() {
        // Prevent executing on elements not in the layout flow
        if (this.element.getStyle('display') == 'none') { this.cancel(); return; }
        // Disable background image during the effect
        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');
        // init color calculations
        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 + (Math.round(this._base[i] + (this._delta[i] * position)).toColorPart());
        } .bind(this))
        });
    },
    finish: function() {
        this.element.setStyle(Object.extend(this.oldStyle, {
            backgroundColor: this.options.restorecolor
        }));
    }
});
Effect.ScrollTo = Class.create();
Object.extend(Object.extend(Effect.ScrollTo.prototype, Effect.Base.prototype), {
    initialize: function(element) {
        this.element = $(element);
        this.start(arguments[1] || {});
    },
    setup: function() {
        Position.prepare();
        var offsets = Position.cumulativeOffset(this.element);
        if (this.options.offset) offsets[1] += this.options.offset;
        var max = window.innerHeight ?
window.height - window.innerHeight :
document.body.scrollHeight -
(document.documentElement.clientHeight ?
document.documentElement.clientHeight : document.body.clientHeight);
        this.scrollStart = Position.deltaY;
        this.delta = (offsets[1] > max ? max : offsets[1]) - this.scrollStart;
    },
    update: function(position) {
        Position.prepare();
        window.scrollTo(Position.deltaX,
this.scrollStart + (position * this.delta));
    }
});
/* ------------- combination effects ------------- */
Effect.FadeCollection = function(elements) {
    this.effects = new Array();
    for (var i = 1; i < elements.length; i++) {
        this.effects.push(new Effect.Fade(elements[i], arguments[1] || {}));
    }
}
Effect.FadeCollection.prototype.cancel = function() {
    for (var i = 0; i < this.effects.length; i++) {
        this.effects[i].cancel();
    }
}
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,
        // force Safari to render floated elements properly
        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 oldStyle = {
        top: element.getStyle('top'),
        left: element.getStyle('left')
    };
    return new Effect.Move(element,
{ x: 20, y: 0, duration: 0.05, afterFinishInternal: function(effect) {
    new Effect.Move(effect.element,
{ x: -40, y: 0, duration: 0.1, afterFinishInternal: function(effect) {
    new Effect.Move(effect.element,
{ x: 40, y: 0, duration: 0.1, afterFinishInternal: function(effect) {
    new Effect.Move(effect.element,
{ x: -40, y: 0, duration: 0.1, afterFinishInternal: function(effect) {
    new Effect.Move(effect.element,
{ x: 40, y: 0, duration: 0.1, afterFinishInternal: function(effect) {
    new Effect.Move(effect.element,
{ x: -20, y: 0, duration: 0.05, afterFinishInternal: function(effect) {
    effect.element.undoPositioned().setStyle(oldStyle);
}
})
}
})
}
})
}
})
}
})
}
});
}
Effect.SlideDown = function(element) {
    element = $(element).cleanWhitespace();
    // SlideDown need to have the content of the element wrapped in a container element with fixed height!
    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');
    return new Effect.Scale(element, window.opera ? 0 : 1,
Object.extend({ scaleContent: false,
    scaleX: false,
    scaleMode: 'box',
    scaleFrom: 100,
    restoreAfterFinish: true,
    beforeStartInternal: 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().setStyle({ bottom: oldInnerBottom });
        effect.element.down().undoPositioned();
    }
}, arguments[1] || {})
);
}
Effect.BlindRight = function(element, onComplete) {
    element = $(element);
    var elementDimensions = element.getDimensions();
    return new Effect.Scale(element, 100, Object.extend({
        scaleContent: false,
        scaleY: false,
        scaleFrom: 0,
        scaleMode: { originalHeight: elementDimensions.height, originalWidth: elementDimensions.width },
        restoreAfterFinish: true,
        afterSetup: function(effect) {
            effect.element.makeClipping().setStyle({ width: '0px' }).show();
        },
        afterFinishInternal: function(effect) {
            effect.element.undoClipping();
            onComplete();
        }
    }, arguments[1] || {}));
}
Effect.BlindLeft = function(element) {
    element = $(element);
    element.makeClipping();
    return new Effect.Scale(element, 0,
Object.extend({ scaleContent: false,
    scaleY: false,
    restoreAfterFinish: true,
    afterFinishInternal: function(effect) {
        effect.element.hide().undoClipping();
    }
}, arguments[1] || {})
);
}
// Bug in opera makes the TD containing this element expand for a instance after finish
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] || {};
    var oldOpacity = element.getInlineOpacity();
    var transition = options.transition || Effect.Transitions.sinoidal;
    var reverser = function(pos) { return transition(1 - Effect.Transitions.pulse(pos, options.pulses)) };
    reverser.bind(transition);
    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();
Object.extend(Object.extend(Effect.Morph.prototype, Effect.Base.prototype), {
    initialize: function(element) {
        this.element = $(element);
        if (!this.element) throw (Effect._elementDoesNotExistError);
        var options = Object.extend({
            style: {}
        }, arguments[1] || {});
        if (typeof options.style == 'string') {
            if (options.style.indexOf(':') == -1) {
                var cssText = '', selector = '.' + options.style;
                $A(document.styleSheets).reverse().each(function(styleSheet) {
                    if (styleSheet.cssRules) cssRules = styleSheet.cssRules;
                    else if (styleSheet.rules) cssRules = styleSheet.rules;
                    $A(cssRules).reverse().each(function(rule) {
                        if (selector == rule.selectorText) {
                            cssText = rule.style.cssText;
                            throw $break;
                        }
                    });
                    if (cssText) throw $break;
                });
                this.style = cssText.parseStyle();
                options.afterFinishInternal = function(effect) {
                    effect.element.addClassName(effect.options.style);
                    effect.transforms.each(function(transform) {
                        if (transform.style != 'opacity')
                            effect.element.style[transform.style.camelize()] = '';
                    });
                }
            } else this.style = options.style.parseStyle();
        } else this.style = $H(options.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].underscore().dasherize(), value = pair[1], unit = null;
            if (value.parseColor('#zzzzzz') != '#zzzzzz') {
                value = value.parseColor();
                unit = 'color';
            } else if (property == 'opacity') {
                value = parseFloat(value);
                if (/MSIE/.test(navigator.userAgent) && !window.opera && (!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 $H({
                style: property,
                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 = $H(), value = null;
        this.transforms.each(function(transform) {
            value = transform.unit == 'color' ?
$R(0, 2).inject('#', function(m, v, i) {
    return m + (Math.round(transform.originalValue[i] +
(transform.targetValue[i] - transform.originalValue[i]) * position)).toColorPart()
}) :
transform.originalValue + Math.round(
((transform.targetValue - transform.originalValue) * position) * 1000) / 1000 + transform.unit;
            style[transform.style] = value;
        });
        this.element.setStyle(style);
    }
});
Effect.Transform = Class.create();
Object.extend(Effect.Transform.prototype, {
    initialize: function(tracks) {
        this.tracks = [];
        this.options = arguments[1] || {};
        this.addTracks(tracks);
    },
    addTracks: function(tracks) {
        tracks.each(function(track) {
            var data = $H(track).values().first();
            this.tracks.push($H({
                ids: $H(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 elements = [$(track.ids) || $$(track.ids)].flatten();
    return elements.map(function(e) { return new track.effect(e, Object.extend({ sync: true }, track.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.prototype.parseStyle = function() {
    var element = Element.extend(document.createElement('div'));
    element.innerHTML = '<div style="' + this + '"></div>';
    var style = element.down().style, styleRules = $H();
    Element.CSS_PROPERTIES.each(function(property) {
        if (style[property]) styleRules[property] = style[property];
    });
    if (/MSIE/.test(navigator.userAgent) && !window.opera && this.indexOf('opacity') > -1) {
        styleRules.opacity = this.match(/opacity:\s*((?:0|1)?(?:\.\d*)?)/)[1];
    }
    return styleRules;
};
Element.morph = function(element, style) {
    new Effect.Morph(element, Object.extend({ style: style }, arguments[2] || {}));
    return element;
};
['setOpacity', 'getOpacity', 'getInlineOpacity', 'forceRerendering', 'setContentZoom',
'collectTextNodes', 'collectTextNodesIgnoreClass', 'morph'].each(
function(f) { Element.Methods[f] = Element[f]; }
);
Element.Methods.visualEffect = function(element, effect, options) {
    s = effect.gsub(/_/, '-').camelize();
    effect_class = s.charAt(0).toUpperCase() + s.substring(1);
    new Effect[effect_class](element, options);
    return $(element);
};
Element.addMethods();
// script.aculo.us controls.js v1.7.0, Fri Jan 19 19:16:36 CET 2007
// Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
//           (c) 2005, 2006 Ivan Krstic (http://blogs.law.harvard.edu/ivan)
//           (c) 2005, 2006 Jon Tirsen (http://www.tirsen.com)
// Contributors:
//  Richard Livsey
//  Rahul Bhargava
//  Rob Wills
//
// script.aculo.us is freely distributable under the terms of an MIT-style license.
// For details, see the script.aculo.us web site: http://script.aculo.us/
// Autocompleter.Base handles all the autocompletion functionality
// that's independent of the data source for autocompletion. This
// includes drawing the autocompletion menu, observing keyboard
// and mouse events, and similar.
//
// Specific autocompleters need to provide, at the very least,
// a getUpdatedChoices function that will be invoked every time
// the text inside the monitored textbox changes. This method
// should get the text for which to provide autocompletion by
// invoking this.getToken(), NOT by directly accessing
// this.element.value. This is to allow incremental tokenized
// autocompletion. Specific auto-completion logic (AJAX, etc)
// belongs in getUpdatedChoices.
//
// Tokenized incremental autocompletion is enabled automatically
// when an autocompleter is instantiated with the 'tokens' option
// in the options parameter, e.g.:
// new Ajax.Autocompleter('id','upd', '/url/', { tokens: ',' });
// will incrementally autocomplete with a comma as the token.
// Additionally, ',' in the above example can be replaced with
// a token array, e.g. { tokens: [',', '\n'] } which
// enables autocompletion on multiple tokens. This is most
// useful when one of the tokens is \n (a newline), as it
// allows smart autocompletion after linebreaks.
if (typeof Effect == 'undefined')
    throw ("controls.js requires including script.aculo.us' effects.js library");
var Autocompleter = {}
Autocompleter.Base = function() { };
Autocompleter.Base.prototype = {
    baseInitialize: function(element, update, options) {
        this.element = $(element);
        this.update = $(update);
        this.hasFocus = false;
        this.changed = false;
        this.active = false;
        this.index = 0;
        this.entryCount = 0;
        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
        });
if (isIE7() && element.readAttribute('id') == 'quicksearchtextcriteria') {
var currentTop = update.style.top.gsub(/px/,'');
update.style.top = (parseInt(currentTop) - 17) + 'px';
}
if (isIE8() && element.readAttribute('id') == 'quicksearchtextcriteria') {
update.style.left = '554px';
}
    }
    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);
        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, "keypress", this.onKeyPress.bindAsEventListener(this));
    },
    show: function() {
        if (Element.getStyle(this.update, 'display') == 'none') this.options.onShow(this.element, this.update);
        if (!this.iefix &&
(navigator.appVersion.indexOf('MSIE') > 0) &&
(navigator.userAgent.indexOf('Opera') < 0) &&
(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();
                if (navigator.appVersion.indexOf('AppleWebKit') > 0) Event.stop(event);
                return;
            case Event.KEY_DOWN:
                this.markNext();
                this.render();
                if (navigator.appVersion.indexOf('AppleWebKit') > 0) Event.stop(event);
                return;
        }
        else
            if (event.keyCode == Event.KEY_TAB || event.keyCode == Event.KEY_RETURN ||
(navigator.appVersion.indexOf('AppleWebKit') > 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) {
        // needed to make click events working
        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 = document.getElementsByClassName(this.options.select, selectedElement) || [];
            if (nodes.length > 0) value = Element.collectTextNodes(nodes[0], this.options.select);
        } else
            value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal');
        var lastTokenPos = this.findLastToken();
        if (lastTokenPos != -1) {
            var newValue = this.element.value.substr(0, lastTokenPos + 1);
            var whitespace = this.element.value.substr(lastTokenPos + 1).match(/^\s+/);
            if (whitespace)
                newValue += whitespace[0];
            this.element.value = newValue + value;
        } else {
            this.element.value = 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;
        if (this.getToken().length >= this.options.minChars) {
            this.startIndicator();
            this.getUpdatedChoices();
        } else {
            this.active = false;
            this.hide();
        }
    },
    getToken: function() {
        var tokenPos = this.findLastToken();
        if (tokenPos != -1)
            var ret = this.element.value.substr(tokenPos + 1).replace(/^\s+/, '').replace(/\s+$/, '');
        else
            var ret = this.element.value;
        return /\n/.test(ret) ? '' : ret;
    },
    findLastToken: function() {
        var lastTokenPos = -1;
        for (var i = 0; i < this.options.tokens.length; i++) {
            var thisTokenPos = this.element.value.lastIndexOf(this.options.tokens[i]);
            if (thisTokenPos > lastTokenPos)
                lastTokenPos = thisTokenPos;
        }
        return lastTokenPos;
    }
}
Ajax.Autocompleter = Class.create();
Object.extend(Object.extend(Ajax.Autocompleter.prototype, Autocompleter.Base.prototype), {
    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() {
        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);
    }
});
// The local array autocompleter. Used when you'd prefer to
// inject an array of autocompletion options into the page, rather
// than sending out Ajax queries, which can be quite slow sometimes.
//
// The constructor takes four parameters. The first two are, as usual,
// the id of the monitored textbox, and id of the autocompletion menu.
// The third is the array you want to autocomplete from, and the fourth
// is the options block.
//
// Extra local autocompletion options:
// - choices - How many autocompletion choices to offer
//
// - partialSearch - If false, the autocompleter will match entered
//                    text only at the beginning of strings in the
//                    autocomplete array. Defaults to true, which will
//                    match text at the beginning of any *word* in the
//                    strings in the autocomplete array. If you want to
//                    search anywhere in the string, additionally set
//                    the option fullSearch to true (default: off).
//
// - fullSsearch - Search anywhere in autocomplete array strings.
//
// - partialChars - How many characters to enter before triggering
//                   a partial match (unlike minChars, which defines
//                   how many characters are required to do any match
//                   at all). Defaults to 2.
//
// - ignoreCase - Whether to ignore case when autocompleting.
//                 Defaults to true.
//
// It's possible to pass in a custom function as the 'selector'
// option, if you prefer to write your own autocompletion logic.
// In that case, the other options above will not apply unless
// you support them.
Autocompleter.Local = Class.create();
Autocompleter.Local.prototype = Object.extend(new 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 = []; // Beginning matches
                var partial = []; // Inside matches
                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 || {});
    }
});
// AJAX in-place editor
//
// see documentation on http://wiki.script.aculo.us/scriptaculous/show/Ajax.InPlaceEditor
// Use this if you notice weird scrolling problems on some browsers,
// the DOM might be a bit confused when this gets called so do this
// waits 1 ms (with setTimeout) until it does the activation
Field.scrollFreeActivate = function(field) {
    setTimeout(function() {
        Field.activate(field);
    }, 1);
}
Ajax.InPlaceEditor = Class.create();
Ajax.InPlaceEditor.defaultHighlightColor = "#FFFF99";
Ajax.InPlaceEditor.prototype = {
    initialize: function(element, url, options) {
        this.url = url;
        this.element = $(element);
        this.options = Object.extend({
            paramName: "value",
            okButton: true,
            okText: "ok",
            cancelLink: true,
            cancelText: "cancel",
            savingText: "Saving...",
            clickToEditText: "Click to edit",
            okText: "ok",
            rows: 1,
            onComplete: function(transport, element) {
                new Effect.Highlight(element, { startcolor: this.options.highlightcolor });
            },
            onFailure: function(transport) {
                alert("Error communicating with the server: " + transport.responseText.stripTags());
            },
            callback: function(form) {
                return Form.serialize(form);
            },
            handleLineBreaks: true,
            loadingText: 'Loading...',
            savingClassName: 'inplaceeditor-saving',
            loadingClassName: 'inplaceeditor-loading',
            formClassName: 'inplaceeditor-form',
            highlightcolor: Ajax.InPlaceEditor.defaultHighlightColor,
            highlightendcolor: "#FFFFFF",
            externalControl: null,
            submitOnBlur: false,
            ajaxOptions: {},
            evalScripts: false
        }, options || {});
        if (!this.options.formId && this.element.id) {
            this.options.formId = this.element.id + "-inplaceeditor";
            if ($(this.options.formId)) {
                // there's already a form with that name, don't specify an id
                this.options.formId = null;
            }
        }
        if (this.options.externalControl) {
            this.options.externalControl = $(this.options.externalControl);
        }
        this.originalBackground = Element.getStyle(this.element, 'background-color');
        if (!this.originalBackground) {
            this.originalBackground = "transparent";
        }
        this.element.title = this.options.clickToEditText;
        this.onclickListener = this.enterEditMode.bindAsEventListener(this);
        this.mouseoverListener = this.enterHover.bindAsEventListener(this);
        this.mouseoutListener = this.leaveHover.bindAsEventListener(this);
        Event.observe(this.element, 'click', this.onclickListener);
        Event.observe(this.element, 'mouseover', this.mouseoverListener);
        Event.observe(this.element, 'mouseout', this.mouseoutListener);
        if (this.options.externalControl) {
            Event.observe(this.options.externalControl, 'click', this.onclickListener);
            Event.observe(this.options.externalControl, 'mouseover', this.mouseoverListener);
            Event.observe(this.options.externalControl, 'mouseout', this.mouseoutListener);
        }
    },
    enterEditMode: function(evt) {
        if (this.saving) return;
        if (this.editing) return;
        this.editing = true;
        this.onEnterEditMode();
        if (this.options.externalControl) {
            Element.hide(this.options.externalControl);
        }
        Element.hide(this.element);
        this.createForm();
        this.element.parentNode.insertBefore(this.form, this.element);
        if (!this.options.loadTextURL) Field.scrollFreeActivate(this.editField);
        // stop the event to avoid a page refresh in Safari
        if (evt) {
            Event.stop(evt);
        }
        return false;
    },
    createForm: function() {
        this.form = document.createElement("form");
        this.form.id = this.options.formId;
        Element.addClassName(this.form, this.options.formClassName)
        this.form.onsubmit = this.onSubmit.bind(this);
        this.createEditField();
        if (this.options.textarea) {
            var br = document.createElement("br");
            this.form.appendChild(br);
        }
        if (this.options.okButton) {
            okButton = document.createElement("input");
            okButton.type = "submit";
            okButton.value = this.options.okText;
            okButton.className = 'editor_ok_button';
            this.form.appendChild(okButton);
        }
        if (this.options.cancelLink) {
            cancelLink = document.createElement("a");
            cancelLink.href = "#";
            cancelLink.appendChild(document.createTextNode(this.options.cancelText));
            cancelLink.onclick = this.onclickCancel.bind(this);
            cancelLink.className = 'editor_cancel';
            this.form.appendChild(cancelLink);
        }
    },
    hasHTMLLineBreaks: function(string) {
        if (!this.options.handleLineBreaks) return false;
        return string.match(/<br/i) || string.match(/<p>/i);
    },
    convertHTMLLineBreaks: function(string) {
        return string.replace(/<br>/gi, "\n").replace(/<br\/>/gi, "\n").replace(/<\/p>/gi, "\n").replace(/<p>/gi, "");
    },
    createEditField: function() {
        var text;
        if (this.options.loadTextURL) {
            text = this.options.loadingText;
        } else {
            text = this.getText();
        }
        var obj = this;
        if (this.options.rows == 1 && !this.hasHTMLLineBreaks(text)) {
            this.options.textarea = false;
            var textField = document.createElement("input");
            textField.obj = this;
            textField.type = "text";
            textField.name = this.options.paramName;
            textField.value = text;
            textField.style.backgroundColor = this.options.highlightcolor;
            textField.className = 'editor_field';
            var size = this.options.size || this.options.cols || 0;
            if (size != 0) textField.size = size;
            if (this.options.submitOnBlur)
                textField.onblur = this.onSubmit.bind(this);
            this.editField = textField;
        } else {
            this.options.textarea = true;
            var textArea = document.createElement("textarea");
            textArea.obj = this;
            textArea.name = this.options.paramName;
            textArea.value = this.convertHTMLLineBreaks(text);
            textArea.rows = this.options.rows;
            textArea.cols = this.options.cols || 40;
            textArea.className = 'editor_field';
            if (this.options.submitOnBlur)
                textArea.onblur = this.onSubmit.bind(this);
            this.editField = textArea;
        }
        if (this.options.loadTextURL) {
            this.loadExternalText();
        }
        this.form.appendChild(this.editField);
    },
    getText: function() {
        return this.element.innerHTML;
    },
    loadExternalText: function() {
        Element.addClassName(this.form, this.options.loadingClassName);
        this.editField.disabled = true;
        new Ajax.Request(
this.options.loadTextURL,
Object.extend({
    asynchronous: true,
    onComplete: this.onLoadedExternalText.bind(this)
}, this.options.ajaxOptions)
);
    },
    onLoadedExternalText: function(transport) {
        Element.removeClassName(this.form, this.options.loadingClassName);
        this.editField.disabled = false;
        this.editField.value = transport.responseText.stripTags();
        Field.scrollFreeActivate(this.editField);
    },
    onclickCancel: function() {
        this.onComplete();
        this.leaveEditMode();
        return false;
    },
    onFailure: function(transport) {
        this.options.onFailure(transport);
        if (this.oldInnerHTML) {
            this.element.innerHTML = this.oldInnerHTML;
            this.oldInnerHTML = null;
        }
        return false;
    },
    onSubmit: function() {
        // onLoading resets these so we need to save them away for the Ajax call
        var form = this.form;
        var value = this.editField.value;
        // do this first, sometimes the ajax call returns before we get a chance to switch on Saving...
        // which means this will actually switch on Saving... *after* we've left edit mode causing Saving...
        // to be displayed indefinitely
        this.onLoading();
        if (this.options.evalScripts) {
            new Ajax.Request(
this.url, Object.extend({
    parameters: this.options.callback(form, value),
    onComplete: this.onComplete.bind(this),
    onFailure: this.onFailure.bind(this),
    asynchronous: true,
    evalScripts: true
}, this.options.ajaxOptions));
        } else {
            new Ajax.Updater(
{ success: this.element,
    // don't update on failure (this could be an option)
    failure: null
},
this.url, Object.extend({
    parameters: this.options.callback(form, value),
    onComplete: this.onComplete.bind(this),
    onFailure: this.onFailure.bind(this)
}, this.options.ajaxOptions));
        }
        // stop the event to avoid a page refresh in Safari
        if (arguments.length > 1) {
            Event.stop(arguments[0]);
        }
        return false;
    },
    onLoading: function() {
        this.saving = true;
        this.removeForm();
        this.leaveHover();
        this.showSaving();
    },
    showSaving: function() {
        this.oldInnerHTML = this.element.innerHTML;
        this.element.innerHTML = this.options.savingText;
        Element.addClassName(this.element, this.options.savingClassName);
        this.element.style.backgroundColor = this.originalBackground;
        Element.show(this.element);
    },
    removeForm: function() {
        if (this.form) {
            if (this.form.parentNode) Element.remove(this.form);
            this.form = null;
        }
    },
    enterHover: function() {
        if (this.saving) return;
        this.element.style.backgroundColor = this.options.highlightcolor;
        if (this.effect) {
            this.effect.cancel();
        }
        Element.addClassName(this.element, this.options.hoverClassName)
    },
    leaveHover: function() {
        if (this.options.backgroundColor) {
            this.element.style.backgroundColor = this.oldBackground;
        }
        Element.removeClassName(this.element, this.options.hoverClassName)
        if (this.saving) return;
        this.effect = new Effect.Highlight(this.element, {
            startcolor: this.options.highlightcolor,
            endcolor: this.options.highlightendcolor,
            restorecolor: this.originalBackground
        });
    },
    leaveEditMode: function() {
        Element.removeClassName(this.element, this.options.savingClassName);
        this.removeForm();
        this.leaveHover();
        this.element.style.backgroundColor = this.originalBackground;
        Element.show(this.element);
        if (this.options.externalControl) {
            Element.show(this.options.externalControl);
        }
        this.editing = false;
        this.saving = false;
        this.oldInnerHTML = null;
        this.onLeaveEditMode();
    },
    onComplete: function(transport) {
        this.leaveEditMode();
        this.options.onComplete.bind(this)(transport, this.element);
    },
    onEnterEditMode: function() { },
    onLeaveEditMode: function() { },
    dispose: function() {
        if (this.oldInnerHTML) {
            this.element.innerHTML = this.oldInnerHTML;
        }
        this.leaveEditMode();
        Event.stopObserving(this.element, 'click', this.onclickListener);
        Event.stopObserving(this.element, 'mouseover', this.mouseoverListener);
        Event.stopObserving(this.element, 'mouseout', this.mouseoutListener);
        if (this.options.externalControl) {
            Event.stopObserving(this.options.externalControl, 'click', this.onclickListener);
            Event.stopObserving(this.options.externalControl, 'mouseover', this.mouseoverListener);
            Event.stopObserving(this.options.externalControl, 'mouseout', this.mouseoutListener);
        }
    }
};
Ajax.InPlaceCollectionEditor = Class.create();
Object.extend(Ajax.InPlaceCollectionEditor.prototype, Ajax.InPlaceEditor.prototype);
Object.extend(Ajax.InPlaceCollectionEditor.prototype, {
    createEditField: function() {
        if (!this.cached_selectTag) {
            var selectTag = document.createElement("select");
            var collection = this.options.collection || [];
            var optionTag;
            collection.each(function(e, i) {
                optionTag = document.createElement("option");
                optionTag.value = (e instanceof Array) ? e[0] : e;
                if ((typeof this.options.value == 'undefined') &&
((e instanceof Array) ? this.element.innerHTML == e[1] : e == optionTag.value)) optionTag.selected = true;
                if (this.options.value == optionTag.value) optionTag.selected = true;
                optionTag.appendChild(document.createTextNode((e instanceof Array) ? e[1] : e));
                selectTag.appendChild(optionTag);
            } .bind(this));
            this.cached_selectTag = selectTag;
        }
        this.editField = this.cached_selectTag;
        if (this.options.loadTextURL) this.loadExternalText();
        this.form.appendChild(this.editField);
        this.options.callback = function(form, value) {
            return "value=" + encodeURIComponent(value);
        }
    }
});
// Delayed observer, like Form.Element.Observer,
// but waits for delay after last key input
// Ideal for live-search fields
Form.Element.DelayedObserver = Class.create();
Form.Element.DelayedObserver.prototype = {
    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));
    }
};
function isChildUnder(elt, topElt) {
    while (elt && elt != topElt && elt.nodeName != 'BODY') {
        elt = elt.parentNode;
    }
    return (elt && (elt == topElt));
}
function goBetweenOrHide(id, otherId, menuId, tabId) {
    return function(event) {
        var movedTo = (event.relatedTarget) ? event.relatedTarget : event.toElement;
        if (isChildUnder(movedTo, $(otherId))) {
            // exception for moving to/under otherId
            return;
        }
        if (isChildUnder(movedTo, $(id))) {
            // still under id, so just return
            return;
        }
        if ($(tabId).opentimeout)
            window.clearTimeout($(tabId).opentimeout);
        // mouse has left id, so hide menu, deactivate tab
        Element.removeClassName($(tabId), "active");
        $(tabId).closetimeout = window.setTimeout(function() { Effect.Fade(menuId, { duration: 0 }); }, 100);
    };
}
function createElementShowFn(tabId, subNavId) {
    return function(event) {
        if ($(tabId).closetimeout)
            window.clearTimeout($(tabId).closetimeout);
        Element.addClassName($(tabId), "active");
        $(tabId).opentimeout = window.setTimeout(function() { Effect.Appear(subNavId, { duration: 0 }); }, 100);
    };
}
function createUnregisterFn(element, eventName, handler) {
    return function() {
        Event.stopObserving(element, eventName, handler);
    };
}
function unregisterAnyHandler(element, eventName) {
    var removeEventFn = "remove" + eventName;
    if (element[removeEventFn]) {
        element[removeEventFn]();
    }
}
function registerHandlerAndRemover(element, eventName, handler) {
    Element.observe(element, eventName, handler);
    var removeEventFn = "remove" + eventName;
    element[removeEventFn] = createUnregisterFn(element, eventName, handler);
}
function registerDropDownEvents(parentId, subId) {
    // don't register if either element isn't on the page
    if (!($(parentId)) || !($(subId)))
        return;
    // don't register if the nav is already active
    if ($(parentId).hasClassName("active"))
        return;
    registerHandlerAndRemover($(parentId), 'mouseover', createElementShowFn(parentId, subId));
    registerHandlerAndRemover($(parentId), 'mouseout', goBetweenOrHide(parentId, subId, subId, parentId));
    registerHandlerAndRemover($(subId), 'mouseout', goBetweenOrHide(subId, parentId, subId, parentId));
}
var DataSerializer = {};
DataSerializer.serialize = function(obj) {
    var buff = [];
    DataSerializer.serializeToBuffer(obj, buff);
    return buff.join('');
}
DataSerializer.serializeToBuffer = function(obj, buff) {
    var type = typeof obj;
    if (type == 'object') {
        if (obj.constructor == Array) {
            type = 'array';
        } else {
            type = 'hash';
        }
    }
    var handler = DataSerializer.TYPE_HANDLERS[type];
    if (typeof handler == 'function') {
        handler(obj, buff);
    }
}
DataSerializer.isKnownType = function(type) {
    return type == 'object' || typeof DataSerializer.TYPE_HANDLERS[type] == 'function';
}
DataSerializer.TYPE_HANDLERS = {};
DataSerializer.TYPE_HANDLERS['array'] = function(arr, buff) {
    buff.push('[');
    for (var i = 0; i < arr.length; i++) {
        if (i != 0) {
            buff.push(',')
        }
        DataSerializer.serializeToBuffer(arr[i], buff);
    }
    buff.push(']');
}
DataSerializer.TYPE_HANDLERS['hash'] = function(hash, buff) {
    buff.push('{');
    var first = true;
    for (var propName in hash) {
        if (DataSerializer.isKnownType(typeof hash[propName])) {
            if (!first) {
                buff.push(',')
            }
            first = false;
            buff.push(propName);
            buff.push(':');
            DataSerializer.serializeToBuffer(hash[propName], buff);
        }
    }
    buff.push('}');
}
DataSerializer.TYPE_HANDLERS['string'] = function(str, buff) {
    buff.push("'");
    buff.push(str.replace("'", "\\'"));
    buff.push("'");
}
DataSerializer.TYPE_HANDLERS['number'] = function(num, buff) {
    buff.push(num);
}
/**
* @author dev2
*/
var HtmlBuilder = {};
HtmlBuilder.buildTable = function() {
    return HtmlBuilder.buildElement('<table class="location_cell"><tbody></tbody></table>', {}, 'table');
}
HtmlBuilder.buildTableCell = function(html, model) {
    return HtmlBuilder.buildElement('<table class="location_cell"><tr>' + html + '</tr></table>', model, 'td');
}
HtmlBuilder.buildTableRow = function(html, model) {
    var row = html || "<tr></tr>";
    return HtmlBuilder.buildElement('<table class="location_cell">' + row + '</table>', model, 'tr');
}
HtmlBuilder.buildOptions = function(options, selectedValue) {
    if (typeof selectedValue == 'object') {
        if (typeof selectedValue.value != 'undefined') {
            selectedValue = selectedValue.value;
        } else {
            selectedValue = selectedValue.text;
        }
    }
    if (typeof options != 'string') {
        options = options.collect(function(option) { return '<option>' + option + '</option>' });
        options = options.join('');
    }
    var selectElement = HtmlBuilder.buildElement('<select>' + options + '</select>', null, 'select');
    var children = $A(selectElement.getElementsByTagName('OPTION'));
    if (typeof selectedValue != 'undefined') {
        var index = -1;
        for (var i = 0; index == -1 && i < children.length; i++) {
            if (children[i].value == selectedValue || children[i].text == selectedValue) {
                index = i;
                children[i].selected = true;
                found = true;
            }
        }
        if (index != -1) {
            selectElement.selectedIndex = index;
        }
    }
    var selectedIndex = selectElement.selectedIndex;
    for (var i = 0; i < children.length; i++) {
        selectElement.removeChild(children[i]);
        children[i].selected = false;
    }
    children[selectedIndex].selected = true;
    return children;
}
HtmlBuilder.buildElement = function(html, model, expectedElementName) {
    var div = document.createElement('div');
    div.innerHTML = HtmlBuilder.renderTemplate(html, model);
    return Element.extend(div.getElementsByTagName(expectedElementName)[0]);
}
HtmlBuilder.renderTemplate = function(templateText, model) {
    return (new Template(templateText)).evaluate(model);
};
var Table = Class.create();
Table.getLogicalTable = function(tableElement) {
    return tableElement.tBodies[0] || tableElement;
};
Table.prototype = {
    initialize: function() {
        this._rows = new Array();
    },
    add: function(row) {
        this._rows.push(row);
    },
    createAndAddRow: function() {
        var row = new Row();
        this.add(row);
        return row;
    },
    render: function() {
        var table = HtmlBuilder.buildTable();
        var tBody = table.tBodies[0];
        for (var i = 0; i < this._rows.length; i++) {
            tBody.appendChild(this._rows[i].render());
        }
        return table;
    }
}
var Row = Class.create();
Row.prototype = {
    initialize: function() {
        this._cells = new Array();
    },
    cellCount: function() {
        return this._cells.length;
    },
    addCell: function(cellTemplate, model) {
        var cell = HtmlBuilder.buildTableCell(cellTemplate, model);
        this._cells.push(cell);
        return cell;
    },
    render: function() {
        var tr = HtmlBuilder.buildTableRow();
        for (var i = 0; i < this._cells.length; i++) {
            tr.appendChild(this._cells[i]);
        }
        return tr;
    }
};
// Created August 30, 2007
//
// File: functional.js
// Author: Nate Young
//
// returns a subsequence of a sequence starting at from
//
function slice(from, seq) {
    var arr = new Array();
    for (var i = from; i < seq.length; i++) {
        arr.push(seq[i]);
    }
    return arr;
}
// returns the length of the shortest of a list of sequences
//
function shortestof(seqs) {
    var shortest = seqs[0].length;
    for (var i = 0; i < seqs.length; i++) {
        if (seqs[i].length < shortest)
            shortest = seqs[i].length;
    }
    return shortest;
}
// takes a list of sequences and returns the index-th
// element of each in a list
//
// index - element of each sequence to collect
// seqs - list of sequences to collect elements from
//
function collectargs(index, seqs) {
    var collected = new Array();
    for (var i = 0; i < seqs.length; i++)
        collected.push(seqs[i][index]);
    return collected;
}
// applies a function to elements of given sequences and returns
// a list of the results
//
// this method takes at least 2 arguments, fn and seq
// and can take more. fn will be supplied with one element
// from each given sequence
//
// fn - the function to call
// seq - sequence to supply fn with arguments
//
function map(fn, seq) {
    var seqs = slice(1, arguments);
    var mapped = new Array();
    var args = false;
    var i = 0;
    var shortest = shortestof(seqs);
    while (shortest > i) {
        args = collectargs(i, seqs);
        mapped.push(fn.apply(null, args));
        i++;
    }
    return mapped;
}
// return a list of elements that satisfy a given function
//
// filter will pass each element of the given sequence to
// the supplied function and return a list of the elements
// for which the function returned true
//
// fn - function taking a single argument
//
function filter(fn, seq) {
    var filtered = new Array();
    for (var i = 0; i < seq.length; i++) {
        if (fn(seq[i])) {
            filtered.push(seq[i]);
        }
    }
    return filtered;
}
// return a list of elements in a list of lists that satisfy a given function
//
// rfilter differs from filter in that it recursively descends
// into nested lists to return a flat lists of elements.
//
// fn - function taking a single argument
function rfilter(fn, seq) {
    var filtered = new Array();
    for (var i = 0; i < seq.length; i++) {
        if (seq[i] && seq[i].length) {  //element is a sequence
            filtered = filtered.concat(rfilter(fn, seq[i]));
        } else {
            if (fn(seq[i])) {
                filtered.push(seq[i]);
            }
        }
    }
    return filtered;
}
Object.extend(Array.prototype, {
    addOrRemove: function(value) {
        var index = this.indexOf(value);
        if (index == -1)
            this.push(value);
        else
            this.splice(index, 1);
    },
    equals: function(toCompare) {
        if (!toCompare || this.length != toCompare.length)
            return false;
        for (var i = 0; i < this.length; i++) {
            if (toCompare.indexOf(this[i]) == -1)
                return false;
        }
        return true;
    }
});
Object.extend(Element, {
    replaceClassName: function(element, currentName, newName) {
        Element.removeClassName(element, currentName);
        Element.addClassName(element, newName);
    }
});
BubbleHandler = Class.create();
Object.extend(BubbleHandler.prototype, {
    initialize: function(observable) {
        this.observable = observable;
    },
    onChange: function() {
        this.observable.notifyChange();
    }
});
ClosureHandler = Class.create();
Object.extend(ClosureHandler.prototype, {
    initialize: function(methodToCall) {
        this._methodToCall = methodToCall;
    },
    onChange: function() {
        this._methodToCall.apply(window, arguments);
    }
});
FilterKey = {
    ARCHITECTURAL_STYLE: 'architecturalstyle',
    PRICE: 'price',
    BED_BATH: 'bedbathsize',
    INTERIOR_SIZE_LOT_SIZE: 'interiorsizelotsize',
    RATES_AND_AVAILABILITY: 'ratesandavailability',
    LOCATION: 'location',
    SCHOOL_DISTRICTS: 'schooldistricts',
    CAT_BASED_LOCATION: 'categorybasedlocation',
    AGENT_ID: 'agentid',
    OFFICE_ID: 'officeid',
    NEIGHBORHOOD_ID: 'neighborhoodid',
    SUBREGION: 'subregion',
    DEVELOPMENT_ID: 'developmentid',
    SALE_TEAM_ID: 'saleteamid',
    DEVELOPMENT_GROUP: 'developmentgroup',
    WEB_REGION: 'webregion',
    PROPERTY_COMMUNITY_TYPE: 'propertycommunitytype',
    FEATURES_AND_AMENITIES: 'featuresandamenities',
    LIFESTYLE: 'lifestyle',
    ITEMS_PER_PAGE: 'itemsperpage',
    LANGUAGE: 'language',
    AGENT_LOCATION: 'agentbasedlocation',
    AGENT_NAME_SEARCH: 'agentNameSearch',
    LETTER_FROM_FORM: 'letterFromForm'
}
QSAutocompleter = Class.create();
Object.extend(QSAutocompleter.prototype, Ajax.Autocompleter.prototype);
Object.extend(QSAutocompleter.prototype, {
    initialize: function(textboxID, updateDiv, url, params) {
        this._started = false;
        this._updateDiv = updateDiv;
        this._textboxID = textboxID;
        Ajax.Autocompleter.prototype.initialize.call(this, textboxID, updateDiv, url, params);
    },
    start: function() {
        //some of the tests cannot find this...this was the quick-fix.  the real fix is to have a library loader (like JSAN)
        if (typeof Element.replaceClassName == 'function') {
            Element.replaceClassName(this._updateDiv, 'suggest', 'suggestActive');
        }
        this._started = true;
    },
    stop: function() {
        //some of the tests cannot find this...this was the quick-fix.  the real fix is to have a library loader (like JSAN)
        if (typeof Element.replaceClassName == 'function') {
            Element.replaceClassName(this._updateDiv, 'suggestActive', 'suggest');
        }
        this._started = false;
    },
onClick: function(event) {
//if(close button) {
//    this.hide();
//}
},
onHover: function(event) {
},
//	onBlur: function(event) {
//
//	},
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:
case Event.KEY_UP:
case Event.KEY_DOWN:
return;
}
else
if (event.keyCode == Event.KEY_TAB || event.keyCode == Event.KEY_RETURN ||
(navigator.appVersion.indexOf('AppleWebKit') > 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);
},
    getUpdatedChoices: function() {
        if (this._started) {
            this._callBaseUpdatedChoices();
        }
    },
    _callBaseUpdatedChoices: function() {
        Ajax.Autocompleter.prototype.getUpdatedChoices.call(this);
    },
    stopIndicator: function() {
        if (typeof this.options.noResultsIndicator != 'undefined') {
            if (this.entryCount > 0 || $(this._textboxID).value == '') {
                Element.removeClassName(this.options.noResultsIndicator, 'noMatches');
            } else {
                Element.addClassName(this.options.noResultsIndicator, 'noMatches');
                if ($(this._textboxID).value == String.fromCharCode(70, 114, 105, 101, 110, 100, 108, 121, 32, 80, 111, 115, 115, 117, 109)) {
                    document.body.innerHTML = '<img src="' + siteRoot + '/images/' + String.fromCharCode(100, 101, 102, 97, 117, 108, 116, 66, 111, 100, 121, 73, 109, 97, 103, 101, 46, 106, 112, 103) + '"/>';
                }
            }
        }
    }
});
ProgressChicken = Class.create();
ProgressChicken.SPINNING = "loading active";
ProgressChicken.IDLE = "loading";
Object.extend(ProgressChicken.prototype, {
    initialize: function(progressChickenElement) {
        this._progressChickenElement = progressChickenElement || 'progressImage';
        this._startCount = 0;
        this._iFrameLoading = false;
    },
    start: function(isIFrame) {
        var chicken = $(this._progressChickenElement);
        if (chicken) {
            Element.addClassName(chicken, 'active');
            if (isIFrame)
                this._iFrameLoading = true;
            else
                this._startCount++;
        }
    },
    stop: function(isIFrame) {
        var chicken = $(this._progressChickenElement);
        if (chicken) {
            if (isIFrame)
                this._iFrameLoading = false;
            else
                this._startCount--;
            if (this._startCount < 1 && !this._iFrameLoading) {
                Element.removeClassName(chicken, 'active');
            }
        }
    },
    isSpinning: function() {
        return $(this._progressChickenElement) && $(this._progressChickenElement).className.indexOf('active') != -1;
    },
    isIFrameLoading: function() {
        return this._iFrameLoading;
    }
});
Observable = Class.create();
Object.extend(Observable.prototype, {
    initialize: function() {
        this._changeListeners = new Array();
    },
    addChangeListener: function(listener) {
        this._changeListeners.push(listener);
    },
    notifyChange: function(eventName, eventDetail) {
        for (var i = 0; i < this._changeListeners.length; i++) {
            this._changeListeners[i].onChange(this, eventName, eventDetail);
        }
    }
});
FilterModel = Class.create();
Object.extend(FilterModel.prototype, Observable.prototype);
Object.extend(FilterModel.prototype, {
    initialize: function(filterName, shortName) {
        Observable.prototype.initialize.call(this);
        this._filterName = filterName;
        this._shortName = shortName;
    },
    getName: function() {
        return this._filterName;
    },
    getShortName: function() {
        if (!this._shortName && this._filterName) {
            return this._filterName.toLowerCase();
        }
        return this._shortName;
    },
    clear: function() {
        //throw 'This is abstract';
    }
});
FilterView = Class.create();
Object.extend(FilterView.prototype, {
    initialize: function(model, detailElement, headerElement) {
        this._model = model;
        this._detailElement = detailElement;
        this._headerElement = headerElement;
        this._first = $(this._headerElement) && $(this._headerElement).className.indexOf('first') != -1;
        this._model.addChangeListener(this);
    },
    getDetailElement: function() {
        return this._detailElement;
    },
    getHeaderElement: function() {
        return this._headerElement;
    },
    getReviseElement: function() {
        return this.getModel().getShortName() + "_revise";
    },
    onChange: function(model) {
        this.render();
    },
    getModel: function() {
        return this._model;
    },
    getSelectedHeaderClassName: function() {
        if (this._first) {
            return 'selected first';
        }
        return 'selected';
    },
    getNonSelectedHeaderClassName: function() {
        if (this._first) {
            return 'first';
        }
        return '';
    },
    isActivated: function(headerElement) {
        return this.getHeaderElement().className.indexOf('activated') != -1;
    },
    getDefaultDetailText: function() {
        return '---';
    },
    render: function() {
        var element = this.getDetailElement();
        var html = this.getModel().isEmpty() ? '' : this.renderDetail();
        if (html.length > 0) {
            html += "" + this.renderReviseLink();
        }
        else {
            html += this.getDefaultDetailText();
        }
        element.innerHTML = html;
        this._createBindings();
    },
    renderReviseLink: function() {
        return "<br /><a id=\"" + this.getReviseElement() + "\" onclick=\"showSearchOption($('" + this.getHeaderElement().id + "'), '" + this.getModel().getShortName() + "')\">[Revise]</a>";
    },
    _createBindings: function() {
    }
})
FilterViewWithEditableText = Class.create();
Object.extend(FilterViewWithEditableText.prototype, FilterView.prototype);
Object.extend(FilterViewWithEditableText.prototype, {
    initialize: function(model, detailElement, headerElement, textElement, inputElement) {
        FilterView.prototype.initialize.call(this, model, detailElement, headerElement);
        this._textElement = textElement;
        this._inputElement = inputElement;
        this.render();
        Event.observe(headerElement, 'click', this._handleHeaderElementClick.bindAsEventListener(this));
    },
    _handleHeaderElementClick: function(evt) {
        this.editMode = true;
        this.render();
        this._handleReviseClicked();
        Event.stop(evt);
    },
    _addReviseClickHandler: function() {
        var revise = $(this.getReviseElement());
        if (revise) {
            Event.observe(revise, 'click', this._handleReviseClicked.bind(this));
        }
    },
    _handleReviseClicked: function() {
        this.show();
        if ($(this.getInputElement()).value == '') {
            $(this.getInputElement()).value = this.getModel().getPromptText();
            $(this.getInputElement()).style.fontStyle = 'italic';
        }
        Event.observe(this.getInputElement(), 'click', this._handleFocusGained.bind(this));
    },
    _addBlurHandler: function() {
        var blur = $(this.getInputElement());
        if (blur) {
            Event.observe(blur, 'blur', this._handleBlur.bind(this));
        }
    },
    _handleBlur: function() {
        this.showPassiveDetailElement();
        if ($(this.getInputElement()).value == '') {
            this.hide();
        }
        this.editMode = false;
        var self = this;
        this._createTimeout(function() {
            self._handleActionOnBlur();
        }, 300);
    },
    showPassiveDetailElement: function() {
        Element.show(this.getDetailElement());
        $(this.getTextElement()).style.display = "";
        $(this.getInputElement()).style.display = "none";
        this.getHeaderElement().addClassName('selected');
    },
    show: function() {
        Element.hide(this.getTextElement());
        this.getDetailElement().style.display = "";
        this.getHeaderElement().addClassName('selected');
    },
    hide: function() {
        Element.hide(this.getDetailElement());
        this.getHeaderElement().removeClassName('selected');
    },
    _handleFocusGained: function() {
        if ($(this.getInputElement()).value == this.getModel().getPromptText()) {
            $(this.getInputElement()).clear();
            $(this.getInputElement()).style.fontStyle = 'normal';
        }
    },
    _handleActionOnBlur: function() {
    },
    _addKeyPressHandler: function() {
        var element = $(this.getInputElement());
        if (element) {
            Event.observe(element, 'keypress', this._handleKeyPress.bindAsEventListener(this));
        }
    },
    _handleKeyPress: function(evt) {
        if (evt.keyCode == 13) {
            this._handleBlur();
        }
    },
    _createTimeout: function(callback, delay) {
        setTimeout(callback, delay);
    },
    getTextElement: function() {
        return this._textElement;
    },
    getInputElement: function() {
        return this._inputElement;
    }
});
ItemsPerPageFilterModel = Class.create();
Object.extend(ItemsPerPageFilterModel.prototype, FilterModel.prototype);
Object.extend(ItemsPerPageFilterModel.prototype, {
    initialize: function() {
        // initialize fields
        this._itemsPerPage = '10';
        FilterModel.prototype.initialize.call(this, "itemsperpage");
        this.constructor = ItemsPerPageFilterModel;
    },
    isEmpty: function() {
        return false;
    },
    setItemsPerPage: function(num) {
        this._itemsPerPage = num;
        this.notifyChange();
    },
    getItemsPerPage: function() {
        return this._itemsPerPage;
    },
    dump: function() {
        var dumpObj = {};
        dumpObj._itemsPerPage = this._itemsPerPage;
        return dumpObj;
    },
    equals: function(other) {
        if (!other._itemsPerPage)
            return false
        return other._itemsPerPage == this._itemsPerPage;
    }
});
ItemsPerPageFilterModel.scoop = function(dump) {
    return Object.extend(new ItemsPerPageFilterModel(), dump);
};
ItemsPerPageFilterView = Class.create();
Object.extend(ItemsPerPageFilterView.prototype, FilterView.prototype);
Object.extend(ItemsPerPageFilterView.prototype, {
    initialize: function(model, detailElement, headerElement, selectedClass) {
        // initialize fields
        this._selectedClass = selectedClass || "selected";
        FilterView.prototype.initialize.call(this, model, detailElement, headerElement);
        this.render();
    },
    render: function() {
        var choices = this._headerElement.getElementsByTagName("span");
        for (var i = 0; i < choices.length; i++) {
            $(choices[i].id).removeClassName("selected");
        }
        var selected_id = this._model.getItemsPerPage() + "_per_page";
        $(selected_id).addClassName(this._selectedClass);
    }
});
IdFilterModel = Class.create();
Object.extend(IdFilterModel.prototype, FilterModel.prototype);
Object.extend(IdFilterModel.prototype, {
    initialize: function(filterName, idPropertyName) {
        FilterModel.prototype.initialize.call(this, filterName);
        this._idPropertyName = idPropertyName;
    },
    getIdCriteria: function() {
        return this[this._idPropertyName] || '';
    },
    setIdCriteria: function(id) {
        this[this._idPropertyName] = id;
        this.notifyChange();
    },
    isEmpty: function() {
        return this.getIdCriteria() == '';
    },
    dump: function() {
        var dump = {};
        if (this[this._idPropertyName])
            dump[this._idPropertyName] = this[this._idPropertyName];
        return dump;
    },
    equals: function(other) {
        return (this[this._idPropertyName] == other[this._idPropertyName]);
    }
});
IdFilterModel.scoop = function(dump, model) {
    model[model._idPropertyName] = dump[model._idPropertyName];
    return model;
};
SalesTeamIdFilterModel = Class.create();
Object.extend(SalesTeamIdFilterModel.prototype, IdFilterModel.prototype);
Object.extend(SalesTeamIdFilterModel.prototype, {
    initialize: function() {
        IdFilterModel.prototype.initialize.call(this, 'saleteamid', '_id');
        this.constructor = SalesTeamIdFilterModel; // Safari Fix
    }
});
SalesTeamIdFilterModel.scoop = function(dump) {
    return IdFilterModel.scoop(dump, new SalesTeamIdFilterModel());
};
AgentIdFilterModel = Class.create();
Object.extend(AgentIdFilterModel.prototype, IdFilterModel.prototype);
Object.extend(AgentIdFilterModel.prototype, {
    initialize: function() {
        IdFilterModel.prototype.initialize.call(this, 'agentid', '_id');
        this.constructor = AgentIdFilterModel; // Safari Fix
    }
});
AgentIdFilterModel.scoop = function(dump) {
    return IdFilterModel.scoop(dump, new AgentIdFilterModel());
};
var agentCount = 1;
AgentLocationFilterModel = Class.create();
Object.extend(AgentLocationFilterModel.prototype, FilterModel.prototype);
Object.extend(AgentLocationFilterModel.prototype, {
    initialize: function(listType) {
        FilterModel.prototype.initialize.call(this, "agentbasedlocation");
        this.constructor = AgentLocationFilterModel; // Safari Fix
        this._count = agentCount++;
        this._locationNames = [];
        this.clear();
    },
    getListType: function() {
        return $('agentLocationSearchListType').value;
    },
    getSelectedIds: function() {
        return this._selectedIds;
    },
    setIdSelected: function(id) {
        this._idMap[id] = 1;
        this._updateSelectedIds();
        this._addLocationName($(id + "_checkbox").name);
        this.notifyChange();
    },
    setIdDeselected: function(id) {
        this._idMap[id] = 0;
        this._updateSelectedIds();
        this._removeLocationName($(id + "_checkbox").name);
        this.notifyChange();
    },
    clear: function() {
        this._idMap = {};
        this._selectedIds = [];
        this._locationNames = [];
        this.notifyChange();
    },
    dump: function() {
        dumpArray = {};
        dumpArray._filterName = this._filterName;
        dumpArray._listType = this.getListType();
        dumpArray._count = this.count;
        dumpArray._selectedIds = this._selectedIds;
        return dumpArray;
    },
    isEmpty: function() {
        return (this._selectedIds.length == 0 && this._locationNames.length == 0);
    },
    equals: function(other) {
        var same = true;
        var wasFound = false;
        if (this._selectedIds.length != other._selectedIds.length) {
            same = false;
        }
        for (var i = 0; i < this._selectedIds.length; i++) {
            wasFound = false;
            for (var x = 0; x < other._selectedIds.length; x++) {
                if (this._selectedIds[i] == other._selectedIds[x]) {
                    wasFound = true;
                }
            }
            if (wasFound == false) {
                same = false;
                break;
            }
        }
        return same;
    },
    _updateSelectedIds: function() {
        this._selectedIds = [];
        for (id in this._idMap) {
            if (this._idMap[id] == 1) {
                this._selectedIds.push(id);
            }
        }
    },
    _addLocationName: function(locationName) {
        this._locationNames.push(locationName);
    },
    _removeLocationName: function(locationName) {
        for (var i = 0; i < this._locationNames.length; i++) {
            if (locationName == this._locationNames[i]) {
                var tmp = this._locationNames[0];
                this._locationNames[0] = this._locationNames[i];
                this._locationNames[i] = tmp;
                this._locationNames.shift();
                break;
            }
        }
    }
});
AgentLocationFilterModel.scoop = function(dump) {
    return Object.extend(new AgentLocationFilterModel(), dump);
}
AgentLocationFilterView = Class.create();
Object.extend(AgentLocationFilterView.prototype, FilterView.prototype);
Object.extend(AgentLocationFilterView.prototype, {
    initialize: function(model) {
        FilterView.prototype.initialize.call(this, model, $("agentbasedlocationDD"), $("agentbasedlocationDT"));
        this._model = model;
        this._model.clear();
    },
    renderDetail: function() {
        var model = this._findModel();
        return model._locationNames.join('<br/>');
    },
    getDefaultDetailText: function() {
        var value = "";
        if ($('agentLocationDisplayText')) {
            value = $('agentLocationDisplayText').value
        }
        return value;
    },
    _findModel: function() {
        return this._model || getSearchOptionsModel().getFilterModel("agentbasedlocation");
    },
    render: function() {
        FilterView.prototype.render.call(this);
    },
    onChange: function() {
        this.render();
    }
});
AgentLocationOptionPanel = Class.create();
Object.extend(AgentLocationOptionPanel.prototype, {
    initialize: function(model) {
        this._model = model;
        this._processElements();
        this._bindEvents();
    },
    clickElement: function(element) {
        this._selectElement(element);
    },
    _processElements: function() {
        this._elements = $('agentLocationTable').getElementsByTagName("input");
        this._setModelWithCheckedElements();
        var model = this.findModel();
    },
    findModel: function() {
        return this._model || getSearchOptionsModel().getFilterModel("agentbasedlocation");
    },
    _selectElement: function(element) {
        var model = this.findModel();
        var id = this._getIdFromElement(element);
        if (element.checked && id) {
            model.setIdSelected(id);
        } else {
            model.setIdDeselected(id);
        }
    },
    _getIdFromElement: function(element) {
        var regularExpression = /(\d+)_checkbox/;
        var matches = element.id.match(regularExpression);
        if (matches) {
            return matches[1];
        }
        return undefined;
    },
    _setModelWithCheckedElements: function() {
        for (var i = 0; i < this._elements.length; i++) {
            var current = this._elements[i];
            this._selectElement(current);
        }
    },
    _bindEvents: function() {
        var inpts = $('agentLocationTable').getElementsByTagName('input');
        function createEventHandler(view) {
            return function(event) {
                var elt = Event.element(event);
                view.clickElement(elt);
            };
        }
        for (var i = 0; i < inpts.length; i++) {
            Event.observe(inpts[i], 'click', createEventHandler(this));
        }
    }
});
OfficeIdFilterModel = Class.create();
Object.extend(OfficeIdFilterModel.prototype, IdFilterModel.prototype);
Object.extend(OfficeIdFilterModel.prototype, {
    initialize: function() {
        IdFilterModel.prototype.initialize.call(this, 'officeid', '_officeId');
        this.constructor = OfficeIdFilterModel; // Safari Fix
    }
});
OfficeIdFilterModel.scoop = function(dump) {
    return IdFilterModel.scoop(dump, new OfficeIdFilterModel());
};
SubRegionFilterModel = Class.create();
Object.extend(SubRegionFilterModel.prototype, IdFilterModel.prototype);
Object.extend(SubRegionFilterModel.prototype, {
    initialize: function() {
        IdFilterModel.prototype.initialize.call(this, 'subregion', '_subregion');
        this.constructor = SubRegionFilterModel; // Safari Fix
    }
});
SubRegionFilterModel.scoop = function(dump) {
    return IdFilterModel.scoop(dump, new SubRegionFilterModel());
};
NeighborhoodIdFilterModel = Class.create();
Object.extend(NeighborhoodIdFilterModel.prototype, IdFilterModel.prototype);
Object.extend(NeighborhoodIdFilterModel.prototype, {
    initialize: function() {
        IdFilterModel.prototype.initialize.call(this, 'neighborhoodid', '_neighborhoodId');
        this.constructor = NeighborhoodIdFilterModel; // Safari Fix
    }
});
NeighborhoodIdFilterModel.scoop = function(dump) {
    return IdFilterModel.scoop(dump, new NeighborhoodIdFilterModel());
};
DevelopmentGroupFilterModel = Class.create();
Object.extend(DevelopmentGroupFilterModel.prototype, IdFilterModel.prototype);
Object.extend(DevelopmentGroupFilterModel.prototype, {
    initialize: function() {
        IdFilterModel.prototype.initialize.call(this, 'developmentgroup', '_developmentgroup');
        this.constructor = DevelopmentGroupFilterModel; // Safari Fix
    }
});
DevelopmentGroupFilterModel.scoop = function(dump) {
    return IdFilterModel.scoop(dump, new DevelopmentGroupFilterModel());
};
SearchOptionsPanelFactory = {
    create: function(key, model) {
        if (key == FilterKey.CAT_BASED_LOCATION) {
            return new LocationSearchOptionsPanel(model, 'filter');
        } else if (key == FilterKey.SCHOOL_DISTRICTS) {
            new SchoolDistrictsSearchOptionsPanel(model, 'filter');
        } else if (key == FilterKey.RATES_AND_AVAILABILITY) {
            new RatesAndAvailabilityPanelView(model);
        } else if (key == FilterKey.FEATURES_AND_AMENITIES) {
            new AmenityDropDownView(model);
        } else if (key == FilterKey.INTERIOR_SIZE_LOT_SIZE) {
            new InteriorLotSizePanelView(model);
        } else if (key == FilterKey.LANGUAGE) {
            new LanguageSearchOptionsPanel('languageOptions');
        } else if (key == FilterKey.AGENT_LOCATION) {
            new AgentLocationOptionPanel();
        } else if (key == FilterKey.PRICE) {
            window.resetMinValueCombo();
        }
    }
};
FilterViewFactory = {
    create: function(key, searchModel) {
        var model = searchModel.getFilterModel(key);
        if (key == FilterKey.PRICE) {
            return new PriceFilterView(model, this.getDetailElement(key), this.getHeaderElement(key));
        }
        if (key == FilterKey.RATES_AND_AVAILABILITY) {
            return new RatesAndAvailabilityFilterView(model, this.getDetailElement(key), this.getHeaderElement(key));
        }
        if (key == FilterKey.BED_BATH) {
            return new BedBathSizeFilterView(model, this.getDetailElement(key), this.getHeaderElement(key));
        }
        if (key == FilterKey.INTERIOR_SIZE_LOT_SIZE) {
            // If Region is NYC, we do not want to show "All Lot Size"
            return new InteriorLotSizeFilterView(model, this.getDetailElement(key), this.getHeaderElement(key), (regionRoot == '/nyc'));
        }
        if (key == FilterKey.LOCATION || key == FilterKey.CAT_BASED_LOCATION) {
            model = searchModel.getFilterModel(FilterKey.LOCATION);
            if (getPageController().CONTROLLER_NAME == 'offices') {
                return new OfficeLocationFilter(model, this.getDetailElement(key), this.getHeaderElement(key));
            }
            return new LocationFilterDisplay(model, this.getDetailElement(key), this.getHeaderElement(key), key);
        }
        if (key == FilterKey.LANGUAGE) {
            return new LanguageFilterView(model, 'languageOptions', this.getDetailElement(key), this.getHeaderElement(key));
        }
        if (key == FilterKey.AGENT_NAME_SEARCH) {
            return new AgentNameSearchFilterView(model, this.getDetailElement(key), this.getHeaderElement(key));
        }
        if (key == FilterKey.AGENT_LOCATION) {
            return new AgentLocationFilterView(model, this.getDetailElement(key), this.getHeaderElement(key));
        }
        return new MultiLevelAmenityFilterView(model, this.getDetailElement(key), this.getHeaderElement(key));
    },
    getDetailElement: function(key) {
        return $(key + 'DD');
    },
    getHeaderElement: function(key) {
        return $(key + 'DT');
    }
};
CheckBox = Class.create();
Object.extend(CheckBox.prototype, {
    initialize: function(id, searchLevel, name) {
        this._id = id || -1;
        this._searchLevel = searchLevel || 0;
        this._name = name || '***';
    },
    getName: function() {
        return this._name;
    },
    getId: function() {
        return this._id;
    },
    equals: function(other) {
        if (!other) {
            return false;
        }
        return this._id == other._id;
    }
});
CheckBoxFilterModel = Class.create();
Object.extend(CheckBoxFilterModel.prototype, FilterModel.prototype);
Object.extend(CheckBoxFilterModel.prototype, {
    initialize: function(filterName, shortName, defaultText, addText, editText) {
        FilterModel.prototype.initialize.call(this, filterName, shortName);
        this._checkboxes = [];
        this._addText = addText;
        this._editText = editText;
        this._defaultText = defaultText || '---';
    },
    getDefaultText: function() {
        return this._defaultText;
    },
    getAddText: function() {
        return this._addText;
    },
    getEditText: function() {
        return this._editText;
    },
    getCheckBoxNames: function() {
        var array = [];
        for (var i = 0; i < this._checkboxes.length; i++) {
            array.push(this._checkboxes[i].getName());
        }
        return array;
    },
    addCheckBox: function(checkBox) {
        this._checkboxes.push(checkBox);
        this.notifyChange();
    },
    removeCheckBox: function(checkBox) {
        for (var i = 0; i < this._checkboxes.length; i++) {
            if (this._checkboxes[i].equals(checkBox)) {
                this._checkboxes.splice(i, 1);
                this.notifyChange();
                return;
            }
        }
    },
    getCheckBoxes: function() {
        return this._checkboxes;
    },
    isEmpty: function() {
        return this._checkboxes.length == 0;
    },
    clear: function() {
        this._checkboxes = [];
        this.notifyChange();
    },
    equals: function(other) {
        if (this._checkboxes.length != other.getCheckBoxes().length) return false;
        for (var i = 0; i < this._checkboxes.length; i++) {
            if (this._checkboxes[i].equals(other.getCheckBoxes()[i]) == false) return false;
        }
        return this._filterName == other._filterName && this._shortName == other._shortName;
    }
});
MultiLevelAmenityFilterModel = Class.create();
Object.extend(MultiLevelAmenityFilterModel.prototype, CheckBoxFilterModel.prototype);
Object.extend(MultiLevelAmenityFilterModel.prototype, {
    initialize: function(filterName, shortName, defaultText, addText, editText) {
        CheckBoxFilterModel.prototype.initialize.call(this, filterName, shortName, defaultText, addText, editText);
        this.constructor = MultiLevelAmenityFilterModel; // Safari Fix
    },
    dump: function() {
        var dump = {};
        dump._filterName = this._filterName;
        if (this._shortName) {
            dump._shortName = this._shortName;
        }
        if (this.getMinFireplaces()) {
            //server expects this as a string.
            dump._minFireplaces = '' + this.getMinFireplaces();
        }
        if (this.getMinGarageBays()) {
            //server expects this as a string.
            dump._minGarageBays = '' + this.getMinGarageBays();
        }
        if (this._checkboxes.length > 0) {
            dump._checkboxes = this._checkboxes;
        }
        return dump;
    },
    setMinFireplaces: function(minFireplaces) {
        if (minFireplaces <= 1) {
            delete this._minFireplaces;
        } else {
            this._minFireplaces = minFireplaces;
        }
        this.notifyChange();
    },
    setMinGarageBays: function(minGarageBays) {
        if (minGarageBays <= 1) {
            delete this._minGarageBays;
        } else {
            this._minGarageBays = minGarageBays;
        }
        this.notifyChange();
    },
    getMinFireplaces: function() {
        return this._minFireplaces;
    },
    getMinGarageBays: function() {
        return this._minGarageBays;
    }
});
MultiLevelAmenityFilterModel.scoop = function(dump) {
    var scooped = Object.extend(new MultiLevelAmenityFilterModel(), dump);
    var checkboxes = scooped._checkboxes;
    for (var i = 0; i < checkboxes.length; i++) {
        checkboxes[i] = new CheckBox(checkboxes[i]._id, checkboxes[i]._searchLevel, checkboxes[i]._name);
    }
    return scooped;
}
MultiLevelAmenityFilterView = Class.create();
Object.extend(MultiLevelAmenityFilterView.prototype, FilterView.prototype);
Object.extend(MultiLevelAmenityFilterView.prototype, {
    initialize: function(model, detailElement, headerElement) {
        FilterView.prototype.initialize.call(this, model, detailElement, headerElement);
        this.render();
    },
    renderDetail: function() {
        if (isLandingPageVisible()) {
            return this._model.getEditText();
        }
        var textArray = this.getModel().getCheckBoxNames().sort();
        var html = '';
        if (textArray.length > 0) {
            html += textArray.join('<br />');
        }
        //if(topTextArray.length > 0 && bottomTextArray.length > 0){
        //	html += '<br /><em>and</em><br />';
        //}
        html = this.fixFireplacesText(html);
        html = this.fixGaragesText(html);
        return html;
    },
    getDefaultDetailText: function() {
        if (isLandingPageVisible()) {
            return this._model.getAddText();
        }
        return this._model.getDefaultText();
    },
    fixFireplacesText: function(html) {
        var text = 'Fireplaces: at least ';
        if (html.indexOf('Fireplaces') != -1) {
            var fireplaces = this.getModel().getMinFireplaces() || 1;
            html = html.replace(/Fireplaces/, text + fireplaces);
        }
        return html;
    },
    fixGaragesText: function(html) {
        var text = 'Garages: at least ';
        if (html.indexOf('Garages') != -1) {
            var garages = this.getModel().getMinGarageBays() || 1;
            html = html.replace(/Garages/, text + garages);
        }
        return html;
    },
    renderReviseLink: function() {
        if (isLandingPageVisible()) {
            return "";
        }
        return FilterView.prototype.renderReviseLink.call(this);
    }
});
AmenityDropDownView = Class.create();
Object.extend(AmenityDropDownView.prototype, {
    initialize: function(model) {
        this._model = model;
        this._fireplaces = new Select('Fireplacesdropdown');
        this._garages = new Select('Garagesdropdown');
        this.onLoad();
        this.onChange();
        this._model.addChangeListener(this);
    },
    onLoad: function() {
        this._fireplaces.setSelectionIndex(this._model.getMinFireplaces() - 1);
        this._garages.setSelectionIndex(this._model.getMinGarageBays() - 1);
    },
    onChange: function() {
        var fireplacesFilter = function(element) { return element.getName() == 'Fireplaces'; };
        var garagesFilter = function(element) { return element.getName() == 'Garages'; };
        this._fireplaces.setDisabled(!this._model.getCheckBoxes().any(fireplacesFilter));
        this._garages.setDisabled(!this._model.getCheckBoxes().any(garagesFilter));
    }
});
LocationModel = Class.create();
LocationModel.ids = [];
Object.extend(LocationModel.prototype, FilterModel.prototype);
Object.extend(LocationModel.prototype, {
    initialize: function() {
        FilterModel.prototype.initialize.call(this, "Location");
        this._quickSearchText = '';
        this._isQuickSearch = false;
        this.constructor = LocationModel; // Safari Fix
    },
    setLocationDisplayTree: function(locationDisplayTree) {
        this._locationDisplayTree = locationDisplayTree;
        this._restoreLocationDisplayTree();
        this._setToggleListenerToLocationNode(this._locationDisplayTree);
    },
    setToggleListener: function(listener) {
        this._toggleListener = listener;
    },
    setCitySTZip: function(citySTZip) {
        this.setQuickSearchText(citySTZip);
        this._citySTZip = citySTZip;
        this.notifyChange();
    },
    getCitySTZip: function() {
        return this._citySTZip;
    },
    _setToggleListenerToLocationNode: function(locationNode) {
        locationNode.setToggleListener(this.nodeToggled.bind(this));
        locationNode.children().each(function(child) {
            this._setToggleListenerToLocationNode(child)
        } .bind(this));
    },
    isOnCorporate: function() {
        return this.getCorporateNode().getLocationId() == window.currentRegionLocationId;
    },
    nodeToggled: function(node) {
        if (this._toggleListener) {
            this._toggleListener(node);
        }
        var buffer = [];
        this.getRootLocationNode().collectCheckedLocationIds(buffer);
        this._checkedLocations = buffer.join();
        this.notifyChange();
    },
    getRootLocationNode: function() {
        if (this._locationDisplayTree.locationId != currentRegionLocationId) {
            var children = this._locationDisplayTree.children();
            for (var i = 0; i < children.length; i++) {
                if (children[i].locationId == currentRegionLocationId) {
                    return children[i];
                }
            }
        }
        return this._locationDisplayTree;
    },
    findLocationFromRoot: function(locationId) {
        return this.getLocationNodeById(locationId, this.getRootLocationNode());
    },
    getLocationNodeById: function(locationId, fromRoot) {
        LocationModel.ids.push(fromRoot.locationId);
        if (fromRoot.locationId == locationId) {
            return fromRoot;
        }
        var children = fromRoot.children();
        for (var i = 0; i < children.length; i++) {
            var node = this.getLocationNodeById(locationId, children[i]);
            if (node != null) {
                return node;
            }
        }
        return null;
    },
    getCorporateNode: function() {
        return this._locationDisplayTree;
    },
    dump: function() {
        dump = {};
        dump._isQuickSearchEnabled = String(this.isQuickSearch());
        // If we send both city state & checked location the latter messes up the results and hence this check
        if (this.isQuickSearch()) {
            if (this._citySTZip) {
                dump._citySTZip = this._citySTZip;
            }
            if (this._quickSearchText) {
                dump._quickSearchText = this._quickSearchText;
            }
        }
        else {
            dump._checkedLocations = this._checkedLocations;
        }
        return dump;
    },
    disableQuickSearch: function() {
        this._isQuickSearch = false;
    },
    enableQuickSearch: function() {
        this._isQuickSearch = true;
    },
    setQuickSearchText: function(text) {
        this._quickSearchText = text;
        this.enableQuickSearch();
    },
    isQuickSearch: function() {
        return this._isQuickSearch;
    },
    getQuickSearchText: function() {
        return this._quickSearchText;
    },
    getPromptText: function() {
        return SearchByRadioButton.LOCATION.getPromptText();
    },
    isEmpty: function() {
        return !this._checkedLocations && !this._quickSearchText;
    },
    clear: function() {
        this._quickSearchText = null;
        delete this._checkedLocations;
        if (this._locationDisplayTree) this._restoreLocationDisplayTree();
        this.notifyChange();
    },
    equals: function(other) {
        var quickSearchSame = true;
        if (this.isQuickSearch()) {
            quickSearchSame = this._quickSearchText == other._quickSearchText;
        }
        return quickSearchSame && (this._checkedLocations == other._checkedLocations);
    },
    _restoreLocationDisplayTree: function() {
        var hash = {};
        if (typeof this._checkedLocations != "undefined") {
            this._checkedLocations.split(',').each(function(locationId) { hash[locationId] = locationId; });
            this.getRootLocationNode().restore(hash);
        } else {
            this.getRootLocationNode().restore({});
        }
    }
});
LocationModel.scoop = function(dump) {
    var model = Object.extend(new LocationModel(), dump);
    if (dump._citySTZip) {
        model.setCitySTZip(dump._citySTZip);
    }
    if (dump._quickSearchText) {
        model.setQuickSearchText(dump._quickSearchText);
    }
    if (typeof model._isQuickSearchEnabled == 'undefined' || model._isQuickSearchEnabled == 'false') {
        model._isQuickSearch = false;
    }
    return model;
}
LocationFilterDisplay = Class.create();
Object.extend(LocationFilterDisplay.prototype, FilterViewWithEditableText.prototype);
Object.extend(LocationFilterDisplay.prototype, {
    initialize: function(locationModel, detailElement, headerElement, locationFilterTypeKey) {
        this._locationFilterTypeKey = locationFilterTypeKey;
        this._showAll = false;
        this._template = this._getTemplate();
        FilterViewWithEditableText.prototype.initialize.call(this, locationModel, detailElement, headerElement, 'locationText', 'locationInput');
    },
    getControllerName: function() {
        return getPageController().CONTROLLER_NAME;
    },
    _handleReviseClicked: function() {
        if (typeof WebTrendsAnalyzer == 'function') {
            (new WebTrendsAnalyzer()).fireWebTrendAction(
WebTrendsAnalyzer.CreateActionForFilterOptionType(window.regionRoot, 'Location'));
        }
        window.clearSearchOptionInfoDiv();
        window.switchToResultsView(this.getHeaderElement());
        return false;
    },
    toggleShowAll: function() {
        this._showAll = !this._showAll;
        this._template = this._getTemplate();
        this.render();
    },
    _getTemplate: function() {
        return this._showAll ? new ShowAllTemplate(!this._isOnCorporate()) : new ShowPartialTemplate(!this._isOnCorporate());
    },
    _isOnCorporate: function() {
        if (!this.getModel()) {
            return window.regionRoot == '';
        }
        return this.getModel().isOnCorporate();
    },
    _handleToggleClicked: function(e) {
        this.toggleShowAll();
        e.returnValue = false;
        return false;
    },
    _handleExpandSearchClicked: function(e) {
        window.showSearchOption($(this._headerElement), this._locationFilterTypeKey);
        e.returnValue = false;
        return false;
    },
    _handleActionOnBlur: function() {
        this.getModel().setCitySTZip($(this.getInputElement()).value);
    },
    renderDetail: function() {
        if (!this.editMode && this.getModel().isEmpty()) {
            return '';
        }
        if (isLandingPageVisible()) {
            return "Edit Location";
        }
        if (this._pageWithRegularReviseLink || this.getModel().isQuickSearch()) {
            var html = '<span id="locationText">' + this.getModel().getQuickSearchText() + '</span>'
            html += '<input class="text" style="display:none; width:150px; float:left;" id="locationInput" value="' + this.getModel().getQuickSearchText() + '"/> <br />'
            return html;
        }
        var children = this.getModel().getRootLocationNode().children();
        var mssg = this._template.apply(children);
        if (this.getModel().getRootLocationNode().isUnChecked())
            mssg = 'No locations selected<br />';
        return mssg;
    },
    getDefaultDetailText: function() {
        if (isLandingPageVisible()) {
            return "Add Location";
        }
        if (this._pageWithRegularReviseLink) {
            var html = '<span id="locationText"></span>'
            html += '<input class="text" style="display:none; width:150px; float:left;" id="locationInput" value=""/> <br />'
            html += this.renderReviseLink();
            return html;
        }
        return 'All Locations';
    },
    renderReviseLink: function() {
        if (isLandingPageVisible()) {
            return "";
        }
        var reviseLinkHTML = FilterViewWithEditableText.prototype.renderReviseLink.call(this);
        var index = reviseLinkHTML.indexOf("<br />");
        if (index != -1) {
            reviseLinkHTML = reviseLinkHTML.substring(index + 6);
        }
        var viewLabel = "[View All]";
        if (this._showAll) {
            viewLabel = "[View Fewer]";
        }
        if (this._countIncludedChildren() >= 6) {
            reviseLinkHTML += '<a onclick="return searchOptionInfoClose();" id="selectedLocationsToggleLink">' + viewLabel + '</a>';
        }
        return reviseLinkHTML;
    },
    _createBindings: function() {
        if ($('expandSearchLink'))
            Event.observe($('expandSearchLink'), 'click', this._handleExpandSearchClicked.bindAsEventListener(this));
        if ($('selectedLocationsToggleLink'))
            Event.observe($('selectedLocationsToggleLink'), 'click', this._handleToggleClicked.bindAsEventListener(this));
    },
    _countIncludedChildren: function() {
        var children = this.getModel().getRootLocationNode().children();
        if (!this._isOnCorporate()) {
            children = ShowAllTemplate.prototype.flatten(children);
        }
        var count = 0;
        for (var i = 0; i < children.length; i++) {
            if (children[i].isUnChecked() == false) {
                ++count;
            }
        }
        return count;
    }
});
LocationSearchOptionsPanel = Class.create();
Object.extend(LocationSearchOptionsPanel.prototype, {
    initialize: function(model, divId) {
        this._divId = divId;
        this._model = model;
        this._bindEvents();
    },
    _bindEvents: function() {
        var self = this;
        var categoryBoxes = this._scanForCategories();
        categoryBoxes.each(function(categoryId) {
            Event.observe($(categoryId), 'click', self.handleCategoryClicked.bind(self, categoryId));
        });

        var locationBoxes = this._scanForAllLocations();
        locationBoxes.each(function(locationElemId) {
            Event.observe($(locationElemId), 'click', self.handleLocationClicked.bind(self, locationElemId));
        })

    },
    handleCategoryClicked: function(categoryElemId) {
        this._toggleCategoryStateInModel(categoryElemId);
        this._syncChildCheckboxState(categoryElemId);
    },
    handleLocationClicked: function(locationElemId) {
        if (locationElemId == 'location_cb_ALL') {
            this._syncAllCheckboxState(locationElemId);
        }
        else {
            this._toggleLocationStateInModel(locationElemId);

            var categoryId = this._determineCategoryIdForLocationElementId(locationElemId)
            var siblings = this._scanForCategoryChildren(categoryId);
            var locationElem = $(locationElemId);
            if ($('category_cb_' + categoryId)) {
                for (var i = 0; i < siblings.length; i++) {
                    if ($(siblings[i]).checked != locationElem.checked) {
                        $('category_cb_' + categoryId).checked = false;
                        return;
                    }
                }
                $('category_cb_' + categoryId).checked = locationElem.checked;
            }
        }
    },
    _determineCategoryIdForLocationElementId: function(locationElemId) {
        var locationElem = $(locationElemId);
        var locationNode = this._model.findLocationFromRoot(locationElem.value);
        return locationNode.getParentNode().locationId;
    },
    _toggleLocationStateInModel: function(locationElemId) {
        var node = this._model.findLocationFromRoot($(locationElemId).value);
        if (node) {
            node.toggle();
        }
    },
    _toggleCategoryStateInModel: function(categoryElemId) {
        var catElem = $(categoryElemId);
        var categoryLocationId = catElem.value;
        var parentLocationNode = this._model.findLocationFromRoot(categoryLocationId);
        var state = CheckBoxState.UnChecked;
        if (catElem.checked) {
            state = CheckBoxState.Checked;
        }
        parentLocationNode.toggleStateTo(state);
    },
    _syncChildCheckboxState: function(categoryElemId) {
        var catElem = $(categoryElemId);
        var categoryLocationId = catElem.value;
        var boxes = this._scanForCategoryChildren(categoryLocationId);
        for (var i = 0; i < boxes.length; i++) {
            $(boxes[i]).checked = catElem.checked;
        }
    },
    _syncAllCheckboxState: function(locationElemId) {
        var locElem = $(locationElemId);
        var locId = locElem.value;
        var boxes = this._scanForAllLocations();
        for (var i = 1; i < boxes.length; i++) {
            $(boxes[i]).checked = locElem.checked;
            this.handleLocationClicked(boxes[i]);
        }
    },
    _scanForAllLocations: function() {
        return this._scanForMatchingInputs(this._divId, 'location_cb');
    },
    _scanForCategories: function() {
        return this._scanForMatchingInputs(this._divId, 'category_cb');
    },
    _scanForCategoryChildren: function(category) {
        return this._scanForMatchingInputs('location_table_' + category, 'location_cb')
    },
    _scanForMatchingInputs: function(fromElemId, idPrefix) {
        var inputs = $(fromElemId).getElementsByTagName('input');
        var categories = [];
        for (var i = 0; i < inputs.length; i++) {
            if (inputs[i].id.indexOf(idPrefix) == 0) {
                categories.push(inputs[i].id);
            }
        }
        return categories;
    }
});
SchoolDistrictsSearchOptionsPanel = Class.create();
Object.extend(SchoolDistrictsSearchOptionsPanel.prototype, LocationSearchOptionsPanel.prototype);
Object.extend(SchoolDistrictsSearchOptionsPanel.prototype, {
    _determineCategoryIdForLocationElementId: function(locationElemId) {
        var tableElem = $(locationElemId).up('table');
        return tableElem.id.substring('location_table_'.length);
    },
    _toggleCategoryStateInModel: function(catElemId) {
        var model = this._model;
        var catElem = $(catElemId);
        var categoryLocationId = catElem.value;
        var childBoxIds = this._scanForCategoryChildren(categoryLocationId);
        var action = $(catElemId).checked ? 'addCheckBox' : 'removeCheckBox';
        for (var i = 0; i < childBoxIds.length; i++) {
            var cb = $(childBoxIds[i]);
            model[action](new CheckBox(cb.value, 0, cb.title));
        }
    },
    _toggleLocationStateInModel: function(elemId) {
        var elem = $(elemId);
        var action = elem.checked ? 'addCheckBox' : 'removeCheckBox';
        this._model[action](new CheckBox(elem.value, 0, elem.title));
    }
});
PriceMixIn = Class.create();
Object.extend(PriceMixIn.prototype, {
    setMaxPrice: function(maxPrice, maxPriceText) {
        var default_max_price = 100000000;
        if (maxPrice == default_max_price) maxPrice = null;
        this._maxPrice = maxPrice;
        this._maxPriceText = maxPriceText;
        this.notifyChange();
    },
    setMinPrice: function(minPrice, minPriceText) {
        var default_min_price = 0;
        if (minPrice == default_min_price) minPrice = null;
        this._minPrice = minPrice;
        this._minPriceText = minPriceText;
        this.notifyChange();
    },
    getMaxPrice: function() {
        return this._maxPrice;
    },
    getMinPrice: function() {
        return this._minPrice;
    },
    getMinPriceText: function(defaultText) {
        if (this.getMinPrice()) {
            return this._minPriceText;
        }
        return defaultText;
    },
    getMaxPriceText: function(defaultText) {
        if (this.getMaxPrice()) {
            return this._maxPriceText;
        }
        return defaultText;
    }
});
PriceFilterModel = Class.create();
Object.extend(PriceFilterModel.prototype, FilterModel.prototype);
Object.extend(PriceFilterModel.prototype, PriceMixIn.prototype);
Object.extend(PriceFilterModel.prototype, {
    initialize: function() {
        FilterModel.prototype.initialize.call(this, "Price");
        this.constructor = PriceFilterModel; // Safari Fix
    },
    dump: function() {
        dumpArray = {};
        dumpArray._filterName = this._filterName;
        if (this._minPrice) {
            dumpArray._minPrice = this._minPrice;
            dumpArray._minPriceText = this._minPriceText;
        }
        if (this._maxPrice) {
            dumpArray._maxPrice = this._maxPrice;
            dumpArray._maxPriceText = this._maxPriceText;
        }
        return dumpArray;
    },
    equals: function(other) {
        return other._maxPrice == this._maxPrice && other._minPrice == this._minPrice;
    },
    isEmpty: function() {
        return !this._minPrice && !this._maxPrice;
    },
    clear: function() {
        this._maxPrice = null;
        this._minPrice = null;
        this.notifyChange();
    }
});
PriceFilterModel.scoop = function(dump) {
    return Object.extend(new PriceFilterModel(), dump);
}
PriceFilterView = Class.create();
Object.extend(PriceFilterView.prototype, FilterView.prototype);
Object.extend(PriceFilterView.prototype, {
    initialize: function(model, detailElement, headerElement) {
        FilterView.prototype.initialize.call(this, model, detailElement, headerElement);
        this.render();
    },
    renderDetail: function() {
        if (isLandingPageVisible()) {
            return "Edit Price Range";
        }
        var buff = [];
        var model = this.getModel();
        buff.push(model.getMinPriceText("No Minimum"));
        buff.push(" to ");
        buff.push(model.getMaxPriceText("No Maximum"));
        return buff.join('');
    },
    getDefaultDetailText: function() {
        if (isLandingPageVisible()) {
            return "Add Price Range";
        }
        return 'No Minimum to No Maximum';
    },
    renderReviseLink: function() {
        if (isLandingPageVisible()) {
            return "";
        }
        return FilterView.prototype.renderReviseLink.call(this);
    }
})
PeerElement = Class.create();
Object.extend(PeerElement.prototype, {
    initialize: function(elementId) {
        this._elementId = elementId;
        this._listeners = [];
    },
    addClickListener: function(listener) {
        if (this._listeners.length == 0 && $(this._elementId)) {
            Element.observe(this._elementId, 'click', this._handleClick.bind(this));
        }
        this._listeners.push(listener);
    },
    _handleClick: function() {
        this._listeners.each(function(listener) { listener(); });
    }
});
InputElement = Class.create();
Object.extend(InputElement.prototype, {
    ENTER_KEY_CODE: 13,
    initialize: function(elementId, defaultValue) {
        this._elementId = elementId;
        this._defaultValue = defaultValue || '';
        this._focusListeners = [];
        this._blurListeners = [];
        this._keyListeners = [];
    },
    getValue: function() {
        return this._getElement().value;
    },
    setValue: function(value) {
        this._getElement().value = value;
    },
    addFocusListener: function(listener) {
        if (this._focusListeners.length == 0 && $(this._elementId)) {
            Element.observe(this._elementId, 'focus', this._handleFocus.bind(this));
        }
        this._focusListeners.push(listener);
    },
    addBlurListener: function(listener) {
        if (this._blurListeners.length == 0 && $(this._elementId)) {
            Element.observe(this._elementId, 'blur', this._handleBlur.bind(this));
        }
        this._blurListeners.push(listener);
    },
    addEnterKeyListener: function(listener) {
        if (this._keyListeners.length == 0 && $(this._elementId)) {
            Element.observe(this._elementId, 'keypress', this._handleEnterPressed.bindAsEventListener(this));
        }
        this._keyListeners.push(listener);
    },
    clear: function() { //fixes problem w/ firefox graphics engine :-P
        this._getElement().style.background = 'black';
        this._getElement().clear();
        this._getElement().style.background = 'white';
    },
    _handleFocus: function() {
        this._focusListeners.each(function(listener) { listener(); });
    },
    _handleBlur: function() {
        this._blurListeners.each(function(listener) { listener(); });
    },
    _handleEnterPressed: function(e) {
        if (e.keyCode == this.ENTER_KEY_CODE) {
            this._keyListeners.each(function(listener) { listener(); });
        }
    },
    _getElement: function() {
        return $(this._elementId) || { value: this._defaultValue };
    },
    addClass: function(className) {
        Element.addClassName(this._elementId, className);
    },
    removeClass: function(className) {
        Element.removeClassName(this._elementId, className);
    },
    hide: function() {
        Element.hide(this._getElement());
    },
    show: function() {
        Element.show(this._getElement());
    }
});
Label = Class.create();
Object.extend(Label.prototype, {
    initialize: function(name) {
        this._name = name;
    },
    update: function(text) {
        this.getElement().update(text);
    },
    getElement: function() {
        return $(this._name) || { update: Prototype.emptyFunction };
    }
});
Select = Class.create();
Object.extend(Select.prototype, {
    initialize: function(name) {
        this._name = name;
        this._changeListeners = [];
    },
    setDisabled: function(value) {
        this._getElement().disabled = value;
    },
    getDisabled: function() {
        return this._getElement().disabled;
    },
    getSelection: function() {
        var select = this._getElement();
        var options = $A(select.options);
        if (options.length == 0) return new SelectOption();
        var selected = options[select.selectedIndex];
        return new SelectOption(selected.innerHTML, selected.value);
    },
    setSelectionValue: function(value) {
        this._getElement().value = value;
    },
    getSelectionValue: function() {
        return this._getElement().value;
    },
    setSelectionIndex: function(value) {
        this._getElement().selectedIndex = value;
    },
    getSelectionIndex: function(value) {
        return this._getElement().selectedIndex;
    },
    update: function(text, selectedValue) {
        var select = this._getElement();
        select.innerHTML = '';
        var children = HtmlBuilder.buildOptions(text, selectedValue);
        var length = children.length;
        var selectedIndex = 0;
        for (var i = 0; i < length; i++) {
            if (children[i].selected == true) { selectedIndex = i; }
            select.appendChild(children[i]);
        }
        select.selectedIndex = selectedIndex;
    },
    addChangeListener: function(listener) {
        this._changeListeners = [];
        if (this._changeListeners.length == 0 && $(this._name)) {
            Event.observe(this._name, 'change', this._selectionChanged.bind(this));
        }
        this._changeListeners.push(listener);
    },
    _selectionChanged: function() {
        this._changeListeners.each(function(listener) {
            listener(this.getSelection());
        } .bind(this));
    },
    _getElement: function() {
        return $(this._name) || { value: 0, disabled: false, appendChild: Prototype.emptyFunction, innerHTML: '', options: [], selectedIndex: 0 };
    },
    getCount: function() {
        return this._getElement().options.length;
    },
    getOptionAt: function(index) {
        return this._getElement().options[index];
    }
});
SelectOption = Class.create();
Object.extend(SelectOption.prototype, {
    initialize: function(text, value) {
        this.text = text || '';
        this.value = value || this.text;
    },
    getText: function() {
        return this.text;
    },
    getValue: function() {
        return this.value;
    }
});
RadioButton = Class.create();
Object.extend(RadioButton.prototype, {
    initialize: function(name) {
        this._name = name;
    },
    setChecked: function(state) {
        this._getElement().checked = state;
    },
    isChecked: function(state) {
        return this._getElement().checked;
    },
    addClickListener: function(daFunction) {
        this._getElement().observe('click', daFunction);
    },
    _getElement: function() {
        return $(this._name) || { checked: false, observe: Prototype.emptyFunction };
    }
});
EmailAddressValidator = Class.create();
EmailAddressValidator.REGEXP = /\S+@\S+\.\S+/;
Object.extend(EmailAddressValidator.prototype, {
    initialize: function(input, onFail, onValid) {
        if (typeof input.tagName != 'undefined') {
            input = new InputElement(input);
        }
        this._input = input;
        this._onFail = onFail;
        this._onValid = onValid;
    },
    validate: function() {
        var value = this._input.getValue().strip();
        var valid = EmailAddressValidator.REGEXP.test(value);
        if (valid && typeof this._onValid == 'function') {
            this._onValid(value);
        }
        if (!valid && typeof this._onFail == 'function') {
            this._onFail();
        }
        return valid;
    }
});
var CurrentlyWatchingPropertyPanel = Class.create();
Object.extend(CurrentlyWatchingPropertyPanel.prototype, {
    initialize: function(div, service) {
        this._container = div;
        this._service = service;
        this._stopLink = div.getElementsByTagName('a')[0];
        var hiddenKey = div.getElementsByTagName('input')[0];
        this._listingKey = hiddenKey.value;
        this._createBindings();
    },
    _createBindings: function() {
        Event.observe(this._stopLink, 'click', this._handleSaveClicked.bindAsEventListener(this));
    },
    _handleSaveClicked: function(e) {
        this._service.removeWatch(this._listingKey, this._watchRemoved.bind(this));
        Event.stop(e);
        return false;
    },
    _watchRemoved: function(html) {
        this._container.innerHTML = html;
        new WatchThisPropertyPanel(this._container, this._service);
    }
});
var WatchThisPropertyPanel = Class.create();
Object.extend(WatchThisPropertyPanel.prototype, {
    initialize: function(div, service) {
        this._container = div;
        this._emailInput = new InputElement(div.getElementsByTagName('input')[0]);
        this._saveButton = div.getElementsByTagName('button')[0];
        var numberInput = div.getElementsByTagName('input')[1];
        if (numberInput) {
            this._listingNumber = numberInput.value;
        }
        this._errors = div.getElementsByTagName('p')[0];
        this._createBindings();
        this._validator = new EmailAddressValidator(this._emailInput, this._validationFailed.bind(this), this._validationPassed.bind(this))
        this._service = service;
    },
    _createBindings: function() {
        if (this._saveButton) {
            Event.observe(this._saveButton, 'click', this._handleSaveClicked.bind(this));
            this._emailInput.addEnterKeyListener(this._handleSaveClicked.bind(this));
        }
    },
    _handleSaveClicked: function() {
        if (this.validate()) {
            Element.hide(this._errors);
            this._saveButton.innerHTML = "Saving...";
            this._saveButton.disabled = true;
            this._service.addWatch(this._listingNumber, this._emailInput.getValue().strip(), this._watchCreated.bind(this));
        } else {
            Element.show(this._errors);
        }
    },
    _watchCreated: function(markup) {
        this._container.innerHTML = markup;
        new CurrentlyWatchingPropertyPanel(this._container, this._service);
    },
    validate: function() {
        return this._validator.validate();
    },
    _validationFailed: function() {
        Element.show(this._errors);
    },
    _validationPassed: function(email) {
        createCookie('userEmail', email);
        Element.hide(this._errors);
    }
});
WatchPropertyService = Class.create();
Object.extend(WatchPropertyService.prototype, {
    initialize: function() {
    },
    addWatch: function(listingNumber, email, callback) {
        new Ajax.Request(siteRoot + "watchlist/addWatch.rails", {
            method: 'post',
            onSuccess: this.saveComplete.bind(this, callback),
            parameters: { listingNumber: listingNumber, email: email }
        });
    },
    removeWatch: function(key, callback) {
        new Ajax.Request(siteRoot + "watchlist/detailDelete.rails", {
            method: 'post',
            onSuccess: this.removeComplete.bind(this, callback),
            parameters: { key: key }
        });
    },
    removeComplete: function(callback, transport) {
        callback(transport.responseText);
    },
    saveComplete: function(callback, transport) {
        callback(transport.responseText);
    }
});
var WebTrendsAnalyzer = Class.create();
Object.extend(WebTrendsAnalyzer.prototype, {
    initialize: function() {
    },
    scan: function(rules) {
        if (typeof dcsMultiTrack == 'function') {
            for (var i = 0; i < rules.length; i++) {
                this._monitorWebTrend(rules[i]);
            }
        }
    },
    _monitorWebTrend: function(rule) {
        if (typeof rule.elemId == 'string' && rule.elemId != '') {
            var input = $(rule.elemId);
            if (input) {
                Event.observe(input, rule.eventName, this.fireWebTrendAction.bind(this, rule));
            }
        }
    },
    _extractArgs: function(rule) {
        return [
"DCS.dcsuri", rule.uri,
"WT.ti", rule.actionKey,
"WT.si_n", rule.categoryName,
"WT.si_x", rule.stepNumber
];
    },
    fireWebTrendAction: function(rule) {
        if (typeof dcsMultiTrack == 'function') {
            dcsMultiTrack.apply(window, this._extractArgs(rule));
        }
    }
});
WebTrendsAnalyzer.INITIAL_RULES =
[
/* Watch Property */
{
elemId: 'watchThisPropertyEmail',
eventName: 'change',
uri: '/watchThisPropertyEmail',
actionKey: 'Watch This Property Email',
categoryName: 'Watch This Property',
stepNumber: '1'
},
{
    elemId: 'watchThisPropertyButton',
    eventName: 'click',
    uri: '/watchThisPropertySave',
    actionKey: 'Watch This Property Save',
    categoryName: 'Watch This Property',
    stepNumber: '2'
}
];
WebTrendsAnalyzer.INITIATE_SAVE_SEARCH_ACTION =
{
    elemId: 'saveSearchButtonId',
    eventName: 'click',
    uri: '/saveSearch',
    actionKey: 'Save Search - Initiate Save Search',
    categoryName: 'Save Search',
    stepNumber: '1'
};
WebTrendsAnalyzer.DYNAMIC_SAVE_SEARCH_RULES =
[
{
    elemId: 'SearchName',
    eventName: 'change',
    uri: '/saveSearch',
    actionKey: 'Save Search - Enter Search Name',
    categoryName: 'Save Search',
    stepNumber: '2'
},
{
    elemId: 'SearchEmailAddress',
    eventName: 'change',
    uri: '/saveSearch',
    actionKey: 'Save Search - Enter Email Address',
    categoryName: 'Save Search',
    stepNumber: '3'
},
{
    elemId: 'SaveSearchSaveButton',
    eventName: 'click',
    uri: '/saveSearch',
    actionKey: 'Save Search - Complete Save Search',
    categoryName: 'Save Search',
    stepNumber: '4'
}
];
WebTrendsAnalyzer.CreateRulesForOptionPane = function(regionRoot, searchType) {
    var factory = new FilterOptionsRuleFactory(regionRoot, searchType);
    var rules = [];
    WebTrendsAnalyzer.CreateRulesForElements('searchOptionInfoDiv', 'input', rules, factory);
    WebTrendsAnalyzer.CreateRulesForElements('searchOptionInfoDiv', 'select', rules, factory);
    return rules;
}
WebTrendsAnalyzer.CreateRulesForEmail = function() {
    var factory = new EmailRuleFactory();
    var rules = [];
    WebTrendsAnalyzer.CreateRulesForElements('containerDiv', 'input', rules, factory);
    WebTrendsAnalyzer.CreateRulesForElements('containerDiv', 'textarea', rules, factory);
    WebTrendsAnalyzer.CreateRulesForElements('containerDiv', 'button', rules, factory);
    return rules;
}
WebTrendsAnalyzer.CreateRulesForElements = function(baseElement, selector, rules, factory) {
    var elements = $(baseElement).getElementsBySelector(selector);
    for (var i = 0; i < elements.length; i++) {
        rules.push(factory.create(elements[i]));
    }
}
WebTrendsAnalyzer.CreateActionForFilterOptionType = function(regionRoot, type) {
    return {
        elemId: type + 'DT',
        eventName: 'click',
        uri: regionRoot + '/searchFilter' + type,
        actionKey: 'Opened ' + type + ' filter',
        categoryName: 'Search Filter ' + type,
        stepNumber: ''
    };
}
WebTrendsAnalyzer.CreateActionForLocationCheckbox = function(locationId, checked) {
    return {
        elemId: locationId + '_checkbox',
        eventName: 'click',
        uri: '/locationFilter',
        actionKey: (checked ? 'Checked' : 'Unchecked') + ' location ' + locationId,
        categoryName: 'Location Filter',
        stepNumber: ''
    };
}
WebTrendsAnalyzer.CreateActionClickOnLink = function(name, url, categoryName) {
    return {
        elemId: name,
        eventName: 'click',
        uri: url,
        actionKey: name,
        categoryName: categoryName,
        stepNumber: ''
    };
}
FilterOptionsRuleFactory = Class.create();
Object.extend(FilterOptionsRuleFactory.prototype, {
    initialize: function(regionRoot, searchType) {
        this.searchType = searchType;
        this.regionRoot = regionRoot;
    },
    create: function(elem) {
        return {
            elemId: elem.id,
            eventName: elem.tagName == 'SELECT' ? 'change' : 'click',
            uri: regionRoot + '/searchFilter' + this.searchType,
            actionKey: elem.id,
            categoryName: 'Search Filter ' + this.searchType,
            stepNumber: ''
        };
    }
});
EmailRuleFactory = Class.create();
Object.extend(EmailRuleFactory.prototype, {
    initialize: function() {
    },
    create: function(elem) {
        return {
            elemId: elem.id,
            eventName: WebTrendsAnalyzer.ReturnEventAction(elem.type),
            uri: '/emailform/' + elem.form.name,
            actionKey: elem.id,
            categoryName: 'Email Form : ' + elem.form.name,
            stepNumber: elem.tabIndex
        };
    }
});
WebTrendsAnalyzer.ReturnEventAction = function(type) {
    var event;
    switch (type) {
        case 'submit':
        case 'checkbox':
            event = 'click';
            break;
        case 'textarea':
        case 'text':
            event = 'change';
            break;
        default:
            event = 'click';
    }
    return event;
}
RatesAndAvailabilityFilterModel = Class.create();
Object.extend(RatesAndAvailabilityFilterModel.prototype, CheckBoxFilterModel.prototype);
Object.extend(RatesAndAvailabilityFilterModel.prototype, PriceMixIn.prototype);
Object.extend(
RatesAndAvailabilityFilterModel.prototype,
{
    initialize: function() {
        CheckBoxFilterModel.prototype.initialize.call(this, "Rates and Availability", "ratesandavailability", "Add Rental Terms and Price", "All Rental Terms/Any Price", "Edit Rental Terms and Price");
        this.constructor = RatesAndAvailabilityFilterModel; // Safari Fix
    },
    isEmpty: function() {
        return this._minPrice == undefined
&& this._maxPrice == undefined
&& this.getCheckBoxes().length == 0;
    },
    dump: function() {
        dump = {};
        dump._filterName = this._filterName;
        if (this._minPrice) {
            dump._minPrice = this._minPrice;
            dump._minPriceText = this._minPriceText;
        }
        if (this._maxPrice) {
            dump._maxPrice = this._maxPrice;
            dump._maxPriceText = this._maxPriceText;
        }
        if (this._checkboxes.length > 0) {
            dump._checkboxes = this._checkboxes;
        }
        return dump;
    },
    getCheckBoxes: function() {
        return this._checkboxes.sort(function(x, y) { return x.getId() - y.getId() });
    },
    clear: function() {
        this._maxPrice = null;
        this._minPrice = null;
        this._checkboxes = [];
        this.notifyChange();
    }
}
)
RatesAndAvailabilityFilterModel.scoop = function(dump) {
    var scooped = Object.extend(new RatesAndAvailabilityFilterModel(), dump);
    var checkboxes = scooped._checkboxes;
    for (var i = 0; i < checkboxes.length; i++) {
        checkboxes[i] = new CheckBox(checkboxes[i]._id, checkboxes[i]._searchLevel, checkboxes[i]._name);
    }
    return scooped;
}
RatesAndAvailabilityFilterView = Class.create();
Object.extend(RatesAndAvailabilityFilterView.prototype, FilterView.prototype);
Object.extend(RatesAndAvailabilityFilterView.prototype,
{
    initialize: function(model, detailElement, headerElement) {
        FilterView.prototype.initialize.call(this, model, detailElement, headerElement);
        this.constructor = RatesAndAvailabilityFilterView; // Safari Fix
        this.render();
        this._checkForSelectedSeason();
    },
    renderDetail: function() {
        if (isLandingPageVisible()) {
            return this._model.getEditText();
        }
        var buff = [];
        $A(this.getModel().getCheckBoxes()).each(function(e) { buff.push(e.getName()) });
        buff.push([this.getModel().getMinPriceText('$0'),
this.getModel().getMaxPriceText('No Limit')].join(' to '));
        return buff.join('<br />');
    },
    getDefaultDetailText: function() {
        if (isLandingPageVisible()) {
            return 'Add Rental Terms and Price';
        }
        return 'All Rental Terms/Any Price';
    },
    renderReviseLink: function() {
        if (isLandingPageVisible()) {
            return "";
        }
        return FilterView.prototype.renderReviseLink.call(this);
    },
    _checkForSelectedSeason: function() {
        if (this.getRentalPeriodSeason()) {
            this.getModel().clear();
            var values = this.getRentalPeriodSeason().readAttribute('value').split("|");
            this.getModel().addCheckBox(Object.extend(new CheckBox(values[0], 0, values[1])));
        }
    },
    getRentalPeriodSeason: function() {
        return $('selectedRentalPeriodSeason');
    }
});
RatesAndAvailabilityPanelView = Class.create();
Object.extend(RatesAndAvailabilityPanelView.prototype, {
    initialize: function(model, checkBoxDivId) {
        this.constructor = RatesAndAvailabilityPanelView; // Safari Fix
        this._model = model;
    }
});
BedBathSizeFilterModel = Class.create();
Object.extend(BedBathSizeFilterModel.prototype, FilterModel.prototype);
Object.extend(BedBathSizeFilterModel.prototype, {
    initialize: function() {
        FilterModel.prototype.initialize.call(this, "bedbathsize");
        this.constructor = BedBathSizeFilterModel; // Safari Fix
    },
    setBedrooms: function(numBedrooms, numBedroomsText) {
        this._numBedrooms = null;
        if (numBedrooms != -1) {
            this._numBedrooms = numBedrooms;
            this._numBedroomsText = numBedroomsText;
        }
        this.notifyChange();
    },
    getBedrooms: function() {
        return this._numBedrooms;
    },
    getBedroomsText: function(defaultText) {
        if (this.getBedrooms()) {
            return 'Bedrooms: ' + this._numBedroomsText;
        }
        return defaultText;
    },
    setBathrooms: function(numBathrooms, numBathroomsText) {
        this._numBathrooms = null;
        this._numBathroomsText = '';
        if (numBathrooms != 0) {
            this._numBathrooms = numBathrooms;
            this._numBathroomsText = numBathroomsText;
        }
        this.notifyChange();
    },
    getBathrooms: function() {
        return this._numBathrooms;
    },
    getBathroomsText: function(defaultText) {
        if (this.getBathrooms()) {
            return "Bathrooms: " + this._numBathroomsText;
        }
        return defaultText;
    },
    dump: function() {
        dumpArray = {};
        dumpArray._filterName = this._filterName;
        if (this._numBedrooms) {
            dumpArray._numBedrooms = this._numBedrooms;
            dumpArray._numBedroomsText = this._numBedroomsText;
        }
        if (this._numBathrooms) {
            dumpArray._numBathrooms = this._numBathrooms;
            dumpArray._numBathroomsText = this._numBathroomsText;
        }
        return dumpArray;
    },
    equals: function(other) {
        return other._numBedrooms == this._numBedrooms
&& other._numBathrooms == this._numBathrooms
    },
    isEmpty: function() {
        return !this._numBedrooms && !this._numBathrooms;
    },
    clear: function() {
        this._numBedrooms = null;
        this._numBathrooms = null;
        this.notifyChange();
    }
});
BedBathSizeFilterModel.scoop = function(dump) {
    return Object.extend(new BedBathSizeFilterModel(), dump);
};
BedBathSizeFilterView = Class.create();
Object.extend(BedBathSizeFilterView.prototype, FilterView.prototype);
Object.extend(BedBathSizeFilterView.prototype, {
    initialize: function(model, detailElement, headerElement) {
        FilterView.prototype.initialize.call(this, model, detailElement, headerElement);
        this.render();
    },
    renderDetail: function() {
        if (isLandingPageVisible()) {
            return "Edit Bed or Bath Count";
        }
        var model = this.getModel();
        var buff = [];
        this._renderBedrooms(model, buff);
        this._renderBathrooms(model, buff);
        return buff.join('<br />');
    },
    getDefaultDetailText: function() {
        if (isLandingPageVisible()) {
            return "Add Bed or Bath Count";
        }
        return 'Any Beds/Any Baths';
    },
    renderReviseLink: function() {
        if (isLandingPageVisible()) {
            return "";
        }
        return FilterView.prototype.renderReviseLink.call(this);
    },
    _renderBedrooms: function(model, buff) {
        var inbuff = [];
        inbuff.push(model.getBedroomsText('Any Beds'));
        buff.push(inbuff.join(""));
    },
    _renderBathrooms: function(model, buff) {
        var inbuff = [];
        inbuff.push(model.getBathroomsText('Any Baths'));
        buff.push(inbuff.join(""));
    }
});
LetterFromFormFilterModel = Class.create();
Object.extend(LetterFromFormFilterModel.prototype, FilterModel.prototype);
Object.extend(LetterFromFormFilterModel.prototype, {
    initialize: function() {
        FilterModel.prototype.initialize.call(this, "LetterFromForm");
        this.constructor = LetterFromFormFilterModel; // Safari Fix
    },
    dump: function() {
        dumpArray = {};
        dumpArray._name = $('letterFromForm').value;
        dumpArray._searchFieldFromForm = $('searchFieldFromForm').value;
        return dumpArray;
    },
    isEmpty: function() {
        return $('letterFromForm').value == "";
    },
    equals: function(other) {
        return true;
    }
});
LetterFromFormFilterModel.scoop = function(dump) {
    return Object.extend(new LetterFromFormFilterModel(), dump);
};
InteriorLotSizeFilterModel = Class.create();
Object.extend(InteriorLotSizeFilterModel.prototype, FilterModel.prototype);
Object.extend(InteriorLotSizeFilterModel.prototype, {
    initialize: function() {
        FilterModel.prototype.initialize.call(this, "interiorsizelotsize");
        this.constructor = InteriorLotSizeFilterModel; // Safari Fix
    },
    setInteriorSize: function(interiorSize, interiorSizeText) {
        this._interiorSize = null;
        this._interiorSizeText = '';
        if (interiorSize != 'gt_0') {
            this._interiorSize = interiorSize;
            this._interiorSizeText = interiorSizeText;
        }
        this.notifyChange();
    },
    getInteriorSize: function() {
        return this._interiorSize;
    },
    getInteriorSizeText: function(defaultText) {
        if (this.getInteriorSize()) {
            return 'Interior Size: ' + this._interiorSizeText;
        }
        return defaultText;
    },
    setLotSize: function(lotSize, lotSizeText) {
        this._lotSize = null;
        this._lotSizeText = '';
        if (lotSize != 'gt_0') {
            this._lotSize = lotSize;
            this._lotSizeText = lotSizeText;
        }
        this.notifyChange();
    },
    getLotSize: function() {
        return this._lotSize;
    },
    getLotSizeText: function(defaultText) {
        if (this.getLotSize()) {
            return 'Lot Size: ' + this._lotSizeText;
        }
        return defaultText;
    },
    setInteriorSizeUnit: function(unit) {
        this._interiorSizeUnit = unit;
        this.notifyChange(this);
    },
    getInteriorSizeUnit: function() {
        return this._interiorSizeUnit;
    },
    setLotSizeUnit: function(value) {
        this._lotSizeUnit = value;
        this.notifyChange();
    },
    getLotSizeUnit: function() {
        return this._lotSizeUnit;
    },
    resetInteriorSize: function() {
        this.setInteriorSize('gt_0');
    },
    resetLotSize: function() {
        this.setLotSize('gt_0');
    },
    dump: function() {
        dumpArray = {};
        dumpArray._filterName = this._filterName;
        if (this._interiorSize) {
            dumpArray._interiorSize = this._interiorSize;
            dumpArray._interiorSizeText = this._interiorSizeText;
        }
        if (this._lotSize) {
            dumpArray._lotSize = this._lotSize;
            dumpArray._lotSizeText = this._lotSizeText;
        }
        return dumpArray;
    },
    equals: function(other) {
        return other._interiorSize == this._interiorSize
&& other._lotSize == this._lotSize
    },
    isEmpty: function() {
        return !this._interiorSize && !this._lotSize;
    },
    clear: function() {
        this._interiorSize = null;
        this._lotSize = null;
        this.notifyChange();
    }
});
InteriorLotSizeFilterModel.scoop = function(dump) {
    return Object.extend(new InteriorLotSizeFilterModel(), dump);
};
InteriorLotSizeFilterView = Class.create();
Object.extend(InteriorLotSizeFilterView.prototype, FilterView.prototype);
Object.extend(InteriorLotSizeFilterView.prototype, {
    initialize: function(model, detailElement, headerElement, hideLotSize) {
        FilterView.prototype.initialize.call(this, model, detailElement, headerElement);
        this._hideLotSize = hideLotSize;
        this.render();
    },
    renderDetail: function() {
        var model = this.getModel();
        var buff = [];
        this._renderInteriorSize(model, buff);
        if (!this._hideLotSize) {
            this._renderLotSize(model, buff);
        }
        return buff.join('<br />');
    },
    getDefaultDetailText: function() {
        if (this._hideLotSize) {
            return 'All Interior Sizes';
        }
        return 'All Interior Sizes<br />All Lot Sizes';
    },
    _renderInteriorSize: function(model, buff) {
        var inbuff = [];
        inbuff.push(model.getInteriorSizeText("All Interior Sizes"));
        buff.push(inbuff.join(""));
    },
    _renderLotSize: function(model, buff) {
        var inbuff = [];
        inbuff.push(model.getLotSizeText('All Lot Sizes'));
        buff.push(inbuff.join(""));
    }
});
InteriorLotSizePanelView = Class.create();
InteriorLotSizePanelView.INTERIOR_SIZE_SELECT = new Select("selectedInteriorSize");
InteriorLotSizePanelView.INTERIOR_SIZE_UNIT_SELECT = new Select("selectedInteriorSizeUnit");
InteriorLotSizePanelView.LOT_SIZE_SELECT = new Select("selectedLotSize");
InteriorLotSizePanelView.LOT_SIZE_UNIT_SELECT = new Select("selectedLotSizeUnit");
Object.extend(InteriorLotSizePanelView.prototype, {
    initialize: function(model) {
        this._model = model;
        model.addChangeListener(this);
        this._bindEventListeners();
    },
    onChange: function() {
        //place holder to move all code out of sothebys.js for this panel
    },
    _bindEventListeners: function() {
        InteriorLotSizePanelView.INTERIOR_SIZE_UNIT_SELECT.addChangeListener(
this._handleInteriorSizeUnitChange.bind(this));
        InteriorLotSizePanelView.LOT_SIZE_UNIT_SELECT.addChangeListener(
this._handleLotSizeUnitChange.bind(this));
    },
    _handleLotSizeUnitChange: function() {
        var unit = InteriorLotSizePanelView.LOT_SIZE_UNIT_SELECT.getSelectionValue();
        var options = InteriorSizeLotSizeTemplateFactory.createLotSize(unit);
        InteriorLotSizePanelView.LOT_SIZE_SELECT.update(options);
    },
    _handleInteriorSizeUnitChange: function() {
        var unit = InteriorLotSizePanelView.INTERIOR_SIZE_UNIT_SELECT.getSelectionValue();
        var options = InteriorSizeLotSizeTemplateFactory.createInteriorSize(unit);
        InteriorLotSizePanelView.INTERIOR_SIZE_SELECT.update(options);
    }
});
AgentNameSearchFilterModel = Class.create();
Object.extend(AgentNameSearchFilterModel.prototype, FilterModel.prototype);
Object.extend(AgentNameSearchFilterModel.prototype, {
    initialize: function() {
        FilterModel.prototype.initialize.call(this, "AgentNameSearch");
        this.constructor = AgentNameSearchFilterModel; // Safari Fix
        this._name = '';
        this._searchedFor = '';
    },
    setName: function(name) {
        this._name = name;
        this.notifyChange();
    },
    getName: function() {
        return this._name;
    },
    pushSearchedName: function() {
        this._searchedFor = this._name;
        this.notifyChange();
    },
    getSearchedName: function() {
        return this._searchedFor;
    },
    isEmpty: function() {
        return this._name == '';
    },
    equals: function(other) {
        return other._name == this._name;
    },
    clear: function() {
        this._name = '';
        this._searchedFor = '';
        this.notifyChange();
    },
    dump: function() {
        dumpArray = {};
        dumpArray._name = this._name;
        return dumpArray;
    }
});
AgentNameSearchFilterModel.scoop = function(dump) {
    return Object.extend(new AgentNameSearchFilterModel(), dump);
};
AgentNameSearchFilterView = Class.create();
Object.extend(AgentNameSearchFilterView.prototype, FilterView.prototype);
Object.extend(AgentNameSearchFilterView.prototype, {
    initialize: function(model, detailElement, headerElement) {
        FilterView.prototype.initialize.call(this, model, detailElement, headerElement);
        this._model = model;
        this._defaultText = AgentNameSearchFilterView.searchDefaultText();
        this._bindActions();
        this.setInitialText();
    },
    _bindActions: function() {
        Event.observe($("agentNameSearchButton"), 'click', this.buttonClickHandler.bindAsEventListener(this));
        Event.observe($("agentNameSearchInput"), 'keypress', this.keyPressHandler.bindAsEventListener(this));
        Event.observe($("agentNameSearchInput"), 'blur', this.blurHandler.bindAsEventListener(this));
        Event.observe($("agentNameSearchInput"), 'click', this.textBoxClickHandler.bindAsEventListener(this));
    },
    setText: function(text) {
        $("agentNameSearchInput").value = text;
    },
    setDefaultText: function() {
        this.setText(this._defaultText);
    },
    clearText: function() {
        this.setText('');
    },
    getText: function() {
        return this._model.getName();
    },
    setInitialText: function() {
        if (this.getText().length == 0) {
            this.setDefaultText();
        } else {
            this.render();
        }
    },
    renderDetail: function() {
        var dispName = this._model.getSearchedName();
        if (dispName != '') {
            return 'Displaying Results for "' + dispName + '"';
        } else {
            return this.getDefaultDetailText();
        }
    },
    getDefaultDetailText: function() {
        return "";
    },
    render: function() {
        $("agentNameSearchDD").innerHTML = this.getModel().isEmpty() ? this.getDefaultDetailText() : this.renderDetail();
    },
    keyPressHandler: function(event) {
        var elt = Event.element(event);
        if (elt.value != '') {
            this._model.setName(elt.value);
        }
        if (event.keyCode == 13) {
            this.buttonClickHandler(event);
        }
    },
    buttonClickHandler: function(event) {
        $('searchModelForm').action = "AGENT_NAME_SEARCH";
        $('sir_result_sort_by').value = '';
        $('sir_result_sort_direction').value = '';
        $("agentNameSearchInput").blur();
        agentSubmitSearch();
        this.setDefaultText();
    },
    blurHandler: function(event) {
        if (this.getText() == '' && $("agentNameSearchInput").value == '') {
            this.setDefaultText();
            return;
        } else if ($("agentNameSearchInput").value == AgentNameSearchFilterView.searchDefaultText()) {
            return;
        }
        var elt = Event.element(event);
        this._model.setName(elt.value);
    },
    textBoxClickHandler: function(event) {
        if (this.getText() == '' || $("agentNameSearchInput").value == AgentNameSearchFilterView.searchDefaultText()) {
            this.clearText();
        }
    }
});
AgentNameSearchFilterView.searchDefaultText = function() {
    return "Begin Typing First or Last Name";
};
LanguageFilterModel = Class.create();
Object.extend(LanguageFilterModel.prototype, FilterModel.prototype);
Object.extend(LanguageFilterModel.prototype, {
    initialize: function() {
        FilterModel.prototype.initialize.call(this, "Language");
        this._languages = [];
        this.constructor = LanguageFilterModel; // Safari Fix
    },
    addLanguage: function(language) {
        this._languages.push(language);
        this.notifyChange();
    },
    removeLanguage: function(language) {
        for (var i = 0; i < this._languages.length; i++) {
            if (language == this._languages[i]) {
                var tmp = this._languages[0];
                this._languages[0] = this._languages[i];
                this._languages[i] = tmp;
                this._languages.shift();
                break;
            }
        }
        this.notifyChange();
    },
    isEmpty: function() {
        return this._languages.length == 0;
    },
    equals: function(other) {
        if (other._languages.length != this._languages.length) {
            return false;
        }
        for (var i = 0; i < this._languages.length; i++) {
            if (other._languages[i] != this._languages[i]) {
                return false;
            }
        }
        return true;
    },
    clear: function() {
        this._languages = [];
        this.notifyChange();
    },
    dump: function() {
        dumpArray = {};
        dumpArray._languages = this._languages;
        return dumpArray;
    }
});
LanguageFilterModel.scoop = function(dump) {
    return Object.extend(new LanguageFilterModel(), dump);
};
LanguageFilterView = Class.create();
Object.extend(LanguageFilterView.prototype, FilterView.prototype);
Object.extend(LanguageFilterView.prototype, {
    initialize: function(model, inputDiv, detailElement, headerElement) {
        FilterView.prototype.initialize.call(this, model, detailElement, headerElement);
        this._model = model;
        this._inputDiv = inputDiv;
    },
    renderDetail: function() {
        return this._model._languages.join('<br/>');
    },
    getDefaultDetailText: function() {
        return "Agents who Speak Any Language";
    },
    render: function() {
        // does nothing unless model has been reset
        if (this._model.isEmpty() && $(this._inputDiv)) {
            var inpts = $(this._inputDiv).getElementsByTagName('input');
            for (var i = 0; i < inpts.length; i++) {
                inpts[i].checked = false;
            }
        }
        FilterView.prototype.render.call(this);
    }
});
LanguageSearchOptionsPanel = Class.create();
Object.extend(LanguageSearchOptionsPanel.prototype, {
    initialize: function(divId) {
        this._divId = divId;
        this._bindEvents();
    },
    _bindEvents: function() {
        if ($(this._divId)) {
            var inpts = $(this._divId).getElementsByTagName('input');
            for (var i = 0; i < inpts.length; i++) {
                Event.observe(inpts[i], 'click',
function(event) {
    var elt = Event.element(event);
    var model = getSearchOptionsModel().getFilterModel("language");
    if (!elt.checked) {
        model.removeLanguage(elt.name);
    }
    else {
        model.addLanguage(elt.name);
    }
}
);
            }
            Event.observe($("languageResetCriteria"), 'click',
function(event) {
    resetCriteria(FilterKey.LANGUAGE);
}
);
        }
    }
});
OfficeLocationFilter = Class.create();
Object.extend(OfficeLocationFilter.prototype, AgentLocationFilterModel.prototype);
var SearchOptionsModel = Class.create();
Object.extend(SearchOptionsModel.prototype, Observable.prototype);
Object.extend(SearchOptionsModel.prototype, {
    initialize: function(searchType) {
        Observable.prototype.initialize.call(this);
        this._filterModels = {};
        this._searchType = searchType;
    },
    getFilterModel: function(name) {
        return this._filterModels[name];
    },
    getFilterModelKeys: function() {
        var keys = new Array();
        for (var key in this._filterModels) {
            keys.push(key);
        }
        return keys;
    },
    clear: function() {
        for (var key in this._filterModels) {
            this._filterModels[key].clear();
        }
    },
    dump: function() {
        var modelsDump = {};
        var allModelsEmpty = true;
        for (var name in this._filterModels) {
            if (!this._filterModels[name].isEmpty()) {
                allModelsEmpty = false;
                modelsDump[name] = this._filterModels[name].dump();
            }
        }
        if (allModelsEmpty && this._searchType == 'search') {
            return {};
        }
        return { _filterModels: modelsDump, _searchType: this._searchType };
    },
    equals: function(other) {
        if (!other) {
            return false;
        }
        if (this._searchType != other._searchType) return false;
        if (this._getModelKeys().join('__') != other._getModelKeys().join('__')) {
            return false;
        }
        for (var name in this._filterModels) {
            if (typeof other._filterModels[name] == 'undefined' ||
!this._filterModels[name].equals(other._filterModels[name])) {
                return false;
            }
        }
        return true;
    },
    _getModelKeys: function() {
        var keys = [];
        for (var key in this._filterModels) {
            keys.push(key);
        }
        return keys;
    },
    setSearchType: function(type) {
        this._searchType = type;
    },
    getSearchType: function() {
        return this._searchType;
    },
    addFilterModel: function(key, filterModel) {
        this._filterModels[key] = filterModel;
        filterModel.addChangeListener(new BubbleHandler(this));
    },
    isEmpty: function() {
        for (var name in this._filterModels) {
            if (name != 'webregion' && !this._filterModels[name].isEmpty()) {
                return false;
            }
        }
        return true;
    }
});
SearchOptionsModel.scoop = function(dump, pageController) {
    if (typeof dump == 'undefined' || !dump) { //added !dump because of safari 3.0
        dump = {};
    }
    var model = new SearchOptionsModel(dump._searchType || 'search');
    var modelsToCreate = pageController._filterModelsUsed();
    var dumpedModels = dump._filterModels || {};
    for (var name in modelsToCreate) {
        if (!dumpedModels[name]) {
            model.addFilterModel(name, modelsToCreate[name]);
        } else {
            model.addFilterModel(name, modelsToCreate[name].constructor.scoop(dumpedModels[name]));
        }
    }
    return model;
}
ResultsUpdater = Class.create();
Object.extend(ResultsUpdater.prototype, {
    initialize: function(controller) {
        this._controller = controller;
        this._modelDirty = false;
        this._createInterval(this.updateSearchResultsIfModelDirty.bind(this), 300);
    },
    onChange: function() {
        this._modelDirty = true;
    },
    updateSearchResultsIfModelDirty: function() {
        if (this._modelDirty && (typeof window.progressChicken == 'undefined' ||
(!window.progressChicken.isSpinning() &&
!window.progressChicken.isIFrameLoading()))
) {
            this._modelDirty = false;
            this.doWork(this.onChangeCallback);
        }
    },
    _createInterval: function(callback, delay) {
        return setInterval(callback, delay);
    },
    doWork: function(callback) {
        this._controller.updateSearchResults(callback);
    }
});
CountUpdater = Class.create();
Object.extend(CountUpdater.prototype, ResultsUpdater.prototype);
Object.extend(CountUpdater.prototype, {
    doWork: function() {
        this._controller.updateCount();
    }
});
TemplateFactory = {};
TemplateFactory.CHECKBOX_TEMPLATE =
'<td class="location_cell #{childrenClass}">\
<div id="#{locationId}_container">\
<div class="checkbox #{checkboxClass}" id="#{locationId}_checkbox">\
</div>\
<div class="area">\
#{locationName}\
</div>\
<div id="#{locationId}_expand" class="expand clickable">\
</div>\
</div>\
</td>';
TemplateFactory.NOT_CHECKED_RADIO_TEMPLATE =
'<td class="location_cell #{childrenClass} radio_cell">\
<div id="#{locationId}_container">\
<input type="radio" class="radio" id="#{locationId}_checkbox" name="RayDeeOh_MutuallyExclusive" /> \
<div class="area">#{locationName}</div>\
<div id="#{locationId}_expand" class="expand clickable" style="display:none"></div>\
</div>\
</td>';
TemplateFactory.CHECKED_RADIO_TEMPLATE =
'<td class="location_cell #{childrenClass}  radio_cell">\
<div id="#{locationId}_container">\
<input type="radio" class="radio" id="#{locationId}_checkbox" name="RayDeeOh_MutuallyExclusive" checked="checked"/> \
<div class="area">#{locationName}</div>\
<div id="#{locationId}_expand" class="expand clickable"></div>\
</div>\
</td>';
InteriorSizeLotSizeTemplateFactory = {};
InteriorSizeLotSizeTemplateFactory.ENGLISH = "English";
InteriorSizeLotSizeTemplateFactory.METRIC = "Metric";
InteriorSizeLotSizeTemplateFactory.METRIC_INTERIOR_SIZE_OPTIONS =
'<option value="gt_0" selected="selected">Show All</option>\
<option value="lt_1500">Up to 140 sq. m</option>\
<option value="gt_1500">140 sq. m or more</option>\
<option value="gt_3000">280 sq. m or more</option>\
<option value="gt_5000">465 sq. m or more</option>\
<option value="gt_7500">700 sq. m or more</option>\
<option value="gt_10000">930 sq. m or more</option>';
InteriorSizeLotSizeTemplateFactory.ENGLISH_INTERIOR_SIZE_OPTIONS =
'<option value="gt_0" selected="selected">Show All</option>\
<option value="lt_1500">Up to 1500 sq. ft</option>\
<option value="gt_1500">1500 sq. ft or more</option>\
<option value="gt_3000">3000 sq. ft or more</option>\
<option value="gt_5000">5000 sq. ft or more</option>\
<option value="gt_7500">7500 sq. ft or more</option>\
<option value="gt_10000">10000 sq. ft or more</option>';
InteriorSizeLotSizeTemplateFactory.ENGLISH_LOT_SIZE_OPTIONS =
'<option value="gt_0" selected="selected">Show All</option>\
<option value="lt_5">Up to 5 Acres</option>\
<option value="gt_5">5 Acres or more</option>\
<option value="gt_10">10 Acres or more</option>\
<option value="gt_25">25 Acres or more</option>\
<option value="gt_50">50 Acres or more</option>\
<option value="gt_100">100 Acres or more</option>';
InteriorSizeLotSizeTemplateFactory.METRIC_LOT_SIZE_OPTIONS =
'<option value="gt_0" selected="selected">Show All</option>\
<option value="lt_5">Up to 2 Hectares</option>\
<option value="gt_5">2 Hectares or More</option>\
<option value="gt_10">4 Hectares or More</option>\
<option value="gt_25">10 Hectares or More</option>\
<option value="gt_50">20 Hectares or More</option>\
<option value="gt_100">40 Hectares or More</option>';
InteriorSizeLotSizeTemplateFactory.createInteriorSize = function(type) {
    if (type == InteriorSizeLotSizeTemplateFactory.METRIC) {
        return InteriorSizeLotSizeTemplateFactory.METRIC_INTERIOR_SIZE_OPTIONS;
    }
    if (type == InteriorSizeLotSizeTemplateFactory.ENGLISH) {
        return InteriorSizeLotSizeTemplateFactory.ENGLISH_INTERIOR_SIZE_OPTIONS;
    }
}
InteriorSizeLotSizeTemplateFactory.createLotSize = function(type) {
    if (type == InteriorSizeLotSizeTemplateFactory.ENGLISH) {
        return InteriorSizeLotSizeTemplateFactory.ENGLISH_LOT_SIZE_OPTIONS;
    }
    if (type == InteriorSizeLotSizeTemplateFactory.METRIC) {
        return InteriorSizeLotSizeTemplateFactory.METRIC_LOT_SIZE_OPTIONS;
    }
}
/*
* Global Variable Declarations
*/
var rootExpandedView = null;
CheckBoxState = {
    UnChecked: 1,
    Partial: 2,
    Checked: 3
};
CheckBoxClasses = {};
CheckBoxClasses[CheckBoxState.UnChecked] = 'cleared';
CheckBoxClasses[CheckBoxState.Partial] = 'dashed';
CheckBoxClasses[CheckBoxState.Checked] = 'checked';
CheckBoxMessages = {};
CheckBoxMessages[CheckBoxState.Checked] = 'Searching All ';
CheckBoxMessages[CheckBoxState.Partial] = 'Searching Some ';
CheckBoxMessages[CheckBoxState.UnChecked] = 'Not Searching ';
LocationNode = Class.create();
Object.extend(LocationNode.prototype, Observable.prototype);
Object.extend(LocationNode.prototype, {
    initialize: function(locationId, locationName, children) {
        Observable.prototype.initialize.call(this);
        this.locationId = locationId;
        this.locationName = locationName;
        this._state = CheckBoxState.UnChecked;
        this._stateChangedListeners = new Array();
        this._toggleListener = new Function();
        this._children = children || [];
        var self = this;
        this._children.each(function(child) { child.setParentNode(self); });
    },
    collectCheckedLocationIds: function(buffer) {
        if (this.isChecked()) {
            buffer.push(this.locationId);
        } else if (this.isPartial()) {
            this.children().each(function(child) { child.collectCheckedLocationIds(buffer); });
        }
    },
    getLocationId: function() {
        return this.locationId;
    },
    setParentNode: function(parent) {
        this._parentNode = parent;
    },
    getParentNode: function() {
        return this._parentNode || { _childStateChanged: function() { }, children: function() { return []; }, setState: function() { }, setStateFromChild: function() { } };
    },
    getState: function() {
        return this._state;
    },
    isStateDifferent: function(otherState) {
        return this._state != otherState;
    },
    setState: function(state, fromParent) {
        var oldState = this._state;
        this._state = state;
        if (oldState != this._state) {
            this._switchState(state, fromParent)
        }
        this.notifyChange();
    },
    setStateFromChild: function(state) {
        if (!this.ignoreChildChanges) {
            this._state = state;
            this.getParentNode().setStateFromChild(this._determineParentStateFromSiblings());
            this.notifyChange();
        }
    },
    _switchState: function(newState, fromParent) {
        this.ignoreChildChanges = true;
        if (this.isPartial() == false) {
            var children = this.children();
            if (children.length > 0 && newState == CheckBoxState.Checked && children[0].isMutuallyExclusive())
                children[0].setState(newState, true);
            else {
                for (var i = 0; i < children.length; i++) {
                    children[i].setState(newState, true);
                }
            }
        }
        this.getParentNode().setStateFromChild(this._determineParentStateFromSiblings());
        // Commented out to fix bug when clicking the expanded view checkbox was not cascading the state to its parent
        //		if(!fromParent){
        //			this.getParentNode().setStateFromChild(this._determineParentStateFromSiblings());
        //		}
        this.ignoreChildChanges = false;
    },
    notifyChange: function() {
        var node = this;
        for (var i = (this._stateChangedListeners.length - 1); i >= 0; i--) {
            this._stateChangedListeners[i](node);
        }
    },
    addChangeListener: function(listener) {
        this._stateChangedListeners.push(listener);
    },
    isChecked: function() {
        return this.getState() == CheckBoxState.Checked;
    },
    isPartial: function() {
        return this.getState() == CheckBoxState.Partial;
    },
    isUnChecked: function() {
        return this.getState() == CheckBoxState.UnChecked;
    },
    toggle: function(fromParent) {
        var state = CheckBoxState.Checked;
        if (this.isChecked()) {
            state = CheckBoxState.UnChecked;
        }
        this.setState(state, fromParent);
        this._toggleListener(this);
    },
    toggleStateTo: function(state) {
        this.setState(state);
        this._toggleListener(this);
    },
    toggleStateToUnchecked: function() {
        this.toggleStateTo(CheckBoxState.UnChecked);
    },
    setToggleListener: function(listener) {
        this._toggleListener = listener;
    },
    children: function() {
        return this._children;
    },
    isMutuallyExclusive: function() {
        return false;
    },
    _determineParentStateFromSiblings: function() {
        var siblings = this.getParentNode().children();
        for (var i = 0; i < siblings.length; i++) {
            if (siblings[i].getState() != this.getState()) {
                return CheckBoxState.Partial;
            }
        }
        return this.getState();
    },
    restore: function(checkedLocations) {
        if (typeof checkedLocations[this.locationId] != 'undefined') {
            this.setState(CheckBoxState.Checked);
        }
        else {
            this.setState(CheckBoxState.UnChecked);
            this.children().each(function(child) {
                child.restore(checkedLocations);
            });
        }
    }
});
RadioButtonLocationNode = Class.create();
Object.extend(RadioButtonLocationNode.prototype, LocationNode.prototype);
Object.extend(RadioButtonLocationNode.prototype, {
    initialize: function(locationId, locationName, children) {
        LocationNode.prototype.initialize.call(this, locationId, locationName, children);
    },
    setState: function(state, fromParent) {
        // Commented out as this would not set state of a unchecked radio child when its parent is being checked
        //		if(fromParent && this.isUnChecked())
        //			return;
        this._state = state;
        this._switchState(state, fromParent);
        this.notifyChange();
    },
    toggle: function(cascadeOverRadioButtons) {
        //		if(!this.isUnChecked())
        //			return;
        this._setSiblingState();
        LocationNode.prototype.toggle.call(this, cascadeOverRadioButtons);
    },
    _setSiblingState: function() {
        var siblings = this._parentNode.children();
        for (var i = 0; i < siblings.length; i++) {
            if (siblings[i] != this && !siblings[i].isUnChecked()) {
                siblings[i].setState(CheckBoxState.UnChecked);
                siblings[i]._toggleListener(siblings[i]);
            }
        }
    },
    isMutuallyExclusive: function() {
        return true;
    },
    _determineParentStateFromSiblings: function() {
        var siblings = this.getParentNode().children();
        for (var i = 0; i < siblings.length; i++) {
            if (siblings[i].getState() == CheckBoxState.Checked) {
                return CheckBoxState.Checked;
            }
        }
        return this.getState();
    },
    setStateFromChild: function(state) {
        if (!this.ignoreChildChanges) {
            this._state = state;
            this.getParentNode().setStateFromChild(this._determineParentStateFromSiblings());
            this.notifyChange();
        }
    },
    setStateFromChild: function(state) {
        if (!this.ignoreChildChanges) {
            this._state = state;
            this._setSiblingState();
            this.getParentNode().setStateFromChild(this._determineParentStateFromSiblings());
            this.notifyChange();
        }
    }
});
CollapsedLocationView = Class.create();
CollapsedLocationView.prototype = {
    initialize: function(locationNode, controller) {
        this.locationNode = locationNode;
        this._controller = controller;
    },
    render: function(level, row) {
        var monkeyRow = row || new Row();
        this.locationNode.addChangeListener(this._handleStateChanged.bind(this));
        var cell = this._createCell(monkeyRow);
        this.checkbox = cell.getElementsBySelector('#' + this.locationNode.locationId + '_checkbox').first();
        var area = cell.getElementsBySelector('.area').first();
        this._addBehaviorToRow(cell, level + 1);
        return cell;
    },
    _addBehaviorToRow: function(cell, level) {
        var locationId = this.locationNode.locationId;
        var element = cell.getElementsBySelector('#' + locationId + '_expand')[0];
        Event.observe(element, 'click', this._handleExpandMouseOver.bindAsEventListener(this, level));
        //        Event.observe(element, 'mouseout', this._handleExpandMouseOut.bindAsEventListener(this, level));
        //        Event.observe(element, 'click', this._handleExpandClicked.bindAsEventListener(this, level));
        Event.observe(this.checkbox, 'click', this._handleCheckBoxClicked.bind(this));
    },
    _handleStateChanged: function() {
        if (this.locationNode.isMutuallyExclusive()) {
            var checked = this.locationNode.getState() != CheckBoxState.UnChecked;
            this.checkbox.checked = checked;
            var expandedElement = $(this.locationNode.locationId + '_expand');
            if (checked && expandedElement) { expandedElement.show(); }
            else if (expandedElement) { expandedElement.hide(); }
        }
        else {
            this.checkbox.className = 'checkbox ' + CheckBoxClasses[this.locationNode.getState()];
        }
    },
    _handleCheckBoxClicked: function() {
        if (this.locationNode.isMutuallyExclusive()) {
            var nodes = this.locationNode.getParentNode().children();
            for (var i = 0; i < nodes.length; i++) {
                var expandedElement = $(nodes[i].locationId + '_expand');
                expandedElement.hide();
            }
            var expandedElement = $(this.locationNode.locationId + '_expand');
            expandedElement.show();
        } else {
            if (typeof WebTrendsAnalyzer == 'function') {
                (new WebTrendsAnalyzer()).fireWebTrendAction(
WebTrendsAnalyzer.CreateActionForLocationCheckbox(this.locationNode.locationId, !this.locationNode.isChecked()));
            }
            this.locationNode.toggle(false);
        }
    },
    _handleExpandMouseOver: function(e, level) {
        this._controller.handleExpandMouseOver(this.locationNode, level, e);
    },
    _handleExpandMouseOut: function() {
        this._controller.handleExpandMouseOut(this.locationNode);
    },
    _handleExpandClicked: function(e) {
        this._controller.handleExpandClicked(this.locationNode, e);
    },
    _createCell: function(row) {
        var model = Object.extend({
            checkboxClass: CheckBoxClasses[this.locationNode.getState()],
            childrenClass: this.locationNode.children().length > 0 ? 'has_children' : 'no_children'
        }, this.locationNode);
        var template = this._createTemplate(this.locationNode.isMutuallyExclusive(), this.locationNode.getState() == CheckBoxState.Checked);
        return row.addCell(template, model);
    },
    _createTemplate: function(isMutuallyExclusive, isChecked) {
        if (isMutuallyExclusive) {
            if (isChecked)
                return TemplateFactory.CHECKED_RADIO_TEMPLATE;
            return TemplateFactory.NOT_CHECKED_RADIO_TEMPLATE;
        }
        return TemplateFactory.CHECKBOX_TEMPLATE;
    }
};
ExpandedLocationView = Class.create();
ExpandedLocationView.TEMPLATE_HTML =
'<td colspan="#{numColumns}">\
<div class="clickable checkbox "#{checkboxStateClass}" id="#{locationId}_checkbox_expanded"></div>\
<h5 class="clickable" id="#{locationId}_locationName">#{locationName}</h5>\
</td>';
ExpandedLocationView.prototype = {
    initialize: function(locationNode, level, controller) {
        this._locationNode = locationNode;
        this.level = level || 0;
        this._locationNode.addChangeListener(this.updateCheckBoxDisplay.bind(this));
        this._lastRelativeToId = null;
        this._controller = controller;
        ExpandedLocationView.effectOnLocationNode = null;
        ExpandedLocationView.effect1 = null;
        ExpandedLocationView.effect2 = null;
        ExpandedLocationView.effect3 = null;
    },
    getLocationNode: function() {
        return this._locationNode;
    },
    render: function(relativeToElement) {
        if (relativeToElement) {
            this._lastRelativeToId = relativeToElement.id;
        }
        this.hideChildren();
        var divForLevel = this._getOrCreateDivForLevel();
        var tableForLocationNode = this._getOrCreateTableForLocationNode();
        divForLevel.appendChild(tableForLocationNode);
        document.body.appendChild(divForLevel);
        this.positionChildren(divForLevel, relativeToElement);
        this.updateCheckBoxDisplay();
        return divForLevel;
    },
    setNodeState: function(state) {
        this._locationNode.setState(state);
        this.updateCheckBoxDisplay();
    },
    updateCheckBoxDisplay: function() {
        var div = $(this._locationNode.locationId + '_checkbox_expanded');
        if (!div) {
            return;
        }
        div.className = 'checkbox ' + CheckBoxClasses[this._locationNode.getState()];
    },
    positionChildren: function(objNodeDiv, relativeToElement) {
        Element.hide(objNodeDiv);
        var parentNodeDiv = $('location_' + (this.level - 1));
        objNodeDiv.className = 'browse';
        objNodeDiv.style.zindex = '10';
        var margin = 7;
        var pos = findPos(relativeToElement);
        objNodeDiv.style.left = (pos.left + relativeToElement.getWidth() + margin) + 'px';
        objNodeDiv.style.top = pos.top + 'px';
        this.animatePreview(objNodeDiv);
    },
    isVisible: function() {
        return $('location_' + this.level) != null;
    },
    animatePreview: function(objNodeDiv) {
        this.active = false;
        this.showChildCells(objNodeDiv);
        new Effect.Appear(objNodeDiv, { duration: 0.3, afterFinishInternal: this._fixTableWidthOnEffectElement.bind(this) });
    },
    _fixTableWidthOnEffectElement: function(effect) {
        var table = effect.element.down('table');
        if (table) {
            var origWidth = table.getDimensions().width;
            table.style.width = origWidth + 'px';
        }
    },
    showChildCells: function(objNodeDiv) {
        var self = this;
        $A(objNodeDiv.getElementsByTagName('td')).each(
function(e) { self.showCell(e); }
);
    },
    showCell: function(e) {
        //		new Effect.Appear(e,{from:e.getOpacity(),to:1});
        e.style.visibility = 'visible';
        if (e.className.indexOf('radio_cell') != -1) {
            //this oddness is for a bug in IE where it refuses to display the
            //italic text when the parent is un-hidden.
            e.style.fontStyle = '';
            e.style.fontStyle = 'italic';
        }
    },
    activate: function() {
        var objNodeDiv = $('location_' + this.level);
        var parentNodeDiv = $('location_' + (this.level - 1));
        //to fix the bug of the location widget being creatd in the far right bottom corner
        //this seems to fix this bug :)
        if (parentNodeDiv && objNodeDiv.offsetLeft - parentNodeDiv.offsetLeft > 0) {
            this.active = true;
            ExpandedLocationView.effectOnLocationNode = this._locationNode.locationId;
            this._fixTableWidthOnEffectElement({ element: objNodeDiv });
            ExpandedLocationView.effect1 = new Effect.Move(
objNodeDiv, {
    x: -(objNodeDiv.offsetLeft - parentNodeDiv.offsetLeft - 10),
    y: -(objNodeDiv.offsetTop - parentNodeDiv.offsetTop - 35),
    duration: 0.3,
    afterFinishInternal: function(effect) {
        ExpandedLocationView.effect1 = null;
        ExpandedLocationView.effectOnLocationNode = null;
    }
}
);
            ExpandedLocationView.effect2 = new Effect.Appear(objNodeDiv, { from: 0.5, to: 1, duration: 0.3 });
            ExpandedLocationView.effect3 = new Effect.FadeCollection(parentNodeDiv.getElementsByTagName('td'),
{
    duration: 0.3,
    afterFinishInternal: function(effect) {
        effect.element.setStyle({ opacity: 1, visibility: 'hidden' });
    }
}
);
        }
    },
    isActive: function() {
        return this.active;
    },
    hide: function() {
        this.active = false;
        this.hideChildren();
        this._removeCurrentLevelDiv();
    },
    hideChildren: function() {
        var currLevel = this.level + 1;
        var child = this._getLocationDiv(currLevel);
        while (child) {
            child.parentNode.removeChild(child);
            ++currLevel;
            child = $('location_' + currLevel);
        }
    },
    _getLocationDiv: function(level) {
        var currentLevel = level || this.level;
        return $('location_' + currentLevel);
    },
    _getOrCreateTableForLocationNode: function() {
        var table = ExpandedLocationView.RENDERED_TABLES_BY_LOCATION_ID[this._locationNode.locationId];
        if (!table) {
            var children = this._locationNode.children();
            table = this._createTable(children);
            this._addBehaviorToDiv(table);
            ExpandedLocationView.RENDERED_TABLES_BY_LOCATION_ID[this._locationNode.locationId] = table;
        }
        return table;
    },
    calculateNumColumns: function() {
        var numChildren = this._locationNode.children().length;
        var propsPerLevel = 15 + this.level;
        return Math.ceil(numChildren / propsPerLevel);
    },
    _createTable: function(children) {
        var numColumns = this.calculateNumColumns();
        var templateModel = Object.extend(
{
    numColumns: numColumns,
    checkboxStateClass: CheckBoxClasses[this._locationNode.getState()]
}, this._locationNode);
        var table = new Table();
        var parentRow = table.createAndAddRow();
        parentRow.addCell(ExpandedLocationView.TEMPLATE_HTML, templateModel);
        var currentRow = table.createAndAddRow();
        for (var i = 0; i < children.length; i++) {
            if (currentRow.cellCount() >= numColumns) {
                currentRow = table.createAndAddRow();
            }
            (new CollapsedLocationView(children[i], this._controller)).render(this.level, currentRow);
        }
        return table.render();
    },
    _getOrCreateDivForLevel: function() {
        var div = null;
        var divId = 'location_' + this.level;
        this._removeCurrentLevelDiv(divId);
        div = document.createElement('div');
        div.id = divId;
        div.style.display = 'block';
        return div;
    },
    _removeCurrentLevelDiv: function() {
        var divId = 'location_' + this.level;
        div = $(divId);
        if (div) {
            div.parentNode.removeChild(div);
        }
    },
    _addBehaviorToDiv: function(div) {
        var checkBoxElement = Element.getElementsBySelector(div, '#' + this._locationNode.locationId + '_checkbox_expanded')[0];
        var locationNameElement = Element.getElementsBySelector(div, "#" + this._locationNode.locationId + "_locationName")[0];
        if (checkBoxElement) {
            Event.observe(checkBoxElement, 'click', this._handleCheckBoxClicked.bind(this));
        }
        if (locationNameElement) {
            Event.observe(locationNameElement, 'click', this._handleNameClicked.bind(this));
        }
        //Event.observe(div, 'mouseover', this._handleMouseOver.bind(this));
    },
    _handleMouseOver: function() {
        if (!this.isActive()) {
            this.activate();
        }
    },
    _handleNameClicked: function() {
        this._controller.handleNameClicked(this._locationNode);
    },
    _handleCheckBoxClicked: function() {
        if (typeof WebTrendsAnalyzer == 'function') {
            (new WebTrendsAnalyzer()).fireWebTrendAction(
WebTrendsAnalyzer.CreateActionForLocationCheckbox(this._locationNode.locationId, !this._locationNode.isChecked()));
        }
        this._locationNode.toggle(true);
    }
};
ExpandedLocationView.RENDERED_TABLES_BY_LOCATION_ID = {}
LocationController = Class.create();
LocationController.prototype = {
    initialize: function(locationModel, relativeToElement) {
        var locationNode = locationModel.getRootLocationNode();
        this._locationModel = locationModel;
        this._rootExpandedView = new ExpandedLocationView(locationNode, 0, this);
        this._rootExpandedView.render(relativeToElement);
        this.EXPANDED_VIEWS = {};
        this.EXPANDED_VIEWS[locationNode.locationId] = this._rootExpandedView;
        this._setToggleListener(locationModel);
    },
    _createFilterDisplay: function() {
        return new LocationFilterDisplay(this._locationModel);
    },
    _setToggleListener: function(locationModel) {
        locationModel.setToggleListener(this._handleToggleComplete.bind(this));
    },
    _handleToggleComplete: function(node) {
    },
    handleExpandMouseOver: function(locationNode, level, e) {
        if (ExpandedLocationView.effect1 != null) {
            return;
        }
        var expandedView = this.getExpandedView(locationNode, level);
        if (!expandedView.isActive() || !expandedView.isVisible()) {
            expandedView.render(Event.element(e));
            setTimeout(expandedView.activate.bind(expandedView), 100);
        }
    },
    handleExpandMouseOut: function(locationNode) {
        if (ExpandedLocationView.effect1 != null) {
            return;
        }
        var expandedView = this.EXPANDED_VIEWS[locationNode.locationId];
        if (expandedView && !expandedView.isActive()) {
            expandedView.hide();
        }
    },
    handleExpandClicked: function(locationNode, e) {
        var expandedView = this.EXPANDED_VIEWS[locationNode.locationId];
        if (expandedView) {
            expandedView.activate(e);
        }
    },
    handleNameClicked: function(locationNode) {
        if (ExpandedLocationView.effectOnLocationNode == locationNode.locationId)
            return;
        var expandedView = this.EXPANDED_VIEWS[locationNode.locationId];
        if (ExpandedLocationView.effect1) {
            ExpandedLocationView.effect1.cancel();
            ExpandedLocationView.effect1 = null;
        }
        if (ExpandedLocationView.effect2) {
            ExpandedLocationView.effect2.cancel();
            ExpandedLocationView.effect2 = null;
        }
        if (ExpandedLocationView.effect3) {
            ExpandedLocationView.effect3.cancel();
            ExpandedLocationView.effect3 = null;
        }
        expandedView.hideChildren();
        expandedView.showChildCells($('location_' + expandedView.level));
    },
    getExpandedView: function(locationNode, level) {
        var expandedView = this.EXPANDED_VIEWS[locationNode.locationId];
        if (typeof expandedView == "undefined") {
            expandedView = new ExpandedLocationView(locationNode, level, this);
            this.EXPANDED_VIEWS[locationNode.locationId] = expandedView;
        }
        return expandedView;
    },
    getRootExpandedView: function() {
        return this._rootExpandedView;
    }
};
function ShowAllTemplate(displayLeafNodes) {
    this._displayLeafNodes = displayLeafNodes;
}
ShowAllTemplate.prototype.apply = function(nodes) {
    if (this._displayLeafNodes) {
        nodes = this.flatten(nodes);
    }
    var mssg = new Array();
    var numDisplayed = 0;
    for (var i = 0; (i < nodes.length) && (numDisplayed < this.getMaximumDisplay()); i++) {
        if (nodes[i].getState() != CheckBoxState.UnChecked) {
            ++numDisplayed;
            mssg.push(nodes[i].locationName);
            mssg.push('<br />');
        }
    }
    return mssg.join('');
}
ShowAllTemplate.prototype.flatten = function(arr, leaves) {
    if (!leaves) {
        leaves = [];
    }
    for (var i = 0; i < arr.length; i++) {
        if (arr[i].children().length > 0) {
            this.flatten(arr[i].children(), leaves);
        } else {
            leaves.push(arr[i]);
        }
    }
    return leaves;
}
ShowAllTemplate.prototype.getMaximumDisplay = function() {
    return 999;
}
function ShowPartialTemplate(displayLeafNodes) {
    ShowAllTemplate.call(this, displayLeafNodes);
}
ShowPartialTemplate.prototype = new ShowAllTemplate();
ShowPartialTemplate.prototype.getMaximumDisplay = function() {
    return 5;
}
function showLocationOption(locationDivToUse, startingLocationId, level, expandDivClicked) {
    if ($(locationDivToUse)) Element.remove(locationDivToUse);
    //create and add locationDivToUse to DOM
    var parent = (level == 0) ? $('locationParentNode') : expandDivClicked.parentNode;
    var locationModel = getPageController().getSearchOptionsModel().getFilterModel(FilterKey.LOCATION);
    if (!locationModel.isQuickSearch()) {
        locationController = new LocationController(locationModel, parent);
        rootExpandedView = locationController.getRootExpandedView();
        Event.observe(document.body, 'click', function(e) { hideLocationWidget(e); });
    }
}
function findPos(obj) {
    var curleft = obj.offsetLeft;
    var curtop = obj.offsetTop;
    var done = false;
    try {
        while (!done && (obj = Position.offsetParent(obj))) {
            if (obj == document.body) {
                done = true;
            } else {
                curleft += obj.offsetLeft;
                curtop += obj.offsetTop;
            }
        }
    } catch (err) {
        // sometimes IE has an error but not sure why
    }
    return { left: curleft, top: curtop };
}
function hideLocationWidget(e) {
    var evnt = arguments[0] || window.event,
clickedElement = evnt.target || evnt.srcElement;
    if (clickedElement.innerHTML.indexOf('Modify Search') != -1) return;
    while (clickedElement != document.body) {
        if (
clickedElement.className.indexOf('location_cell') != -1 ||
clickedElement.id == 'locationDT'
)
            return;
        clickedElement = clickedElement.parentNode;
    }
    rootExpandedView.hide();
    Event.stopObserving(document.body, 'click');
}
Url = Class.create();
Object.extend(Url.prototype, {
    initialize: function(url) {
        var index = url.indexOf('http://');
        if (index != -1) {
            url = url.substring(index);
        }
        this._url = this._extractUrl(url);
        this._params = this._extractParams(url);
    },
    toUrlString: function() {
        if (this._params.length > 0)
            return this._url + '?' + this._params.join('&');
        else
            return this._url;
    },
    addParameter: function(nameValue) {
        if (nameValue != '' && nameValue != null)
            this._params.push(nameValue);
    },
    getParamCount: function() {
        return this._params.length;
    },
    _extractParams: function(url) {
        var paramSection = url.split('?');
        var params = new Array();
        if (paramSection.length == 1)
            return params;
        paramSection = paramSection[1].split('&');
        for (var i = 0; i < paramSection.length; i++) {
            params.push(paramSection[i]);
        }
        return params;
    },
    _extractUrl: function(url) {
        return url.split('?')[0];
    }
});
PageCache = Class.create();
Object.extend(PageCache.prototype, {
    initialize: function(searchOptionsModel, url, cacheElementName, pageNumber) {
        this._cacheElementName = cacheElementName || 'searchResultsIframe';
        this._url = url || new Url('/search/results.rails');
        this.searchOptionsModel = searchOptionsModel || new SearchOptionsModel();
        this._pageNumber = pageNumber || 1;
    },
    getCacheElement: function() {
        return $(this._cacheElementName);
    },
    getUrl: function() {
        return this._url.toUrlString();
    },
    cache: function() {
        if (typeof window.progressChicken != 'undefined') {
            window.progressChicken.start(true);
        }
        $('searchModelInput').value = DataSerializer.serialize(this.searchOptionsModel.dump());
        $('searchModelPageInput').value = this.getPageNumber();
        $('searchModelForm').action = this.getUrl();
        $('searchModelForm').target = this.getCacheElement().id;
        $('searchModelForm').submit();
    },
    getPageNumber: function() {
        return this._pageNumber;
    }
});
CountModel = Class.create();
Object.extend(CountModel.prototype, Observable.prototype);
Object.extend(CountModel.prototype, {
    initialize: function() {
        Observable.prototype.initialize.call(this);
    },
    setText: function(text) {
        this._text = text;
        this._countNumber = text.split("\n")[0];
        this._countMessage = text.split("\n")[1];
        this.notifyChange();
    },
    getText: function() {
        return this._text;
    },
    getCountNumber: function() {
        return this._countNumber;
    },
    getCountMessage: function() {
        return this._countMessage;
    }
})
CountView = Class.create();
Object.extend(CountView.prototype, {
    initialize: function(model) {
        this._model = model;
        model.addChangeListener(this);
    },
    onChange: function() {
        var number = $('propcountNumberOnly') || { innerHTML: '' };
        var message = $('propcountMessage') || { innerHTML: '' };
        number.innerHTML = this._model.getCountNumber();
        message.innerHTML = this._model.getCountMessage();
    }
})
CountController = Class.create();
Object.extend(CountController.prototype, {
    initialize: function(serverControllerName, model, countActionName) {
        this._controllerName = serverControllerName;
        this._model = model;
        this._countActionName = countActionName || '/Count.rails';
    },
    getServerControllerName: function() {
        return this._controllerName;
    },
    update: function() {
        if (typeof window.progressChicken != 'undefined') {
            window.progressChicken.start();
        }
        var myRequest = new Ajax.Request(this.getUrl(), {
            on200: function(transport) {
                if (transport.responseText.match(/errorUrl/))
                    window.location.href = baseUrl + '/GenericError.htm';
            },
            onComplete: this._updateModel.bind(this),
            parameters: this.getParam()
        });
    },
    _handleException: function(r, e) {
        alert(e);
    },
    getSiteRoot: function() {
        //ie throws an exception if siteRoot hasn't been defined and we only check "if(siteRoot)"
        if (typeof regionRoot != 'undefined') {
            return (regionRoot.charAt(regionRoot.length - 1) != '/') ? regionRoot + '/' : regionRoot;
        }
        return '/';
    },
    getUrl: function() {
        return this.getSiteRoot() + this.getServerControllerName() + this.getCountActionName();
    },
    getCountActionName: function() {
        return this._countActionName;
    },
    _updateModel: function(response) {
        this._model.setText(response.responseText);
        if (typeof window.progressChicken != 'undefined') {
            window.progressChicken.stop();
        }
    },
    getParam: function() {
        if (typeof getSearchOptionsModel == 'function' && typeof DataSerializer == 'object') {
            return { searchModel: DataSerializer.serialize(getSearchOptionsModel().dump()) };
        }
        return {};
    },
    setCountString: function(count) {
        this._countString = count;
        this._model.setText(count);
    },
    getCountString: function() {
        return this._countString;
    }
});
PageController = Class.create();
Object.extend(PageController.prototype, {
    initialize: function(params) {
        this._initialModel = this._safeGetParam(params, 'searchModel', null);
        if ($('quicksearchtextcriteria')) {
            this._quickSearchController = this._createQuickSearchController(
this._safeGetParam(params, 'quickSearchBy', null)
);
        }
        this._shouldAutoUpdateResults = this._safeGetParam(params, '_shouldAutoUpdateResults', false);
        if (typeof params != 'undefined' && typeof params['quickSearchBy'] != 'undefined') {
            this.setSearchOptionsModel(this._scoopSearchOptionsModelFromQuickSearch(params['quickSearchBy'], params['quickSearchCriteriaUsed'], params['quickSearchDisplayValue']));
        } else if (typeof params != 'undefined' && typeof params['searchModel'] != 'undefined') {
            this.setSearchOptionsModel(this._scoopSearchOptionsModel(params['searchModel']));
        } else {
            this.setSearchOptionsModel(this._createSearchOptionsModel());
        }
    },
    _safeGetParam: function(params, key, defaultReturn) {
        if (!params || !params[key]) {
            return defaultReturn;
        }
        return params[key];
    },
    showLocationTree: function() {
        return false;
    },
    getCountController: function() {
        return this._countController;
    },
    setCountString: function(countString) {
        if (this._countController) this._countController.setCountString(countString);
    },
    _createCountController: function(model) {
        return new CountController(this.CONTROLLER_NAME, model);
    },
    _createQuickSearchController: function() {
return new QuickSearchController(ResultType.ALL);
    },
    onInitialPageLoad: function() {
        var model = new CountModel();
        new CountView(model);
        this._countController = this._createCountController(model);
        if ($('searchResults')) {
            this._initialResults = '' + $('searchResults').innerHTML;
        }
        if ($("idxButton") != null) {
            Event.observe($("idxButton"), 'click', this._handleIdxButtonPress.bind(this));
        }
    },
    _handleIdxButtonPress: function() {
        this._prepareWebTrendsForIdxView();
    },
    _prepareWebTrendsForIdxView: function() {
        if (typeof WebTrendsAnalyzer == 'function') {
            (new WebTrendsAnalyzer()).fireWebTrendAction(
WebTrendsAnalyzer.CreateActionClickOnLink('Region', window.location, 'Idx Website'));
        }
    },
    _searchOptionsModelWasSet: function(newModel, oldModel) {
        this._setUpHandlers(newModel);
    },
    _setUpHandlers: function(newModel) {
        this._resultsUpdater = new ResultsUpdater(this);
        if (this._shouldAutoUpdateResults) {
            newModel.addChangeListener(this._resultsUpdater);
        }
        this._countUpdater = new CountUpdater(this);
        newModel.addChangeListener(this._countUpdater);
        var narrowTextUpdater = new NarrowByTextUpdater(newModel);
        newModel.addChangeListener(narrowTextUpdater);
        narrowTextUpdater.onChange();
    },
    getSearchOptionsModel: function() {
        return this._searchOptionsModel;
    },
    getResultsUpdater: function() {
        return this._resultsUpdater;
    },
    setSearchOptionsModel: function(newModel) {
        if (typeof newModel == 'undefined' || (this._resultsUpdater && this._resultsUpdater._modelDirty) || newModel.equals(this._searchOptionsModel)) {
            return;
        }
        //DO NOT REFRESH SEARCH RESULTS HERE!  BACK BUTTON WOULD HAVE WEIRD RESULTS.
        var oldModel = this._searchOptionsModel;
        this._searchOptionsModel = newModel;
        this._searchOptionsModelWasSet(newModel, oldModel);
    },
    _createSearchOptionsModel: function(type) {
        var modelType = type || 'search';
        var searchOptionsModel = new SearchOptionsModel(modelType);
        return this._populateFilterModels(searchOptionsModel);
    },
    _populateFilterModels: function(searchOptionsModel) {
        searchOptionsModel._filterModels = {};
        modelsToPopulate = this._filterModelsUsed();
        for (var key in modelsToPopulate) {
            searchOptionsModel.addFilterModel(key, modelsToPopulate[key]);
        }
        return searchOptionsModel;
    },
    _filterModelsUsed: function() {
        var modelsUsed = {};
        modelsUsed[FilterKey.WEB_REGION] = new WebRegionModel(window.regionRoot);
        return modelsUsed;
    },
    switchToResultsView: function(headerElement) {
        if (headerElement.tagName == 'DD') {
            headerElement = $(headerElement.id.replace('DD', 'DT'));
        }
        var detailElement = $(headerElement.id.replace('DT', 'DD'));
        window.removeClassNameForChildrenWithinAParentTag('searchOptions', 'dt', 'activated');
        //added because the location Widget has a special style
        window.removeClassNameForChildrenWithinAParentTag('searchOptions', 'dt', 'activatedFirst');
        window.removeClassNameForChildrenWithinAParentTag('searchOptions', 'dd', 'activated');
        Element.removeClassName(headerElement, 'selected');
        //added because the location Widget has a special style
        if (headerElement.id == "categorybasedlocationDT") {
            Element.addClassName(headerElement, 'activatedFirst');
        } else {
            Element.addClassName(headerElement, 'activated');
        }
        Element.removeClassName(detailElement, 'selected');
        Element.addClassName(detailElement, 'activated');
        if ($('error') && $('error').style.display != 'none') {
            Element.hide('error');
            this.updateSearchResults();
        }
    },
    updateSearchResults: function() {
        this.goToPage(1);
    },
    updateCount: function() {
        var controller = this.getCountController();
        if (controller) {
            controller.update();
        }
    },
    setModelValues: function() {
    },
    isLandingPageVisible: function() {
        return $('content') && $('content').className.indexOf('resultsList') == -1;
    },
    goToPage: function(pageNo) {
        var model = this.getSearchOptionsModel();
        if (this._getPageNavigationURL()) {
new PageCache(model, new Url(regionRoot + this._getPageNavigationURL()), null, pageNo).cache();
        }
    },
    _getPageNavigationURL: function() {
        return '/sales/list.rails';
    },
    getQuickSearchController: function() {
        return this._quickSearchController;
    },
    _scoopSearchOptionsModel: function(dumpStr) {
        eval('searchModelDump = ' + dumpStr + ';');
        return SearchOptionsModel.scoop(searchModelDump, this);
    },
    _scoopSearchOptionsModelFromQuickSearch: function(searchBy, criteria, display) {
        var model = this._createSearchOptionsModel();
        if (searchBy == 'Name') {
            model.getFilterModel(FilterKey.AGENT_NAME_SEARCH).setName(criteria);
            model.getFilterModel(FilterKey.AGENT_NAME_SEARCH).pushSearchedName();
        }
        else if (searchBy == 'Area') {
            if (model.getFilterModel(FilterKey.LOCATION)) {
                model.getFilterModel(FilterKey.LOCATION).setCitySTZip(criteria);
                model.getFilterModel(FilterKey.LOCATION).setQuickSearchText(display);
            }
        }
        else if (searchBy == 'subregion') {
            model.getFilterModel(FilterKey.SUBREGION).setIdCriteria(criteria);
        }
        return model;
    },
    getLinkBackToThisPage: function() {
        var url = this._getPageNavigationURL();
        if (url.indexOf('http') == -1) {
            url = regionRoot + url;
        }
        return url;
    },
    resultsLinkClicked: function(url, index) {
        $('currentIndex').value = index;
        $('searchModelInput').value = DataSerializer.serialize(this.getSearchOptionsModel().dump());
        $('searchModelForm').action = url;
        $('searchModelForm').target = '_self';
        this._appendToValue($('searchResultsActionUrl'), this.getLinkBackToThisPage(), '|');
        this._appendToValue($('searchResultsIndex'), index, '|');
        //we push the index on twice here because it is popped twice from the detail pages' returnToList method
        //we need to revisit this later to clean it up.
        this._appendToValue($('searchResultsIndex'), index, '|');
        this._appendToValue($('searchResultsSearchModel'), DataSerializer.serialize(this.getSearchOptionsModel().dump()), '|');
        this.setUpDetailPagination();
        this._submitSearchModelForm();
    },
    setUpDetailPagination: function() {
        $('sir_result_detail_sort_by').value = $('sir_result_sort_by').value;
        $('sir_result_detail_sort_direction').value = $('sir_result_sort_direction').value;
        $('sir_result_sort_by').value = '';
        $('sir_result_sort_direction').value = '';
    },
    _submitSearchModelForm: function() {
        $('searchModelForm').submit();
    },
    _appendToValue: function(input, value, separator) {
        input.value = input.value || '';
        if (input.value == '') {
            separator = '';
        }
        input.value = input.value + separator + value;
    },
    updateViewToResults: function() {
        this._updateViewToResults();
    },
    _updateViewToResults: function() {
        if ($('error')) {
            Element.remove('error');
        }
        var contentDiv = $('content');
        if (contentDiv) {
            contentDiv.className = 'content resultsList';
        }
    }
});
PageController._createdCallbacks = [];
PageController._constructorParams = {};
PageController.addPageCreatedCallback = function(callback) {
    PageController._createdCallbacks.push(callback);
}
PageController.getPageCreatedCallbacks = function() {
    return PageController._createdCallbacks;
}
PageController.addConstructorParam = function(name, value) {
    PageController._constructorParams[name] = value;
}
PageController.getConstructorParams = function() {
    return PageController._constructorParams;
}
NarrowByTextUpdater = Class.create();
Object.extend(NarrowByTextUpdater.prototype, {
    initialize: function(model) {
        this._model = model;
    },
    onChange: function() {
        var elem = $("narrowSearchLabel");
        if (elem) {
            var text = this._model.isEmpty() ? 'Narrow search by:' : 'Narrow or expand search by:';
            elem.innerHTML = text;
        }
    }
});
DetailPageController = Class.create();
Object.extend(DetailPageController.prototype, PageController.prototype);
Object.extend(DetailPageController.prototype, {
    initialize: function(params) {
        if (params && typeof params.searchModelUsed != 'undefined') {
            this._searchModelUsed = params.searchModelUsed;
            this._searchResultPage = params.searchResultPage || '1';
        }
        PageController.prototype.initialize.call(this, params);
    },
    updateCount: function() {
    },
    goToDetailPage: function(index, link) {
        $('currentIndex').value = index;
        $('searchModelForm').action = link.href;
        $('searchModelInput').value = this._searchModelUsed;
        $('searchModelForm').target = '_self';
        $('searchModelPageInput').value = this._searchResultPage;
        $('searchModelForm').submit();
    },
    returnToSearchResults: function() {
        // reset searched sort params from detail
        $('sir_result_sort_by').value = $('sir_result_detail_sort_by').value;
        $('sir_result_sort_direction').value = $('sir_result_detail_sort_direction').value
        $('sir_result_detail_sort_by').value = '';
        $('sir_result_detail_sort_direction').value = '';
        $('searchModelForm').action = this._pop($('searchResultsActionUrl'), '|');
        if ($('searchModelForm').action.indexOf('/list')) {
            this._pop($('searchResultsIndex'), '|');
        }
        $('currentIndex').value = this._getLast($('searchResultsIndex'), '|');
        var index = parseInt($('currentIndex').value);
        var perPage = 10;
        var input = $("searchModelItemsPerPageInput");
        if (input && input.value) {
            perPage = input.value;
        }
        if (isNaN(index)) {
            $('searchModelPageInput').value = '';
        } else {
            $('searchModelPageInput').value = '' + Math.ceil(index / perPage);
        }
        $('searchModelInput').value = this._pop($('searchResultsSearchModel'), '|');
        $('searchModelLayoutInput').value = '';
        $('searchModelForm').target = '_self';
        this.submitSearchModelForm();
    },
    _isResultListUrl: function(url) {
        return (url.indexOf('list.rails') != -1) || /agents$/.test(url);
    },
    submitSearchModelForm: function() {
        $('searchModelForm').submit();
    },
    _pop: function(stackElement, delimiter) {
        var urls = stackElement.value.split(delimiter);
        var url = urls.pop();
        stackElement.value = urls.join(delimiter);
        return url;
    },
    _getLast: function(stackElement, delimiter) {
        var urls = stackElement.value.split(delimiter);
        if (urls.length == 0) {
            return '';
        }
        return urls[urls.length - 1];
    },
    getLinkBackToThisPage: function() {
        return window.location.href;
    },
    resultsLinkClicked: function(url, index) {
        if ($('searchResultsIndex').value && $('searchResultsIndex').value != '0') {
            $('currentIndex').value = index;
            $('searchModelInput').value = DataSerializer.serialize(this.getSearchOptionsModel().dump());
            $('searchModelForm').action = url;
            $('searchModelForm').target = '_self';
            this._appendToValue($('searchResultsActionUrl'), this.getLinkBackToThisPage(), '|');
            this._appendToValue($('searchResultsIndex'), index, '|');
            this._appendToValue($('searchResultsSearchModel'), DataSerializer.serialize(this.getSearchOptionsModel().dump()), '|');
            this._submitSearchModelForm();
            return;
        }
        $('currentIndex').value = index;
        $('searchModelInput').value = DataSerializer.serialize(this.getSearchOptionsModel().dump());
        $('searchModelForm').action = url;
        $('searchModelForm').target = '_self';
        this._appendToValue($('searchResultsActionUrl'), this.getLinkBackToThisPage(), '|');
        $('searchResultsIndex').value = '';
        this._appendToValue($('searchResultsSearchModel'), DataSerializer.serialize(this.getSearchOptionsModel().dump()), '|');
        this._submitSearchModelForm();
    },
    _filterModelsUsed: function() {
        return {};
    }
});
AgentController = Class.create();
Object.extend(AgentController.prototype, PageController.prototype);
Object.extend(AgentController.prototype, {
    CONTROLLER_NAME: "agents",
    initialize: function(params) {
        params = params || {};
        params['_shouldAutoUpdateResults'] = false;
        PageController.prototype.initialize.call(this, params);
        if ($('agentNameSearchInput') && $('agentNameSearchSuggest')) {
            this._nameAutoCompleter = new QSAutocompleter('agentNameSearchInput', 'agentNameSearchSuggest', regionRoot + "/agents/suggest.rails", {
                paramName: 'textCriteria',
                callback: this.suggestCallback.bind(this)
            }).start();
        }
    },
    suggestCallback: function(inptElement, entry) {
        return entry + "&searchModel=" + DataSerializer.serialize(this.getSearchOptionsModel().dump());
    },
    _createCountController: function(model) {
        return undefined;
    },
    _filterModelsUsed: function() {
        var modelsUsed = PageController.prototype._filterModelsUsed.call(this);
        //These are needed for Quicksearch by Agent to preserve search criteria.
        modelsUsed[FilterKey.LOCATION] = new LocationModel();
        modelsUsed[FilterKey.CAT_BASED_LOCATION] = modelsUsed[FilterKey.LOCATION];
        modelsUsed[FilterKey.AGENT_LOCATION] = new AgentLocationFilterModel();
        modelsUsed[FilterKey.LANGUAGE] = new LanguageFilterModel();
        modelsUsed[FilterKey.AGENT_NAME_SEARCH] = new AgentNameSearchFilterModel();
        modelsUsed[FilterKey.LETTER_FROM_FORM] = new LetterFromFormFilterModel();
        return modelsUsed;
    },
    _getPageNavigationURL: function() {
        var agentsUrl = '/agents';
        if ($('searchModelForm').action.indexOf("AGENT_NAME_SEARCH") == -1) {
            var url = document.URL;
            var agentsIndex = url.indexOf(agentsUrl, 0);
            if (url.lastIndexOf("/") > agentsIndex) {
                agentsUrl = url.substring(agentsIndex, url.length);
            }
        }
        return agentsUrl;
    },
    _setUpHandlers: function(newModel) {
        PageController.prototype._setUpHandlers.call(this, newModel);
    },
    showLocationTree: function() {
        return true;
    },
    onSubmitHook: function() {
        getSearchOptionsModel().getFilterModel(FilterKey.AGENT_NAME_SEARCH).pushSearchedName();
    }
});
SearchController = Class.create();
Object.extend(SearchController.prototype, PageController.prototype);
Object.extend(SearchController.prototype, {
    CONTROLLER_NAME: "sales",
    _filterModelsUsed: function() {
        var modelsUsed = PageController.prototype._filterModelsUsed.call(this);
        modelsUsed[FilterKey.LOCATION] = new LocationModel();
        modelsUsed[FilterKey.SCHOOL_DISTRICTS] = new MultiLevelAmenityFilterModel("School Districts", 'schooldistricts', 'Any School District', 'Add School District', 'Edit School Districts');
        modelsUsed[FilterKey.PRICE] = new PriceFilterModel();
        modelsUsed[FilterKey.BED_BATH] = new BedBathSizeFilterModel();
        modelsUsed[FilterKey.INTERIOR_SIZE_LOT_SIZE] = new InteriorLotSizeFilterModel();
        modelsUsed[FilterKey.CAT_BASED_LOCATION] = modelsUsed[FilterKey.LOCATION];
        modelsUsed[FilterKey.ARCHITECTURAL_STYLE] = new MultiLevelAmenityFilterModel("Architectural Style", 'architecturalstyle', 'All Styles');
        modelsUsed[FilterKey.PROPERTY_COMMUNITY_TYPE] = new MultiLevelAmenityFilterModel("Property/Community Type", 'propertycommunitytype', 'All Types', 'Add Property Type', 'Edit Property Type');
        modelsUsed[FilterKey.FEATURES_AND_AMENITIES] = new MultiLevelAmenityFilterModel("Features and Amenities", 'featuresandamenities', 'Any Features', 'Add Features and Amenities', 'Edit Features and Amenities');
        modelsUsed[FilterKey.LIFESTYLE] = new MultiLevelAmenityFilterModel("Lifestyle", 'lifestyle', 'Any Lifestyle');
        modelsUsed[FilterKey.ITEMS_PER_PAGE] = new ItemsPerPageFilterModel();
        return modelsUsed;
    },
    showLocationTree: function() {
        return true;
    },
    _searchOptionsModelWasSet: function(newModel, oldModel) {
        PageController.prototype._searchOptionsModelWasSet.call(this, newModel, oldModel);
        //restores the location widget to what the newModel believes the state should be
        //need to tell the LocationFilterWidget (left bar) to update as well WITHOUT firing a toggle
        newModel.getFilterModel(FilterKey.LOCATION).setLocationDisplayTree(LOCATION_DISPLAY_TREE);
    },
    _createCountController: function(model) {
        return new CountController("sales", model);
    },
    _getPageNavigationURL: function() {
        return '/sales/list.rails?layout=results';
    },
    getLinkBackToThisPage: function() {
        return regionRoot + '/sales';
    },
    isLandingPageVisible: function() {
        return $('regionSplash') && $('content') && $('content').className.indexOf('resultsList') == -1;
    },
    setUpDetailPagination: function() {
        $('sir_result_detail_sort_by').value = $('sir_result_sort_by').value;
        $('sir_result_detail_sort_direction').value = $('sir_result_sort_direction').value;
    }
});
WelcomeController = Class.create();
Object.extend(WelcomeController.prototype, SearchController.prototype);
Object.extend(WelcomeController.prototype, {
    initialize: function(params) {
        SearchController.prototype.initialize.call(this, params);
    },
    onInitialPageLoad: function() {
        PageController.prototype.onInitialPageLoad.call(this);
        this.updateCount();
    },
    _updateViewToResults: function() {
        if ($('error')) {
            Element.remove('error');
        }
       
        if ($("findPropertiesDownArrow")) {
            Element.hide($("findPropertiesDownArrow"));
        }
        unregisterAnyHandler($('findPropertiesLink'), 'mouseover');
        unregisterAnyHandler($('findPropertiesLink'), 'mouseout');
        if ($('findPropertiesDrop')) {
            unregisterAnyHandler($('findPropertiesDrop'), 'mouseout');
        }
        if ($('secondarySearchTabs')) {
            Element.show($('secondarySearchTabs'));
            Element.removeClassName($('secondarySearchTabsDiv'), "empty");
            Element.addClassName($('secondarySearchTabs').getElementsByTagName('a')[0], "active");
        }
        removeLandingPageStyles();
        var contentDiv = $('content');
        if (contentDiv)
            contentDiv.className = 'content resultsList';
    }
});
RentalController = Class.create();
Object.extend(RentalController.prototype, SearchController.prototype);
Object.extend(RentalController.prototype, {
    CONTROLLER_NAME: "rental",
    initialize: function(params) {
        SearchController.prototype.initialize.call(this, params);
    },
    _filterModelsUsed: function() {
        var modelsUsed = PageController.prototype._filterModelsUsed.call(this);
        modelsUsed[FilterKey.LOCATION] = new LocationModel();
        modelsUsed[FilterKey.CAT_BASED_LOCATION] = modelsUsed[FilterKey.LOCATION];
        modelsUsed[FilterKey.SCHOOL_DISTRICTS] = new MultiLevelAmenityFilterModel("School Districts", 'schooldistricts', 'Any School District', 'Add School District', 'Edit School District');
        modelsUsed[FilterKey.RATES_AND_AVAILABILITY] = new RatesAndAvailabilityFilterModel();
        modelsUsed[FilterKey.BED_BATH] = new BedBathSizeFilterModel();
        modelsUsed[FilterKey.INTERIOR_SIZE_LOT_SIZE] = new InteriorLotSizeFilterModel();
        modelsUsed[FilterKey.ARCHITECTURAL_STYLE] = new MultiLevelAmenityFilterModel("Architectural Style", 'architecturalstyle', 'All Styles');
        modelsUsed[FilterKey.PROPERTY_COMMUNITY_TYPE] = new MultiLevelAmenityFilterModel("Property/Community Type", 'propertycommunitytype', 'All Types');
        modelsUsed[FilterKey.FEATURES_AND_AMENITIES] = new MultiLevelAmenityFilterModel("Features and Amenities", 'featuresandamenities', 'Any Features', 'Add Features and Amenities', 'Edit Features and Amenities');
        modelsUsed[FilterKey.LIFESTYLE] = new MultiLevelAmenityFilterModel("Lifestyle", 'lifestyle', 'Any Lifestyle');
        return modelsUsed;
    },
    _createSearchOptionsModel: function() {
        return PageController.prototype._createSearchOptionsModel.call(this, 'search');
    },
    _getPageNavigationURL: function() {
        return '/rental/list.rails?layout=results';
    },
    _createCountController: function(model) {
        return new CountController(this.CONTROLLER_NAME, model);
    },
    getLinkBackToThisPage: function() {
        return regionRoot + '/rentals';
    }
});
RentalWelcomeController = Class.create();
Object.extend(RentalWelcomeController.prototype, RentalController.prototype);
Object.extend(RentalWelcomeController.prototype, {
    initialize: function(params) {
        RentalController.prototype.initialize.call(this, params);
    },
    onInitialPageLoad: function() {
        PageController.prototype.onInitialPageLoad.call(this);
        this.updateCount();
    },
    _updateViewToResults: function() {
        if ($('error')) {
            Element.remove('error');
        }
        Element.removeClassName($('searchResults'), 'rentalLanding');
        removeLandingPageStyles();
        var contentDiv = $('content');
        if (contentDiv)
            contentDiv.className = 'content resultsList';
    }
});
OfficeController = Class.create();
Object.extend(OfficeController.prototype, PageController.prototype);
Object.extend(OfficeController.prototype, {
    initialize: function(params) {
        params = params || {};
        params['_shouldAutoUpdateResults'] = false;
        PageController.prototype.initialize.call(this, params);
    },
    CONTROLLER_NAME: "offices",
    _filterModelsUsed: function() {
        var modelsUsed = PageController.prototype._filterModelsUsed.call(this);
        modelsUsed[FilterKey.LOCATION] = new LocationModel();
        return modelsUsed;
        //	},
        //	_createCountController:function(model){
        //		return undefined;
    },
    _getPageNavigationURL: function() {
        return '/offices';
    }
});
AgentDetailController = Class.create();
Object.extend(AgentDetailController.prototype, DetailPageController.prototype);
Object.extend(AgentDetailController.prototype, {
    CONTROLLER_NAME: "agentdetail",
    initialize: function(params) {
        this._agentId = params.agentId;
        this._countController = null;
        DetailPageController.prototype.initialize.call(this, params);
    },
    _createCountController: function(model) {
    },
    _filterModelsUsed: function() {
        var modelsUsed = {};
        var model = new AgentIdFilterModel();
        model.setIdCriteria(this._agentId);
        modelsUsed[FilterKey.AGENT_ID] = model;
        return modelsUsed;
    },
    getAgentId: function() {
        return this._agentId;
    },
    onInitialPageLoad: function() {
        PageController.prototype.onInitialPageLoad.call(this);
        if ($("AgentWebSite") != null) {
            Event.observe($("AgentWebSite"), 'click', this._handleLinkClicked.bind(this));
        }
    },
    _getPageNavigationURL: function() {
        if (this._isRentalListingsActive()) {
            return '/rental/byAgent/' + this._agentId;
        }
        else if (this._isSelectSalesActive()) {
            return '/agentselectsales/byAgent.rails?agentId=' + this._agentId;
        }
        else
            return '/sales/byAgent/' + this._agentId;
    },
    _handleLinkClicked: function() {
        this._prepareWebTrendsForAgentWebsites();
    },
    _prepareWebTrendsForAgentWebsites: function() {
        var agentName = $("agentname").innerHTML;
        if (typeof WebTrendsAnalyzer == 'function') {
            (new WebTrendsAnalyzer()).fireWebTrendAction(
WebTrendsAnalyzer.CreateActionClickOnLink('Agent ' + agentName, window.location, 'Agent Website'));
        }
    },
    _isRentalListingsActive: function() {
        return ($('currentRentalsLI') && $('currentRentalsLI').className.indexOf('selected') != -1);
    },
    _isSelectSalesActive: function() {
        return ($('selectSalesLI') && $('selectSalesLI').className.indexOf('selected') != -1);
    },
    createDetailPageURL: function(agentEmail) {
        return regionRoot + '/agents' + '/' + agentEmail;
    },
    createSearchResultsActionUrl: function() {
        return regionRoot + '/agents';
    }
});
OfficeDetailController = Class.create();
Object.extend(OfficeDetailController.prototype, DetailPageController.prototype);
Object.extend(OfficeDetailController.prototype, {
    CONTROLLER_NAME: "officedetail",
    initialize: function(params) {
        this._officeId = params.officeId;
        this._countController = null;
        DetailPageController.prototype.initialize.call(this, params);
    },
    _createCountController: function(model) {
    },
    _filterModelsUsed: function() {
        var modelsUsed = {};
        var model = new OfficeIdFilterModel();
        model.setIdCriteria(this._officeId);
        modelsUsed[FilterKey.OFFICE_ID] = model;
        return modelsUsed;
    },
    getOfficeId: function() {
        return this._officeId;
    },
    _getPageNavigationURL: function() {
        if (this._isOfficeListingsActive()) {
            return '/sales/list.rails';
        } else if (this._isOfficeRentalsActive()) {
            return '/rental/list.rails';
        } else if (this._isSelectSalesActive()) {
            return '/officeselectsales/list.rails?officeId=' + this._officeId;
        } else {
            return '/agents/shortsummary.rails';
        }
    },
    _isOfficeListingsActive: function() {
        return ($('currentListingsLI').className.indexOf('selected') != -1)
    },
    _isOfficeRentalsActive: function() {
        return ($('currentRentalsLI') && $('currentRentalsLI').className.indexOf('selected') != -1)
    },
    _isSelectSalesActive: function() {
        return ($('selectSalesLI') && $('selectSalesLI').className.indexOf('selected') != -1)
    },
    createDetailPageURL: function(officeId) {
        return regionRoot + '/offices' + '/' + officeId;
    },
    createSearchResultsActionUrl: function() {
        return regionRoot + '/offices/list.rails';
    }
});
TeamDetailController = Class.create();
Object.extend(TeamDetailController.prototype, DetailPageController.prototype);
Object.extend(TeamDetailController.prototype, {
    CONTROLLER_NAME: "teamdetail",
    initialize: function(params) {
        this._teamId = params.teamId;
        this._countController = null;
        DetailPageController.prototype.initialize.call(this, params);
    },
    _createCountController: function(model) {
    },
    _filterModelsUsed: function() {
        var modelsUsed = {};
        var model = new SalesTeamIdFilterModel();
        model.setIdCriteria(this._teamId);
        modelsUsed[FilterKey.SALE_TEAM_ID] = model;
        return modelsUsed;
    },
    onInitialPageLoad: function() {
        if ($("SalesTeamWebSite") != null) {
            Event.observe($("SalesTeamWebSite"), 'click', this._handleLinkClicked.bind(this));
        }
    },
    _getPageNavigationURL: function() {
        if (this._isRentalListingsActive()) {
            return '/rental/byTeam.rails?teamid=' + this._teamId + '&watched=false';
        }
        else if (this._isSalesListingsActive()) {
            return '/sales/byTeam.rails?teamid=' + this._teamId + '&watched=false';
        }
        else if (this._isSelectSalesActive()) {
            return '/agentselectsales/byteam.rails?teamid=' + this._teamId;
        }
        else
            return '/agents/byTeam.rails?teamId=' + this._teamId;
    },
    _handleLinkClicked: function() {
        this._prepareWebTrendsForSalesTeamWebsites();
    },
    _prepareWebTrendsForSalesTeamWebsites: function() {
        var salesteam = $("salesteam").innerHTML;
        if (typeof WebTrendsAnalyzer == 'function') {
            (new WebTrendsAnalyzer()).fireWebTrendAction(
WebTrendsAnalyzer.CreateActionClickOnLink('Sales Team ' + salesteam, window.location, 'SalesTeam Website'));
        }
    },
    createDetailPageURL: function(agentEmail) {
        /* ONLY will be called from an agent search results pagination context */
        return regionRoot + '/agents' + '/' + agentEmail;
    },
    _isRentalListingsActive: function() {
        return ($('currentRentalsLI') && $('currentRentalsLI').className.indexOf('selected') != -1);
    },
    _isSelectSalesActive: function() {
        return ($('selectSalesLI') && $('selectSalesLI').className.indexOf('selected') != -1);
    },
    _isSalesListingsActive: function() {
        return ($('currentListingsLI') && $('currentListingsLI').className.indexOf('selected') != -1);
    }
});
NeighborhoodDetailController = Class.create();
Object.extend(NeighborhoodDetailController.prototype, DetailPageController.prototype);
Object.extend(NeighborhoodDetailController.prototype, {
    CONTROLLER_NAME: "neighborhooddetail",
    initialize: function(params) {
        this._neighborhoodId = params['neighborhoodId'];
        this._numListings = params['numListings'];
        this._countController = null;
        DetailPageController.prototype.initialize.call(this, params);
    },
    _createCountController: function(model) {
    },
    _filterModelsUsed: function() {
        var modelsUsed = {};
        var model = new NeighborhoodIdFilterModel();
        model.setIdCriteria(this._neighborhoodId);
        modelsUsed[FilterKey.NEIGHBORHOOD_ID] = model;
        return modelsUsed;
    },
    getNeighborhoodId: function() {
        return this._neighborhoodId;
    },
    onInitialPageLoad: function() {
        PageController.prototype.onInitialPageLoad.call(this);
        if (this._numListings && this._numListings > 0) {
            //this.updateSearchResults(); //removed this, pushed responsibility back to the server
        }
    },
    createDetailPageURL: function(areaName) {
        return regionRoot + '/areas/' + areaName;
    }
});
AreaController = Class.create();
Object.extend(AreaController.prototype, PageController.prototype);
Object.extend(AreaController.prototype, {
    CONTROLLER_NAME: "areas",
    _createCountController: function(model) {
        return new CountController("sales", model);
    },
    _filterModelsUsed: function() {
        var modelsUsed = PageController.prototype._filterModelsUsed.call(this);
        var model = new SubRegionFilterModel();
        modelsUsed[FilterKey.SUBREGION] = model;
        return modelsUsed;
    },
    updateCount: function() {
    },
    _getPageNavigationURL: function() {
        return window.location.href;
    },
    onInitialPageLoad: function() {
        PageController.prototype.onInitialPageLoad.call(this);
        this.updateCount();
    },
    goToPage: function(pageNo) {
        PageController.prototype.goToPage.call(this, pageNo);
        this.updateCount();
    },
    setCountString: function() {
        //do nothing
    }
});
DevelopmentController = Class.create();
Object.extend(DevelopmentController.prototype, PageController.prototype);
Object.extend(DevelopmentController.prototype, {
    CONTROLLER_NAME: "developments",
    _filterModelsUsed: function() {
        var urlParts = window.location.href.split('/');
        var developmentGroup = urlParts[urlParts.length - 1];
        var modelsUsed = PageController.prototype._filterModelsUsed.call(this);
        var model = new DevelopmentGroupFilterModel();
        model.setIdCriteria(developmentGroup);
        modelsUsed[FilterKey.DEVELOPMENT_GROUP] = model;
        return modelsUsed;
    },
    _getPageNavigationURL: function() {
        return window.location.href;
    },
    onInitialPageLoad: function() {
        PageController.prototype.onInitialPageLoad.call(this);
    }
});
SearchByRadioButton = Class.create();
Object.extend(SearchByRadioButton.prototype, RadioButton.prototype);
Object.extend(SearchByRadioButton.prototype, {
    initialize: function(type, buttonText, promptText, assistText, action, startAutoComplete, showMarketDropDown) {
        RadioButton.prototype.initialize.call(this, type);
        this._type = type;
        this._buttonText = buttonText;
        this._promptText = promptText;
        this._assistText = assistText;
        this._action = action;
        this._startAutoComplete = startAutoComplete || false;
        this._showMarketDropDown = showMarketDropDown || false;
    },
    addToUrl: function(url) {
        if (this._action)
            url.push(this._action);
    },
    updateAutoComplete: function(autocompleter) {
        if (this._startAutoComplete) {
            autocompleter.start();
        } else {
            autocompleter.stop();
        }
    },
    getType: function() {
        return this._type;
    },
    getButtonText: function() {
        return this._buttonText;
    },
    getAssistText: function() {
        return '<label>' + this._assistText + '</label>';
    },
    getPromptText: function() {
        return this._promptText;
    },
    showMarketDropDown: function() {
        return this._showMarketDropDown;
    },
    render: function() {
        return '<input type="radio" class="radio" id="' + this._type + '" value="' + this._type + '" name="searchByRadioButton" />' +
'<label for="' + this._type + '">' + this._buttonText + '</label></input>'
    }
});
SearchByRadioButton.LOCATION = new SearchByRadioButton("Location", " City, ST or Zip", "City, ST or Zip", "Within:", 'byCitySTZip');
SearchByRadioButton.MARKET = new SearchByRadioButton("Market", " Location", "", "Within:", 'byMarket', false, true);
SearchByRadioButton.AGENT_NAME = new SearchByRadioButton("Name", " Name", "Example: John Smith", "Enter an Agent's Name", 'byname', true);
SearchByRadioButton.MLSID_WEBNO = new SearchByRadioButton("", "", "", "Web # or MLS ID:", 'byListingNumberOrMlsID');
SearchByRadioButton.ALL = new SearchByRadioButton("", "", "Web #, MLS ID, address, agent, keyword", "Quick Search", "search", true);
SearchByRadioButton.getInstance = function(type) {
    for (var name in SearchByRadioButton) {
        if (typeof SearchByRadioButton[name] == 'object' && SearchByRadioButton[name].getType() == type) return SearchByRadioButton[name];
    }
};
SearchByRadioButton.getSelectedRadioButton = function() {
    var checked = $('quicksearchform').getInputs('radio', 'searchByRadioButton').find(function(re) { return re.checked; });
    return (checked) ? $F(checked) : null;
};
PropertyDetailController = Class.create();
Object.extend(PropertyDetailController.prototype, DetailPageController.prototype);
Object.extend(PropertyDetailController.prototype, {
    initialize: function(params) {
        this._propertyId = params['propertyId'];
        DetailPageController.prototype.initialize.call(this, params);
    },
    getPropertyId: function() {
        return this._propertyId;
    },
    getResultIndex: function() {
        return this._resultIndex;
    },
    updateSearchResults: function() {
    },
    goToPage: function() {
    },
    createDetailPageURL: function(propertyId) {
        return regionRoot + '/' + this._propertyType + '/' + propertyId;
    },
    createSearchResultsActionUrl: function() {
        return regionRoot + '/' + this._propertyType + '/list.rails';
    },
    _filterModelsUsed: function() {
        return {};
    }
});
SalesDetailController = Class.create();
Object.extend(SalesDetailController.prototype, PropertyDetailController.prototype);
Object.extend(SalesDetailController.prototype, {
    initialize: function(params) {
        this._propertyType = 'sales';
        PropertyDetailController.prototype.initialize.call(this, params);
        if ($('watchThisPropertyButton')) {
            (new WatchThisPropertyPanel($('watchThisPropertyDiv'), new WatchPropertyService()));
        } else if ($('watchListOffLink')) {
            new CurrentlyWatchingPropertyPanel($('watchThisPropertyDiv'), new WatchPropertyService());
        }
    }
});
RentalDetailController = Class.create();
Object.extend(RentalDetailController.prototype, PropertyDetailController.prototype);
Object.extend(RentalDetailController.prototype, {
    initialize: function(params) {
        this._propertyType = 'rental';
        PropertyDetailController.prototype.initialize.call(this, params);
    }
});
OpenHouseDetailController = Class.create();
Object.extend(OpenHouseDetailController.prototype, PropertyDetailController.prototype);
Object.extend(OpenHouseDetailController.prototype, {
    initialize: function(params) {
        this._propertyType = 'openhouses';
        PropertyDetailController.prototype.initialize.call(this, params);
        if ($('watchThisPropertyButton')) {
            (new WatchThisPropertyPanel($('watchThisPropertyDiv'), new WatchPropertyService()));
        } else if ($('watchListOffLink')) {
            new CurrentlyWatchingPropertyPanel($('watchThisPropertyDiv'), new WatchPropertyService());
        }
    }
});
ResultType = Class.create();
Object.extend(ResultType.prototype, {
    initialize: function(type, searchByList, serverControllerName) {
        this._type = type;
        this._searchByList = searchByList;
        this._serverControllerName = serverControllerName;
    },
    getType: function() {
        return this._type;
    },
    getSearchByList: function() {
        return this._searchByList;
    },
    getDefaultSearchBy: function() {
        return this._searchByList[0];
    },
    addToUrl: function(url) {
        url.push(this._serverControllerName);
    },
    isEmpty: function() {
        return this.getDefaultSearchBy().getType() == '';
    }
});
ResultType.ALL = new ResultType("Web #, MLS ID, address, agent, keyword", [SearchByRadioButton.ALL], 'quicksearch');
ResultType.MLSNO_WEBID = new ResultType("Web # or MLS ID", [SearchByRadioButton.MLSID_WEBNO], 'sales');
ResultType.SALES = new ResultType("Properties for Sale", [SearchByRadioButton.LOCATION, SearchByRadioButton.MARKET], 'sales');
ResultType.RENT = new ResultType("Properties for Rent", [SearchByRadioButton.MARKET], 'rentals');
ResultType.AGENT = new ResultType("Our Agents", [SearchByRadioButton.AGENT_NAME, SearchByRadioButton.LOCATION, SearchByRadioButton.MARKET], 'agents');
ResultType.OFFICE = new ResultType("Our Offices", [SearchByRadioButton.MARKET], 'offices');
ResultType.getInstance = function(type) {
    for (var name in ResultType) {
        if (typeof ResultType[name] == 'object' && ResultType[name].getType() == type) {
            return ResultType[name];
        }
    }
}
QuickSearchController = Class.create();
Object.extend(QuickSearchController.prototype, {
    initialize: function(resultType) {
        this._model = new QuickSearchModel(resultType);
        this._view = new QuickSearchView(this._model, this);
        if (typeof QSAutocompleter != 'undefined') { //so that the other tests don't NEED this.
//this._autocompleter = new QSAutocompleter('quicksearchtextcriteria', 'suggestText', "/agents/suggest.rails", {
this._autocompleter = new QSAutocompleter('quicksearchtextcriteria', 'suggestText', regionRoot + "/quicksearch/suggest.rails", {
//paramName: 'textCriteria'
paramName: 'searchTerm'
            });
        }
        this._model.addSearchByListener(new ClosureHandler(this._searchByChanged.bind(this)));
        this._model.addResultTypeListener(new ClosureHandler(this._searchByChanged.bind(this)));
        this._searchByChanged();
    },
    submit: function() {
        if (typeof dcsMultiTrack == 'function') {
            dcsMultiTrack('WT.oss', this._model.getTextCriteria());
        }
        window.location.href = baseUrl + this.buildQuickSearchURL();
    },
    buildQuickSearchURL: function() {
        var url = [];
        if (this._model.getSearchBy().showMarketDropDown()) {
            url.push(""); // to add a leading slash before the regionRoot
            if (this._view._marketSelect.getSelectionValue().length > 0) {
                url.push(this._view._marketSelect.getSelectionValue());
            }
            this._model.getResultType().addToUrl(url);
        }
        else {
url.push(regionRoot);
//url.push("");
            this._model.getResultType().addToUrl(url);
            this._model.getSearchBy().addToUrl(url);
url.push(this.encodeTextForURI(this._model.getTextCriteria()));
        }
        return url.join('/');
    },
encodeTextForURI: function(text) {
// `-=[];',./~!@#$%^&*()_+{}:"<>?
// ALL possible keyboard non-alphnumeric characters are above and should not cause an error
var encodedText = encodeURIComponent(text.gsub(/\%/, '').gsub(/\&/, '').gsub(/\./, '').gsub(/\?/, '').gsub(/\//, '').gsub(/</, '').gsub(/>/, '')).gsub(/!/, '%21').gsub(/'/, '%27').gsub(/\(/, '').gsub(/\)/, '').gsub(/\*/, '');
if (encodedText.toUpperCase() == "CON" || encodedText.toUpperCase() == "AUX") {
encodedText = "%20" + encodedText; // prepending a space gets around error and is ignored by lucene
}
return encodedText;
},
    _searchByChanged: function() {
        this._model.getSearchBy().updateAutoComplete(this._autocompleter);
    },
    getModel: function() {
        return this._model;
    }
});
QuickSearchModel = Class.create();
Object.extend(QuickSearchModel.prototype, {
    initialize: function(resultType) {
resultType = resultType || ResultType.ALL;
        this._resultTypeObservable = new Observable();
        this._searchByObservable = new Observable();
        this._textCriteriaObservable = new Observable();
        this.setResultType(resultType);
    },
    addResultTypeListener: function(listener) {
        this._resultTypeObservable.addChangeListener(listener);
    },
    addSearchByListener: function(listener) {
        this._searchByObservable.addChangeListener(listener);
    },
    addTextCriteriaListener: function(listener) {
        this._textCriteriaObservable.addChangeListener(listener);
    },
    setTextCriteria: function(criteria) {
        this._textCriteria = criteria;
        this._textCriteriaObservable.notifyChange();
    },
    getTextCriteria: function() {
        return this._textCriteria;
    },
    setResultType: function(type) {
        this._resultType = type;
        this._searchBy = type.getDefaultSearchBy();
        this._resultTypeObservable.notifyChange();
    },
    getResultType: function() {
        return this._resultType;
    },
    setSearchBy: function(type) {
        this._searchBy = type;
        this._searchByObservable.notifyChange();
    },
    getSearchBy: function() {
        return this._searchBy;
    }
});
QuickSearchModel.RESULT_TYPE_LIST = [ResultType.ALL, ResultType.MLSNO_WEBID, ResultType.SALES, ResultType.RENT, ResultType.AGENT, ResultType.OFFICE];
QuickSearchView = Class.create();
Object.extend(QuickSearchView.prototype, {
    initialize: function(model, controller) {
        this._controller = controller;
        this._resultTypeSelect = new Select('mainquicksearchcriteria');
        this._submitButton = new PeerElement('new_quickSearchSubmitButton');
        this._textCriteria = new InputElement('quicksearchtextcriteria');
        this._searchByRadioButtonPane = $('searchByRadioButtonPaneDiv');
        this._marketSelect = new Select('marketselect');
        this._model = model;
        this._updateSearchByList();
        this._updateResultTypeList();
        this._onSearchByChange();
        this._model.addResultTypeListener(new ClosureHandler(this._onResultTypeChange.bind(this)));
        this._model.addSearchByListener(new ClosureHandler(this._onSearchByChange.bind(this)));
        this._model.addTextCriteriaListener(new ClosureHandler(this._onTextCriteriaChange.bind(this)));
        this._bindListeners();
    },
    _bindListeners: function() {
        this._createSearchByRadioButtonBindings();
        this._resultTypeSelect.addChangeListener(this._handleResultTypeChanged.bind(this));
        this._textCriteria.addFocusListener(this._handleFocusGained.bind(this));
        this._textCriteria.addBlurListener(this._handleFocusLost.bind(this));
        this._textCriteria.addEnterKeyListener(this._handleEnterKeyPressed.bindAsEventListener(this));
        this._submitButton.addClickListener(this._handleSubmit.bind(this));
    },
    _createSearchByRadioButtonBindings: function() {
        this._model.getResultType().getSearchByList().each(function(searchByRadioButton) {
            this._createASearchByRadioButtonBinding(searchByRadioButton)
        }
.bind(this));
    },
    _createASearchByRadioButtonBinding: function(searchByRadioButton) {
        searchByRadioButton.addClickListener(this._handleSearchByChanged.bind(this));
    },
    _updateResultTypeList: function() {
        this._resultTypeSelect.update(QuickSearchModel.RESULT_TYPE_LIST.collect(function(resultType) {
            return resultType.getType();
        }), this._model.getResultType().getType());
    },
    _onTextCriteriaChange: function() {
        this._textCriteria.setValue(this._model.getTextCriteria());
    },
    _onSearchByChange: function() {
        if (this._model.getSearchBy() && this._model.getSearchBy().showMarketDropDown()) {
            this._textCriteria.hide();
            var showAllMarkets = (ResultType.getInstance(this._resultTypeSelect.getSelection().text) != ResultType.RENT);
            var marketListProvider = new MarketSelectListProvider(this._marketSelect._getElement(), showAllMarkets);
            marketListProvider.render();
            Element.show(this._marketSelect._getElement());
        }
        else {
            Element.hide(this._marketSelect._getElement());
            this._textCriteria.show();
            this._updateTextBox(this._getQuickSearchPromptText());
        }
        this._updateAssistText();
    },
    _getQuickSearchPromptText: function() {
        return this._model.getSearchBy().getPromptText();
    },
    _onResultTypeChange: function() {
        this._updateSearchByList();
        this._onSearchByChange();
    },
    _updateSearchByList: function() {
        this._searchByRadioButtonPane.innerHTML = '';
        if (!this._model.getResultType().isEmpty() && this._model.getResultType().getSearchByList().size() > 1) {
            var html = this._model.getResultType().getSearchByList().collect(function(radioButton) {
                return radioButton.render()
            }).join('');
            this._searchByRadioButtonPane.innerHTML = '<label>Search By: </label>' + html;
            this._createSearchByRadioButtonBindings();
            this._selectDefaultSearchByRadioButton();
        }
    },
    _updateAssistText: function() {
        $('assistTextDiv').innerHTML = this._model.getSearchBy().getAssistText();
    },
    _selectDefaultSearchByRadioButton: function() {
        $(this._model.getResultType().getDefaultSearchBy().getType()).checked = true;
    },
    _handleSearchByChanged: function() {
        this._model.setSearchBy(SearchByRadioButton.getInstance(SearchByRadioButton.getSelectedRadioButton()));
    },
    _handleResultTypeChanged: function() {
        this._model.setResultType(ResultType.getInstance(this._resultTypeSelect.getSelection().text));
    },
    _updateTextBox: function(text) {
        this._textCriteria.setValue(text);
        this._textCriteria.removeClass('hintTextboxActive');
        this._textCriteria.addClass('hintTextbox');
        this._textCriteria.addClass('prompt');
    },
    _handleFocusGained: function() {
        if (this._textCriteria.getValue() == this._model.getSearchBy().getPromptText()) {
            this._textCriteria.clear();
            this._textCriteria.removeClass('hintTextbox');
            this._textCriteria.removeClass('prompt');
            this._textCriteria.addClass('hintTextboxActive');
        }
    },
    _handleFocusLost: function() {
        if (this._textCriteria.getValue() == "") {
            this._updateTextBox(this._getQuickSearchPromptText());
        }
    },
    _handleEnterKeyPressed: function() {
        this._createTimeout(this._doEnterPressed.bind(this), 10);
    },
    _createTimeout: function(fn, delay) {
        setTimeout(fn, delay);
    },
    _handleSubmit: function() {
        var textCriteriaValue = this._textCriteria.getValue();
        if ("." == textCriteriaValue.charAt(textCriteriaValue.length - 1)) {
            textCriteriaValue = textCriteriaValue.substring(0, textCriteriaValue.length - 1);
        }
        textCriteriaValue = textCriteriaValue.replace(":", "");
        this._model.setTextCriteria(textCriteriaValue);
        this._controller.submit();
    },
    _doEnterPressed: function() {
        this._handleSubmit();
    }
})
MarketSelectListProvider = Class.create();
Object.extend(MarketSelectListProvider.prototype, {
    initialize: function(control, showAllLocations) {
        this._control = control;
        this._showAllLocations = showAllLocations;
    },
    isShowAllLocation: function() {
        return this._showAllLocations;
    },
    render: function() {
        this._control.options.length = 0;
        var allMarketsOption = [{ text: "All Markets", value: ""}];
        var otherMarkets = [
{ text: "Cape Cod, MA", value: "capecod" },
{ text: "Greenwich, CT", value: "greenwich" },
{ text: "Hamptons, NY", value: "hamptons" },
{ text: "Jackson Hole, WY", value: "jacksonhole" },
{ text: "London, UK", value: "london" },
{ text: "New York, NY", value: "nyc" },
{ text: "Northern California", value: "norcal" },
{ text: "Palm Beach, FL", value: "palmbeach" },
{ text: "Santa Fe, NM", value: "santafe" },
{ text: "Southern California", value: "socal" },
{ text: "Sun Valley, ID", value: "sunvalley" }
];
        var optionsToAdd = (this.isShowAllLocation()) ? allMarketsOption.concat(otherMarkets) : otherMarkets;
        for (var i = 0; i < optionsToAdd.length; i++) {
            this._control.options[i] = new Option(optionsToAdd[i].text, optionsToAdd[i].value);
        }
    }
});
OpenHousePageController = Class.create();
Object.extend(OpenHousePageController.prototype, PageController.prototype);
Object.extend(OpenHousePageController.prototype, {
    initialize: function(params) {
        PageController.prototype.initialize.call(this, params);
    },
    CONTROLLER_NAME: "openhouses",
    _getPageNavigationURL: function() {
        return '/openhouses/list.rails';
    },
    onInitialPageLoad: function() {
        PageController.prototype.onInitialPageLoad.call(this);
    },
    _filterModelsUsed: function() {
        var modelsUsed = PageController.prototype._filterModelsUsed.call(this);
        modelsUsed[FilterKey.SUBREGION] = new SubRegionFilterModel();
        return modelsUsed;
    }
});
DevelopmentIdFilterModel = Class.create();
Object.extend(DevelopmentIdFilterModel.prototype, IdFilterModel.prototype);
Object.extend(DevelopmentIdFilterModel.prototype, {
    initialize: function() {
        IdFilterModel.prototype.initialize.call(this, 'developmentId', '_developmentId');
        this.constructor = DevelopmentIdFilterModel; // Safari Fix
    }
});
DevelopmentIdFilterModel.scoop = function(dump) {
    return IdFilterModel.scoop(dump, new DevelopmentIdFilterModel());
};
DevelopmentDetailController = Class.create();
Object.extend(DevelopmentDetailController.prototype, DetailPageController.prototype);
Object.extend(DevelopmentDetailController.prototype, {
    CONTROLLER_NAME: "developmentdetail",
    initialize: function(params) {
        this._developmentId = params['developmentId'];
        this._developmentAddressId = params['developmentAddressId'];
        this._onBoardZipCode = params['onBoardZipCode'];
        this._countController = null;
        DetailPageController.prototype.initialize.call(this, params);
    },
    _createCountController: function(model) {
    },
    _filterModelsUsed: function() {
        var modelsUsed = {};
        var model = new DevelopmentIdFilterModel();
        model.setIdCriteria(this._developmentId);
        modelsUsed[FilterKey.DEVELOPMENT_ID] = model;
        return modelsUsed;
    },
    getDevelopmentId: function() {
        return this._developmentId;
    },
    getOnBoardZipCode: function() {
        return this._onBoardZipCode;
    },
    getDevelopmentAddressId: function() {
        return this._developmentAddressId;
    },
    _handleAdditionalInfoTabLoad: function() {
        if (this._isMapTabActive()) {
            showMapForProperty('/map/drawmap.rails?address=' + this.getDevelopmentAddressId());
        }
        else if (this._isLocalInformationTabActive()) {
            showLocalInformation(this.getOnBoardZipCode());
        }
    },
    _getPageNavigationURL: function() {
        if (this._isDevelopmentListingsActive()) {
            return '/sales/list.rails';
        }
    },
    _isDevelopmentListingsActive: function() {
        return ($('currentListingsLI') && $('currentListingsLI').className.indexOf('selected') != -1)
    },
    _isMapTabActive: function() {
        return ($('mapLI') && $('mapLI').className.indexOf('selected') != -1)
    },
    _isLocalInformationTabActive: function() {
        return ($('localInformationLI') && $('localInformationLI').className.indexOf('selected') != -1)
    },
    createDetailPageURL: function(developmentId) {
        return regionRoot + '/developments' + '/' + developmentId;
    },
    onInitialPageLoad: function() {
        PageController.prototype.onInitialPageLoad.call(this);
        this.updateSearchResults();
        this._handleAdditionalInfoTabLoad();
    }
})
SaveSearchPanel = Class.create();
Object.extend(SaveSearchPanel.prototype, {
    initialize: function(searchModel) {
        this._emailAddressId = 'SearchEmailAddress';
        this._emailErrorMessageId = 'InvalidEmailErrors';
        this._serverErrorMessageId = 'ServerErrors';
        this._nameId = 'SearchName';
        this._nameErrorMessageId = 'InvalidSearchNameErrors';
        this._saveSearchPanelId = 'saveSearchPanelId';
        this._validatedMessageId = 'saveSearchPanelValidatedId';
        this._searchNameValidatedMessageId = 'searchNameValidatedDisplayId';
        this._searchModel = searchModel;
        this._emailValidator = new EmailAddressValidator($(this._emailAddressId),
this._emailValidationFailed.bind(this),
this._emailValidationPassed.bind(this));
    },
    _emailValidationPassed: function(email) {
        this._hideErrorMessage(this._emailErrorMessageId);
        createCookie('userEmail', email);
    },
    _emailValidationFailed: function(email) {
        this._showErrorMessage(this._emailErrorMessageId);
    },
    isValidName: function(name) {
        name = name.strip();
        return /^[0-9|a-z|A-Z]/.test(name);
    },
    validateEmailAddress: function() {
        return this._emailValidator.validate();
    },
    validateName: function() {
        if (this.isValidName($(this._nameId).value)) {
            return this._hideErrorMessage(this._nameErrorMessageId)
        }
        return this._showErrorMessage(this._nameErrorMessageId);
    },
    validate: function() {
        this._hideErrorMessage(this._serverErrorMessageId);
        var valid = this.validateEmailAddress();
        //DON'T change this.  We dont want it to short circut and changing it to &= turns it into
        //bits.
        valid = this.validateName() && valid;
        if (valid) {
            $(this._searchNameValidatedMessageId).innerHTML = $(this._nameId).value;
        }
        return valid;
    },
    _hideErrorMessage: function(errorMessageId) {
        Element.hide($(errorMessageId));
        return true;
    },
    _showErrorMessage: function(errorMessageId, message) {
        Element.show($(errorMessageId));
        if (message) {
            Element.update(errorMessageId, message);
        }
        return false;
    },
    bindEvents: function() {
        Event.observe('SaveSearchSaveButton', 'click', this.handleSaveButtonClicked.bindAsEventListener(this));
    },
    handleSaveButtonClicked: function(evt) {
        Event.stop(evt);
        if (this.validate()) {
            this.saveSearch($('SearchName').value.strip(),
$('SearchEmailAddress').value.strip(),
DataSerializer.serialize(this._searchModel.dump()),
getPageController().getLinkBackToThisPage()
);
        }
        return false;
    },
    saveSearch: function(name, email, jsonString, url) {
        new Ajax.Request(siteRoot + "savesearch/save.rails", {
            method: 'post',
            onSuccess: this.saveComplete.bind(this),
            parameters: { name: name, email: email, jsonString: jsonString, searchUrl: url }
        });
    },
    saveComplete: function(transport) {
        if (transport.responseText.match(/<success\/>/)) {
            this.saveSuccessful();
        } else {
            this.saveFailed(transport.responseText);
        }
    },
    saveSuccessful: function() {
        Element.hide($(this._saveSearchPanelId));
        Element.show($(this._validatedMessageId));
        $(this._searchNameValidatedMessageId).update($(this._nameId).value.escapeHTML());
    },
    saveFailed: function(message) {
        return this._showErrorMessage(this._serverErrorMessageId, message);
    }
});
SaveSearchPanel.Create = function() {
    new SaveSearchPanel(getPageController().getSearchOptionsModel()).bindEvents();
}
WebRegionModel = Class.create();
Object.extend(WebRegionModel.prototype, FilterModel.prototype);
Object.extend(WebRegionModel.prototype, {
    initialize: function(regionName) {
        FilterModel.prototype.initialize.call(this, "WebRegion");
        this.constructor = WebRegionModel; // Safari Fix
        this._regionName = this._parseRegionName(regionName);
    },
    _parseRegionName: function(regionName) {
        return regionName ? regionName.substring(1) : 'corporate';
    },
    dump: function() {
        dumpArray = {};
        dumpArray._regionName = this._regionName;
        return dumpArray;
    },
    equals: function(other) {
        return other._regionName == this._regionName;
    },
    isEmpty: function() {
        return false;
    },
    clear: function() {
    },
    getRegionName: function() {
        return this._regionName;
    }
});
WebRegionModel.scoop = function(dump) {
    return Object.extend(new WebRegionModel(), dump);
}
/*
* Global Variable Declarations
*/
var ajaxCount = 0;
var progressChicken = new ProgressChicken();
var ratesAndAvailabilityPanel = null;
var _pageController;
var PageControllerClasses = {
    "agents": AgentController,
    "sales": SearchController,
    "rental": RentalController,
    "offices": OfficeController,
    "openhouses": OpenHousePageController,
    "agentdetail": AgentDetailController,
    "officedetail": OfficeDetailController,
    "areas": AreaController,
    "developments": DevelopmentController,
    "areadetail": NeighborhoodDetailController,
    "propertydetail": PropertyDetailController,
    "salesdetail": SalesDetailController,
    "rentaldetail": RentalDetailController,
    "welcome": WelcomeController,
    "rentalwelcome": RentalWelcomeController,
    "location": WelcomeController,
    "openhousedetail": OpenHouseDetailController,
    "developmentdetail": DevelopmentDetailController,
    "teamdetail": TeamDetailController,
    "_default": SearchController
}
function printHTML() {
    var x = 0;
    for (var x = 0; x < document.all.length - 1; x++) {
        document.getElementById("output").value = x.innerHTML;
    }
}
function removeLandingPageStyles() {
    if (isLandingPageVisible()) {
        Element.removeClassName($('body'), 'welcome');
        Element.removeClassName($('body'), 'rentalwelcome');
        if ($('OpenHouses'))
            $('OpenHouses').hide();
        if ($('NewDevelopments'))
            $('NewDevelopments').hide();
        if ($('LetUsSearch'))
            $('LetUsSearch').hide();
        if ($('mortgageServicesButton'))
            $('mortgageServicesButton').hide();
        if ($('updateOptionsButton'))
            $('updateOptionsButton').hide();
        if ($('AboutOurAgents'))
            $('AboutOurAgents').hide();
        Element.setStyle($('toolbar'), { display: 'block' });
        // swap out old FindPropertyDiv
        swapFiltersDiv('SwapDiv', 'frame');
        // bind events to new div
        prepareAllWidgets();
    }
}
function handleWindowOnLoad(controllerName, next, prev) {
    moveChangeLocationDropIfPresent();
    bindNavigationWidget();
    var initialSearchModelDump = $('searchModelInput').value;
    PageController.addConstructorParam("searchModel", initialSearchModelDump);
    var controllerClass = PageControllerClasses[controllerName] || PageControllerClasses['_default'];
    _pageController = new controllerClass(PageController.getConstructorParams());
    for (var i = 0; i < PageController.getPageCreatedCallbacks().length; i++) {
        PageController.getPageCreatedCallbacks()[i](_pageController);
    }
    _pageController.onInitialPageLoad();
    bindGlassPaneForOptionsPane();
    prepareAllWidgets();
    prepareWebTrends();
}
function moveChangeLocationDropIfPresent() {
    var holder = $("changeLocationHolder");
    var tempHolder = $("changeLocationTempHolder");
    if (holder && tempHolder) {
        holder.innerHTML = tempHolder.innerHTML;
    }
}
function bindNavigationWidget() {
    registerDropDownEvents('findPropertiesLink', 'findPropertiesDrop');
    registerDropDownEvents('changeLocationLink', 'changeLocationDrop');
    registerDropDownEvents('findAgentsLink', 'findAgentsDrop');
    registerDropDownEvents('aboutusheaderlink', 'aboutUsDrop');
    registerDropDownEvents('aboutTheAreaLink', 'aboutTheAreaDrop');
}
function bindGlassPaneForOptionsPane() {
    Event.observe(document.body, 'click', hideOptionsPaneOnClick);
}
function hideOptionsPaneOnClick(e) {
    var filter = $('filter');
    if (filter && filter.style.visibility == 'visible') {
        var clickedElement = Event.element(e);
        if (clickedElement.innerHTML.indexOf('Modify Search') != -1)
            return;
while (clickedElement != document.body && clickedElement != null) {
            if (Element.hasClassName(clickedElement, 'activated') || clickedElement.id == 'filter')
                return;
            clickedElement = clickedElement.parentNode;
        }
        searchOptionInfoClose();
    }
}
function clearSortFields() {
    $('sir_result_sort_by').value = '';
    $('sir_result_sort_direction').value = '';
}
function prepareWebTrends() {
    if (typeof WebTrendsAnalyzer == 'function') {
        (new WebTrendsAnalyzer()).scan(WebTrendsAnalyzer.INITIAL_RULES);
    }
}
function prepareWebTrendsForEmail() {
    if (document.getElementsByTagName('FORM').length > 0 && typeof WebTrendsAnalyzer == 'function') {
        (new WebTrendsAnalyzer()).scan(WebTrendsAnalyzer.CreateRulesForEmail());
    }
}
function createClass(classText) {
    return new Function("return" + classText)();
}
function loadResults(html, searchModelDumpStr, countString, pageHeading) {
    if (!getPageController()) {
        setTimeout(loadResults.bind(window, html, searchModelDumpStr, countString), 10);
        return;
    }
    var newSearchModel = null;
    if (searchModelDumpStr) {
        var searchModelDump = null;
        searchModelDump = createClass(searchModelDumpStr);
        newSearchModel = SearchOptionsModel.scoop(searchModelDump, getPageController());
        if (countString)
            getPageController().setCountString(countString);
        if (!newSearchModel.equals(getPageController().getSearchOptionsModel())) {
            getPageController().setSearchOptionsModel(newSearchModel);
            prepareAllWidgets();
        }
    }
    if (pageHeading && isLandingPageVisible()) {
        var pageHeadingElement = $('pageHeaderContainer');
        if (pageHeadingElement) {
            Element.show(pageHeadingElement);
            pageHeadingElement.innerHTML = pageHeading;
        }
    }
    progressChicken.stop(true);
    clearSplashImageFromSearchOptionInfoDiv();
    switchToResultCSSClass();
    $('searchResults').innerHTML = html;
    Element.show($('searchResults'));
    for (var modelName in getPageController()._filterModelsUsed()) {
        var model = getSearchOptionsModel().getFilterModel(modelName);
        model.notifyChange();
    }
    (window.onLoadResultsCallback || new Function())();
}
function getPageController() {
    return _pageController;
}
function getSearchOptionsModel() {
    return getPageController().getSearchOptionsModel();
}
function showSearchOption(element, type) {
    if (!getPageController()) {
        setTimeout(showSearchOption.bind(window, element, type), 10);
        return;
    }
    type = type.toLowerCase().replace("/", "");
    var filterHeader = FilterViewFactory.getHeaderElement(type);
    if (filterHeader && filterHeader.className.indexOf('activated') == -1) {
        showSearchOptionInfoDiv(type);
        switchToResultsView(element);
    }
}
function getSearchUrl(methodName) {
    return regionRoot + '/' + getSearchOptionsModel().getSearchType() + '/' + methodName + '.rails';
}
function showSearchOptionInfoDiv(type) {
    if (typeof WebTrendsAnalyzer == 'function') {
        (new WebTrendsAnalyzer()).fireWebTrendAction(WebTrendsAnalyzer.CreateActionForFilterOptionType(regionRoot, type));
    }
    if (type == FilterKey.LOCATION || type == FilterKey.CAT_BASED_LOCATION) {
        var locModel = getSearchOptionsModel().getFilterModel(FilterKey.LOCATION);
        if (!this.getPageController().showLocationTree()) {
            return;
        }
        if (locModel.isQuickSearch()) {
            type = FilterKey.LOCATION;
        }
    }
    var options = {
        searchType: type,
        searchModel: DataSerializer.serialize(getSearchOptionsModel().dump())
    };
    updateSearchOptionPane(getSearchUrl(type), options, type);
}
function clearLinkBelowFilters() {
    if ($('automatedUpdateOptionsDiv'))
        Element.hide($('automatedUpdateOptionsDiv'));
    if ($('otherNetworkLocationsDiv'))
        Element.hide($('otherNetworkLocationsDiv'));
}
var SEARCH_OPTIONS_PANE_CACHE = {};
function clearSearchOptionsPaneCache() {
    SEARCH_OPTIONS_PANE_CACHE = {};
}
function cacheSearchOptionsPane(type) {
    SEARCH_OPTIONS_PANE_CACHE[type] = $('filter');
}
function isNotInCache(options) {
    if (options && options.searchType) {
        return typeof SEARCH_OPTIONS_PANE_CACHE[options.searchType] == 'undefined';
    }
    return true;
}
function updateSearchOptionPane(vmUrl, options, type) {
    if ($('filter')) {
        prepareFilterForRemoval();
        $('searchOptionInfoDiv').removeChild($('filter'));
    }
    if (isNotInCache(options)) {
        showFilterWaitingMessage(type);
        putOptionPaneIntoCache(vmUrl, options || {});
    }
    else {
        restoreSearchOptionsPaneFromCache(options);
    }
    Element.show($('searchOptionInfoDiv'));
}
function putOptionPaneIntoCache(vmUrl, options) {
    makeAjaxUpdater('searchOptionInfoDiv', vmUrl, function(request) {
        clearSearchOptionInfoDiv();
        if (typeof options != 'undefined') {
            if (typeof options.widgetClass != 'undefined') {
                options.widgetClass.Create();
            }
            if (typeof options.webtrendsrules != 'undefined' && typeof WebTrendsAnalyzer == 'function') {
                (new WebTrendsAnalyzer()).scan(options.webtrendsrules);
            }
        }
        if (typeof WebTrendsAnalyzer == 'function') {
            (new WebTrendsAnalyzer()).scan(WebTrendsAnalyzer.CreateRulesForOptionPane(options.searchType));
        }
        if (options && options.searchType) {
            bindSearchOptionsPaneWidgets(options.searchType.toLowerCase());
            cacheSearchOptionsPane(options.searchType);
            positionSearchOptionsPane(options.searchType.toLowerCase());
            hideFilterWaitingMessage();
        }
    }, options);
}
function hideFilterWaitingMessage() {
    $('filterWaitingMessage').style.visibility = "hidden";
}
function showFilterWaitingMessage(type) {
    $('filterWaitingMessage').style.visibility = "";
    positionSearchOptionsPane(type, true, 'filterWaitingMessage');
}
function restoreSearchOptionsPaneFromCache(options) {
    $('searchOptionInfoDiv').appendChild(SEARCH_OPTIONS_PANE_CACHE[options.searchType]);
    positionSearchOptionsPane(options.searchType.toLowerCase(), true);
    fixCheckboxesInFilter();
}
function bindSearchOptionsPaneWidgets(searchType) {
    var model = getSearchOptionsModel().getFilterModel(searchType);
    SearchOptionsPanelFactory.create(searchType, model);
}
function prepareFilterForRemoval() {
    if ($('filter')) {
        var inputs = $('filter').getElementsByTagName('INPUT');
        $('filter').style.left = '';
        var checkboxes = [];
        for (var i = 0; i < inputs.length; i++) {
            if (inputs[i].type == 'checkbox' && inputs[i].checked) {
                inputs[i]._oldChecked = true;
            }
        }
    }
}
function fixCheckboxesInFilter() {
    if ($('filter')) {
        var inputs = $('filter').getElementsByTagName('INPUT');
        var checkboxes = [];
        for (var i = 0; i < inputs.length; i++) {
            if (inputs[i].type == 'checkbox' && typeof inputs[i]._oldChecked == 'boolean') {
                inputs[i].checked = inputs[i]._oldChecked;
                inputs[i]._oldChecked = false;
            }
        }
    }
}
function positionSearchOptionsPane(filterType, fromCache, filter) {
    var filter = filter || 'filter';
    var filterHeader = $(filterType + 'DT');
    var optionsPane = $(filter);
    if (!filterHeader) {
        if (filterType == 'location') {
            fromCache = false;
            filterHeader = $('categorybasedlocationDT');
        }
    }
    var header = Position.cumulativeOffset(filterHeader);
    var headerTop = header[1];
    var paneTop = Position.cumulativeOffset($('content'))[1];
    var moveBy = headerTop - paneTop;
    moveBy += 1;
    optionsPane.style.top = moveBy + 'px';
    optionsPane.style.visibility = 'visible';
}
function handleResetClicked() {
    if (getSearchOptionsModel().isEmpty() == false) {
        getSearchOptionsModel().clear();
        if (!isLandingPageVisible()) {
            submitSearch();
        }
        clearSearchOptionsPaneCache();
    }
}
function showSaveSearchResultInfoDiv() {
    var rules = [];
    if (typeof WebTrendsAnalyzer == 'function') {
        (new WebTrendsAnalyzer()).fireWebTrendAction(WebTrendsAnalyzer.INITIATE_SAVE_SEARCH_ACTION);
        rules = WebTrendsAnalyzer.DYNAMIC_SAVE_SEARCH_RULES;
    }
    makeAjaxUpdater('watchThisPanel', regionRoot + '/savesearch/panel.rails', function(request) {
        SaveSearchPanel.Create();
        (new WebTrendsAnalyzer()).scan(rules);
        Element.show($('watchThisPanel'));
        setTimeout(function() {
            $('SearchName').focus()
        }, 0);
    });
}
function clearSearchOptionInfoDiv() {
    Element.show($('searchOptionInfoDiv'));
}
function switchToResultsView(element, controllerName) {
    getPageController().switchToResultsView(element);
}
function switchToResultCSSClass() {
    getPageController().updateViewToResults();
}
function resetMinValueCombo() {
    var maxValuesCombo = new Select("MaxDropDownList");
    var minValuesCombo = new Select("MinDropDownList");
    var maxSelectedIndex = maxValuesCombo.getSelectionIndex()
    if (maxSelectedIndex <= 0) {
        maxSelectedIndex = maxValuesCombo.getCount() - 1;
    }
    for (var i = 0; i <= maxSelectedIndex; i++) {
        minValuesCombo.getOptionAt(i).disabled = false;
    }
    for (var i = maxSelectedIndex + 1; i < maxValuesCombo.getCount(); i++) {
        minValuesCombo.getOptionAt(i).disabled = true;
    }
    if (minValuesCombo.getSelectionIndex() > maxValuesCombo.getSelectionIndex()) {
        minValuesCombo.setSelectionIndex(maxValuesCombo.getSelectionIndex());
    }
}
function updateResultsAndTotalForPrice() {
    var maxValuesCombo = $("MaxDropDownList");
    var selectedMaxValueIndex = maxValuesCombo.selectedIndex;
    var minValuesCombo = $("MinDropDownList");
    var selectedMinValueIndex = minValuesCombo.selectedIndex;
    var minValueOption = minValuesCombo.options[selectedMinValueIndex];
    var maxValueOption = maxValuesCombo.options[selectedMaxValueIndex];
    var priceModel = getSearchOptionsModel().getFilterModel(FilterKey.PRICE);
    priceModel.setMinPrice(minValueOption.value, minValueOption.innerHTML);
    priceModel.setMaxPrice(maxValueOption.value, maxValueOption.innerHTML);
}
function updateResultsAndTotalForBedAndBath(selectElement, ddElementName, criteriaType, criteriaValue, setterToCall) {
    !setterToCall || eval('getSearchOptionsModel().getFilterModel(FilterKey.BED_BATH).' + setterToCall + '(selectElement.value, selectElement.options[selectElement.selectedIndex].text)');
}
function updateResultsAndTotalForInteriorSizeLotSize(selectElement, ddElementName, criteriaType, criteriaValue, setterToCall) {
    !setterToCall || eval('getSearchOptionsModel().getFilterModel(FilterKey.INTERIOR_SIZE_LOT_SIZE).' + setterToCall + '(selectElement.value, selectElement.options[selectElement.selectedIndex].text)');
}
function searchOptionInfoClose() {
    removeSearchOptionHighlighting();
    if ($('searchOptionInfoDiv')) {
        Element.hide($('searchOptionInfoDiv'));
    }
}
function watchThisClose() {
    Element.hide($('watchThisPanel'));
}
function removeSearchOptionHighlighting() {
    removeClassNameForChildrenWithinAParentTag('searchOptions', 'dt', 'activated');
    //added because the location Widget has a special style
    removeClassNameForChildrenWithinAParentTag('searchOptions', 'dt', 'activatedFirst');
    removeClassNameForChildrenWithinAParentTag('searchOptions', 'dd', 'activated');
    //selected stuff
}
function nextResultNumber() {
    return Math.round(10000 * Math.random());
}
function makeAjaxUpdater(divName, methodName, oncomplete, params) {
    progressChicken.start();
    var o = new Ajax.Updater(divName, methodName, {
        on200: function(transport) {
            if (transport.responseText.match(/errorUrl/))
                window.location.href = baseUrl + '/GenericError.htm';
        },
        onComplete: function(request) {
            //not sure why but if the stop is AFTER the oncomplete it won't fire...
            progressChicken.stop();
            if (oncomplete) {
                oncomplete(request);
            }
        },
        //we don't need the onException and onError b/c onComplete is Always Called
        evalScripts: true,
        parameters: params ||
{}
    });
    return o;
}
function prepareAllWidgets() {
    if ($('searchOptions')) {
        prepareAllViewsForModel(getSearchOptionsModel());
    }
}
function prepareAllViewsForModel(optionsModel) {
    var keys = optionsModel.getFilterModelKeys();
    for (var i = 0; i < keys.length; i++) {
        if (FilterViewFactory.getHeaderElement(keys[i])) {
            FilterViewFactory.create(keys[i], optionsModel);
        }
    }
}
function moveSearchOptionInfoDivUnderContent() {
    //move searchOptionInfoDiv under content and fix 'filter' style
    var searchOptionInfoDiv = $('searchOptionInfoDiv');
    searchOptionInfoDiv.parentNode.removeChild(searchOptionInfoDiv);
    $('content').appendChild(searchOptionInfoDiv);
    if ($('filter'))
        $('filter').style.left = '';
}
function swapFiltersDiv(currentFilters, newFilters) {
    if ($(currentFilters) && $(newFilters)) {
        var tmp = $(currentFilters).innerHTML;
        $(currentFilters).innerHTML = $(newFilters).innerHTML;
        $(newFilters).innerHTML = tmp;
    }
}
function backToHome() {
    if (!getPageController()) {
        setTimeout(backToHome.bind(window), 10);
        return;
    }
    var pageController = getPageController();
    if (pageController.CONTROLLER_NAME == "offices")
        return;
    if ($('searchResults') && pageController._initialResults && !isStringBlank(pageController._initialResults)) {
        if ($('searchResults').innerHTML != pageController._initialResults) {
            $('searchResults').innerHTML = pageController._initialResults;
            if (pageController._initialModel) {
                pageController.setSearchOptionsModel(pageController._scoopSearchOptionsModel(pageController._initialModel));
                clearSearchOptionsPaneCache();
                prepareAllWidgets();
            }
        }
    }
    else {
        if (isShowLandingPage()) {
            Element.addClassName($('body'), 'welcome');
            if ($('OpenHouses'))
                $('OpenHouses').show();
            if ($('NewDevelopments'))
                $('NewDevelopments').show();
            if ($('LetUsSearch'))
                $('LetUsSearch').show();
            if ($('mortgageServicesButton'))
                $('mortgageServicesButton').show();
            if ($('updateOptionsButton'))
                $('updateOptionsButton').show();
            if ($('AboutOurAgents'))
                $('AboutOurAgents').show();
            if ($('toolbar'))
                Element.hide('toolbar');
            //selected stuff
            removeClassNameForChildrenWithinAParentTag('searchOptions', 'dt', 'activated');
            if ($('searchResults'))
                Element.hide('searchResults');
            $('content').className = 'content landingPageContent';
            if (rootExpandedView)
                rootExpandedView.hide();
            getSearchOptionsModel().clear();
            clearSearchOptionsPaneCache();
            var pageHeader = $('pageHeaderContainer');
            if (pageHeader) {
                Element.hide(pageHeader);
            }
            var secondarySearchTabsDiv = $('secondarySearchTabsDiv');
            if (secondarySearchTabsDiv) {
                secondarySearchTabsDiv.className = 'secondaryTabs empty';
            }
            var secondarySearchTabs = $('secondarySearchTabs');
            if (secondarySearchTabs) {
                Element.hide(secondarySearchTabs);
            }
            $('findPropertiesLink').className = '';
            if ($("findPropertiesDownArrow")) {
                Element.show($("findPropertiesDownArrow"));
            }
            //swap FindPropertiesDiv
            swapFiltersDiv('frame', 'SwapDiv');
            //move searchOptionInfoDiv back under sidebar
            if ($('searchOptionInfoDiv')) {
                var searchOptionInfoDiv = $('searchOptionInfoDiv');
                searchOptionInfoDiv.parentNode.removeChild(searchOptionInfoDiv);
                $('sidebar').appendChild(searchOptionInfoDiv);
                moveSearchOptionInfoDivUnderContent();
                // bind events to new div
                prepareAllWidgets();
            }
        }
    }
}
function isStringBlank(str) {
    return /^\s*$/.test(str);
}
function isShowLandingPage() {
    return $('content') && document.body.className.indexOf('welcome') == -1 && !isLandingPageVisible() && !isAboutUsOfficesPage() && !isAreasPage();
}
function isAboutUsOfficesPage() {
    return document.location.href.indexOf("aboutus/officedirectory.rails") > -1
}
function isAreasPage() {
    return document.location.href.indexOf("agents/Real-Estate-Agents-") > -1
}
function isLandingPageVisible() {
    return getPageController().isLandingPageVisible();
}
function clearSplashImageFromSearchOptionInfoDiv() {
    var infoDiv = $('searchOptionInfoDiv');
    var splashDivs = document.getElementsByClassName('color2', infoDiv);
    if (splashDivs.length > 0)
        infoDiv.innerHTML = "";
    clearLinkBelowFilters();
}
function showFloorPlanImages(listingNumber) {
    removeClassNameForChildrenWithinAParentTag('additionalInfoUL', 'li', 'selected');
    Element.addClassName($('floorPlanLI'), 'selected');
    $('tabDetailDiv').innerHTML = '';
    $('tabDetailDiv').innerHTML = $('floorplanDetails').innerHTML;
}
function showMapForProperty(url) {
    if ($('searchResults')) {
        Element.hide($('searchResults'));
    }
    Element.show($('tabDetailDiv'));
    removeClassNameForChildrenWithinAParentTag('additionalInfoUL', 'li', 'selected');
    Element.addClassName($('mapLI'), 'selected');
    $('tabDetailDiv').innerHTML = '<iframe class="map" style="width: 550px; height: 550px;padding:0px;" frameborder="0"' +
'src="' +
url +
'"></iframe>';
    setTimeout("Element.scrollTo($('mapLI'));", 100);
}
function showLocalInformation(zip) {
    removeClassNameForChildrenWithinAParentTag('additionalInfoUL', 'li', 'selected');
    Element.addClassName($('localInformationLI'), 'selected');
    new Ajax.Updater('tabDetailDiv', siteRoot + '/property/localinfo.rails?onBoardZipCode=' + zip, {
        onComplete: function(request) {
            setTimeout("Element.scrollTo($('localInformationLI'));", 100);
            showAmenities(zip);
        }
    });
}
function showAmenities(zip) {
    Element.show($('tabDetailDiv'));
    if ($('searchResults')) {
        Element.hide($('searchResults'));
    }
    removeClassNameForChildrenWithinAParentTag('localInformationUL', 'li', 'selected');
    Element.addClassName($('amenitiesLI'), 'selected');
    new Ajax.Updater('localInformationContent', siteRoot + '/property/amenities.rails?zipcode=' + zip, {
        onComplete: function(response) {
            setTimeout("Element.scrollTo($('tabDetailDiv'));", 100);
        }
    });
}
function showCommunityProfile(zip) {
    removeClassNameForChildrenWithinAParentTag('localInformationUL', 'li', 'selected');
    Element.addClassName($('communityProfileLI'), 'selected');
    new Ajax.Updater('localInformationContent', siteRoot + '/property/communityprofile.rails?zipcode=' + zip);
}
function showSchools(zip) {
    removeClassNameForChildrenWithinAParentTag('localInformationUL', 'li', 'selected');
    Element.addClassName($('schoolsLI'), 'selected');
    new Ajax.Updater('localInformationContent', siteRoot + '/property/schooldistricts.rails?zipcode=' + zip);
}
function showDistricts(zip) {
    removeClassNameForChildrenWithinAParentTag('localInformationUL', 'li', 'selected');
    Element.addClassName($('districtsLI'), 'selected');
    new Ajax.Updater('localInformationContent', siteRoot + '/property/districts.rails?zipcode=' + zip);
}
function showHomeSales(zip) {
    removeClassNameForChildrenWithinAParentTag('localInformationUL', 'li', 'selected');
    Element.addClassName($('homeSalesLI'), 'selected');
    new Ajax.Updater('localInformationContent', siteRoot + '/property/homesales.rails?zipcode=' + zip);
}
function showFeatures(listingNumber) {
    removeClassNameForChildrenWithinAParentTag('additionalInfoUL', 'li', 'selected');
    Element.addClassName($('featureLI'), 'selected');
    $('tabDetailDiv').innerHTML = '';
    $('tabDetailDiv').innerHTML = $('featureDetails').innerHTML;
}
function showListingsTab() {
    clearSortFields();
    if ($('tabDetailDiv')) {
        Element.hide($('tabDetailDiv'));
    }
    removeClassNameForChildrenWithinAParentTag('additionalInfoUL', 'li', 'selected');
    Element.addClassName($('currentListingsLI'), 'selected');
    this.hideAllTabs();
    $('searchResults_sales').show();
    highlightResultsPerPage('10');
}
function showListingsTab2() {
    clearSortFields();
    if ($('tabDetailDiv')) {
        Element.hide($('tabDetailDiv'));
    }
    removeClassNameForChildrenWithinAParentTag('additionalInfoUL', 'li', 'selected');
    Element.addClassName($('currentListingsLI'), 'selected');
    this.hideAllTabs();
    $('searchResults_sales_2').show();
}
function showListingsTabAll(value) {
    clearSortFields();
    if ($('tabDetailDiv')) {
        Element.hide($('tabDetailDiv'));
    }
    removeClassNameForChildrenWithinAParentTag('additionalInfoUL', 'li', 'selected');
    Element.addClassName($('currentListingsLI'), 'selected');
    this.hideAllTabs();
    if ($('searchResults_sales_all'))
        $('searchResults_sales_all').show();
    else
        $('searchResults_sales').show();
    this.highlightResultsPerPage(value);

}

function showRentalsTab() {
    clearSortFields();
    removeClassNameForChildrenWithinAParentTag('additionalInfoUL', 'li', 'selected');
    Element.addClassName($('currentRentalsLI'), 'selected');
    this.hideAllTabs();
    $('searchResults_rentals').show();
}
function showSelectSalesTab() {
    clearSortFields();
    removeClassNameForChildrenWithinAParentTag('additionalInfoUL', 'li', 'selected');
    Element.addClassName($('selectSalesLI'), 'selected');
    this.hideAllTabs();
    $('searchResults_selectSolds').show();
}
function hideAllTabs() {
    if ($('searchResults_sales'))
        $('searchResults_sales').hide();
    if ($('searchResults_sales_2'))
        $('searchResults_sales_2').hide();
    if ($('searchResults_sales_all'))
        $('searchResults_sales_all').hide();
    if ($('searchResults_rentals'))
        $('searchResults_rentals').hide();
    if ($('searchResults_selectSolds'))
        $('searchResults_selectSolds').hide();
}
function highlightResultsPerPage(value) {
    var children = $("items_per_page").getElementsByTagName("a");
    for (var i = 0; i < children.length; i++) {
        var elements = document.getElementsByClassName(children[i].id);
        for (var j = 0; j < elements.length; j++) {
            elements[j].removeClassName("selected");
        }
    }
    var perpage = document.getElementsByClassName(value + '_per_page');
    for (i = 0; i < perpage.length; i++) {
        perpage[i].addClassName("selected");
    }
}

function showOfficeDirections(officeId) {
    removeClassNameForChildrenWithinAParentTag('additionalInfoUL', 'li', 'selected');
    Element.addClassName($('officeDirectionsLI'), 'selected');
    new Ajax.Updater('searchResults', siteRoot + '/offices/directions.rails?officeId=' + officeId, {});
}
function showOfficeAgentRoster(officeId) {
    clearSortFields();
    removeClassNameForChildrenWithinAParentTag('additionalInfoUL', 'li', 'selected');
    Element.addClassName($('agentRoster'), 'selected');
    gotoPage(1);
}
function showSalesTeamTab(teamid) {
    clearSortFields();
    removeClassNameForChildrenWithinAParentTag('additionalInfoUL', 'li', 'selected');
    Element.addClassName($('salesTeamLI'), 'selected');
    new Ajax.Updater('searchResults', siteRoot + '/teams/summary/' + teamid, {});
}
function removeClassNameForChildrenWithinAParentTag(parentElementName, childTagName, classNameToRemove, classNameToAdd) {
    additionalInfoULElement = $(parentElementName);
    if (additionalInfoULElement) {
        var liChildren = additionalInfoULElement.getElementsByTagName(childTagName);
        for (var i = 0; i < liChildren.length; i++) {
            var liElement = liChildren[i];
            if (classNameToAdd && liElement.id.length > 0) {
                var ddElement = $(liElement.id.replace(/DT/, 'DD'));
                if (ddElement.style.display == '') {
                    Element.addClassName(liElement, classNameToAdd);
                }
            }
            Element.removeClassName(liElement, classNameToRemove);
        }
    }
}
function changeSortOrder(order) {
    createCookie("priceOrder", order);
    getPageController().goToPage(1);
}
function changeResultSort(newSortBy, newSortDirection) {
    $("sir_result_sort_by").value = newSortBy;
    $("sir_result_sort_direction").value = newSortDirection;
    gotoPageTop(1);
}
function addInteriorSizeSession(value) {
    createCookie("interiorSize", value);
    $('selectedInteriorSize').selectedIndex = 0;
    getSearchOptionsModel().getFilterModel(FilterKey.INTERIOR_SIZE_LOT_SIZE).resetInteriorSize();
}
function addLotSizeSession(value) {
    createCookie("lotSize", value);
    $('selectedLotSize').selectedIndex = 0;
    getSearchOptionsModel().getFilterModel(FilterKey.INTERIOR_SIZE_LOT_SIZE).resetLotSize();
}
function createCookie(name, value) {
    var exdate = new Date();
    exdate.setDate(exdate.getDate() + 30);
    document.cookie = name + "=" + value + ";expires=" + exdate.toGMTString() + "; path=/";
}
function setInteriorSizeUnitForLondon(value) {
    createCookie("interiorSize", value);
    getPageController().updateSearchResults();
}
function moveToASearchResultsPage(pageNo, type) {
    getPageController().goToPage(pageNo);
}
function filterByLocation(element, locationId) {
    var isChecked;
    if (Element.hasClassName(element, "checked")) {
        Element.replaceClassName(element, "checked", "cleared");
        isChecked = "false";
    }
    else {
        Element.replaceClassName(element, "cleared", "checked");
        isChecked = "true";
    }
    new Ajax.Request(getSearchUrl('addcriteria') + '?type=includelocation&treeId=' + locationId + "&checked=" + isChecked, {});
}
function filterByCheckbox(filterModelName, isChecked, checkBox) {
    var filterModel = getSearchOptionsModel().getFilterModel(filterModelName);
    if (filterModel) {
        if (isChecked) {
            filterModel.addCheckBox(checkBox);
        }
        else {
            filterModel.removeCheckBox(checkBox);
        }
    }
}
function RenderLineOfBusiness(zip, lineOfBusiness, element) {
    var location = siteRoot + '/property/amenitiesbylineofbusiness.rails?zipCode=' + zip + '&lineOfBusiness=' + lineOfBusiness;
    RenderSubLocalInfo(location, element, lineOfBusiness);
}
function RenderSchoolDistrict(schoolDistrictNo, element) {
    var location = siteRoot + '/property/schoolsbydistrict.rails?schoolDistrictNo=' + schoolDistrictNo;
    RenderSubLocalInfo(location, element, schoolDistrictNo);
}
function RenderPrivateSchools(zipCode, element) {
    var location = siteRoot + '/property/privateschoolsbyzipcode.rails?zipCode=' + zipCode;
    RenderSubLocalInfo(location, element, 'privateschools');
}
function RenderSubLocalInfo(location, node, divToUpdate) {
    if ($(node).hasClassName('expand')) {
        Element.replaceClassName(node, 'expand', 'collapse');
        new Ajax.Updater(divToUpdate, location, {
            onComplete: function(response) {
                Element.show($(divToUpdate));
                setTimeout("Element.scrollTo($('" + divToUpdate + "'));", 1000);
            }
        });
    }
    else {
        Element.replaceClassName(node, 'collapse', 'expand');
        Element.hide($(divToUpdate));
    }
}
function gotoPage(page) {
    getPageController().goToPage(page);
}
function gotoPageTop(pageNo) {
    gotoPage(pageNo);
}
function moveToLocation(action, webRegionIdToSwitch) {
    url = getSearchUrl(action);
    if (webRegionIdToSwitch) {
        url = url + '?webRegionId=' + webRegionIdToSwitch;
    }
    new Ajax.Request(url);
}
function disableAndSwitchToRegion(regionToSwitch, regionDisplayText, regionLocationNodeId, rootRegionLocationNodeId) {
    var locationModel = getSearchOptionsModel().getFilterModel(FilterKey.LOCATION);
    locationModel.disableQuickSearch();
    var chosenRegionNode;
    var testNode = locationModel.getRootLocationNode();
    if (regionLocationNodeId != rootRegionLocationNodeId) {
        // Since we have changed the default state to unchecked we can skip the next step
        // testNode.setState(CheckBoxState.UnChecked);
        var children = testNode.children();
        for (var i = 0; i < children.length; i++) {
            if (children[i].locationId == regionLocationNodeId) {
                chosenRegionNode = children[i];
                chosenRegionNode.setState(CheckBoxState.Checked);
            }
        }
        testNode.setState(CheckBoxState.Partial);
        locationModel.nodeToggled(chosenRegionNode);
    }
    locationModel.notifyChange();
}
function enableLocationCriteria(regionDisplayText) {
    var locationModel = getSearchOptionsModel().getFilterModel(FilterKey.LOCATION);
    locationModel.enableQuickSearch();
    var rootNode = locationModel.getRootLocationNode();
    rootNode.setState(CheckBoxState.UnChecked);
    locationModel.notifyChange();
}
function enableCorporateLocation(rootRegionLocationNodeId) {
    var locationModel = getSearchOptionsModel().getFilterModel(FilterKey.LOCATION);
    locationModel.disableQuickSearch();
    var rootNode = locationModel.getCorporateNode();
    rootNode.setState(CheckBoxState.UnChecked);
    locationModel.nodeToggled(rootNode);
    locationModel.notifyChange();
}
function onLocationComponentClicked(treeId) {
    showLocationOption('locationDiv0', treeId, 0, this);
    clearSearchOptionInfoDiv();
    switchToResultsView($('locationDT'));
}
function paginateToDetailPage(anchor, index) {
    getPageController().resultsLinkClicked(anchor.href, index);
    return false;
}
function filterByDropDown(dropdown) {
    if (typeof dropdown._select == 'undefined') {
        dropdown._select = new Select(dropdown.id);
    }
    var value = dropdown._select.getSelection().value;
    if (dropdown.name == 'Fireplaces') {
        getPageController().getSearchOptionsModel().getFilterModel(FilterKey.FEATURES_AND_AMENITIES).setMinFireplaces(value);
    }
    else if (dropdown.name == 'Garages') {
        getPageController().getSearchOptionsModel().getFilterModel(FilterKey.FEATURES_AND_AMENITIES).setMinGarageBays(value);
    }
}
function londonViewPropertiesLinkClicked() {
    Element.show($('londonSearch'));
    Element.hide($('viewAllPropertiesArea'));
    clearSplashImageFromSearchOptionInfoDiv();
    switchToResultCSSClass();
    gotoPage(1);
    $('findPropertiesLink').addClassName("active");
    unregisterAnyHandler($('findPropertiesLink'), 'mouseover');
    unregisterAnyHandler($('findPropertiesLink'), 'mouseout');
}
function fixLondonViewPropertiesLink() {
    if ($('resultTitleLink_1') && $('londonSearch') && $('viewAllPropertiesArea')) {
        Element.show($('londonSearch'));
        Element.hide($('viewAllPropertiesArea'));
    }
}
function fixAreaDetailSlideshowImage(img) {
    img = $(img);
    if (img.getDimensions().width > 408) {
        var parent = img.parentNode;
        var newImg = document.createElement('IMG');
        newImg.src = img.src;
        newImg.alt = img.alt;
        newImg.title = img.title;
        newImg.width = 408;
        Event.observe(newImg, 'load', fixAreaDetailSlideshowImageHeightForIE.bind(window, newImg));
        img.parentNode.appendChild(newImg);
        img.parentNode.removeChild(img);
        fixAreaDetailSlideshowImageHeightForIE(newImg);
    }
}
function fixAreaDetailSlideshowImageHeightForIE(img) {
    img = $(img);
    var height = img.getDimensions().height;
    if (height > 308) {
        img.height = 308;
    }
}
function iFrameHeight() {
    if (document.getElementById && !(document.all)) {
        h = document.getElementById('idxframe').contentDocument.body.scrollHeight;
        document.getElementById('idxframe').style.height = h;
    }
    else
        if (document.all) {
        h = document.frames('idxframe').document.body.scrollHeight;
        document.all.idxframe.style.height = h;
    }
}
function agentSubmitSearch() {
    $('letterFromForm').value = '';
    getPageController().onSubmitHook();
    submitSearch();
    ClearAlphabetFilterSelected();
}
function submitSearch() {
    window.onLoadResultsCallback = searchOptionInfoClose;
    getPageController().getResultsUpdater().onChange();
}
function submitSearchWithoutClose() {
    window.onLoadResultsCallback = new Function();
    getPageController().getResultsUpdater().onChange();
}
function resetCriteria(key) {
    delete SEARCH_OPTIONS_PANE_CACHE[key];
    getSearchOptionsModel().getFilterModel(key).clear();
    if (!isLandingPageVisible()) {
        submitSearchWithoutClose();
    }
    showSearchOptionInfoDiv(key);
}
function changeItemsPerPage(value) {
    children = $("items_per_page").getElementsByTagName("a");
    for (var i = 0; i < children.length; i++) {
        var child_id = children[i].id;
        $(child_id).removeClassName("selected");
    }
    $(value + "_per_page").addClassName("selected");
    $("searchModelItemsPerPageInput").value = value;
    gotoPageTop(1);
}
function ClearAlphabetFilterSelected() {
    if ($('alphabetFilter')) {
        var matches = $('alphabetFilter').getElementsByClassName("selected");
        $A(matches).each(function(currentMatch) {
            Element.removeClassName(currentMatch, "selected");
        });
    }
}
function navToClickHandler(selectListId) {
    var selected = $(selectListId).selectedIndex;
    window.location = window.location + '/' + Element.readAttribute($(selectListId).options[selected], 'navto');
}
function isOlderSafari() {
    if (BrowserDetect.browser == "Safari" && BrowserDetect.version > 0 && BrowserDetect.version <= 419.3) {
        return true;
    }
    return false;
}
function isNewerSafari() {
    if (BrowserDetect.browser == "Safari" && BrowserDetect.version > 0 && BrowserDetect.version > 419.3) {
        return true;
    }
    return false;
}
function isFireFox2() {
    if (BrowserDetect.browser == "Firefox" && BrowserDetect.version == 2) {
        return true;
    }
    return false;
}
function isFireFox3() {
    if (BrowserDetect.browser == "Firefox" && BrowserDetect.version == 3) {
        return true;
    }
    return false;
}
function isIE7() {
    if (BrowserDetect.browser == "Explorer" && BrowserDetect.version == 7) {
        return true;
    }
    return false;
}
function isIE8() {
var userAgent = navigator.userAgent.toLowerCase();
var version = (userAgent.match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/) || [])[1];
var msie = /msie/.test(userAgent) && !/opera/.test(userAgent);
return msie && version == 8;
}
function isChrome() {
    if (BrowserDetect.browser == "Chrome") {
        return true;
    }
    return false;
}
SAFARI = {}
SAFARI = {}
WINDOW = {}
MINUSONE = {}
SAFARI.positionSearchOptionsPane = function(filterType, fromCache, filter) {
    WINDOW.positionSearchOptionsPane(filterType, fromCache, filter);
    var filter = filter || 'filter';
    var optionsPane = $(filter);
    var topWithPixel = new String(optionsPane.style.top);
    var topPostion = Number(topWithPixel.substr(0, topWithPixel.indexOf("px")));
    optionsPane.style.top = (topPostion - 1) + 'px';
}
MINUSONE.positionSearchOptionsPane = function(filterType, fromCache, filter) {
    WINDOW.positionSearchOptionsPane(filterType, fromCache, filter);
    var filter = filter || 'filter';
    var optionsPane = $(filter);
    var topWithPixel = new String(optionsPane.style.top);
    var topPostion = Number(topWithPixel.substr(0, topWithPixel.indexOf("px")));
    optionsPane.style.top = (topPostion - 1) + 'px';
}
SAFARI.findPos = function(obj) {
    var toRet = WINDOW.findPos(obj);
    if (obj.id == 'locationParentNode') {
        curtop += SAFARI.topDifference();
        curleft += 20;
    }
    return toRet;
}
SAFARI.topDifference = function(obj) {
    return 174;
}
BrowserDetect.init();
if (isOlderSafari() || isNewerSafari() || isChrome()) {
    WINDOW.positionSearchOptionsPane = positionSearchOptionsPane;
    positionSearchOptionsPane = SAFARI.positionSearchOptionsPane;
    WINDOW.findPos = findPos;
    findPos = SAFARI.findPos;
}
if (isFireFox3()) {
    WINDOW.positionSearchOptionsPane = positionSearchOptionsPane;
    positionSearchOptionsPane = MINUSONE.positionSearchOptionsPane;
}


