
if (!("console" in window) || !("firebug" in console)) {
(function()
{
    window.console = 
    {
        log: function()
        {
            logFormatted(arguments, "");
        },
        
        debug: function()
        {
           logFormatted(arguments, "debug");
        },
        
        info: function()
        {
            logFormatted(arguments, "info");
        },
        
        warn: function()
        {
           logFormatted(arguments, "warning");
        },
        
        error: function()
        {
         logFormatted(arguments, "error");
        },
        
        assert: function(truth, message)
        {
            if (!truth)
            {
                var args = [];
                for (var i = 1; i < arguments.length; ++i)
                    args.push(arguments[i]);
                
                logFormatted(args.length ? args : ["Assertion Failure"], "error");
                throw message ? message : "Assertion Failure";
            }
        },
        
        dir: function(object)
        {
            var html = [];
                        
            var pairs = [];
            for (var name in object)
            {
                try
                {
                    pairs.push([name, object[name]]);
                }
                catch (exc)
                {
                }
            }
            
            pairs.sort(function(a, b) { return a[0] < b[0] ? -1 : 1; });
            
            html.push('<table>');
            for (var i = 0; i < pairs.length; ++i)
            {
                var name = pairs[i][0], value = pairs[i][1];
                
                html.push('<tr>', 
                '<td class="propertyNameCell"><span class="propertyName">',
                    escapeHTML(name), '</span></td>', '<td><span class="propertyValue">');
                appendObject(value, html);
                html.push('</span></td></tr>');
            }
            html.push('</table>');
            
            logRow(html, "dir");
        },
        
        dirxml: function(node)
        {
            var html = [];
            
            appendNode(node, html);
            logRow(html, "dirxml");
        },
        
        group: function()
        {
            logRow(arguments, "group", pushGroup);
        },
        
        groupEnd: function()
        {
            logRow(arguments, "", popGroup);
        },
        
        time: function(name)
        {
            timeMap[name] = (new Date()).getTime();
        },
        
        timeEnd: function(name)
        {
            if (name in timeMap)
            {
                var delta = (new Date()).getTime() - timeMap[name];
                logFormatted([name+ ":", delta+"ms"]);
                delete timeMap[name];
            }
        },
        
        count: function()
        {
            this.warn(["count() not supported."]);
        },
        
        trace: function()
        {
            this.warn(["trace() not supported."]);
        },
        
        profile: function()
        {
            this.warn(["profile() not supported."]);
        },
        
        profileEnd: function()
        {
        },
        
        clear: function()
        {
            consoleBody.innerHTML = "";
        },

        open: function()
        {
            toggleConsole(true);
        },
        
        close: function()
        {
            if (frameVisible)
                toggleConsole();
        }
    };
 
    // ********************************************************************************************
       
    var consoleFrame = null;
    var consoleBody = null;
    var commandLine = null;
    
    var frameVisible = false;
    var messageQueue = [];
    var groupStack = [];
    var timeMap = {};
    
    var clPrefix = ">>> ";
    
    var isFirefox = navigator.userAgent.indexOf("Firefox") != -1;
    var isIE = navigator.userAgent.indexOf("MSIE") != -1;
    var isOpera = navigator.userAgent.indexOf("Opera") != -1;
    var isSafari = navigator.userAgent.indexOf("AppleWebKit") != -1;

    // ********************************************************************************************

    function toggleConsole(forceOpen)
    {
        frameVisible = forceOpen || !frameVisible;
        if (consoleFrame)
            consoleFrame.style.visibility = frameVisible ? "visible" : "hidden";
        else
            waitForBody();
    }

    function focusCommandLine()
    {
        toggleConsole(true);
        if (commandLine)
            commandLine.focus();
    }

    function waitForBody()
    {
        if (document.body)
        {    
			// fix for the undefined/undefined/firebug.html
			//createFrame();
		}
        else
            setTimeout(waitForBody, 200);
    }    

    function createFrame()
    {
        if (consoleFrame)
            return;
        
        window.onFirebugReady = function(doc)
        {
            window.onFirebugReady = null;

            var toolbar = doc.getElementById("toolbar");
            toolbar.onmousedown = onSplitterMouseDown;

            commandLine = doc.getElementById("commandLine");
            addEvent(commandLine, "keydown", onCommandLineKeyDown);

            addEvent(doc, isIE || isSafari ? "keydown" : "keypress", onKeyDown);
            
            consoleBody = doc.getElementById("log");
            layout();
            flush();
        }

        var baseURL = getFirebugURL();

        consoleFrame = document.createElement("iframe");
        consoleFrame.setAttribute("src", baseURL+"/firebug.html");
        consoleFrame.setAttribute("frameBorder", "0");
        consoleFrame.style.visibility = (frameVisible ? "visible" : "hidden");    
        consoleFrame.style.zIndex = "2147483647";
        consoleFrame.style.position = "fixed";
        consoleFrame.style.width = "100%";
        consoleFrame.style.left = "0";
        consoleFrame.style.bottom = "0";
        consoleFrame.style.height = "200px";
        document.body.appendChild(consoleFrame);
    }
    
    function getFirebugURL()
    {
        var scripts = document.getElementsByTagName("script");
        for (var i = 0; i < scripts.length; ++i)
        {
            if (scripts[i].src.indexOf("firebug.js") != -1)
            {
                var lastSlash = scripts[i].src.lastIndexOf("/");
                return scripts[i].src.substr(0, lastSlash);
            }
        }
    }
    
    function evalCommandLine()
    {
        var text = commandLine.value;
        commandLine.value = "";

        logRow([clPrefix, text], "command");
        
        var value;
        try
        {
            value = eval(text);
        }
        catch (exc)
        {
        }

        //console.log(value);
    }
    
    function layout()
    {
        var toolbar = consoleBody.ownerDocument.getElementById("toolbar");
        var height = consoleFrame.offsetHeight - (toolbar.offsetHeight + commandLine.offsetHeight);
        consoleBody.style.top = toolbar.offsetHeight + "px";
        consoleBody.style.height = height + "px";
        
        commandLine.style.top = (consoleFrame.offsetHeight - commandLine.offsetHeight) + "px";
    }
    
    function logRow(message, className, handler)
    {
        if (consoleBody)
            writeMessage(message, className, handler);
        else
        {
            messageQueue.push([message, className, handler]);
            waitForBody();
        }
    }
    
    function flush()
    {
        var queue = messageQueue;
        messageQueue = [];
        
        for (var i = 0; i < queue.length; ++i)
            writeMessage(queue[i][0], queue[i][1], queue[i][2]);
    }

    function writeMessage(message, className, handler)
    {
        var isScrolledToBottom =
            consoleBody.scrollTop + consoleBody.offsetHeight >= consoleBody.scrollHeight;

        if (!handler)
            handler = writeRow;
        
        handler(message, className);
        
        if (isScrolledToBottom)
            consoleBody.scrollTop = consoleBody.scrollHeight - consoleBody.offsetHeight;
    }
    
    function appendRow(row)
    {
        var container = groupStack.length ? groupStack[groupStack.length-1] : consoleBody;
        container.appendChild(row);
    }

    function writeRow(message, className)
    {
        var row = consoleBody.ownerDocument.createElement("div");
        row.className = "logRow" + (className ? " logRow-"+className : "");
        row.innerHTML = message.join("");
        appendRow(row);
    }

    function pushGroup(message, className)
    {
        logFormatted(message, className);

        var groupRow = consoleBody.ownerDocument.createElement("div");
        groupRow.className = "logGroup";
        var groupRowBox = consoleBody.ownerDocument.createElement("div");
        groupRowBox.className = "logGroupBox";
        groupRow.appendChild(groupRowBox);
        appendRow(groupRowBox);
        groupStack.push(groupRowBox);
    }

    function popGroup()
    {
        groupStack.pop();
    }
    
    // ********************************************************************************************

    function logFormatted(objects, className)
    {
        var html = [];

        var format = objects[0];
        var objIndex = 0;

        if (typeof(format) != "string")
        {
            format = "";
            objIndex = -1;
        }

        var parts = parseFormat(format);
        for (var i = 0; i < parts.length; ++i)
        {
            var part = parts[i];
            if (part && typeof(part) == "object")
            {
                var object = objects[++objIndex];
                part.appender(object, html);
            }
            else
                appendText(part, html);
        }

        for (var i = objIndex+1; i < objects.length; ++i)
        {
            appendText(" ", html);
            
            var object = objects[i];
            if (typeof(object) == "string")
                appendText(object, html);
            else
                appendObject(object, html);
        }
        
        logRow(html, className);
    }

    function parseFormat(format)
    {
        var parts = [];

        var reg = /((^%|[^\\]%)(\d+)?(\.)([a-zA-Z]))|((^%|[^\\]%)([a-zA-Z]))/;    
        var appenderMap = {s: appendText, d: appendInteger, i: appendInteger, f: appendFloat};

        for (var m = reg.exec(format); m; m = reg.exec(format))
        {
            var type = m[8] ? m[8] : m[5];
            var appender = type in appenderMap ? appenderMap[type] : appendObject;
            var precision = m[3] ? parseInt(m[3]) : (m[4] == "." ? -1 : 0);

            parts.push(format.substr(0, m[0][0] == "%" ? m.index : m.index+1));
            parts.push({appender: appender, precision: precision});

            format = format.substr(m.index+m[0].length);
        }

        parts.push(format);

        return parts;
    }

    function escapeHTML(value)
    {
        function replaceChars(ch)
        {
            switch (ch)
            {
                case "<":
                    return "&lt;";
                case ">":
                    return "&gt;";
                case "&":
                    return "&amp;";
                case "'":
                    return "&#39;";
                case '"':
                    return "&quot;";
            }
            return "?";
        };
        return String(value).replace(/[<>&"']/g, replaceChars);
    }

    function objectToString(object)
    {
        try
        {
            return object+"";
        }
        catch (exc)
        {
            return null;
        }
    }

    // ********************************************************************************************

    function appendText(object, html)
    {
        html.push(escapeHTML(objectToString(object)));
    }

    function appendNull(object, html)
    {
        html.push('<span class="objectBox-null">', escapeHTML(objectToString(object)), '</span>');
    }

    function appendString(object, html)
    {
        html.push('<span class="objectBox-string">&quot;', escapeHTML(objectToString(object)),
            '&quot;</span>');
    }

    function appendInteger(object, html)
    {
        html.push('<span class="objectBox-number">', escapeHTML(objectToString(object)), '</span>');
    }

    function appendFloat(object, html)
    {
        html.push('<span class="objectBox-number">', escapeHTML(objectToString(object)), '</span>');
    }

    function appendFunction(object, html)
    {
        var reName = /function ?(.*?)\(/;
        var m = reName.exec(objectToString(object));
        var name = m ? m[1] : "function";
        html.push('<span class="objectBox-function">', escapeHTML(name), '()</span>');
    }
    
    function appendObject(object, html)
    {
        try
        {
            if (object == undefined)
                appendNull("undefined", html);
            else if (object == null)
                appendNull("null", html);
            else if (typeof object == "string")
                appendString(object, html);
            else if (typeof object == "number")
                appendInteger(object, html);
            else if (typeof object == "function")
                appendFunction(object, html);
            else if (object.nodeType == 1)
                appendSelector(object, html);
            else if (typeof object == "object")
                appendObjectFormatted(object, html);
            else
                appendText(object, html);
        }
        catch (exc)
        {
        }
    }
        
    function appendObjectFormatted(object, html)
    {
        var text = objectToString(object);
        var reObject = /\[object (.*?)\]/;

        var m = reObject.exec(text);
        html.push('<span class="objectBox-object">', m ? m[1] : text, '</span>')
    }
    
    function appendSelector(object, html)
    {
        html.push('<span class="objectBox-selector">');

        html.push('<span class="selectorTag">', escapeHTML(object.nodeName.toLowerCase()), '</span>');
        if (object.id)
            html.push('<span class="selectorId">#', escapeHTML(object.id), '</span>');
        if (object.className)
            html.push('<span class="selectorClass">.', escapeHTML(object.className), '</span>');

        html.push('</span>');
    }

    function appendNode(node, html)
    {
        if (node.nodeType == 1)
        {
            html.push(
                '<div class="objectBox-element">',
                    '&lt;<span class="nodeTag">', node.nodeName.toLowerCase(), '</span>');

            for (var i = 0; i < node.attributes.length; ++i)
            {
                var attr = node.attributes[i];
                if (!attr.specified)
                    continue;
                
                html.push('&nbsp;<span class="nodeName">', attr.nodeName.toLowerCase(),
                    '</span>=&quot;<span class="nodeValue">', escapeHTML(attr.nodeValue),
                    '</span>&quot;')
            }

            if (node.firstChild)
            {
                html.push('&gt;</div><div class="nodeChildren">');

                for (var child = node.firstChild; child; child = child.nextSibling)
                    appendNode(child, html);
                    
                html.push('</div><div class="objectBox-element">&lt;/<span class="nodeTag">', 
                    node.nodeName.toLowerCase(), '&gt;</span></div>');
            }
            else
                html.push('/&gt;</div>');
        }
        else if (node.nodeType == 3)
        {
            html.push('<div class="nodeText">', escapeHTML(node.nodeValue),
                '</div>');
        }
    }

    // ********************************************************************************************
    
    function addEvent(object, name, handler)
    {
        if (document.all)
            object.attachEvent("on"+name, handler);
        else
            object.addEventListener(name, handler, false);
    }
    
    function removeEvent(object, name, handler)
    {
        if (document.all)
            object.detachEvent("on"+name, handler);
        else
            object.removeEventListener(name, handler, false);
    }
    
    function cancelEvent(event)
    {
        if (document.all)
            event.cancelBubble = true;
        else
            event.stopPropagation();        
    }

    function onError(msg, href, lineNo)
    {
        var html = [];
        
        var lastSlash = href.lastIndexOf("/");
        var fileName = lastSlash == -1 ? href : href.substr(lastSlash+1);
        
        html.push(
            '<span class="errorMessage">', msg, '</span>', 
            '<div class="objectBox-sourceLink">', fileName, ' (line ', lineNo, ')</div>'
        );
        
        logRow(html, "error");
    };

    function onKeyDown(event)
    {
        if (event.keyCode == 123)
            toggleConsole();
        else if ((event.keyCode == 108 || event.keyCode == 76) && event.shiftKey
                 && (event.metaKey || event.ctrlKey))
            focusCommandLine();
        else
            return;
        
        cancelEvent(event);
    }

    function onSplitterMouseDown(event)
    {
        if (isSafari || isOpera)
            return;
        
        addEvent(document, "mousemove", onSplitterMouseMove);
        addEvent(document, "mouseup", onSplitterMouseUp);

        for (var i = 0; i < frames.length; ++i)
        {
            addEvent(frames[i].document, "mousemove", onSplitterMouseMove);
            addEvent(frames[i].document, "mouseup", onSplitterMouseUp);
        }
    }
    
    function onSplitterMouseMove(event)
    {
        var win = document.all
            ? event.srcElement.ownerDocument.parentWindow
            : event.target.ownerDocument.defaultView;

        var clientY = event.clientY;
        if (win != win.parent)
            clientY += win.frameElement ? win.frameElement.offsetTop : 0;
        
        var height = consoleFrame.offsetTop + consoleFrame.clientHeight;
        var y = height - clientY;
        
        consoleFrame.style.height = y + "px";
        layout();
    }
    
    function onSplitterMouseUp(event)
    {
        removeEvent(document, "mousemove", onSplitterMouseMove);
        removeEvent(document, "mouseup", onSplitterMouseUp);

        for (var i = 0; i < frames.length; ++i)
        {
            removeEvent(frames[i].document, "mousemove", onSplitterMouseMove);
            removeEvent(frames[i].document, "mouseup", onSplitterMouseUp);
        }
    }
    
    function onCommandLineKeyDown(event)
    {
        if (event.keyCode == 13)
            evalCommandLine();
        else if (event.keyCode == 27)
            commandLine.value = "";
    }
    
    window.onerror = onError;
    addEvent(document, isIE || isSafari ? "keydown" : "keypress", onKeyDown);
    
    if (document.documentElement.getAttribute("debug") == "true")
        toggleConsole(true);
})();
}
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: "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"
		}
	]

};
BrowserDetect.init();

if(BrowserDetect.browser == "Explorer" && BrowserDetect.version < 6) {
	window.location.href = "/error/browser";
}
/*  Prototype JavaScript framework, version 1.5.1.1
 *  (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://www.prototypejs.org/
 *
--------------------------------------------------------------------------*/

var Prototype = {
  Version: '1.5.1.1',

  Browser: {
    IE:     !!(window.attachEvent && !window.opera),
    Opera:  !!window.opera,
    WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1,
    Gecko:  navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1
  },

  BrowserFeatures: {
    XPath: !!document.evaluate,
    ElementExtensions: !!window.HTMLElement,
    SpecificElementExtensions:
      (document.createElement('div').__proto__ !==
       document.createElement('form').__proto__)
  },

  ScriptFragment: '<script[^>]*>([\\S\\s]*?)<\/script>',
  JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/,

  emptyFunction: function() { },
  K: function(x) { return x;}
};

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;
    }
  },

  toJSON: function(object) {
    var type = typeof object;
    switch(type) {
      case 'undefined':
      case 'function':
      case 'unknown': return;
      case 'boolean': return object.toString();
    }
    if (object === null) return 'null';
    if (object.toJSON) return object.toJSON();
    if (object.ownerDocument === document) return;
    var results = [];
    for (var property in object) {
      var value = Object.toJSON(object[property]);
      if (value !== undefined)
        results.push(property.toJSON() + ': ' + value);
    }
    return '{' + results.join(', ') + '}';
  },

  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));
  };
}

Object.extend(Number.prototype, {
  toColorPart: function() {
    return this.toPaddedString(2, 16);
  },

  succ: function() {
    return this + 1;
  },

  times: function(iterator) {
    $R(0, this, true).each(iterator);
    return this;
  },

  toPaddedString: function(length, radix) {
    var string = this.toString(radix || 10);
    return '0'.times(length - string.length) + string;
  },

  toJSON: function() {
    return isFinite(this) ? this.toString() : 'null';
  }
});

Date.prototype.toJSON = function() {
  return '"' + this.getFullYear() + '-' +
    (this.getMonth() + 1).toPaddedString(2) + '-' +
    this.getDate().toPaddedString(2) + 'T' +
    this.getHours().toPaddedString(2) + ':' +
    this.getMinutes().toPaddedString(2) + ':' +
    this.getSeconds().toPaddedString(2) + '"';
};

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;
      }
    }
  }
}
Object.extend(String, {
  interpret: function(value) {
    return value == null ? '' : String(value);
  },
  specialChar: {
    '\b': '\\b',
    '\t': '\\t',
    '\n': '\\n',
    '\f': '\\f',
    '\r': '\\r',
    '\\': '\\\\'
  }
});

Object.extend(String.prototype, {
  gsub: function(pattern, replacement) {
    var result = '', source = this, match;
    replacement = arguments.callee.prepareReplacement(replacement);

    while (source.length > 0) {
      if (match = source.match(pattern)) {
        result += source.slice(0, match.index);
        result += String.interpret(replacement(match));
        source  = source.slice(match.index + match[0].length);
      } else {
        result += source, source = '';
      }
    }
    return result;
  },

  sub: function(pattern, replacement, count) {
    replacement = this.gsub.prepareReplacement(replacement);
    count = 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 self = arguments.callee;
    self.text.data = this;
    return self.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 key = decodeURIComponent(pair.shift());
        var value = pair.length > 1 ? pair.join('=') : pair[0];
        if (value != undefined) value = decodeURIComponent(value);

        if (key in hash) {
          if (hash[key].constructor != Array) hash[key] = [hash[key]];
          hash[key].push(value);
        }
        else hash[key] = value;
      }
      return hash;
    });
  },

  toArray: function() {
    return this.split('');
  },

  succ: function() {
    return this.slice(0, this.length - 1) +
      String.fromCharCode(this.charCodeAt(this.length - 1) + 1);
  },

  times: function(count) {
    var result = '';
    for (var i = 0; i < count; i++) result += this;
    return result;
  },

  camelize: function() {
    var parts = this.split('-'), len = parts.length;
    if (len == 1) return parts[0];

    var camelized = this.charAt(0) == '-'
      ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1)
      : parts[0];

    for (var i = 1; i < len; i++)
      camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);

    return camelized;
  },

  capitalize: function() {
    return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
  },

  underscore: function() {
    return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase();
  },

  dasherize: function() {
    return this.gsub(/_/,'-');
  },

  inspect: function(useDoubleQuotes) {
    var escapedString = this.gsub(/[\x00-\x1f\\]/, function(match) {
      var character = String.specialChar[match[0]];
      return character ? character : '\\u00' + match[0].charCodeAt().toPaddedString(2, 16);
    });
    if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"';
    return "'" + escapedString.replace(/'/g, '\\\'') + "'";
  },

  toJSON: function() {
    return this.inspect(true);
  },

  unfilterJSON: function(filter) {
    return this.sub(filter || Prototype.JSONFilter, '#{1}');
  },

  isJSON: function() {
    var str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, '');
    return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str);
  },

  evalJSON: function(sanitize) {
    var json = this.unfilterJSON();
    try {
      if (!sanitize || json.isJSON()) return eval('(' + json + ')');
    } catch (e) { }
    throw new SyntaxError('Badly formed JSON string: ' + this.inspect());
  },

  include: function(pattern) {
    return this.indexOf(pattern) > -1;
  },

  startsWith: function(pattern) {
    return this.indexOf(pattern) === 0;
  },

  endsWith: function(pattern) {
    var d = this.length - pattern.length;
    return d >= 0 && this.lastIndexOf(pattern) === d;
  },

  empty: function() {
    return this == '';
  },

  blank: function() {
    return /^\s*$/.test(this);
  }
});

if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, {
  escapeHTML: function() {
    return this.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
  },
  unescapeHTML: function() {
    return this.replace(/&amp;/g,'&').replace(/&lt;/g,'<').replace(/&gt;/g,'>');
  }
});

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;

Object.extend(String.prototype.escapeHTML, {
  div:  document.createElement('div'),
  text: document.createTextNode('')
});

with (String.prototype.escapeHTML) div.appendChild(text);

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 = {}, $continue = new Error('"throw $continue" is deprecated, use "return" instead');

var Enumerable = {
  each: function(iterator) {
    var index = 0;
    try {
      this._each(function(value) {
        iterator(value, index++);
      });
    } 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;
  }
}

if (Prototype.Browser.WebKit) {
  $A = Array.from = function(iterable) {
    if (!iterable) return [];
    if (!(typeof iterable == 'function' && iterable == '[object NodeList]') &&
      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(sorted) {
    return this.inject([], function(array, value, index) {
      if (0 == index || (sorted ? array.last() != value : !array.include(value)))
        array.push(value);
      return array;
    });
  },

  clone: function() {
    return [].concat(this);
  },

  size: function() {
    return this.length;
  },

  inspect: function() {
    return '[' + this.map(Object.inspect).join(', ') + ']';
  },

  toJSON: function() {
    var results = [];
    this.each(function(object) {
      var value = Object.toJSON(object);
      if (value !== undefined) results.push(value);
    });
    return '[' + results.join(', ') + ']';
  }
});

Array.prototype.toArray = Array.prototype.clone;

function $w(string) {
  string = string.strip();
  return string ? string.split(/\s+/) : [];
}

if (Prototype.Browser.Opera){
  Array.prototype.concat = function() {
    var array = [];
    for (var i = 0, length = this.length; i < length; i++) array.push(this[i]);
    for (var i = 0, length = arguments.length; i < length; i++) {
      if (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(object) {
  if (object instanceof Hash) this.merge(object);
  else Object.extend(this, object || {});
};

Object.extend(Hash, {
  toQueryString: function(obj) {
    var parts = [];
    parts.add = arguments.callee.addPair;

    this.prototype._each.call(obj, function(pair) {
      if (!pair.key) return;
      var value = pair.value;

      if (value && typeof value == 'object') {
        if (value.constructor == Array) value.each(function(value) {
          parts.add(pair.key, value);
        });
        return;
      }
      parts.add(pair.key, value);
    });

    return parts.join('&');
  },

  toJSON: function(object) {
    var results = [];
    this.prototype._each.call(object, function(pair) {
      var value = Object.toJSON(pair.value);
      if (value !== undefined) results.push(pair.key.toJSON() + ': ' + value);
    });
    return '{' + results.join(', ') + '}';
  }
});

Hash.toQueryString.addPair = function(key, value, prefix) {
  key = encodeURIComponent(key);
  if (value === undefined) this.push(key);
  else this.push(key + '=' + (value == null ? '' : encodeURIComponent(value)));
}

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(', ') + '}>';
  },

  toJSON: function() {
    return Hash.toJSON(this);
  }
});

function $H(object) {
  if (object instanceof Hash) return object;
  return new Hash(object);
};

// Safari iterates over shadowed properties
if (function() {
  var i = 0, Test = function(value) { this.key = value };
  Test.prototype.key = 'foo';
  for (var property in new Test('bar')) i++;
  return i > 1;
}()) Hash.prototype._each = function(iterator) {
  var cache = [];
  for (var key in this) {
    var value = this[key];
    if ((value && value == Hash.prototype[key]) || cache.include(key)) continue;
    cache.push(key);
    var pair = [key, value];
    pair.key = key;
    pair.value = value;
    iterator(pair);
  }
};
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) {}
      }
    });
  }
};

function callInProgress(xmlhttp) {
    switch (xmlhttp.readyState) {
        case 1:
    case 2:
    case 3:
        return true;
        break;
        // Case 4 and 0
        default:
        return false;
        break;

    }

}

Object.extend(Ajax.Responders, Enumerable);

Ajax.Responders.register({
	onCreate: function(request) {
		Ajax.activeRequestCount++
		request['timeoutId'] = window.setTimeout(function() {
			if (callInProgress(request.transport)) {
	                request.transport.abort();
	                alert("A network connection error has occured. Please try again later.");
					if (request.options['onFailure']) {
	                    request.options['onFailure'](request.transport, request.json);
	                }
					try {
						window.location.reload(true);
					} catch(err) {}
	                
			}
		}, 180000); //180 Second timeout
	},
	onComplete: function(request) {
		Ajax.activeRequestCount--;
	    window.clearTimeout(request['timeoutId']);
			
	}
		
	/*
  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,
  _gracefulTimer: null,
  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 = Object.clone(this.options.parameters);

    if (!['get', 'post'].include(this.method)) {
      // simulate other verbs over post
      params['_method'] = this.method;
      this.method = 'post';
    }

    this.parameters = params;

    if (params = Hash.toQueryString(params)) {
      // when GET, append parameters to URL
      if (this.method == 'get')
        this.url += (this.url.include('?') ? '&' : '?') + params;
      else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent))
        params += '&_=';
    }

    try {
      if (this.options.onCreate) this.options.onCreate(this.transport);
      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();

      this.body = this.method == 'post' ? (this.options.postBody || params) : null;
      this.transport.send(this.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);
      }

      var contentType = this.getHeader('Content-type');
      if (contentType && contentType.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 ? json.evalJSON() : null;
    } catch (e) { return null }
  },

  evalResponse: function() {
    try {
      return eval((this.transport.responseText || '').unfilterJSON());
    } catch (e) {
      this.dispatchException(e);
    }
  },

  dispatchException: function(exception) {
    (this.options.onException || Prototype.emptyFunction)(this, exception);
    Ajax.Responders.dispatch('onException', this, exception);
  }
});

Ajax.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) {
    var q = ".//*[contains(concat(' ', @class, ' '), ' " + className + " ')]";
    return document._getElementsByXPath(q, parentElement);
  }

} else document.getElementsByClassName = function(className, parentElement) {
  var children = ($(parentElement) || document.body).getElementsByTagName('*');
  var elements = [], child, pattern = new RegExp("(^|\\s)" + className + "(\\s|$)");
  for (var i = 0, length = children.length; i < length; i++) {
    child = children[i];
    var elementClassName = child.className;
    if (elementClassName.length == 0) continue;
    if (elementClassName == className || elementClassName.match(pattern))
      elements.push(Element.extend(child));
  }
  return elements;
};

/*--------------------------------------------------------------------------*/

if (!window.Element) var Element = {};

Element.extend = function(element) {
  var F = Prototype.BrowserFeatures;
  if (!element || !element.tagName || element.nodeType == 3 ||
   element._extended || F.SpecificElementExtensions || element == window)
    return element;

  var methods = {}, tagName = element.tagName, cache = Element.extend.cache,
   T = Element.Methods.ByTag;

  // extend methods for all tags (Safari doesn't need this)
  if (!F.ElementExtensions) {
    Object.extend(methods, Element.Methods),
    Object.extend(methods, Element.Methods.Simulated);
  }

  // extend methods for specific tags
  if (T[tagName]) Object.extend(methods, T[tagName]);

  for (var property in methods) {
    var value = methods[property];
    if (typeof value == 'function' && !(property in element))
      element[property] = cache.findOrStore(value);
  }

  element._extended = Prototype.emptyFunction;
  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) {
    $(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('*')).each(Element.extend);
  },

  firstDescendant: function(element) {
    element = $(element).firstChild;
    while (element && element.nodeType != 1) element = element.nextSibling;
    return $(element);
  },

  immediateDescendants: function(element) {
    if (!(element = $(element).firstChild)) return [];
    while (element && element.nodeType != 1) element = element.nextSibling;
    if (element) return [element].concat($(element).nextSiblings());
    return [];
  },

  previousSiblings: function(element) {
    return $(element).recursivelyCollect('previousSibling');
  },

  nextSiblings: function(element) {
    return $(element).recursivelyCollect('nextSibling');
  },

  siblings: function(element) {
    element = $(element);
    return element.previousSiblings().reverse().concat(element.nextSiblings());
  },

  match: function(element, selector) {
    if (typeof selector == 'string')
      selector = new Selector(selector);
    return selector.match($(element));
  },

  up: function(element, expression, index) {
    element = $(element);
    if (arguments.length == 1) return $(element.parentNode);
    var ancestors = element.ancestors();
    return expression ? Selector.findElement(ancestors, expression, index) :
      ancestors[index || 0];
  },

  down: function(element, expression, index) {
    element = $(element);
    if (arguments.length == 1) return element.firstDescendant();
    var descendants = element.descendants();
    return expression ? Selector.findElement(descendants, expression, index) :
      descendants[index || 0];
  },

  previous: function(element, expression, index) {
    element = $(element);
    if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element));
    var previousSiblings = element.previousSiblings();
    return expression ? Selector.findElement(previousSiblings, expression, index) :
      previousSiblings[index || 0];
  },

  next: function(element, expression, index) {
    element = $(element);
    if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element));
    var nextSiblings = element.nextSiblings();
    return expression ? Selector.findElement(nextSiblings, expression, index) :
      nextSiblings[index || 0];
  },

  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 (Prototype.Browser.IE) {
      if (!element.attributes) return null;
      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];
      return attribute ? attribute.nodeValue : null;
    }
    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.blank();
  },

  descendantOf: function(element, ancestor) {
	try {
		element = $(element), ancestor = $(ancestor);
	    while (element = element.parentNode)
	      if (element == ancestor) return true;
	    return false;
	} catch(err) {}
    
  },

  scrollTo: function(element) {
    element = $(element);
    var pos = Position.cumulativeOffset(element);
    window.scrollTo(pos[0], pos[1]);
    return element;
  },

  getStyle: function(element, style) {
    element = $(element);
    style = style == 'float' ? 'cssFloat' : style.camelize();
    var value = element.style[style];
    if (!value) {
      var css = document.defaultView.getComputedStyle(element, null);
      value = css ? css[style] : null;
    }
    if (style == 'opacity') return value ? parseFloat(value) : 1.0;
    return value == 'auto' ? null : value;
  },

  getOpacity: function(element) {
    return $(element).getStyle('opacity');
  },

  setStyle: function(element, styles, camelized) {
    element = $(element);
    var elementStyle = element.style;

    for (var property in styles)
      if (property == 'opacity') element.setOpacity(styles[property])
      else
        elementStyle[(property == 'float' || property == 'cssFloat') ?
          (elementStyle.styleFloat === undefined ? 'cssFloat' : 'styleFloat') :
          (camelized ? property : property.camelize())] = styles[property];

    return element;
  },

  setOpacity: function(element, value) {
    element = $(element);
    element.style.opacity = (value == 1 || value === '') ? '' :
      (value < 0.00001) ? 0 : value;
    return element;
  },

  getDimensions: function(element) {
    element = $(element);
    var display = $(element).getStyle('display');
    if (display != 'none' && display != null) // Safari bug
      return {width: element.offsetWidth, height: element.offsetHeight};

    // 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,
  childElements: Element.Methods.immediateDescendants
});

if (Prototype.Browser.Opera) {
  Element.Methods._getStyle = Element.Methods.getStyle;
  Element.Methods.getStyle = function(element, style) {
    switch(style) {
      case 'left':
      case 'top':
      case 'right':
      case 'bottom':
        if (Element._getStyle(element, 'position') == 'static') return null;
      default: return Element._getStyle(element, style);
    }
  };
}
else if (Prototype.Browser.IE) {
  Element.Methods.getStyle = function(element, style) {
    element = $(element);
    style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize();
    var value = element.style[style];
    if (!value && element.currentStyle) value = element.currentStyle[style];

    if (style == 'opacity') {
      if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/))
        if (value[1]) return parseFloat(value[1]) / 100;
      return 1.0;
    }

    if (value == 'auto') {
      if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none'))
        return element['offset'+style.capitalize()] + 'px';
      return null;
    }
    return value;
  };

  Element.Methods.setOpacity = function(element, value) {
    element = $(element);
    var filter = element.getStyle('filter'), style = element.style;
    if (value == 1 || value === '') {
      style.filter = filter.replace(/alpha\([^\)]*\)/gi,'');
      return element;
    } else if (value < 0.00001) value = 0;
    style.filter = filter.replace(/alpha\([^\)]*\)/gi, '') +
      'alpha(opacity=' + (value * 100) + ')';
    return element;
  };

  // IE is missing .innerHTML support for TABLE-related elements
  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;
  }
}
else if (Prototype.Browser.Gecko) {
  Element.Methods.setOpacity = function(element, value) {
    element = $(element);
    element.style.opacity = (value == 1) ? 0.999999 :
      (value === '') ? '' : (value < 0.00001) ? 0 : value;
    return element;
  };
}

Element._attributeTranslations = {
  names: {
    colspan:   "colSpan",
    rowspan:   "rowSpan",
    valign:    "vAlign",
    datetime:  "dateTime",
    accesskey: "accessKey",
    tabindex:  "tabIndex",
    enctype:   "encType",
    maxlength: "maxLength",
    readonly:  "readOnly",
    longdesc:  "longDesc"
  },
  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;
    }
  }
};

(function() {
  Object.extend(this, {
    href: this._getAttr,
    src:  this._getAttr,
    type: this._getAttr,
    disabled: this._flag,
    checked:  this._flag,
    readonly: this._flag,
    multiple: this._flag
  });
}).call(Element._attributeTranslations.values);

Element.Methods.Simulated = {
  hasAttribute: function(element, attribute) {
    var t = Element._attributeTranslations, node;
    attribute = t.names[attribute] || attribute;
    node = $(element).getAttributeNode(attribute);
    return node && node.specified;
  }
};

Element.Methods.ByTag = {};

Object.extend(Element, Element.Methods);

if (!Prototype.BrowserFeatures.ElementExtensions &&
 document.createElement('div').__proto__) {
  window.HTMLElement = {};
  window.HTMLElement.prototype = document.createElement('div').__proto__;
  Prototype.BrowserFeatures.ElementExtensions = true;
}

Element.hasAttribute = function(element, attribute) {
  if (element.hasAttribute) return element.hasAttribute(attribute);
  return Element.Methods.Simulated.hasAttribute(element, attribute);
};

Element.addMethods = function(methods) {
  var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag;

  if (!methods) {
    Object.extend(Form, Form.Methods);
    Object.extend(Form.Element, Form.Element.Methods);
    Object.extend(Element.Methods.ByTag, {
      "FORM":     Object.clone(Form.Methods),
      "INPUT":    Object.clone(Form.Element.Methods),
      "SELECT":   Object.clone(Form.Element.Methods),
      "TEXTAREA": Object.clone(Form.Element.Methods)
    });
  }

  if (arguments.length == 2) {
    var tagName = methods;
    methods = arguments[1];
  }

  if (!tagName) Object.extend(Element.Methods, methods || {});
  else {
    if (tagName.constructor == Array) tagName.each(extend);
    else extend(tagName);
  }

  function extend(tagName) {
    tagName = tagName.toUpperCase();
    if (!Element.Methods.ByTag[tagName])
      Element.Methods.ByTag[tagName] = {};
    Object.extend(Element.Methods.ByTag[tagName], methods);
  }

  function copy(methods, destination, onlyIfAbsent) {
    onlyIfAbsent = onlyIfAbsent || false;
    var cache = Element.extend.cache;
    for (var property in methods) {
      var value = methods[property];
      if (!onlyIfAbsent || !(property in destination))
        destination[property] = cache.findOrStore(value);
    }
  }

  function findDOMClass(tagName) {
    var klass;
    var trans = {
      "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph",
      "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList",
      "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading",
      "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote",
      "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION":
      "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD":
      "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR":
      "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET":
      "FrameSet", "IFRAME": "IFrame"
    };
    if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element';
    if (window[klass]) return window[klass];
    klass = 'HTML' + tagName + 'Element';
    if (window[klass]) return window[klass];
    klass = 'HTML' + tagName.capitalize() + 'Element';
    if (window[klass]) return window[klass];

    window[klass] = {};
    window[klass].prototype = document.createElement(tagName).__proto__;
    return window[klass];
  }

  if (F.ElementExtensions) {
    copy(Element.Methods, HTMLElement.prototype);
    copy(Element.Methods.Simulated, HTMLElement.prototype, true);
  }

  if (F.SpecificElementExtensions) {
    for (var tag in Element.Methods.ByTag) {
      var klass = findDOMClass(tag);
      if (typeof klass == "undefined") continue;
      copy(T[tag], klass.prototype);
    }
  }

  Object.extend(Element, Element.Methods);
  delete Element.ByTag;
};

var 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);
/* Portions of the Selector class are derived from Jack Slocum????????s DomQuery,
 * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style
 * license.  Please see http://www.yui-ext.com/ for more information. */

var Selector = Class.create();

Selector.prototype = {
  initialize: function(expression) {
    this.expression = expression.strip();
    this.compileMatcher();
  },

  compileMatcher: function() {
    // Selectors with namespaced attributes can't use the XPath version
    if (Prototype.BrowserFeatures.XPath && !(/\[[\w-]*?:/).test(this.expression))
      return this.compileXPathMatcher();

    var e = this.expression, ps = Selector.patterns, h = Selector.handlers,
        c = Selector.criteria, le, p, m;

    if (Selector._cache[e]) {
      this.matcher = Selector._cache[e]; return;
    }
    this.matcher = ["this.matcher = function(root) {",
                    "var r = root, h = Selector.handlers, c = false, n;"];

    while (e && le != e && (/\S/).test(e)) {
      le = e;
      for (var i in ps) {
        p = ps[i];
        if (m = e.match(p)) {
          this.matcher.push(typeof c[i] == 'function' ? c[i](m) :
    	      new Template(c[i]).evaluate(m));
          e = e.replace(m[0], '');
          break;
        }
      }
    }

    this.matcher.push("return h.unique(n);\n}");
    eval(this.matcher.join('\n'));
    Selector._cache[this.expression] = this.matcher;
  },

  compileXPathMatcher: function() {
    var e = this.expression, ps = Selector.patterns,
        x = Selector.xpath, le,  m;

    if (Selector._cache[e]) {
      this.xpath = Selector._cache[e]; return;
    }

    this.matcher = ['.//*'];
    while (e && le != e && (/\S/).test(e)) {
      le = e;
      for (var i in ps) {
        if (m = e.match(ps[i])) {
          this.matcher.push(typeof x[i] == 'function' ? x[i](m) :
            new Template(x[i]).evaluate(m));
          e = e.replace(m[0], '');
          break;
        }
      }
    }

    this.xpath = this.matcher.join('');
    Selector._cache[this.expression] = this.xpath;
  },

  findElements: function(root) {
    root = root || document;
    if (this.xpath) return document._getElementsByXPath(this.xpath, root);
    return this.matcher(root);
  },

  match: function(element) {
    return this.findElements(document).include(element);
  },

  toString: function() {
    return this.expression;
  },

  inspect: function() {
    return "#<Selector:" + this.expression.inspect() + ">";
  }
};

Object.extend(Selector, {
  _cache: {},

  xpath: {
    descendant:   "//*",
    child:        "/*",
    adjacent:     "/following-sibling::*[1]",
    laterSibling: '/following-sibling::*',
    tagName:      function(m) {
      if (m[1] == '*') return '';
      return "[local-name()='" + m[1].toLowerCase() +
             "' or local-name()='" + m[1].toUpperCase() + "']";
    },
    className:    "[contains(concat(' ', @class, ' '), ' #{1} ')]",
    id:           "[@id='#{1}']",
    attrPresence: "[@#{1}]",
    attr: function(m) {
      m[3] = m[5] || m[6];
      return new Template(Selector.xpath.operators[m[2]]).evaluate(m);
    },
    pseudo: function(m) {
      var h = Selector.xpath.pseudos[m[1]];
      if (!h) return '';
      if (typeof h === 'function') return h(m);
      return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m);
    },
    operators: {
      '=':  "[@#{1}='#{3}']",
      '!=': "[@#{1}!='#{3}']",
      '^=': "[starts-with(@#{1}, '#{3}')]",
      '$=': "[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']",
      '*=': "[contains(@#{1}, '#{3}')]",
      '~=': "[contains(concat(' ', @#{1}, ' '), ' #{3} ')]",
      '|=': "[contains(concat('-', @#{1}, '-'), '-#{3}-')]"
    },
    pseudos: {
      'first-child': '[not(preceding-sibling::*)]',
      'last-child':  '[not(following-sibling::*)]',
      'only-child':  '[not(preceding-sibling::* or following-sibling::*)]',
      'empty':       "[count(*) = 0 and (count(text()) = 0 or translate(text(), ' \t\r\n', '') = '')]",
      'checked':     "[@checked]",
      'disabled':    "[@disabled]",
      'enabled':     "[not(@disabled)]",
      'not': function(m) {
        var e = m[6], p = Selector.patterns,
            x = Selector.xpath, le, m, v;

        var exclusion = [];
        while (e && le != e && (/\S/).test(e)) {
          le = e;
          for (var i in p) {
            if (m = e.match(p[i])) {
              v = typeof x[i] == 'function' ? x[i](m) : new Template(x[i]).evaluate(m);
              exclusion.push("(" + v.substring(1, v.length - 1) + ")");
              e = e.replace(m[0], '');
              break;
            }
          }
        }
        return "[not(" + exclusion.join(" and ") + ")]";
      },
      'nth-child':      function(m) {
        return Selector.xpath.pseudos.nth("(count(./preceding-sibling::*) + 1) ", m);
      },
      'nth-last-child': function(m) {
        return Selector.xpath.pseudos.nth("(count(./following-sibling::*) + 1) ", m);
      },
      'nth-of-type':    function(m) {
        return Selector.xpath.pseudos.nth("position() ", m);
      },
      'nth-last-of-type': function(m) {
        return Selector.xpath.pseudos.nth("(last() + 1 - position()) ", m);
      },
      'first-of-type':  function(m) {
        m[6] = "1"; return Selector.xpath.pseudos['nth-of-type'](m);
      },
      'last-of-type':   function(m) {
        m[6] = "1"; return Selector.xpath.pseudos['nth-last-of-type'](m);
      },
      'only-of-type':   function(m) {
        var p = Selector.xpath.pseudos; return p['first-of-type'](m) + p['last-of-type'](m);
      },
      nth: function(fragment, m) {
        var mm, formula = m[6], predicate;
        if (formula == 'even') formula = '2n+0';
        if (formula == 'odd')  formula = '2n+1';
        if (mm = formula.match(/^(\d+)$/)) // digit only
          return '[' + fragment + "= " + mm[1] + ']';
        if (mm = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
          if (mm[1] == "-") mm[1] = -1;
          var a = mm[1] ? Number(mm[1]) : 1;
          var b = mm[2] ? Number(mm[2]) : 0;
          predicate = "[((#{fragment} - #{b}) mod #{a} = 0) and " +
          "((#{fragment} - #{b}) div #{a} >= 0)]";
          return new Template(predicate).evaluate({
            fragment: fragment, a: a, b: b });
        }
      }
    }
  },

  criteria: {
    tagName:      'n = h.tagName(n, r, "#{1}", c);   c = false;',
    className:    'n = h.className(n, r, "#{1}", c); c = false;',
    id:           'n = h.id(n, r, "#{1}", c);        c = false;',
    attrPresence: 'n = h.attrPresence(n, r, "#{1}"); c = false;',
    attr: function(m) {
      m[3] = (m[5] || m[6]);
      return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}"); c = false;').evaluate(m);
    },
    pseudo:       function(m) {
      if (m[6]) m[6] = m[6].replace(/"/g, '\\"');
      return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m);
    },
    descendant:   'c = "descendant";',
    child:        'c = "child";',
    adjacent:     'c = "adjacent";',
    laterSibling: 'c = "laterSibling";'
  },

  patterns: {
    // combinators must be listed first
    // (and descendant needs to be last combinator)
    laterSibling: /^\s*~\s*/,
    child:        /^\s*>\s*/,
    adjacent:     /^\s*\+\s*/,
    descendant:   /^\s/,

    // selectors follow
    tagName:      /^\s*(\*|[\w\-]+)(\b|$)?/,
    id:           /^#([\w\-\*]+)(\b|$)/,
    className:    /^\.([\w\-\*]+)(\b|$)/,
    pseudo:       /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|\s|(?=:))/,
    attrPresence: /^\[([\w]+)\]/,
    attr:         /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\]]*?)\4|([^'"][^\]]*?)))?\]/
  },

  handlers: {
    // UTILITY FUNCTIONS
    // joins two collections
    concat: function(a, b) {
      for (var i = 0, node; node = b[i]; i++)
        a.push(node);
      return a;
    },

    // marks an array of nodes for counting
    mark: function(nodes) {
      for (var i = 0, node; node = nodes[i]; i++)
        node._counted = true;
      return nodes;
    },

    unmark: function(nodes) {
      for (var i = 0, node; node = nodes[i]; i++)
        node._counted = undefined;
      return nodes;
    },

    // mark each child node with its position (for nth calls)
    // "ofType" flag indicates whether we're indexing for nth-of-type
    // rather than nth-child
    index: function(parentNode, reverse, ofType) {
      parentNode._counted = true;
      if (reverse) {
        for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) {
          node = nodes[i];
          if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++;
        }
      } else {
        for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++)
          if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++;
      }
    },

    // filters out duplicates and extends all nodes
    unique: function(nodes) {
      if (nodes.length == 0) return nodes;
      var results = [], n;
      for (var i = 0, l = nodes.length; i < l; i++)
        if (!(n = nodes[i])._counted) {
          n._counted = true;
          results.push(Element.extend(n));
        }
      return Selector.handlers.unmark(results);
    },

    // COMBINATOR FUNCTIONS
    descendant: function(nodes) {
      var h = Selector.handlers;
      for (var i = 0, results = [], node; node = nodes[i]; i++)
        h.concat(results, node.getElementsByTagName('*'));
      return results;
    },

    child: function(nodes) {
      var h = Selector.handlers;
      for (var i = 0, results = [], node; node = nodes[i]; i++) {
        for (var j = 0, children = [], child; child = node.childNodes[j]; j++)
          if (child.nodeType == 1 && child.tagName != '!') results.push(child);
      }
      return results;
    },

    adjacent: function(nodes) {
      for (var i = 0, results = [], node; node = nodes[i]; i++) {
        var next = this.nextElementSibling(node);
        if (next) results.push(next);
      }
      return results;
    },

    laterSibling: function(nodes) {
      var h = Selector.handlers;
      for (var i = 0, results = [], node; node = nodes[i]; i++)
        h.concat(results, Element.nextSiblings(node));
      return results;
    },

    nextElementSibling: function(node) {
      while (node = node.nextSibling)
	      if (node.nodeType == 1) return node;
      return null;
    },

    previousElementSibling: function(node) {
      while (node = node.previousSibling)
        if (node.nodeType == 1) return node;
      return null;
    },

    // TOKEN FUNCTIONS
    tagName: function(nodes, root, tagName, combinator) {
      tagName = tagName.toUpperCase();
      var results = [], h = Selector.handlers;
      if (nodes) {
        if (combinator) {
          // fastlane for ordinary descendant combinators
          if (combinator == "descendant") {
            for (var i = 0, node; node = nodes[i]; i++)
              h.concat(results, node.getElementsByTagName(tagName));
            return results;
          } else nodes = this[combinator](nodes);
          if (tagName == "*") return nodes;
        }
        for (var i = 0, node; node = nodes[i]; i++)
          if (node.tagName.toUpperCase() == tagName) results.push(node);
        return results;
      } else return root.getElementsByTagName(tagName);
    },

    id: function(nodes, root, id, combinator) {
      var targetNode = $(id), h = Selector.handlers;
      if (!nodes && root == document) return targetNode ? [targetNode] : [];
      if (nodes) {
        if (combinator) {
          if (combinator == 'child') {
            for (var i = 0, node; node = nodes[i]; i++)
              if (targetNode.parentNode == node) return [targetNode];
          } else if (combinator == 'descendant') {
            for (var i = 0, node; node = nodes[i]; i++)
              if (Element.descendantOf(targetNode, node)) return [targetNode];
          } else if (combinator == 'adjacent') {
            for (var i = 0, node; node = nodes[i]; i++)
              if (Selector.handlers.previousElementSibling(targetNode) == node)
                return [targetNode];
          } else nodes = h[combinator](nodes);
        }
        for (var i = 0, node; node = nodes[i]; i++)
          if (node == targetNode) return [targetNode];
        return [];
      }
      return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : [];
    },

    className: function(nodes, root, className, combinator) {
      if (nodes && combinator) nodes = this[combinator](nodes);
      return Selector.handlers.byClassName(nodes, root, className);
    },

    byClassName: function(nodes, root, className) {
      if (!nodes) nodes = Selector.handlers.descendant([root]);
      var needle = ' ' + className + ' ';
      for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) {
        nodeClassName = node.className;
        if (nodeClassName.length == 0) continue;
        if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle))
          results.push(node);
      }
      return results;
    },

    attrPresence: function(nodes, root, attr) {
      var results = [];
      for (var i = 0, node; node = nodes[i]; i++)
        if (Element.hasAttribute(node, attr)) results.push(node);
      return results;
    },

    attr: function(nodes, root, attr, value, operator) {
      if (!nodes) nodes = root.getElementsByTagName("*");
      var handler = Selector.operators[operator], results = [];
      for (var i = 0, node; node = nodes[i]; i++) {
        var nodeValue = Element.readAttribute(node, attr);
        if (nodeValue === null) continue;
        if (handler(nodeValue, value)) results.push(node);
      }
      return results;
    },

    pseudo: function(nodes, name, value, root, combinator) {
      if (nodes && combinator) nodes = this[combinator](nodes);
      if (!nodes) nodes = root.getElementsByTagName("*");
      return Selector.pseudos[name](nodes, value, root);
    }
  },

  pseudos: {
    'first-child': function(nodes, value, root) {
      for (var i = 0, results = [], node; node = nodes[i]; i++) {
        if (Selector.handlers.previousElementSibling(node)) continue;
          results.push(node);
      }
      return results;
    },
    'last-child': function(nodes, value, root) {
      for (var i = 0, results = [], node; node = nodes[i]; i++) {
        if (Selector.handlers.nextElementSibling(node)) continue;
          results.push(node);
      }
      return results;
    },
    'only-child': function(nodes, value, root) {
      var h = Selector.handlers;
      for (var i = 0, results = [], node; node = nodes[i]; i++)
        if (!h.previousElementSibling(node) && !h.nextElementSibling(node))
          results.push(node);
      return results;
    },
    'nth-child':        function(nodes, formula, root) {
      return Selector.pseudos.nth(nodes, formula, root);
    },
    'nth-last-child':   function(nodes, formula, root) {
      return Selector.pseudos.nth(nodes, formula, root, true);
    },
    'nth-of-type':      function(nodes, formula, root) {
      return Selector.pseudos.nth(nodes, formula, root, false, true);
    },
    'nth-last-of-type': function(nodes, formula, root) {
      return Selector.pseudos.nth(nodes, formula, root, true, true);
    },
    'first-of-type':    function(nodes, formula, root) {
      return Selector.pseudos.nth(nodes, "1", root, false, true);
    },
    'last-of-type':     function(nodes, formula, root) {
      return Selector.pseudos.nth(nodes, "1", root, true, true);
    },
    'only-of-type':     function(nodes, formula, root) {
      var p = Selector.pseudos;
      return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root);
    },

    // handles the an+b logic
    getIndices: function(a, b, total) {
      if (a == 0) return b > 0 ? [b] : [];
      return $R(1, total).inject([], function(memo, i) {
        if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i);
        return memo;
      });
    },

    // handles nth(-last)-child, nth(-last)-of-type, and (first|last)-of-type
    nth: function(nodes, formula, root, reverse, ofType) {
      if (nodes.length == 0) return [];
      if (formula == 'even') formula = '2n+0';
      if (formula == 'odd')  formula = '2n+1';
      var h = Selector.handlers, results = [], indexed = [], m;
      h.mark(nodes);
      for (var i = 0, node; node = nodes[i]; i++) {
        if (!node.parentNode._counted) {
          h.index(node.parentNode, reverse, ofType);
          indexed.push(node.parentNode);
        }
      }
      if (formula.match(/^\d+$/)) { // just a number
        formula = Number(formula);
        for (var i = 0, node; node = nodes[i]; i++)
          if (node.nodeIndex == formula) results.push(node);
      } else if (m = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
        if (m[1] == "-") m[1] = -1;
        var a = m[1] ? Number(m[1]) : 1;
        var b = m[2] ? Number(m[2]) : 0;
        var indices = Selector.pseudos.getIndices(a, b, nodes.length);
        for (var i = 0, node, l = indices.length; node = nodes[i]; i++) {
          for (var j = 0; j < l; j++)
            if (node.nodeIndex == indices[j]) results.push(node);
        }
      }
      h.unmark(nodes);
      h.unmark(indexed);
      return results;
    },

    'empty': function(nodes, value, root) {
      for (var i = 0, results = [], node; node = nodes[i]; i++) {
        // IE treats comments as element nodes
        if (node.tagName == '!' || (node.firstChild && !node.innerHTML.match(/^\s*$/))) continue;
        results.push(node);
      }
      return results;
    },

    'not': function(nodes, selector, root) {
      var h = Selector.handlers, selectorType, m;
      var exclusions = new Selector(selector).findElements(root);
      h.mark(exclusions);
      for (var i = 0, results = [], node; node = nodes[i]; i++)
        if (!node._counted) results.push(node);
      h.unmark(exclusions);
      return results;
    },

    'enabled': function(nodes, value, root) {
      for (var i = 0, results = [], node; node = nodes[i]; i++)
        if (!node.disabled) results.push(node);
      return results;
    },

    'disabled': function(nodes, value, root) {
      for (var i = 0, results = [], node; node = nodes[i]; i++)
        if (node.disabled) results.push(node);
      return results;
    },

    'checked': function(nodes, value, root) {
      for (var i = 0, results = [], node; node = nodes[i]; i++)
        if (node.checked) results.push(node);
      return results;
    }
  },

  operators: {
    '=':  function(nv, v) { return nv == v; },
    '!=': function(nv, v) { return nv != v; },
    '^=': function(nv, v) { return nv.startsWith(v); },
    '$=': function(nv, v) { return nv.endsWith(v); },
    '*=': function(nv, v) { return nv.include(v); },
    '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); },
    '|=': function(nv, v) { return ('-' + nv.toUpperCase() + '-').include('-' + v.toUpperCase() + '-'); }
  },

  matchElements: function(elements, expression) {
    var matches = new Selector(expression).findElements(), h = Selector.handlers;
    h.mark(matches);
    for (var i = 0, results = [], element; element = elements[i]; i++)
      if (element._counted) results.push(element);
    h.unmark(matches);
    return results;
  },

  findElement: function(elements, expression, index) {
    if (typeof expression == 'number') {
      index = expression; expression = false;
    }
    return Selector.matchElements(elements, expression || '*')[index || 0];
  },

  findChildElements: function(element, expressions) {
    var exprs = expressions.join(','), expressions = [];
    exprs.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) {
      expressions.push(m[1].strip());
    });
    var results = [], h = Selector.handlers;
    for (var i = 0, l = expressions.length, selector; i < l; i++) {
      selector = new Selector(expressions[i].strip());
      h.concat(results, selector.findElements(element));
    }
    return (l > 1) ? h.unique(results) : results;
  }
});

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 != null) {
         	if (key in result) {
            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(form).invoke('disable');
    return form;
  },

  enable: function(form) {
    form = $(form);
    Form.getElements(form).invoke('enable');
    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;
  },

  request: function(form, options) {
    form = $(form), options = Object.clone(options || {});

    var params = options.parameters;
    options.parameters = form.serialize(true);

    if (params) {
      if (typeof params == 'string') params = params.toQueryParams();
      Object.extend(options.parameters, params);
    }

    if (form.hasAttribute('method') && !options.method)
      options.method = form.method;

    return new Ajax.Request(form.readAttribute('action'), options);
  }
}

/*--------------------------------------------------------------------------*/

Form.Element = {
  focus: function(element) {
    $(element).focus();
    return element;
  },

  select: function(element) {
    $(element).select();
    return element;
  }
}

Form.Element.Methods = {
  serialize: function(element) {
    element = $(element);
    if (!element.disabled && element.name) {
      var value = element.getValue();
      if (value != undefined) {
        var pair = {};
        pair[element.name] = value;
        return 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);
    try {
      element.focus();
      if (element.select && (element.tagName.toLowerCase() != 'input' ||
        !['button', 'reset', 'submit'].include(element.type)))
        element.select();
    } catch (e) {}
    return element;
  },

  disable: function(element) {
    element = $(element);
    element.blur();
    element.disabled = true;
    return element;
  },

  enable: function(element) {
    element = $(element);
    element.disabled = false;
    return element;
  }
}

/*--------------------------------------------------------------------------*/

var Field = Form.Element;
var $F = Form.Element.Methods.getValue;

/*--------------------------------------------------------------------------*/

Form.Element.Serializers = {
  input: function(element) {
    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' &&
      (Prototype.Browser.WebKit || element.attachEvent))
      name = 'keydown';

    Event._observeAndCache(element, name, observer, useCapture);
  },

  stopObserving: function(element, name, observer, useCapture) {
    element = $(element);
    useCapture = useCapture || false;

    if (name == 'keypress' &&
        (Prototype.Browser.WebKit || element.attachEvent))
      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 (Prototype.Browser.IE)
  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 (Prototype.Browser.WebKit) {
  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();Object.extend(Event, {
  _domReady : function() {
    if (arguments.callee.done) return;
    arguments.callee.done = true;

    if (this._timer)  clearInterval(this._timer);
    
    this._readyCallbacks.each(function(f) { f() });
    this._readyCallbacks = null;
},
  onDOMReady : function(f) {
	
	if (!this._readyCallbacks) {
      var domReady = this._domReady.bind(this);
      
      if (document.addEventListener)
        document.addEventListener("DOMContentLoaded", domReady, false);
        
        /*@cc_on @*/
        /*@if (@_win32)
            document.write("<script id=__ie_onload defer src=javascript:void(0)><\/script>");
            document.getElementById("__ie_onload").onreadystatechange = function() {
                if (this.readyState == "complete") domReady(); 
            };
        /*@end @*/
        
        if (/WebKit/i.test(navigator.userAgent)) { 
          this._timer = setInterval(function() {
            if (/loaded|complete/.test(document.readyState)) domReady(); 
          }, 10);
        }
        
        Event.observe(window, 'load', domReady);
        Event._readyCallbacks =  [];
    }
    Event._readyCallbacks.push(f);

  }
});









// Copyright (c) 2005-2006 Justin Palmer (http://encytemedia.com)
// Examples and documentation (http://encytemedia.com/event-selectors)
// Inspired by the work of Ben Nolan's Behaviour (http://bennolan.com/behaviour)
// Modified by Leo Plaw August 2006 (http://leo-plaw.guildmedia.net)

var EventSelectors = {
	version: '1.0_pre',
	cache: [],
	rules: {},

	register: function(newRules){
		for (var property in newRules) { this.rules[property] = newRules[property]; }
	},

  start: function(rules) {
		this.register(rules);
		this.timer = new Array();
		this._extendRules();
		//var startTime = (new Date()).getTime();
		this.assign();
		//alert("assign: " + ((new Date()).getTime() - startTime) + "ms to crawl DOM and attach event handlers.");

	},

	assign: function() {
		var observer = null;
		this._unloadCache();
		
		this.rules._each(function(rule) {

			var selectors = $A(rule.key.split(','));
			selectors.each(function(selector) {
				var pair = selector.split(/:(?=[a-z]+$)/);
				var event = pair[1];
				
				var selectorResults = [];

				selectorResults = $$(pair[0]);
				
				selectorResults.each(function(element) {
						var len = pair.length;
					if(pair[1] == '' || pair.length == 1) return rule.value(element);
					if(event.toLowerCase() == 'loaded') {
						this.timer[pair[0]] = setInterval(this._checkLoaded.bind(this, element, pair[0], rule), 15);
					} else {
						observer = function(event) {
						
						try
						{
							var element = Event.element(event);
							if (element.nodeType == 3)	   // Safari Bug (Fixed in Webkit)
								element = element.parentNode;
							rule.value($(element), event);
						} catch(err) {}
								

						};
						this.cache.push([element, event, observer]);
						Event.observe(element, event, observer);
					}
				}.bind(this));
			}.bind(this));
		}.bind(this));
	},

	apply: function() {
		this.assign();
	},

	addRules: function(newRules) {
		Object.extend(newRules, this.rules);
	},

	addLoadEvent: function(func){
		Event.observe(window, 'load', func);
	},

	_unloadCache: function() {
		if (!this.cache) return;
		for (var i = 0; i < this.cache.length; i++) {
			Event.stopObserving.apply(this, this.cache[i]);
			this.cache[i][0] = null;
		}
		this.cache = [];
	},

	_checkLoaded: function(element, timer, rule) {
		var node = $(element);
		if(element.tagName != 'undefined') {
			clearInterval(this.timer[timer]);
			rule.value(node);
		}
	},

	_extendRules: function() {
			
  		
		Object.extend(this.rules, {
		 _each: function(iterator) {
			 for (key in this) {
			 
				 if(key == '_each') continue;
				 var value = this[key];
				 var pair = [key, value];
				 pair.key = key;
				 pair.value = value;
				 iterator(pair);
				 
			 }
		 }
		 
		});
	}
};

// Remove/Comment this if you do not wish to reapply Rules automatically
// on Ajax request.
function ignore_behaviours(check_url) {
  //console.log('ignore_behaviours -> check_url : ' + check_url);
  
  var urls = [];
  
  // list of urls which are not to run behaviours on
  urls[urls.length] = '/assets/javascripts/metrics/s_code.js';
  urls[urls.length] = '/customer/ajax/yourstyle/handleBMI.jsp';
  urls[urls.length] = '/customer/ajax/yourstyle/handleUserAction.jsp';
  urls[urls.length] = '/customer/ajax/yourstyle/buildQuestionnaire.jsp';
  urls[urls.length] = '/customer/ajax/find_a_centre/details.jsp';
  var ignore = false;
  
  urls.each(function(url) {
    if (url == check_url || check_url.indexOf(url) != -1) {
      ignore = true;
      return;
    }
  });
  
  //console.log('ignore_behaviours -> ignore? ' + (ignore ? 'yes' : 'no'));
  
  return ignore;
};

Ajax.Responders.register({
	onComplete: function(transport) { 
	  if (!ignore_behaviours(transport.url)) {
	    setTimeout(function(){
			EventSelectors.apply();
			$$('.dialog #find_centre_form .fcInput, .dialog #find_centre_form .find_centre_cancel_img, .dialog #find_centre_form img').each(function(i) {
				i.style.display = "inline";
			});
			
		}, 1);
	  }
	}
});
var CookieTest = {
	enabled: false,
	lastNumber: null,
	set : function()
	{
		var rand = Math.floor( Math.random() * 11 );
		CookieTest.lastNumber = rand;
		document.cookie = ("validCookie="+ rand +";path=/").replace(/null/g, "");
	},
	get : function()
	{
		var nameEQ = "validCookie=";
		var cookiesList = document.cookie.split(';');
		
		var found = false;
		for ( var i = 0, len = cookiesList.length; i < len; i++ )
		{
			var c = cookiesList[i];
			
			var cookieValue = null;
			
			while (c.charAt(0)==' ') 
			{
				c = c.substring(1, c.length);
			}

			if (c.indexOf(nameEQ) == 0)
			{
				
				cookieValue =  c.substring(nameEQ.length, c.length).replace(/null/g, "");
				
				if(cookieValue === null || cookieValue == 'undefined')
				{
					return false;
				}
				else
				{
					return CookieTest.cookieValue = cookieValue;
				}
			}
		}

		return false;
	},
	validate : function() 
	{
		var cookieEnabled = (window.navigator.cookieEnabled) ? true : false;
		CookieTest.set();

		if((BrowserDetect.browser == 'Explorer' && BrowserDetect.version == 6) && document.cookie.length >= 1)
		{
			CookieTest.enabled = true;
		}
		else if((BrowserDetect.browser == 'Explorer' && BrowserDetect.version == 6) && document.cookie.length == 0 || document.cookie == "")
		{
			CookieTest.enabled = false;
			var x = "12345";
			document.cookie="validCookie="+x+";"; //Hack to add a few characters to the cookie.
		}
		else if(CookieTest.get() === false || !cookieEnabled || cookieEnabled === 'undefined' && (CookieTest.cookieValue != CookieTest.lastNumber))
		{		
			CookieTest.enabled = false;
		}
		else
		{
			CookieTest.enabled = true;
		}
	}
};

Event.onDOMReady(function(){
	
	if(Windows.windows.length != 0) return;
	
	EventSelectors.start();
		Metrics.track('pageview', {
			userLevel: 'anonymous user',
			accountId: '0',
			visitorID: Metrics.readVisitorID()
		});

	
	CookieTest.validate();	

	if(!CookieTest.enabled)
	{
		var env = JCEnvironment.environmentName;
		
		if(env == "jcrgjennycraigcomdev" || env == "jcrgtest141") {
	
		} else {
			//Dialog.info({url: '/customer/ajax/error/error_cookie.jsp'}, {
		    //     windowParameters: 
		    //        {className: 'jenny_craig_dialog', width: 606, showLoading: true}
		    // });
		}

	}

});

var behaviors = {
	'a#enterSite:click' : function(element, evt) {
		Event.stop(evt);
		Windows.close(Windows.focusedWindow.getId());
		return false;
	},
	
	'#enterSiteNow:click' : function(element, evt) {
		Event.stop(evt);
		Windows.close(Windows.focusedWindow.getId());
		return false;
	}
};

EventSelectors.register(behaviors);


// script.aculo.us effects.js v1.7.1_beta3, Fri May 25 17:19:41 +0200 2007

// Copyright (c) 2005-2007 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(Prototype.Browser.WebKit) window.scrollBy(0,0);
  return element;
}

Element.getInlineOpacity = function(element){
  return $(element).style.opacity || '';
}

Element.forceRerendering = function(element) {
  try {
    element = $(element);
    var n = document.createTextNode(' ');
    element.appendChild(n);
    element.removeChild(n);
  } catch(e) { }
};

/*--------------------------------------------------------------------------*/

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(Prototype.Browser.IE) tagifyStyle += ';zoom:1';
    
    element = $(element);
    $A(element.childNodes).each( function(child) {
      if(child.nodeType==3) {
        child.nodeValue.toArray().each( function(character) {
          element.insertBefore(
            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) {
    var pos = ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4;
    return (pos > 1 ? 1 : pos);
  },
  wobble: function(pos) {
    return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5;
  },
  pulse: function(pos, pulses) { 
    pulses = pulses || 5; 
    return (
      Math.round((pos % (1/pulses)) * pulses) == 0 ? 
            ((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++) 
      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:        100,   // 100= assume 66fps max.
  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) {
    function codeForEvent(options,eventName){
      return (
        (options[eventName+'Internal'] ? 'this.options.'+eventName+'Internal(this);' : '') +
        (options[eventName] ? 'this.options.'+eventName+'(this);' : '')
      );
    }
    if(options.transition === false) options.transition = Effect.Transitions.linear;
    this.options      = Object.extend(Object.extend({},Effect.DefaultOptions), options || {});
    this.currentFrame = 0;
    this.state        = 'idle';
    this.startOn      = this.options.delay*1000;
    this.finishOn     = this.startOn+(this.options.duration*1000);
    this.fromToDelta  = this.options.to-this.options.from;
    this.totalTime    = this.finishOn-this.startOn;
    this.totalFrames  = this.options.fps*this.options.duration;
    
    eval('this.render = function(pos){ '+
      'if(this.state=="idle"){this.state="running";'+
      codeForEvent(options,'beforeSetup')+
      (this.setup ? 'this.setup();':'')+ 
      codeForEvent(options,'afterSetup')+
      '};if(this.state=="running"){'+
      'pos=this.options.transition(pos)*'+this.fromToDelta+'+'+this.options.from+';'+
      'this.position=pos;'+
      codeForEvent(options,'beforeUpdate')+
      (this.update ? 'this.update(pos);':'')+
      codeForEvent(options,'afterUpdate')+
      '}}');
    
    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.totalTime,
          frame = Math.round(pos * this.totalFrames);
      if(frame > this.currentFrame) {
        this.render(pos);
        this.currentFrame = frame;
      }
    }
  },
  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(Prototype.Browser.IE && (!this.element.currentStyle.hasLayout))
      this.element.setStyle({zoom: 1});
    var options = Object.extend({
      from: this.element.getOpacity() || 0.0,
      to:   1.0
    }, arguments[1] || {});
    this.start(options);
  },
  update: function(position) {
    this.element.setOpacity(position);
  }
});

Effect.Move = Class.create();
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.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] || {})
  );
}

// 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] = '';
          });
        }
      } 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], value = pair[1], unit = null;

      if(value.parseColor('#zzzzzz') != '#zzzzzz') {
        value = value.parseColor();
        unit  = 'color';
      } else if(property == 'opacity') {
        value = parseFloat(value);
        if(Prototype.Browser.IE && (!this.element.currentStyle.hasLayout))
          this.element.setStyle({zoom: 1});
      } else if(Element.CSS_LENGTH.test(value)) {
          var components = value.match(/^([\+\-]?[0-9\.]+)(.*)$/);
          value = parseFloat(components[1]);
          unit = (components.length == 3) ? components[2] : null;
      }

      var originalValue = this.element.getStyle(property);
      return { 
        style: property.camelize(), 
        originalValue: unit=='color' ? parseColor(originalValue) : parseFloat(originalValue || 0), 
        targetValue: unit=='color' ? parseColor(value) : value,
        unit: unit
      };
    }.bind(this)).reject(function(transform){
      return (
        (transform.originalValue == transform.targetValue) ||
        (
          transform.unit != 'color' &&
          (isNaN(transform.originalValue) || isNaN(transform.targetValue))
        )
      )
    });
  },
  update: function(position) {
    var style = {}, transform, i = this.transforms.length;
    while(i--)
      style[(transform = this.transforms[i]).style] = 
        transform.unit=='color' ? '#'+
          (Math.round(transform.originalValue[0]+
            (transform.targetValue[0]-transform.originalValue[0])*position)).toColorPart() +
          (Math.round(transform.originalValue[1]+
            (transform.targetValue[1]-transform.originalValue[1])*position)).toColorPart() +
          (Math.round(transform.originalValue[2]+
            (transform.targetValue[2]-transform.originalValue[2])*position)).toColorPart() :
        transform.originalValue + Math.round(
          ((transform.targetValue - transform.originalValue) * position) * 1000)/1000 + transform.unit;
    this.element.setStyle(style, true);
  }
});

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 = document.createElement('div');
  element.innerHTML = '<div style="' + this + '"></div>';
  var style = element.childNodes[0].style, styleRules = $H();
  
  Element.CSS_PROPERTIES.each(function(property){
    if(style[property]) styleRules[property] = style[property]; 
  });
  if(Prototype.Browser.IE && 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;
};

['getInlineOpacity','forceRerendering','setContentZoom',
 'collectTextNodes','collectTextNodesIgnoreClass','morph'].each( 
  function(f) { Element.Methods[f] = Element[f]; }
);

Element.Methods.visualEffect = function(element, effect, options) {
  s = effect.dasherize().camelize();
  effect_class = s.charAt(0).toUpperCase() + s.substring(1);
  new Effect[effect_class](element, options);
  return $(element);
};

Element.addMethods();var Window = Class.create();
Window.keepMultiModalWindow = false;
Window.hasEffectLib = String.prototype.parseColor != null;
Window.resizeEffectDuration = 0.4;
Window.prototype = {
    initialize: function() {
        var C;
        var B = 0;
        if (arguments.length > 0) {
            if (typeof arguments[0] == "string") {
                C = arguments[0];
                B = 1;
            } else {
                C = arguments[0] ? arguments[0].id: null
            }
        }
        if (!C) {
            C = "window_" + new Date().getTime()
            }
        if ($(C)) {
	
        }
        this.options = Object.extend({
            className: "dialog",
            minWidth: 100,
            minHeight: 20,
            resizable: true,
            closable: true,
            minimizable: true,
            maximizable: true,
            draggable: true,
            userData: null,
            showEffect: (Window.hasEffectLib ? Effect.Appear: Element.show),
            hideEffect: (Window.hasEffectLib ? Effect.Fade: Element.hide),
            showEffectOptions: {},
            hideEffectOptions: {},
            effectOptions: null,
            parent: document.body,
            title: "&nbsp;",
            url: null,
            onload: Prototype.emptyFunction,
            width: 200,
            height: 30,
            opacity: 1,
            recenterAuto: true,
            wiredDrag: false,
            closeCallback: null,
            destroyOnClose: false,
            gridX: 1,
            gridY: 1,
            showLoading: false
        }, arguments[B] || {});
        if (typeof this.options.top == "undefined" && typeof this.options.bottom == "undefined") {
            this.options.top = this._round(Math.random() * 500, this.options.gridY)
            }
        if (typeof this.options.left == "undefined" && typeof this.options.right == "undefined") {
            this.options.left = this._round(Math.random() * 500, this.options.gridX)
            }
        if (this.options.effectOptions) {
            Object.extend(this.options.hideEffectOptions, this.options.effectOptions);
            Object.extend(this.options.showEffectOptions, this.options.effectOptions);
            if (this.options.showEffect == Element.Appear) {
                this.options.showEffectOptions.to = this.options.opacity
            }
        }
        if (Window.hasEffectLib) {
            if (this.options.showEffect == Effect.Appear) {
                this.options.showEffectOptions.to = this.options.opacity
            }
            if (this.options.hideEffect == Effect.Fade) {
                this.options.hideEffectOptions.from = this.options.opacity
            }
        }
        if (this.options.hideEffect == Element.hide) {
            this.options.hideEffect = function() {
                Element.hide(this.element);
                if (this.options.destroyOnClose) {
                    this.destroy()
                    }
            }.bind(this)
            }
        if (this.options.parent != document.body) {
            this.options.parent = $(this.options.parent)
            }
        this.element = this._createWindow(C);
        this.eventMouseDown = this._initDrag.bindAsEventListener(this);
        this.eventMouseUp = this._endDrag.bindAsEventListener(this);
        this.eventMouseMove = this._updateDrag.bindAsEventListener(this);
        this.eventOnLoad = this._getWindowBorderSize.bindAsEventListener(this);
        this.eventMouseDownContent = this.toFront.bindAsEventListener(this);
        this.eventResize = this._recenter.bindAsEventListener(this);
        this.topbar = $(this.element.id + "_top");
        this.bottombar = $(this.element.id + "_bottom");
        this.content = $(this.element.id + "_content");
        Event.observe(this.topbar, "mousedown", this.eventMouseDown);
        Event.observe(this.bottombar, "mousedown", this.eventMouseDown);
        Event.observe(this.content, "mousedown", this.eventMouseDownContent);
        Event.observe(window, "load", this.eventOnLoad);
        Event.observe(window, "resize", this.eventResize);
        Event.observe(window, "scroll", this.eventResize);
        if (this.options.draggable) {
            var A = this; [this.topbar, this.topbar.up().previous(), this.topbar.up().next()].each(function(D) {
                D.observe("mousedown", A.eventMouseDown);
                D.addClassName("top_draggable")
                }); [this.bottombar.up(), this.bottombar.up().previous(), this.bottombar.up().next()].each(function(D) {
                D.observe("mousedown", A.eventMouseDown);
                D.addClassName("bottom_draggable")
                })
            }
        if (this.options.resizable) {
            this.sizer = $(this.element.id + "_sizer");
            Event.observe(this.sizer, "mousedown", this.eventMouseDown)
            }
        this.useLeft = null;
        this.useTop = null;
        if (typeof this.options.left != "undefined") {
            this.element.setStyle({
                left: parseFloat(this.options.left) + "px"
            });
            this.useLeft = true
        } else {
            this.element.setStyle({
                right: parseFloat(this.options.right) + "px"
            });
            this.useLeft = false
        }
        if (typeof this.options.top != "undefined") {
            this.element.setStyle({
                top: parseFloat(this.options.top) + "px"
            });
            this.useTop = true
        } else {
            this.element.setStyle({
                bottom: parseFloat(this.options.bottom) + "px"
            });
            this.useTop = false
        }
        this.storedLocation = null;
        this.setOpacity(this.options.opacity);
        if (this.options.zIndex) {
            this.setZIndex(this.options.zIndex)
            }
        if (this.options.destroyOnClose) {
            this.setDestroyOnClose(true)
            }
        this._getWindowBorderSize();
        this.width = this.options.width;
        this.height = this.options.height;
        this.visible = false;
        this.constraint = false;
        this.constraintPad = {
            top: 0,
            left: 0,
            bottom: 0,
            right: 0
        };
        if (this.width && this.height) {
            this.setSize(this.options.width, this.options.height)
            }
        this.setTitle(this.options.title);
        Windows.register(this)
        },
    destroy: function() {
        this._notify("onDestroy");
        Event.stopObserving(this.topbar, "mousedown", this.eventMouseDown);
        Event.stopObserving(this.bottombar, "mousedown", this.eventMouseDown);
        Event.stopObserving(this.content, "mousedown", this.eventMouseDownContent);
        Event.stopObserving(window, "load", this.eventOnLoad);
        Event.stopObserving(window, "resize", this.eventResize);
        Event.stopObserving(window, "scroll", this.eventResize);
        Event.stopObserving(this.content, "load", this.options.onload);
        if (this._oldParent) {
            var C = this.getContent();
            var A = null;
            for (var B = 0; B < C.childNodes.length; B++) {
                A = C.childNodes[B];
                if (A.nodeType == 1) {
                    break
                }
                A = null
            }
            if (A) {
                this._oldParent.appendChild(A)
                }
            this._oldParent = null
        }
        if (this.sizer) {
            Event.stopObserving(this.sizer, "mousedown", this.eventMouseDown)
            }
        if (this.options.url) {
            this.content.src = null
        }
        if (this.iefix) {
            Element.remove(this.iefix)
            }
        Element.remove(this.element);
        Windows.unregister(this)
        },
    setCloseCallback: function(A) {
        this.options.closeCallback = A
    },
    getContent: function() {
        return this.content
    },
    setContent: function(G, F, B) {
        var A = $(G);
        if (null == A) {
            throw "Unable to find element '" + G + "' in DOM"
        }
        this._oldParent = A.parentNode;
        var E = null;
        var D = null;
        if (F) {
            E = Element.getDimensions(A)
            }
        if (B) {
            D = Position.cumulativeOffset(A)
            }
        var C = this.getContent();
        this.setHTMLContent("");
        C = this.getContent();
        C.appendChild(A);
        A.show();
        if (F) {
            this.setSize(E.width, E.height)
            }
        if (B) {
            this.setLocation(D[1] - this.heightN, D[0] - this.widthW)
            }
    },
    setHTMLContent: function(A) {
        if (this.options.url) {
            this.content.src = null;
            this.options.url = null;
            var B = "<div id=\"" + this.getId() + "_content\" class=\"" + this.options.className + "_content\"> </div>";
            $(this.getId() + "_table_content").innerHTML = B;
            this.content = $(this.element.id + "_content")
            }
        this.getContent().innerHTML = A
    },
    setAjaxContent: function(B, A, D, C) {
        this.showFunction = D ? "showCenter": "show";
        this.showModal = C || false;
        A = A || {};
        this.setHTMLContent("");
        this.onComplete = A.onComplete;
        if (!this._onCompleteHandler) {
            this._onCompleteHandler = this._setAjaxContent.bind(this)
            }
        A.onComplete = this._onCompleteHandler;
        new Ajax.Request(B, A);
        A.onComplete = this.onComplete
    },
    _setAjaxContent: function(A) {
        Element.update(this.getContent(), A.responseText);
        if (this.onComplete) {
            this.onComplete(A)
            }
        this.onComplete = null;
        this[this.showFunction](this.showModal)
        },
    setURL: function(A) {
        if (this.options.url) {
            this.content.src = null
        }
        this.options.url = A;
        var B = "<iframe frameborder='0' name='" + this.getId() + "_content'  id='" + this.getId() + "_content' src='" + A + "' width='" + this.width + "' height='" + this.height + "'> </iframe>";
        $(this.getId() + "_table_content").innerHTML = B;
        this.content = $(this.element.id + "_content")
        },
    getURL: function() {
        return this.options.url ? this.options.url: null
    },
    refresh: function() {
        if (this.options.url) {
            $(this.element.getAttribute("id") + "_content").src = this.options.url
        }
    },
    setCookie: function(B, C, M, E, A) {
        B = B || this.element.id;
        this.cookie = [B, C, M, E, A];
        var K = WindowUtilities.getCookie(B);
        if (K) {
            var L = K.split(",");
            var I = L[0].split(":");
            var H = L[1].split(":");
            var J = parseFloat(L[2]),
            F = parseFloat(L[3]);
            var G = L[4];
            var D = L[5];
            this.setSize(J, F);
            if (G == "true") {
                this.doMinimize = true
            } else {
                if (D == "true") {
                    this.doMaximize = true
                }
            }
            this.useLeft = I[0] == "l";
            this.useTop = H[0] == "t";
            this.element.setStyle(this.useLeft ? {
                left: I[1]
                }: {
                right: I[1]
                });
            this.element.setStyle(this.useTop ? {
                top: H[1]
                }: {
                bottom: H[1]
                })
            }
    },
    getId: function() {
        return this.element.id
    },
    setDestroyOnClose: function() {
        this.options.destroyOnClose = true
    },
    setConstraint: function(A, B) {
        this.constraint = A;
        this.constraintPad = Object.extend(this.constraintPad, B || {});
        if (this.useTop && this.useLeft) {
            this.setLocation(parseFloat(this.element.style.top), parseFloat(this.element.style.left))
            }
    },
    _initDrag: function(B) {
        if (Event.element(B) == this.sizer && this.isMinimized()) {
            return
        }
        if (Event.element(B) != this.sizer && this.isMaximized()) {
            return
        }
        if (window.ie && this.heightN == 0) {
            this._getWindowBorderSize()
            }
        this.pointer = [this._round(Event.pointerX(B), this.options.gridX), this._round(Event.pointerY(B), this.options.gridY)];
        if (this.options.wiredDrag) {
            this.currentDrag = this._createWiredElement()
            } else {
            this.currentDrag = this.element
        }
        if (Event.element(B) == this.sizer) {
            this.doResize = true;
            this.widthOrg = this.width;
            this.heightOrg = this.height;
            this.bottomOrg = parseFloat(this.element.getStyle("bottom"));
            this.rightOrg = parseFloat(this.element.getStyle("right"));
            this._notify("onStartResize")
            } else {
            this.doResize = false;
            var A = $(this.getId() + "_close");
            if (A && Position.within(A, this.pointer[0], this.pointer[1])) {
                this.currentDrag = null;
                return
            }
            this.toFront();
            if (!this.options.draggable) {
                return
            }
            this._notify("onStartMove")
            }
        Event.observe(document, "mouseup", this.eventMouseUp, false);
        Event.observe(document, "mousemove", this.eventMouseMove, false);
        WindowUtilities.disableScreen("__invisible__", "__invisible__", this.overlayOpacity);
        document.body.ondrag = function() {
            return false
        };
        document.body.onselectstart = function() {
            return false
        };
        this.currentDrag.show();
        Event.stop(B)
        },
    _round: function(B, A) {
        return A == 1 ? B: B = Math.floor(B / A) * A
    },
    _updateDrag: function(B) {
        var A = [this._round(Event.pointerX(B), this.options.gridX), this._round(Event.pointerY(B), this.options.gridY)];
        var J = A[0] - this.pointer[0];
        var I = A[1] - this.pointer[1];
        if (this.doResize) {
            var H = this.widthOrg + J;
            var D = this.heightOrg + I;
            J = this.width - this.widthOrg;
            I = this.height - this.heightOrg;
            if (this.useLeft) {
                H = this._updateWidthConstraint(H)
                } else {
                this.currentDrag.setStyle({
                    right: (this.rightOrg - J) + "px"
                })
                }
            if (this.useTop) {
                D = this._updateHeightConstraint(D)
                } else {
                this.currentDrag.setStyle({
                    bottom: (this.bottomOrg - I) + "px"
                })
                }
            this.setSize(H, D);
            this._notify("onResize")
            } else {
            this.pointer = A;
            if (this.useLeft) {
                var C = parseFloat(this.currentDrag.getStyle("left")) + J;
                var G = this._updateLeftConstraint(C);
                this.pointer[0] += G - C;
                this.currentDrag.setStyle({
                    left: G + "px"
                })
                } else {
                this.currentDrag.setStyle({
                    right: parseFloat(this.currentDrag.getStyle("right")) - J + "px"
                })
                }
            if (this.useTop) {
                var F = parseFloat(this.currentDrag.getStyle("top")) + I;
                var E = this._updateTopConstraint(F);
                this.pointer[1] += E - F;
                this.currentDrag.setStyle({
                    top: E + "px"
                })
                } else {
                this.currentDrag.setStyle({
                    bottom: parseFloat(this.currentDrag.getStyle("bottom")) - I + "px"
                })
                }
            this._notify("onMove")
            }
        if (this.iefix) {
            this._fixIEOverlapping()
            }
        this._removeStoreLocation();
        Event.stop(B)
        },
    _endDrag: function(A) {
        WindowUtilities.enableScreen("__invisible__");
        if (this.doResize) {
            this._notify("onEndResize")
            } else {
            this._notify("onEndMove")
            }
        Event.stopObserving(document, "mouseup", this.eventMouseUp, false);
        Event.stopObserving(document, "mousemove", this.eventMouseMove, false);
        Event.stop(A);
        this._hideWiredElement();
        this._saveCookie();
        document.body.ondrag = null;
        document.body.onselectstart = null
    },
    _updateLeftConstraint: function(B) {
        if (this.constraint && this.useLeft && this.useTop) {
            var A = this.options.parent == document.body ? WindowUtilities.getPageSize().windowWidth: this.options.parent.getDimensions().width;
            if (B < this.constraintPad.left) {
                B = this.constraintPad.left
            }
            if (B + this.width + this.widthE + this.widthW > A - this.constraintPad.right) {
                B = A - this.constraintPad.right - this.width - this.widthE - this.widthW
            }
        }
        return B
    },
    _updateTopConstraint: function(C) {
        if (this.constraint && this.useLeft && this.useTop) {
            var A = this.options.parent == document.body ? WindowUtilities.getPageSize().windowHeight: this.options.parent.getDimensions().height;
            var B = this.height + this.heightN + this.heightS;
            if (C < this.constraintPad.top) {
                C = this.constraintPad.top
            }
            if (C + B > A - this.constraintPad.bottom) {
                C = A - this.constraintPad.bottom - B
            }
        }
        return C
    },
    _updateWidthConstraint: function(A) {
        if (this.constraint && this.useLeft && this.useTop) {
            var B = this.options.parent == document.body ? WindowUtilities.getPageSize().windowWidth: this.options.parent.getDimensions().width;
            var C = parseFloat(this.element.getStyle("left"));
            if (C + A + this.widthE + this.widthW > B - this.constraintPad.right) {
                A = B - this.constraintPad.right - C - this.widthE - this.widthW
            }
        }
        return A
    },
    _updateHeightConstraint: function(B) {
        if (this.constraint && this.useLeft && this.useTop) {
            var A = this.options.parent == document.body ? WindowUtilities.getPageSize().windowHeight: this.options.parent.getDimensions().height;
            var C = parseFloat(this.element.getStyle("top"));
            if (C + B + this.heightN + this.heightS > A - this.constraintPad.bottom) {
                B = A - this.constraintPad.bottom - C - this.heightN - this.heightS
            }
        }
        return B
    },
    _createWindow: function(A) {
        var F = this.options.className;
        var D = document.createElement("div");
        D.setAttribute("id", A);
        D.className = "dialog";
        var E;
        if (this.options.url) {
            E = "<iframe frameborder=\"0\" name=\"" + A + "_content\"  id=\"" + A + "_content\" src=\"" + this.options.url + "\"> </iframe>"
        } else {
            E = "<div id=\"" + A + "_content\" class=\"" + F + "_content\"> </div>"
        }
        var G = this.options.closable ? "<div class='" + F + "_close' id='" + A + "_close' onclick='Windows.close(\"" + A + "\", event)'> </div>": "";
        var H = this.options.minimizable ? "<div class='" + F + "_minimize' id='" + A + "_minimize' onclick='Windows.minimize(\"" + A + "\", event)'> </div>": "";
        var I = this.options.maximizable ? "<div class='" + F + "_maximize' id='" + A + "_maximize' onclick='Windows.maximize(\"" + A + "\", event)'> </div>": "";
        var C = this.options.resizable ? "class='" + F + "_sizer' id='" + A + "_sizer'": "class='" + F + "_se'";
        var B = "../themes/default/blank.gif";
        D.innerHTML = G + H + I + "      <table id='" + A + "_row1' class=\"top table_window\">        <tr>          <td class='" + F + "_nw'></td>          <td class='" + F + "_n'><div id='" + A + "_top' class='" + F + "_title title_window'>" + this.options.title + "</div></td>          <td class='" + F + "_ne'></td>        </tr>      </table>      <table id='" + A + "_row2' class=\"mid table_window\">        <tr>          <td class='" + F + "_w'></td>            <td id='" + A + "_table_content' class='" + F + "_content' valign='top'>" + E + "</td>          <td class='" + F + "_e'></td>        </tr>      </table>        <table id='" + A + "_row3' class=\"bot table_window\">        <tr>          <td class='" + F + "_sw'></td>            <td class='" + F + "_s'><div id='" + A + "_bottom' class='status_bar'><span style='float:left; width:1px; height:1px'></span></div></td>            <td " + C + "></td>        </tr>      </table>    ";
        Element.hide(D);
        this.options.parent.insertBefore(D, this.options.parent.firstChild);
        Event.observe($(A + "_content"), "load", this.options.onload);
        return D
    },
    changeClassName: function(A) {
        var B = this.options.className;
        var D = this.getId();
        var C = this;
        $A(["_close", "_minimize", "_maximize", "_sizer", "_content"]).each(function(E) {
            C._toggleClassName($(D + E), B + E, A + E)
            });
        $$("#" + D + " td").each(function(E) {
            E.className = E.className.sub(B, A)
            });
        this.options.className = A
    },
    _toggleClassName: function(C, B, A) {
        if (C) {
            C.removeClassName(B);
            C.addClassName(A)
            }
    },
    setLocation: function(C, B) {
        C = this._updateTopConstraint(C);
        B = this._updateLeftConstraint(B);
        var A = this.currentDrag || this.element;
        A.setStyle({
            top: C + "px"
        });
        A.setStyle({
            left: B + "px"
        });
        this.useLeft = true;
        this.useTop = true
    },
    getLocation: function() {
        var A = {};
        if (this.useTop) {
            A = Object.extend(A, {
                top: this.element.getStyle("top")
                })
            } else {
            A = Object.extend(A, {
                bottom: this.element.getStyle("bottom")
                })
            }
        if (this.useLeft) {
            A = Object.extend(A, {
                left: this.element.getStyle("left")
                })
            } else {
            A = Object.extend(A, {
                right: this.element.getStyle("right")
                })
            }
        return A
    },
    getSize: function() {
        return {
            width: this.width,
            height: this.height
        }
    },
    setSize: function(C, B, A) {
        C = parseFloat(C);
        B = parseFloat(B);
        if (!this.minimized && C < this.options.minWidth) {
            C = this.options.minWidth
        }
        if (!this.minimized && B < this.options.minHeight) {
            B = this.options.minHeight
        }
        if (this.options.maxHeight && B > this.options.maxHeight) {
            B = this.options.maxHeight
        }
        if (this.options.maxWidth && C > this.options.maxWidth) {
            C = this.options.maxWidth
        }
        if (this.useTop && this.useLeft && Window.hasEffectLib && Effect.ResizeWindow && A) {
            new Effect.ResizeWindow(this, null, null, C, B, {
                duration: Window.resizeEffectDuration
            })
            } else {
            this.width = C;
            this.height = B;
            var E = this.currentDrag ? this.currentDrag: this.element;
            E.setStyle({
                width: C + this.widthW + this.widthE + "px"
            });
            E.setStyle({
                height: B + this.heightN + this.heightS + "px"
            });
            if (!this.currentDrag || this.currentDrag == this.element) {
                var D = $(this.element.id + "_content");
                D.setStyle({
                    height: B + "px"
                });
                D.setStyle({
                    width: C + "px"
                })
                }
        }
    },
    updateHeight: function() {
        this.setSize(this.width, this.content.scrollHeight, true)
        },
    updateWidth: function() {
        this.setSize(this.content.scrollWidth, this.height, true)
        },
    toFront: function() {
        if (this.element.style.zIndex < Windows.maxZIndex) {
            this.setZIndex(Windows.maxZIndex + 1)
            }
        this._notify("onFocus");
        if (this.iefix) {
            this._fixIEOverlapping()
            }
    },
    show: function(C) {
        if (C) {
            if (typeof this.overlayOpacity == "undefined") {
                var B = this;
                setTimeout(function() {
                    B.show(C)
                    }, 10);
                return
            }
            Windows.addModalWindow(this);
            this.modal = true;
            this.setZIndex(Windows.maxZIndex + 1);
            Windows.unsetOverflow(this)
            } else {
            if (!this.element.style.zIndex) {
                this.setZIndex(Windows.maxZIndex+++1)
                }
        }
        if (this.oldStyle) {
            this.getContent().setStyle({
                overflow: this.oldStyle
            })
            }
        if (!this.width || !this.height) {
            var A = WindowUtilities._computeSize(this.content.innerHTML, this.content.id, this.width, this.height, 0, this.options.className);
            if (this.height) {
                this.width = A + 5
            } else {
                this.height = A + 5
            }
        }
        this.setSize(this.width, this.height);
        if (this.centered) {
            this._center(this.centerTop, this.centerLeft)
            }
        this._notify("onBeforeShow");
        var D = this;
        this.options.showEffectOptions.beforeStart = D.hideThrobber;
        if (this.options.showEffect != Element.show && this.options.showEffectOptions) {
            this.options.showEffect(this.element, this.options.showEffectOptions)
            } else {
            this.options.showEffect(this.element)
            }
        this._checkIEOverlapping();
        this.visible = true;
        WindowUtilities.focusedWindow = this;
        this._notify("onShow")
        },
    hideThrobber: function() {
        if ($("overlay_modal")) {
            if ($("overlay_modal").down()) {
                $("overlay_modal").down().style.display = "none";
                if (BrowserDetect.browser == "Explorer" && BrowserDetect.version == "6") {
                    $("ieSelectFrameFix").style.display = "block"
                }
            }
        }
    },
    showCenter: function(A, C, B) {
        this.centered = true;
        this.centerTop = C;
        this.centerLeft = B;
        this.show(A)
        },
    isVisible: function() {
        return this.visible
    },
    _center: function(C, B) {
        var D = WindowUtilities.getWindowScroll();
        var A = WindowUtilities.getPageSize();
        if (typeof C == "undefined") {
            C = (A.windowHeight - (this.height + this.heightN + this.heightS)) / 2
        }
        C += D.top;
        if (typeof B == "undefined") {
            B = (A.windowWidth - (this.width + this.widthW + this.widthE)) / 2
        }
        B += D.left;
        this.setLocation(C, B);
        this.toFront()
        },
    _recenter: function(B) {
        if (this.centered) {
            var A = WindowUtilities.getPageSize();
            if (this.pageSize && this.pageSize.windowWidth == A.windowWidth && this.pageSize.windowHeight == A.windowHeight) {
                return
            }
            this.pageSize = A;
            if ($("overlay_modal")) {
                $("overlay_modal").setStyle({
                    height: (A.pageHeight + "px")
                    })
                }
            if ($("overlay_modal")) {}
            if (this.options.recenterAuto) {
                this._center(this.centerTop, this.centerLeft)
                }
        }
    },
    hide: function() {
        this.visible = false;
        if (this.modal) {
            Windows.removeModalWindow(this);
            Windows.resetOverflow()
            }
        this.oldStyle = this.getContent().getStyle("overflow") || "auto";
        this.getContent().setStyle({
            overflow: "hidden"
        });
        this.options.hideEffect(this.element, this.options.hideEffectOptions);
        if (this.iefix) {
            this.iefix.hide()
            }
        if (!this.doNotNotifyHide) {
            this._notify("onHide")
            }
    },
    close: function() {
        if (this.visible) {
            if (this.options.closeCallback && !this.options.closeCallback(this)) {
                return
            }
            if (this.options.destroyOnClose) {
                var A = this.destroy.bind(this);
                if (this.options.hideEffectOptions.afterFinish) {
                    var B = this.options.hideEffectOptions.afterFinish;
                    this.options.hideEffectOptions.afterFinish = function() {
                        B();
                        A();
                        }
                } else {
                    this.options.hideEffectOptions.afterFinish = function() {
                        A();
                        }
                }
            }
            Windows.updateFocusedWindow();
            this.doNotNotifyHide = true;
            this.hide();
            this.doNotNotifyHide = false;
            this._notify("onClose");
			
			try {
				$$('embed').each(function(embeddedFlash) {

					if(embeddedFlash.style.display == 'none') {
						embeddedFlash.show();
					}
				});
			} catch(err) {}
			
        }
    },
    minimize: function() {
        if (this.resizing) {
            return
        }
        var A = $(this.getId() + "_row2");
        if (!this.minimized) {
            this.minimized = true;
            var D = A.getDimensions().height;
            this.r2Height = D;
            var C = this.element.getHeight() - D;
            if (this.useLeft && this.useTop && Window.hasEffectLib && Effect.ResizeWindow) {
                new Effect.ResizeWindow(this, null, null, null, this.height - D, {
                    duration: Window.resizeEffectDuration
                })
                } else {
                this.height -= D;
                this.element.setStyle({
                    height: C + "px"
                });
                A.hide()
                }
            if (!this.useTop) {
                var B = parseFloat(this.element.getStyle("bottom"));
                this.element.setStyle({
                    bottom: (B + D) + "px"
                })
                }
        } else {
            this.minimized = false;
            var D = this.r2Height;
            this.r2Height = null;
            if (this.useLeft && this.useTop && Window.hasEffectLib && Effect.ResizeWindow) {
                new Effect.ResizeWindow(this, null, null, null, this.height + D, {
                    duration: Window.resizeEffectDuration
                })
                } else {
                var C = this.element.getHeight() + D;
                this.height += D;
                this.element.setStyle({
                    height: C + "px"
                });
                A.show()
                }
            if (!this.useTop) {
                var B = parseFloat(this.element.getStyle("bottom"));
                this.element.setStyle({
                    bottom: (B - D) + "px"
                })
                }
            this.toFront()
            }
        this._notify("onMinimize");
        this._saveCookie()
        },
    maximize: function() {
        if (this.isMinimized() || this.resizing) {
            return
        }
        if (window.ie && this.heightN == 0) {
            this._getWindowBorderSize()
            }
        if (this.storedLocation != null) {
            this._restoreLocation();
            if (this.iefix) {
                this.iefix.hide()
                }
        } else {
            this._storeLocation();
            Windows.unsetOverflow(this);
            var G = WindowUtilities.getWindowScroll();
            var B = WindowUtilities.getPageSize();
            var F = G.left;
            var E = G.top;
            if (this.options.parent != document.body) {
                G = {
                    top: 0,
                    left: 0,
                    bottom: 0,
                    right: 0
                };
                var D = this.options.parent.getDimensions();
                B.windowWidth = D.width;
                B.windowHeight = D.height;
                E = 0;
                F = 0
            }
            if (this.constraint) {
                B.windowWidth -= Math.max(0, this.constraintPad.left) + Math.max(0, this.constraintPad.right);
                B.windowHeight -= Math.max(0, this.constraintPad.top) + Math.max(0, this.constraintPad.bottom);
                F += Math.max(0, this.constraintPad.left);
                E += Math.max(0, this.constraintPad.top)
                }
            var C = B.windowWidth - this.widthW - this.widthE;
            var A = B.windowHeight - this.heightN - this.heightS;
            if (this.useLeft && this.useTop && Window.hasEffectLib && Effect.ResizeWindow) {
                new Effect.ResizeWindow(this, E, F, C, A, {
                    duration: Window.resizeEffectDuration
                })
                } else {
                this.setSize(C, A);
                this.element.setStyle(this.useLeft ? {
                    left: F
                }: {
                    right: F
                });
                this.element.setStyle(this.useTop ? {
                    top: E
                }: {
                    bottom: E
                })
                }
            this.toFront();
            if (this.iefix) {
                this._fixIEOverlapping()
                }
        }
        this._notify("onMaximize");
        this._saveCookie()
        },
    isMinimized: function() {
        return this.minimized
    },
    isMaximized: function() {
        return (this.storedLocation != null)
        },
    setOpacity: function(A) {
		
        if (Element.setOpacity) {
            Element.setOpacity(this.element, A)
        }

    },
    setZIndex: function(A) {
        this.element.setStyle({
            zIndex: A
        });
        Windows.updateZindex(A, this)
        },
    setTitle: function(A) {
        if (!A || A == "") {
            A = "&nbsp;"
        }
        Element.update(this.element.id + "_top", A)
        },
    setStatusBar: function(B) {
        var A = $(this.getId() + "_bottom");
        if (typeof(B) == "object") {
            if (this.bottombar.firstChild) {
                this.bottombar.replaceChild(B, this.bottombar.firstChild)
                } else {
                this.bottombar.appendChild(B)
                }
        } else {
            this.bottombar.innerHTML = B
        }
    },
    _checkIEOverlapping: function() {
        if (!this.iefix && (navigator.appVersion.indexOf("MSIE") > 0) && (navigator.userAgent.indexOf("Opera") < 0) && (this.element.getStyle("position") == "absolute")) {
            new Insertion.After(this.element.id, "<iframe id=\"" + this.element.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.element.id + "_iefix")
            }
        if (this.iefix) {
            setTimeout(this._fixIEOverlapping.bind(this), 50)
            }
    },
    _fixIEOverlapping: function() {
        Position.clone(this.element, this.iefix);
        this.iefix.style.zIndex = this.element.style.zIndex - 1;
        this.iefix.show()
        },
    _getWindowBorderSize: function(B) {
        var C = this._createHiddenDiv(this.options.className + "_n");
        this.heightN = Element.getDimensions(C).height;
        C.parentNode.removeChild(C);
        var C = this._createHiddenDiv(this.options.className + "_s");
        this.heightS = Element.getDimensions(C).height;
        C.parentNode.removeChild(C);
        var C = this._createHiddenDiv(this.options.className + "_e");
        this.widthE = Element.getDimensions(C).width;
        C.parentNode.removeChild(C);
        var C = this._createHiddenDiv(this.options.className + "_w");
        this.widthW = Element.getDimensions(C).width;
        C.parentNode.removeChild(C);
        var C = document.createElement("div");
        C.className = "overlay_" + this.options.className;
        document.body.appendChild(C);
        var A = this;
        setTimeout(function() {
            A.overlayOpacity = ($(C).getStyle("opacity"));
            C.parentNode.removeChild(C)
            }, 10);
        if (window.ie) {
            this.heightS = $(this.getId() + "_row3").getDimensions().height;
            this.heightN = $(this.getId() + "_row1").getDimensions().height
        }
        if (window.khtml && !window.webkit) {
            this.setSize(this.width, this.height)
            }
        if (this.doMaximize) {
            this.maximize()
            }
        if (this.doMinimize) {
            this.minimize()
            }
    },
    _createHiddenDiv: function(B) {
        var A = document.body;
        var C = document.createElement("div");
        C.setAttribute("id", this.element.id + "_tmp");
        C.className = B;
        C.style.display = "none";
        C.innerHTML = "";
        A.insertBefore(C, A.firstChild);
        return C
    },
    _storeLocation: function() {
        if (this.storedLocation == null) {
            this.storedLocation = {
                useTop: this.useTop,
                useLeft: this.useLeft,
                top: this.element.getStyle("top"),
                bottom: this.element.getStyle("bottom"),
                left: this.element.getStyle("left"),
                right: this.element.getStyle("right"),
                width: this.width,
                height: this.height
            }
        }
    },
    _restoreLocation: function() {
        if (this.storedLocation != null) {
            this.useLeft = this.storedLocation.useLeft;
            this.useTop = this.storedLocation.useTop;
            if (this.useLeft && this.useTop && Window.hasEffectLib && Effect.ResizeWindow) {
                new Effect.ResizeWindow(this, this.storedLocation.top, this.storedLocation.left, this.storedLocation.width, this.storedLocation.height, {
                    duration: Window.resizeEffectDuration
                })
                } else {
                this.element.setStyle(this.useLeft ? {
                    left: this.storedLocation.left
                }: {
                    right: this.storedLocation.right
                });
                this.element.setStyle(this.useTop ? {
                    top: this.storedLocation.top
                }: {
                    bottom: this.storedLocation.bottom
                });
                this.setSize(this.storedLocation.width, this.storedLocation.height)
                }
            Windows.resetOverflow();
            this._removeStoreLocation()
            }
    },
    _removeStoreLocation: function() {
        this.storedLocation = null
    },
    _saveCookie: function() {
        if (this.cookie) {
            var A = "";
            if (this.useLeft) {
                A += "l:" + (this.storedLocation ? this.storedLocation.left: this.element.getStyle("left"))
                } else {
                A += "r:" + (this.storedLocation ? this.storedLocation.right: this.element.getStyle("right"))
                }
            if (this.useTop) {
                A += ",t:" + (this.storedLocation ? this.storedLocation.top: this.element.getStyle("top"))
                } else {
                A += ",b:" + (this.storedLocation ? this.storedLocation.bottom: this.element.getStyle("bottom"))
                }
            A += "," + (this.storedLocation ? this.storedLocation.width: this.width);
            A += "," + (this.storedLocation ? this.storedLocation.height: this.height);
            A += "," + this.isMinimized();
            A += "," + this.isMaximized();
            WindowUtilities.setCookie(A, this.cookie)
            }
    },
    _createWiredElement: function() {
        if (!this.wiredElement) {
            if (window.ie) {
                this._getWindowBorderSize()
                }
            var B = document.createElement("div");
            B.className = "wired_frame " + this.options.className + "_wired_frame";
            B.style.position = "absolute";
            this.options.parent.insertBefore(B, this.options.parent.firstChild);
            this.wiredElement = $(B)
            }
        if (this.useLeft) {
            this.wiredElement.setStyle({
                left: this.element.getStyle("left")
                })
            } else {
            this.wiredElement.setStyle({
                right: this.element.getStyle("right")
                })
            }
        if (this.useTop) {
            this.wiredElement.setStyle({
                top: this.element.getStyle("top")
                })
            } else {
            this.wiredElement.setStyle({
                bottom: this.element.getStyle("bottom")
                })
            }
        var A = this.element.getDimensions();
        this.wiredElement.setStyle({
            width: A.width + "px",
            height: A.height + "px"
        });
        this.wiredElement.setStyle({
            zIndex: Windows.maxZIndex + 30
        });
        return this.wiredElement
    },
    _hideWiredElement: function() {
        if (!this.wiredElement || !this.currentDrag) {
            return
        }
        if (this.currentDrag == this.element) {
            this.currentDrag = null
        } else {
            if (this.useLeft) {
                this.element.setStyle({
                    left: this.currentDrag.getStyle("left")
                    })
                } else {
                this.element.setStyle({
                    right: this.currentDrag.getStyle("right")
                    })
                }
            if (this.useTop) {
                this.element.setStyle({
                    top: this.currentDrag.getStyle("top")
                    })
                } else {
                this.element.setStyle({
                    bottom: this.currentDrag.getStyle("bottom")
                    })
                }
            this.currentDrag.hide();
            this.currentDrag = null;
            if (this.doResize) {
                this.setSize(this.width, this.height)
                }
        }
    },
    _notify: function(A) {
        if (this.options[A]) {
            this.options[A](this)
            } else {
            Windows.notify(A, this)
            }
    }
};
var Windows = {
    windows: [],
    modalWindows: [],
    observers: [],
    focusedWindow: null,
    maxZIndex: 0,
    overlayShowEffectOptions: {
        duration: 0.5
    },
    overlayHideEffectOptions: {
        duration: 0.5
    },
    addObserver: function(A) {
        this.removeObserver(A);
        this.observers.push(A)
        },
    removeObserver: function(A) {
        this.observers = this.observers.reject(function(B) {
            return B == A
        })
        },
    notify: function(A, B) {
        this.observers.each(function(C) {
            if (C[A]) {
                C[A](A, B)
                }
        })
        },
    getWindow: function(A) {
        return this.windows.detect(function(B) {
            return B.getId() == A
        })
        },
    getFocusedWindow: function() {
        return this.focusedWindow
    },
    updateFocusedWindow: function() {
        this.focusedWindow = this.windows.length >= 2 ? this.windows[this.windows.length - 2] : null
    },
    register: function(A) {
        this.windows.push(A)
        },
    addModalWindow: function(B) {
        var A = !B.options.showLoading;
        if (this.modalWindows.length == 0) {
            if (A === true) {
                WindowUtilities.disableScreen(B.options.className, "overlay_modal", B.overlayOpacity, B.getId())
                }
        } else {
            if (Window.keepMultiModalWindow) {
                $("overlay_modal").style.zIndex = Windows.maxZIndex + 1;
                Windows.maxZIndex += 1;
                WindowUtilities._hideSelect(this.modalWindows.last().getId())
                } else {
                this.modalWindows.last().element.hide()
                }
            WindowUtilities._showSelect(B.getId())
            }
        this.modalWindows.push(B)
        },
    removeModalWindow: function(A) {
        this.modalWindows.pop();
        if (this.modalWindows.length == 0) {
            WindowUtilities.enableScreen()
            } else {
            if (Window.keepMultiModalWindow) {
                this.modalWindows.last().toFront();
                WindowUtilities._showSelect(this.modalWindows.last().getId())
                } else {
                this.modalWindows.last().element.show()
                }
        }
    },
    register: function(A) {
        this.windows.push(A)
        },
    unregister: function(A) {
        this.windows = this.windows.reject(function(B) {
            return B == A
        })
        },
    closeAll: function() {
        this.windows.each(function(A) {
            Windows.close(A.getId())
            })
        },
    closeAllModalWindows: function() {
        WindowUtilities.enableScreen();
        this.modalWindows.each(function(A) {
            if (A) {
                A.close()
                }
        })
        },
    minimize: function(C, A) {
        var B = this.getWindow(C);
        if (B && B.visible) {
            B.minimize()
            }
        Event.stop(A)
        },
    maximize: function(C, A) {
        var B = this.getWindow(C);
        if (B && B.visible) {
            B.maximize()
            }
        Event.stop(A)
        },
    close: function(C, A) {
        var B = this.getWindow(C);
        if (B) {
            B.close()
            }
        if (A) {
            Event.stop(A)
            }
    },
    unsetOverflow: function(A) {
        this.windows.each(function(B) {
            B.oldOverflow = B.getContent().getStyle("overflow") || "auto";
            B.getContent().setStyle({
                overflow: "hidden"
            })
            });
        if (A && A.oldOverflow) {
            A.getContent().setStyle({
                overflow: A.oldOverflow
            })
            }
    },
    resetOverflow: function() {
        this.windows.each(function(A) {
            if (A.oldOverflow) {
                A.getContent().setStyle({
                    overflow: A.oldOverflow
                })
                }
        })
        },
    updateZindex: function(A, B) {
        if (A > this.maxZIndex) {
            this.maxZIndex = A
        }
        this.focusedWindow = B
    }
};
var Dialog = {
    dialogId: null,
    onCompleteFunc: null,
    callFunc: null,
    parameters: null,
    confirm: function(D, C) {
        if (D && typeof D != "string") {
            Dialog._runAjaxRequest(D, C, Dialog.confirm);
            return
        }
        D = D || "";
        C = C || {};
        var F = C.okLabel ? C.okLabel: "Ok";
        var A = C.cancelLabel ? C.cancelLabel: "Cancel";
        C = Object.extend(C, C.windowParameters || {});
        C.windowParameters = C.windowParameters || {};
        C.className = C.className || "alert";
        var B = "class ='" + (C.buttonClass ? C.buttonClass + " ": "") + " ok_button'";
        var E = "class ='" + (C.buttonClass ? C.buttonClass + " ": "") + " cancel_button'";
        var D = "      <div class='" + C.className + "_message'>" + D + "</div>        <div class='" + C.className + "_buttons'>          <input type='button' value='" + F + "' onclick='Dialog.okCallback()' " + B + "/>          <input type='button' value='" + A + "' onclick='Dialog.cancelCallback()' " + E + "/>        </div>    ";
        return this._openDialog(D, C)
        },
    alert: function(C, B) {
        if (C && typeof C != "string") {
            Dialog._runAjaxRequest(C, B, Dialog.alert);
            return
        }
        C = C || "";
        B = B || {};
        var D = B.okLabel ? B.okLabel: "Ok";
        B = Object.extend(B, B.windowParameters || {});
        B.windowParameters = B.windowParameters || {};
        B.className = B.className || "alert";
        var A = "class ='" + (B.buttonClass ? B.buttonClass + " ": "") + " ok_button'";
        var C = "      <div class='" + B.className + "_message'>" + C + "</div>        <div class='" + B.className + "_buttons'>          <input type='button' value='" + D + "' onclick='Dialog.okCallback()' " + A + "/>        </div>";
        return this._openDialog(C, B)
        },
    info: function(H, K) {
        if (H && typeof H != "string") {
            if (K.windowParameters.showLoading === true) {
                if ($("overlay_modal")) {
                    $("overlay_modal").style.display = "block";
                    var G = $("overlay_modal").down();
                    var J = WindowUtilities.getWindowScroll();
                    var I = WindowUtilities.getPageSize();
                    var F = J.top + I.windowHeight / 2;
                    var A = J.left + I.windowWidth / 2;
                    G.style.top = F + "px";
                    G.style.left = A + "px";
                    G.style.display = "block"
                } else {
                    var E = document.createElement("div");
                    E.id = "overlay_modal";
                    E.className = "overlay_" + K.windowParameters.className;
                    E.style.position = "absolute";
                    E.style.top = "0px";
                    E.style.left = "0px";
                    E.style.width = "100%";
                    E.style.opacity = 0.6;
                    E.style.zIndex = 20;
                    E.style.display = "none";
                    E.overlayOpacity = 0.6;
                    var D = WindowUtilities.getPageSize().pageHeight + "px";
                    E.style.height = D;
                    var G = document.createElement("img");
                    G.style.position = "absolute";
                    G.src = "/assets/images/ajax-loader-big.gif";
                    E.appendChild(G);

					if(arguments[2] != "affirmation") {
						  if (BrowserDetect.browser == "Explorer" && BrowserDetect.version == "6") {
		                        var B = document.createElement("<iframe>");
		                        B.id = "ieSelectFrameFix";
		                        B.style.display = "none";
		                        E.appendChild(B)
		                    }	
					} 

                    document.body.appendChild(E);
                    var J = WindowUtilities.getWindowScroll();
                    var I = WindowUtilities.getPageSize();
                    var F = J.top + I.windowHeight / 2;
                    var A = J.left + I.windowWidth / 2;
                    G.style.top = F + "px";
                    G.style.left = A + "px";
                    E.style.display = "block"
                }
            }
            Dialog._runAjaxRequest(H, K, Dialog.info);
            return;
        }
        H = H || "";
        K = K || {};
        K = Object.extend(K, K.windowParameters || {});
        K.windowParameters = K.windowParameters || {};
        K.className = K.className || "alert";
        var H = "<div id='modal_dialog_message' class='" + K.className + "_message'>" + H + "</div>";
        if (K.showProgress) {
            H += "<div id='modal_dialog_progress' class='" + K.className + "_progress'>  </div>"
        }
        K.ok = null;
        K.cancel = null;
        var C = this._openDialog(H, K);
        return C
    },
    closeInfo: function() {
		try {
			$$('embed').each(function(embeddedFlash) {
				
				if(embeddedFlash.style.display == 'none') {
					embeddedFlash.show();
				}
			});
		} catch(err) {}
        Windows.close(this.dialogId)
    },
    _openDialog: function(E, D) {
		//Try to hide all Flash pieces.
		try {
			$$('embed').each(function(embeddedFlash) {
						//embeddedFlash.hide();
			});
		} catch(err) {}
        var C = D.className;
        if (!D.height && !D.width) {
            D.width = WindowUtilities.getPageSize().pageWidth / 2
        }
        if (D.id) {
            this.dialogId = D.id
        } else {
            var B = new Date();
            this.dialogId = "modal_dialog_" + B.getTime();
            D.id = this.dialogId
        }
        if (!D.height || !D.width) {
            var A = WindowUtilities._computeSize(E, this.dialogId, D.width, D.height, 5, C);
            if (D.height) {
                D.width = A + 5
            } else {
                D.height = A + 5
            }
        }
        D.resizable = D.resizable || false;
        D.effectOptions = D.effectOptions;
        D.minimizable = false;
        D.maximizable = false;
        D.draggable = false;
        var F = new Window(D);
        F.getContent().innerHTML = E;
        F.showCenter(true, D.top, D.left);
        F.setDestroyOnClose();
        F.cancelCallback = D.onCancel || D.cancel;
        F.okCallback = D.onOk || D.ok;
        return F
    },
    _getAjaxContent: function(A) {
        Dialog.callFunc(A.responseText, Dialog.parameters)
        },
    _runAjaxRequest: function(C, B, A) {
        if (C.options == null) {
            C.options = {}
        }
        Dialog.onCompleteFunc = C.options.onComplete;
        Dialog.parameters = B;
        Dialog.callFunc = A;
        C.options.onComplete = Dialog._getAjaxContent;
        new Ajax.Request(C.url, C.options)
        },
    okCallback: function() {
		try {
			$$('embed').each(function(embeddedFlash) {
				//console.log("yo");
				if(embeddedFlash.style.display == 'none') {
					embeddedFlash.show();
				}
			});
		} catch(err) {}
		
        var A = Windows.focusedWindow;
        if (!A.okCallback || A.okCallback(A)) {
            $$("#" + A.getId() + " input").each(function(B) {
                B.onclick = null
            });
            A.close()
            }
    },
    cancelCallback: function() {
		try {
			$$('embed').each(function(embeddedFlash) {
				
				if(embeddedFlash.style.display == 'none') {
					embeddedFlash.show();
				}
			});
		} catch(err) {}
	
        var A = Windows.focusedWindow;
        $$("#" + A.getId() + " input").each(function(B) {
            B.onclick = null
        });
        A.close();
        if (A.cancelCallback) {
            A.cancelCallback(A)
            }
    }
};
if (window.ActiveXObject) {
    window.ie = window[window.XMLHttpRequest ? "ie7": "ie6"] = true
} else {
    if (document.childNodes && !document.all && !navigator.taintEnabled) {
        window.khtml = true
    } else {
        if (document.getBoxObjectFor != null) {
            window.gecko = true
        }
    }
}
var array = navigator.userAgent.match(new RegExp(/AppleWebKit\/([\d\.\+]*)/));
window.webkit = array && array.length == 2 ? parseFloat(array[1]) >= 420: false;
var WindowUtilities = {
    getWindowScroll: function() {
        var C = window;
        var D,
        B,
        A,
        E;
        B = window.pageXOffset || document.documentElement.scrollLeft;
        D = window.pageYOffset || document.documentElement.scrollTop;
        if (window.ie) {
            A = Math.max(document.documentElement.offsetWidth, document.documentElement.scrollWidth)
            } else {
            if (window.khtml) {
                A = document.body.scrollWidth
            } else {
                A = document.documentElement.scrollWidth
            }
        }
        if (window.ie) {
            E = Math.max(document.documentElement.offsetHeight, document.documentElement.scrollHeight)
            } else {
            if (window.khtml) {
                E = document.body.scrollHeight
            } else {
                E = document.documentElement.scrollHeight
            }
        }
        return {
            top: D,
            left: B,
            width: A,
            height: E
        }
    },
    getPageSize: function() {
        var E,
        A;
        if (window.innerHeight && window.scrollMaxY) {
            E = document.body.scrollWidth;
            A = window.innerHeight + window.scrollMaxY
        } else {
            if (document.body.scrollHeight > document.body.offsetHeight) {
                E = document.body.scrollWidth;
                A = document.body.scrollHeight
            } else {
                E = document.body.offsetWidth;
                A = document.body.offsetHeight
            }
        }
        var C,
        F;
        if (self.innerHeight) {
            C = self.innerWidth;
            F = self.innerHeight
        } else {
            if (document.documentElement && document.documentElement.clientHeight) {
                C = document.documentElement.clientWidth;
                F = document.documentElement.clientHeight
            } else {
                if (document.body) {
                    C = document.body.clientWidth;
                    F = document.body.clientHeight
                }
            }
        }
        var D,
        B;
        if (A < F) {
            D = F
        } else {
            D = A
        }
        if (E < C) {
            B = C
        } else {
            B = E
        }
        return {
            pageWidth: B,
            pageHeight: D,
            windowWidth: C,
            windowHeight: F
        }
    },
    disableScreen: function(B, A, D, E) {
        var C = this;
        WindowUtilities.initLightbox(A, B, function() {
            C._disableScreen(B, A, D, E)
            })
        },
    _disableScreen: function(D, C, F, G) {
        var B = document.body;
        var E = $(C);
        var A = WindowUtilities.getPageSize();
        if (G && window.ie) {
            WindowUtilities._hideSelect();
            WindowUtilities._showSelect(G)
            }
       // E.style.height = (A.pageHeight + "px");
		if( (BrowserDetect.browser == "Explorer" && BrowserDetect.version == 6) ) {
			if( (window.location.href).match("/findacentre/locations/us") ) {
				try {
					var vheight = 1500 + "px";

					var page = $$('html')[0];
					page.style.overflow = "hidden";
				} catch(err) {}
				
			} else {
				var vheight = A.pageHeight + "px";
			}
			
			
		} else {
			var vheight = A.pageHeight + "px";
		}
		
        E.style.height = vheight;

		E.style.display = "none";
        if (C == "overlay_modal" && Window.hasEffectLib && Windows.overlayShowEffectOptions) {
            E.overlayOpacity = F;
            new Effect.Appear(E, Object.extend({
                from: 0,
                to: F
            }, Windows.overlayShowEffectOptions))
            } else {
            E.style.display = "block"
        }
    },
    enableScreen: function(B) {
        B = B || "overlay_modal";
        var A = $(B);
        if (A) {
            if (B == "overlay_modal" && Window.hasEffectLib && Windows.overlayHideEffectOptions) {
                new Effect.Fade(A, Object.extend({
                    to: 0
                }, Windows.overlayHideEffectOptions))
                } else {
                A.style.display = "none";
                A.parentNode.removeChild(A)
                }
            if (B != "__invisible__") {
                WindowUtilities._showSelect()
                }
			if( (BrowserDetect.browser == "Explorer" && BrowserDetect.version == 6) ) {
				if( (window.location.href).match("/findacentre/locations/us") ) {
					try {
						var page = $$('html')[0];
						page.style.overflow = "scroll";
					} catch(err){}
					
				}
			} 
				
        }
    },
    _hideSelect: function(A) {
        if (window.ie) {
            A = A == null ? "": "#" + A + " ";
            $$(A + "select").each(function(B) {
                if (!WindowUtilities.isDefined(B.oldVisibility)) {
                    B.oldVisibility = B.style.visibility ? B.style.visibility: "visible";
                    B.style.visibility = "hidden"
                }
            })
            }
    },
    _showSelect: function(A) {
        if (window.ie) {
            A = A == null ? "": "#" + A + " ";
            $$(A + "select").each(function(B) {
                if (WindowUtilities.isDefined(B.oldVisibility)) {
                    try {
                        B.style.visibility = B.oldVisibility
                    } catch(C) {
                        B.style.visibility = "visible"
                    }
                    B.oldVisibility = null
                } else {
                    if (B.style.visibility) {
                        B.style.visibility = "visible"
                    }
                }
            })
            }
    },
    isDefined: function(A) {
        return typeof(A) != "undefined" && A != null
    },
    initLightbox: function(E, C, B) {
        if ($(E)) {
            Element.setStyle(E, {
                zIndex: Windows.maxZIndex + 1
            });
            Windows.maxZIndex++;
            B()
            } else {
            var A = document.body;
            var D = document.createElement("div");
            D.setAttribute("id", E);
            D.className = "overlay_" + C;
            D.style.display = "none";
            D.style.position = "absolute";
            D.style.top = "0";
            D.style.left = "0";
            D.style.zIndex = Windows.maxZIndex + 1;
            Windows.maxZIndex++;
            D.style.width = "100%";
            A.insertBefore(D, A.firstChild);
            if (window.khtml && E == "overlay_modal") {
                setTimeout(function() {
                    B()
                    }, 10)
                } else {
                B()
                }
        }
    },
    setCookie: function(B, A) {
        document.cookie = A[0] + "=" + escape(B) + ((A[1]) ? "; expires=" + A[1].toGMTString() : "") + ((A[2]) ? "; path=" + A[2] : "") + ((A[3]) ? "; domain=" + A[3] : "") + ((A[4]) ? "; secure": "")
        },
    getCookie: function(C) {
        var B = document.cookie;
        var E = C + "=";
        var D = B.indexOf("; " + E);
        if (D == -1) {
            D = B.indexOf(E);
            if (D != 0) {
                return null
            }
        } else {
            D += 2
        }
        var A = document.cookie.indexOf(";", D);
        if (A == -1) {
            A = B.length
        }
        return unescape(B.substring(D + E.length, A))
        },
    _computeSize: function(E, A, B, G, D, F) {
        var I = document.body;
        var C = document.createElement("div");
        C.setAttribute("id", A);
        C.className = F + "_content";
        if (G) {
            C.style.height = G + "px"
        } else {
            C.style.width = B + "px"
        }
        C.style.position = "absolute";
        C.style.top = "0";
        C.style.left = "0";
        C.style.display = "none";
        C.innerHTML = E;
        I.insertBefore(C, I.firstChild);
        var H;
        if (G) {
            H = $(A).getDimensions().width + D
        } else {
            H = $(A).getDimensions().height + D
        }
        I.removeChild(C);
        return H
    }
};var ExperienceFlash = function() {
  var _ = {
    interactive_url : '/customer/ajax/interactive_flash/index.jsp',
    interactive_height : 530,
    interactive_width : 668,
	opened_at : null
  };
  
  return {
    isFirefoxMac: function() {
      return (/Mozilla/.test(navigator.userAgent)) && (/Macintosh/.test(navigator.userAgent));
    }(),
    
    firefoxMacEffectOptions: {
       afterFinish: function() {
		try
		{
			$$('.overlay_ffmac').first().style['opacity'] = 1;
	          $$('.dialog').first().style['opacity'] = 1;
	          $$('.dialog').first().style['paddingTop'] = "5px";
		}
		catch(err){}
          
       }
    },
	effectOptions: {
       afterFinish: function() {
          $$('.dialog').first().style['paddingTop'] = "5px";
       }
    },
    interactive_close : function() {
	   
      // hide the placeholder image
      $('tabbed_experience_placeholder').hide();


      // show the progress tracker
      $('tabbed_experience').show();
	  $('tabbed_experience').style.background= "none";
	  
	  
	  // hide the interactive piece Safari fix
	  $('interactive_experience').hide();

      var secondsOpened = (new Date().getTime() - _.opened_at) / 1000;
      Metrics.closeExperienceFlash(Math.round(secondsOpened));
      
      Windows.close(Windows.focusedWindow.getId());
    },
    
    interactive_open : function() {
	
	console.info("setTimeout for flash");
	setTimeout(function() {	

      Metrics.track("pageview", { pageName: 'Interactive Flash', action: 'Open' });
    
      // set the time interactive_open was called
      _.opened_at = new Date().getTime();
      
       // hide the progress tracker
    	$('tabbed_experience').hide();
	
    	// show the placeholder image
    	$('tabbed_experience_placeholder').show();

      if(Windows.windows.length != 0) return;

      var interactive_modal = Dialog.info({
  		  url: _.interactive_url
      }, {
        windowParameters: {
          className: (ExperienceFlash.isFirefoxMac ? 'ffmac ' : '') + 'modal_experience',
          showEffectOptions: ExperienceFlash.isFirefoxMac ? ExperienceFlash.firefoxMacEffectOptions : ExperienceFlash.effectOptions,
          closable: false,
          width: _.interactive_width,
          height: _.interactive_height,
		  destroyOnClose: true,
          showLoading: true
        }
      });
	
	}, 1000);
	  
    },
    
    tabbed : function(element) {
      if (!$(element)._flashEmbedded) {		
		$('flashLoader').hide();
        var so = new SWFObject("/assets/flash/homepage_feature/jc_homepage.swf", "tabbed_experience_flash", "531", "233", "8", "#FFF");
  //      so.addVariable("backgroundColor", "#a7c8d4");
        so.addVariable("loopDelay", "6000");
        so.addVariable("cycleDelay", "10000");
        so.addVariable("xmlURL", "/assets/flash/homepage_feature/swf_homepage.xml");
        so.addParam("wmode", "opaque");
        so.addParam("scale", "exactfit");
        so.write("tabbed_experience");
        element._flashEmbedded = true;

		$('tabbed_experience').style.background= "url(/assets/images/intros/home/interactive_noflash.jpg)";

		
      }
    },
    
    interactive : function(element) {
      if (!$(element)._flashEmbedded) {
       var so = new SWFObject("/assets/flash/interactive_piece/flash/experience.swf", "interactive_experience_flash", _.interactive_width, _.interactive_height, "8", "#FFF");
        //so.addVariable("marginTop", "10px");
        so.addVariable("loopDelay", "6000");
        so.addVariable("cycleDelay", "10000");
        so.addVariable("CONFIG_FILE", "/customer/callback/flashmodule/experienceConfig.jsp");

		
		try
		{
			if ($('inputTabId')) {
				var tabId = $('inputTabId').value;
				
			} else if (inputTabId) {
				var tabId = inputTabId;
				inputTabId = null;
			}
			if(tabId!=null) {
				if (tabId >= 3) {
					so.addVariable("SECTION", 0);
				} else {
				
					so.addVariable("SECTION", tabId);
				}
				tabId = null;	
			} else {
				so.addVariable("SECTION", 0);
			}
			
			so.addVariable("CATEGORY", inputCategoryId);
			inputCategoryId = null;
			
			so.addVariable("TOPIC", inputTopicId);
			inputTopicId = null;
						
			if (inputReferralLink) {
				so.addVariable("REFERRAL_LINK", inputReferralLink);
				inputReferralLink = null;
			}
			
		}
		catch(err)
		{
			
		}
		
		
		so.addVariable("DATA_PATH", "/assets/flash/interactive_piece/");
        so.addParam("scale", "noscale");
		
        so.write("interactive_experience");
        element._flashEmbedded = true;
      }
    }
  };
}();

var inputTabId;
var inputCategoryId;
var inputTopicId;
var inputReferralLink;

function openExperienceLocation(section, category, topic, referralLink){
	inputTabId = section;
	inputCategoryId = category;
	inputTopicId = topic;
	inputReferralLink = referralLink;
	ExperienceFlash.interactive_open();
}

// openExperienceLocation(0, 0, 0, "external deep linking referral test");
//  usage:  openExperienceLocation(tab#, category#, topic#, "omniture tracking string");
//  the omniture tracking string should be something like: "Food > Breakfast > Featured", or wherever the button is you are
//  calling this function from.


var tertNavTimer = 0;

// Handy cloning of objects
Object.extend(Object, { deepClone: function(object) {
  var objectClone = new object.constructor();
  for (var property in object)
    if (typeof object[property] == 'object' && object[property] != null)
      objectClone[property] = Object.deepClone(object[property]);
    else
      objectClone[property] = object[property];
  return objectClone;
  }
});

// Add a function that merges two objects like Object.extend
// but doesn't modify the base, only a copy of the base
Object.merge = function(base, additions) {
  var copy_of_base = Object.deepClone(base);
  for (var property in additions) {
    copy_of_base[property] = additions[property];
  }
  return copy_of_base;
};

//Bake in an offset for the modal windows
Window.prototype._center = function(top, left) {
  var windowScroll = WindowUtilities.getWindowScroll();
  var pageSize = WindowUtilities.getPageSize();

  if (!top)
    top = (pageSize.windowHeight - (this.height + this.heightN + this.heightS))/2;
  top += windowScroll.top;

  if (!left)
    left = (pageSize.windowWidth - (this.width + this.widthW + this.widthE))/2 - 10; /* magic offset */
  left += windowScroll.left;

  this.setLocation(top, left);
  this.toFront();
};

// Set the highest zIndex of the site
// so that the windows might stack on top of that
Windows.maxZIndex = 20;

// Handy Autotabbing function for forms
var isNN = (navigator.appName.indexOf("Netscape")!=-1);
function autoTab(input, tabAfterLength, event) {
   var keyCode = (isNN) ? event.which : event.keyCode;
   var filter = (isNN) ? [0,8,9] : [0,8,9,16,17,18,37,38,39,40,46];
   if(input.value.length >= tabAfterLength && filter.indexOf(keyCode) == -1) {
      input.value = input.value.slice(0, tabAfterLength);

      // focus the next input (but not if it's a hidden input)
      var allFormElements = input.form.descendants();
      var nextInput = null;
      for(var index = allFormElements.indexOf(input) + 1, len = allFormElements.length; index < len; index++) {
         var candidateElement = allFormElements[index];
         if(candidateElement.tagName.toLowerCase() != 'input') continue;
         if(candidateElement.type.toLowerCase() != 'hidden') {
            nextInput = candidateElement;
            break;
         }
      }
      if(nextInput) nextInput.focus();
   }
}

// Set up some functions for the Experience Piece
ExperiencePiece = {
   popup:{
      open: function() {alert('experience piece opened'); }
   }
};

var InputUpdater = function(element) {
  var button_number = 0;
  var replaceButton = function(old_element, type) {
    button_number++;

     var form = old_element.form;
	 //added code 6/23/2008 to prevent replacing buttons that have no name or id - prevents polldaddy buttons from getting removed
	 if (old_element.name.length <= 0 && old_element.id.length <= 0  ) {
		 return old_element;
	 }
	
     if(type == 'image') {
        var newElementMarkup = '<input type="image" id="new_image_button_' + button_number + '" name="'+old_element.name+'" tabindex="1" />';
     } else {
        var newElementMarkup = '<a class="fcInput" id="new_image_button_' + button_number + '" name="'+old_element.name+'" tabindex="1"></a>';
     }

     new Insertion.Before(old_element, newElementMarkup);
     var new_element = $('new_image_button_' + button_number);

     // if this used to be a reset button, hook up the reset functionality
     if(old_element.type.toUpperCase() == 'RESET') {
        new_element.onclick = function() { form.reset(); 
		
		};
     }

	
     $A(old_element.attributes).each(function(att) {
        if(att.nodeName.toUpperCase() != 'TYPE') {
           new_element.setAttribute(att.nodeName.toUpperCase(), att.nodeValue);
        }
     });

     var imageName = old_element.value.toLowerCase().gsub(/ /, '_');

     // hack for different buttons
     if(old_element.id == 'login_cancel') imageName += '_red';
	 if(old_element.id == 'password_retrieval_cancel') imageName += '_red2';	
     if(old_element.id == 'find_centre_submit') imageName += '_w66';
     if(old_element.id == 'find_centre_cancel') imageName += '_w66';
     if(old_element.id == 'new_activity_submit') imageName += '_w66';
     if(old_element.id == 'affirmation_create_submit') imageName += '_w66';
	 if(old_element.id == 'affirmation_delete_submit') imageName += '_yellow';
     if(old_element.id == 'affirmation_edit_submit') imageName += '_w66';
	 if(old_element.id == 'get_my_coupon') imageName += '_getmycoupon';
	 if(old_element.id == 'ql_submit') imageName += '_ql';
	 if(old_element.id == 'giantcallmenow') imageName += 'giant';
	 if(old_element.id == 'registration_submit') imageName = 'register_button';

     // replace with image
     var newSource = '/assets/images/interface/forms/submit_buttons/' + imageName + '.png';

     if(type == 'image') {
        new_element.src = newSource;
     } else {
        new Insertion.Top(new_element, '<img src="'+newSource+'" class="' + old_element.id +'_img" />');
     }

     // set the new element's id
     new_element.id = old_element.id;

     // remove the element and remember that it existed
     old_element.remove();

     // return the new button
     return new_element;
  };

  // replace all submit buttons with graphical submits
  // using their "value" as the key to find the image
  if(element.type.toUpperCase() == 'SUBMIT') {
  	var replacedButton = replaceButton(element, 'image');

	 	// hack for IE
		if(/MSIE/.test(navigator.userAgent) != false) {
			var hiddenImageSubmitTag = '<input type="hidden" name="'+element.name+'" value="true" />';
			replacedButton.onclick = function() {
        new Insertion.Before(replacedButton, hiddenImageSubmitTag);

		};
	}
  } else if(element.type.toUpperCase() == 'RESET' || element.type.toUpperCase() == 'BUTTON') {
    var replacedButton = replaceButton(element, 'anchor');
  }
};

var behaviors = {

// Adding items for interactive flash piece

	'#showInteractive' : function(element) {
		ExperienceFlash.interactive_open();
	},

//   '#tabbed_experience' : ExperienceFlash.tabbed,
   
   '#interactive_experience' : ExperienceFlash.interactive,
   
   '#interactive_experience_close a:click' : ExperienceFlash.interactive_close,


// End interactive flash piece behavior additions
	

   'body' : function(element) {
      // Force a nice bottom margin
      if(!$('bottomSpacer'))
         new Insertion.Bottom(element, '<div id="bottomSpacer" style="height: 75px; clear: left;"></div>');
   },

   '#content' : function(element) {
      if(typeof $$('#content .topCap').first() == 'undefined' && (/MSIE 6/.test(navigator.userAgent) == false))
         new Insertion.Top(element, '<div class="topCap"></div>');
   },

   '#sidebar' : function(element) {
      if(typeof $$('#sidebar .bottomCap').first() == 'undefined' && (/MSIE 6/.test(navigator.userAgent) == false))
         new Insertion.Bottom(element, '<div class="bottomCap"></div>');
   },

   'input' : InputUpdater,

   'input.date_picker' : function() {
      datePickerController.create();
   },

   '.columns' : function(element) {
      var stripBreaksFromBeginning = function(columnWords) {
         for (var index = 0, len = columnWords.length; index < len; ++index) {
           var item = columnWords[index];

           if(item == '' || item == "\n" || item.indexOf('<br>') > -1) {
             columnWords[index] = '';
           } else {
             break;
           }
         }
         return columnWords;
      };

      var theText = element.innerHTML;
      var words = theText.split(' ');
      var wordCount = words.length;

      if(element.hasClassName('three')) {
         var columns = 3;
      } else if(element.hasClassName('two')) {
         var columns = 2;
      } else {
         var columns = 1;
      }

      var textColumns = new Array();

      words.eachSlice(Math.ceil(wordCount / columns), function(slice) {
         textColumns.push('<p>' + stripBreaksFromBeginning(slice).join(' ') + '</p>');
      });
      new Insertion.Before(element, '<div class="' + element.classNames() + '">' + textColumns.join('') + '</div>');

      element.remove();
   },

   //'.printArticleButton:click' : function(element, evt) {
  //    window.print();
   //   Event.stop(evt);
  // },

   '#jenny_direct:change' : function(element, evt) {
       chooseCentreDirect(element);
   },

   '#centre_member:change' : function(element, evt) {
       chooseCentreDirect(element);
   },

   '#jenny_direct_reg:change, #jenny_direct_reg:click' : function(element, evt) {
       chooseCentreDirectReg(element);
   },

   '#centre_member_reg:change, #centre_member_reg:click' : function(element, evt) {
       chooseCentreDirectReg(element);
   },

   'ul.accordion a.more:click' : function(element, evt) {
	    // Check if timer has started
	
		element = $(element);

		try
		{
			if(tertNavTimer!=0) {
				Event.stop(evt);
			} else {
									
				// Verifying if the menu item has a link. If not, just expand / collapse the menu.
				if (element.href.charAt(element.href.length-1) != '#') {
					 var leftTargetRegion = 10;
		
					 // Menu item is a link. Only expand the menu is the user clicked on the Plus or minus box.
					 if($R(Position.page(element)[0], Position.page(element)[0] + leftTargetRegion).include(Event.pointerX(evt))) {
						 // the user clicked on the +/- (open up the section)
						tertNavTimer = 1;
						menuAction(element, evt);
						var Timer = setTimeout("tertNavTimer = 0", 700);							
				 	 }
				 } else {
						// The menu link hasn't a landing page. Just expand or collapse the menu.
						tertNavTimer = 1;
						menuAction(element, evt);
						var Timer = setTimeout("tertNavTimer = 0", 700);	
				 }	
			}			
		} 
		catch(err) 
		{
			
		}


   },
	'a.showReceiptLogin' : function(element) {
		element.onclick = function(element, evt) {
			setTimeout(function() {
				new Effect.BlindDown($('receiptLogin'));
				return false;
			}, 1000);
		};
	},
	'a.showReceipt' : function(element) {
		element.onclick = function(element, evt) {
			setTimeout(function() {
				if ($('centre_member_reg').checked) {
					new Effect.BlindDown($('receiptProgramDetails'));
				} else {
					new Effect.BlindDown($('receiptProgramDetailsJD'));
				}			
				return false;
			}, 500);
			return false;
		};
	},
	   '.input_only_integers' : function(element, evt){
         element.onblur = element.onkeypress = function(){
			if(!(/^\d+$/.test(element.value))) {
				element.value = '';
			}
		};

   },
   '#callMeFlash' : function(element){
		if (!element._flashEmbedded) {

   	  		var cm = new SWFObject("/assets/flash/homepage_feature/instantcallback.swf", "Instant callback", "211", "42", "8", "#F00");
			cm.addParam("wmode", "transparent");
			//cm.addParam("autostart", "true");
			cm.addParam("loop", "true");
			cm.write(element.id);
        	element._flashEmbedded = true;
      	}

   },
   'div.promoButton:click' : function(element, evt) {
		var node_id = (element.parentNode.id != '') ? element.parentNode.id : element.parentNode.parentNode.id;
		var target = $(element.parentNode.id + '_link').target;
		if (target == "_self") {
   			window.document.location = $(node_id + '_link').href;
   		} else {
   			window.open($(node_id + '_link').href);
   		}
   },
   'div.promoButton:mouseover' : function(element, evt) {
		var node_id = (element.parentNode.id != '') ? element.parentNode.id : element.parentNode.parentNode.id;
		document.body.style['cursor'] = 'pointer';
   		window.status = $(element.parentNode.id + '_link').href;
   		return true;
   } ,
   'div.promoButton:mouseout' : function(element, evt) {
   		document.body.style['cursor'] = 'default';
   		window.status = '';
   		return true;
   } 
};

function chooseCentreDirect(radio)
{
	var centerNum = $('login_centre_number');
	centerNum.disabled =! centerNum.disabled;
}

function chooseCentreDirectReg(radio)
{
	if ($('centre_member_reg').checked) {
		$('centre_number').show();
		$('receiptProgramDetailsJD').hide();
		$('receiptProgramDetails').hide();
	} else {
		$('centre_number').hide();
		$('receiptProgramDetailsJD').hide();
		$('receiptProgramDetails').hide();
	}

	/*
	var centerNum = $('login_centre_number_reg');
	centerNum.disabled=!centerNum.disabled;
	*/
	/*
	var showCentreForm = $('centre_number');
      if($('centre_member_reg').checked) {
      	showCentreForm.show();
      }
      else {
      	showCentreForm.hide();
      }
      if ($('jenny_direct_reg').checked) {
      	showCentreForm.hide();
      } else {
        showCentreForm.show();
      }
	*/
}

function menuAction(element, evt)
{
	
	var effectOptions = {
		duration: 0.25
	};
	
	var parent = element.parentNode;
	var isJennySpecialMenu = false;
	// This loop will look if the menu item is part of myJennyModule which menu has a different behavior.
	// It switch menu item background when the sub menu is open / close.
	while(parent != document.body) {
		if (parent.id == 'myJennyModule') {
			isJennySpecialMenu = true;
			break;
		} else {
			parent = parent.parentNode;
		}
	}
	
	if(element.hasClassName('open')) {
		
		
		// Close the panel
		Effect.BlindUp(element.next(), effectOptions);
		element.removeClassName('open');
	
		//This special menu behavior is used only for that section. Otherwise it follows tertiary navigation standards
		if(isJennySpecialMenu) {
		   bleh = $(element.parentNode);
		   bleh.removeClassName('active');
		}
	 } else {
		// Open the panel
		Effect.BlindDown(element.next(), effectOptions);
		element.addClassName('open');
	
	    //This special menu behavior is used only for that section. Otherwise it follows tertiary navigation standards
		if(isJennySpecialMenu) {
			bleh = $(element.parentNode);
			bleh.addClassName('active');
		}
	 }
	 Event.stop(evt);
}
	
EventSelectors.register(behaviors);

var AjaxLoader = {

	render: function(str) {

		if(str == 'undefinied' || str == null)
		{
			var content = "<div class='ajaxLoader'><img src='/assets/images/ajax-loader.gif' /></div>";
		}
		else
		{
			var content = "<div class='ajaxLoader'><img src='/assets/images/ajax-loader.gif' />" + str + "</div>";
		}
		return content;
	}
};

function InsertFlashObject(element, innerHTML) {
  element.innerHTML = innerHTML;
};

// This should be removed later and a cleaner solution for launching modals from promotions; thought should be put into expanding the 
// promotion data structure to allow for javascript and multiple images.
function phylicia_commercial_wrapper() {
	VideoPlayer.popup.open('/customer/ajax/video/phylicia_commercial.jsp', 345, 290);
}
function val_commercial_wrapper() {
	VideoPlayer.popup.open('/customer/ajax/video/val_commercial.jsp', 377, 317);
}
function latest_commercial_wrapper() {
	VideoPlayer.popup.open('/customer/ajax/video/phylicia_commercial.jsp', 345, 290);
}

//Created Carat code for Find a Centre overlay
function createFACCarat(){
	var axel = Math.random()+"";
	var a = axel * 10000000000000;	
	var whatNow = '<IMG SRC="http://ad.doubleclick.net/activity;src=1528949;type=jenny401;cat=center1;ord=1;num='+ a + '?" WIDTH=1 HEIGHT=1 BORDER=0>';
	setTimeout(function() {
		try{
			$('caratIntegration').innerHTML = whatNow;
		}
		catch(err){
			//console.log("Could not insert HTML");
		}
	}, 2000);
}

var FAC = {
    inProgress: false
};


var behaviors2 = {
	    '#map': function() {
	        if (JCMap.map_initialized == true) {
	            return false;
	        }

	        Event.observe(window, 'unload', GUnload, false);

	        if (GBrowserIsCompatible()) {
	            initialize_map($F('find_centre_searchTerm'));
	            return true;
	        }
	    },

	    '#find_centre_form': function(element) {

	        element.onsubmit = function(evt) {


	               var form = element.tagName.toLowerCase() == 'form' ? element: element.form;
                var input = form['searchTerm'];
                input = Form.Element.getValue(input);

                //Error Check
                if (input == null || input.length == 0) {
                    FAC.inProgress = false;
                    return false;
                }

                // submit the form

                var ajaxOptions = {
                    method: 'post',
                    postBody: Form.serialize(element),
                    onLoading: function(o) {
						EventSelectors.apply();
					},
                    onComplete: function(o) {

						//added to resize the Dialog depending on invalid co-ords
						if($F('fc_invalid_zip') == 'true'){						
							Windows.focusedWindow.setSize(540, 350);
						}						
						if($F('fc_invalid_zip') == 'false'){		
							Windows.focusedWindow.setSize(700, 450); 
						}
                        FAC.inProgress = false;
                    }
                };

                Windows.focusedWindow.setAjaxContent(form.action, ajaxOptions);

		
	            return false;
	        };
	    },
	    '#find_centre_iterative_search': function(element) {
	//stc
	        element.onsubmit = function(evt) {
	            //Event.stop(evt);
	            if (!FAC.inProgress) {
	                FAC.inProgress = true;
	                ////console.log(FAC.inProgress);

	                var form = element.tagName.toLowerCase() == 'form' ? element: element.form;
	                var input = form['searchTerm'];
	                input = Form.Element.getValue(input);

	                //Error Check
	                if (input == null || input.length == 0) {
	                    FAC.inProgress = false;
	                    return false;
	                }

	                // submit the form

	                var ajaxOptions = {
	                    method: 'post',
	                    postBody: Form.serialize(element),
	                    onLoading: function(o) {
							//EventSelectors.apply();
						},
	                    onComplete: function(o) {
							//added to resize the Dialog depending on invalid co-ords

							if($F('fc_invalid_zip') == 'true') {
								try
								{
									Windows.windows[1].setSize(540, 350);
									/*
									setTimeout(function() {
										//Windows.close(Windows.windows[0].getId());
									}, 1000);
									*/
									
								}	
								catch(err)
								{

								}
							}						
							if($F('fc_invalid_zip') == 'false'){	

								Windows.focusedWindow.setSize(700, 450);
							}                        
	                        FAC.inProgress = false;
	                    }
	                };

	                Windows.focusedWindow.setAjaxContent(form.action, ajaxOptions);

	            } else {
	                //locked.
	            }
	            return false;
	        };
	    },

	    '#find_centre_submit': function(element) {
	        element.onclick = function() {
			};
	        element.onmouseover = function() {
	            $(element).setStyle({
	                cursor: "pointer"
	            });
	        };
	    },

	    '#find_centre_cancel': function(element) {

	        element.onclick = function() {
	            Windows.close(Windows.focusedWindow.getId());
	            return false;
	        };
	        element.onmouseover = function() {
	            $(element).setStyle({
	                cursor: "pointer"
	            });
	        };
	    },

	'#findACentreLink a:click, a#findACentreLink:click, #showFindACentre': function(element, evt) {
        if (Windows.windows.length != 0)
            return false;

		//added to change width of Dialog 
		var logged_width = "";
		if (JC.isLoggedIn == true || JC.postalCode != '')
		{
			logged_width = 690;
		}
		else 
		{
			logged_width = 515;
		}

        if (element.id == "showFindACentre") {

            setTimeout(function() {

                Dialog.info({
                    url: "/customer/ajax/find_a_centre/find_a_center_start.jsp"

                }, {
                    windowParameters: {
                        className: 'jenny_craig_dialog',
	                    width: logged_width,
                        showLoading: true
                    }
                });

            }, 1000);
        } else {
            Event.stop(evt);
			

            Dialog.info({
                url: "/customer/ajax/find_a_centre/find_a_center_start.jsp"
            }, {
                windowParameters: {
                    className: 'jenny_craig_dialog',
                    width: logged_width,
                    showLoading: true
                }
            });	

				
        }

		createFACCarat(); 
    },
    '#mapDetails': function(element) {
        setTimeout(function() {
            Event.observe(window, 'unload', GUnload, false);

            if (GBrowserIsCompatible()) {
                var form = $('formJCDetails');

                var lon = form['lon'].value;
                var lat = form['lat'].value;
                var address = form['address'].value;
                var status = form['status'].value;
                var zip = form['zip'].value;

				try {
					initialize_map_details(lat, lon, address, status, zip);
				}
                catch(err) {}

            }
        }, 1000);
        return false;
    },

    // Contact Us page link.
    '#findCentreClick:click': function(element, evt) {

        Event.stop(evt);

        if (Windows.windows.length != 0)
            return false;
        Dialog.info({
            url: element.href
        }, {
            windowParameters: {
                className: 'jenny_craig_dialog',
                width: 690,
                showLoading: true
            }
        });
		
		createFACCarat();

        return false;
    },

    '#findACentreLink a:click, a#findACentreLink:click, #showFindACentre': function(element, evt) {
	
        if (Windows.windows.length != 0)
            return false;

		//added to change width of Dialog 
		var logged_width = "";

		if (JC.isLoggedIn == true || JC.postalCode != '') 
		{
			logged_width = 690;
		}
		else 
		{
			logged_width = 515;
		}

        if (element.id == "showFindACentre") {

            setTimeout(function() {

                Dialog.info({
                    url: "/customer/ajax/find_a_centre/find_a_center_start.jsp"

                }, {
                    windowParameters: {
                        className: 'jenny_craig_dialog',
	                    width: logged_width,
                        showLoading: true
                    }
                });

            }, 1000);
        } else {
            Event.stop(evt);
            Dialog.info({
                url: "/customer/ajax/find_a_centre/find_a_center_start.jsp"
            }, {
                windowParameters: {
                    className: 'jenny_craig_dialog',
                    width: logged_width,
                    showLoading: true
                }
            });		

			setTimeout(function() {
				try {
					if($F('fc_invalid_zip') == 'true') {
						Windows.focusedWindow.setSize(540, 350);	
					} else if ($F('isOurProgramFAQ') == true) {	
						Windows.focusedWindow.setSize(700, 450);
					} 
					
					
					Windows.focusedWindow.showCenter();
					
				} catch(err) {
					//Windows.focusedWindow.setSize(700, 540);
				}
				
			}, 2000);
        }

		createFACCarat();			
		return false;
		
	

    },
    'a.findACentreLinkLocal:click': function(element, evt) {
        
		Event.stop(evt);

        if (Windows.windows.length != 0)
		{
			 return false;
		}
           

		if(JC.isLoggedIn == false)
		{
				if($F('isOurProgramFAQ') == true) {
					
					Dialog.info({ url: element.href }, { 
						windowParameters: {
							className: 'jenny_craig_dialog',
						   	width: 690,
						   	showLoading: true
					}});
				} else {
					Dialog.info({ url: element.href }, { 
						windowParameters: {
							className: 'jenny_craig_dialog',
						   	width: 515,
						   	showLoading: true
					}});
				}
			
		}
		else
		{
			Dialog.info({ url: element.href }, { 
				windowParameters: {
					className: 'jenny_craig_dialog',
				   	width: 690,
				   	showLoading: true
			}});
		}
      

		createFACCarat();
		
        return false;
    },
    '#find_centre_contact_form': function(element) {
        element.onsubmit = function(evt) {
            var form = element.tagName.toLowerCase() == 'form' ? element: element.form;
            var input = form['searchTerm'];
            input = Form.Element.getValue(input);

            if (input == null || input.length == 0) {
                return false;
            }

            Dialog.info({
                url: form.action
            }, {
                windowParameters: {
                    className: 'jenny_craig_dialog',
                    width: 650,
                    showLoading: true
                }
            });

            return false;
        };

    },
    '#findACentreLinkLocal a:click, #showMapDetails': function(element, evt) {

        if (Windows.windows.length != 0)
            return;
			
        if (element.id == "showMapDetails") 
		{
				
            setTimeout(function() {
                var centreID = $('inputCentreId').value;
                Dialog.info({
                    url: "/customer/ajax/find_a_centre/details.jsp?centreID=" + centreID
                }, {
                    windowParameters: {
                        className: 'jenny_craig_dialog',
                        width: 515,
                        showLoading: true
                    }
                });

            }, 1000);
        } 
		else 
		{
            Event.stop(evt);
            Dialog.info({
                url: element.href
            }, {
                windowParameters: {
                    className: 'jenny_craig_dialog',
                    width: 690,
                    showLoading: true
                }
            });

        }

    }
	
};

EventSelectors.register(behaviors2);
// load the Omniture interface
document.write('<script type="text/javascript" src="/assets/javascripts/metrics/s_code.js"></script>');

var Metrics = {

	separator: '_',		//view_id seperator 
	urlSeparator: '/',
	
	linkName: '', 			//name used to track event
	linkType: '', 			//corresponds to Omniture's linkType - exit,download,custom
	campaign_var: 'leadsrc',	//query param key for campaign ids
	
	varsHash: $H(),	//hash storing all vars
	userLevel: null,
	isCoupon: false,
	setVisitorID: function(val) {
	
	},
	createVisitorID: function() {
		return Uuid.create();
	},
	readVisitorID: function() {
		var nameEQ = "visitorID=";
		var cookiesList = document.cookie.split(';');
		
		var found = false;
		//Iterate through all cookies within the browser, find the visitor ID 
		for ( var i = 0, len = cookiesList.length; i < len; i ++ )
		{
		
			var c = cookiesList[i];
			var cookieValue = null;
			while (c.charAt(0)==' ') 
			{
				c = c.substring(1, c.length);
			}

			if (c.indexOf(nameEQ) == 0)
			{
				
				cookieValue =  c.substring(nameEQ.length, c.length).replace(/null/g, "");
				
				if(cookieValue === null || cookieValue == 'undefined')
				{
					found = false;
				}
				else
				{
					found = true;
					return cookieValue;
				}
			}
			else
			{
				found = false;
			}
		}
		
		if(!found)
		{
			//Generate cookie;
			var vid = Metrics.createVisitorID();
			
			var today = new Date();
			today.setTime( today.getTime() );
			//Expiry date of 5 years from current time
			var expiryDate = new Date(today.getTime() + (1825 * 1000 * 60 * 60 * 24));

			document.cookie = ("visitorID="+ vid +";expires=" + expiryDate + ";path=/").replace(/null/g, "");
			
			return vid;
		}
		

		
	},
	track: function(type, options) { //type: event or page

		/***************************
		
		SAMPLE CODE
		
		Flash - note that the element param is set to True.
		getURL("javascript: Metrics.track('event', {linkType: 'custom', linkName: 'Add Weight'}, true)");
		
		Events
		Metrics.track('event', {linkType: 'exit', linkName: 'Link to {partner}'}, this);
		Metrics.track('event', {linkType: 'download', linkName: 'Franchising Information'}, this);
		Metrics.track('event', {linkType: 'download', linkName: 'Franchising Information', linkVars:'userID, userLevel'}, this);
		Metrics.track('event', {linkType: 'custom', linkName: 'Emailed Recipe', linkVars:'userID, userLevel, recipeName', linkEvents:'email'}, this);
		
		PageViews
		Metrics.track('pageview', {pageName: 'food_breakfast_recipe_detail', linkName: 'Link to {partner}'}, this);
		
		***************************/
	
		if(!s) return;
		
		this.setVariable(options);
		
		if (options['userLevel'])
			this.userLevel = options['userLevel'];
	
		switch (type) {
         case 'pageview':
			case 'completed':
				this.analyzePage(type);
				this.commitVars(this.varsHash);
				if(this.isCoupon == false) {
					s.t();	
				}
				break;
			case 'event':
				this.clearVars();
				this.commitVars(this.varsHash);
				var element = arguments[2];
				s.tl(element,linkType,linkName);
				break;
			default:	//type param undeclared
				//console.log("A call to metrics was attempted, but no Type (pageview/event) was specified.");
		}
		
		return void(0); 
	},

	weightTracker: function(goalWeight, newWeight) {
		if (!s) return;
		
		if (goalWeight < newWeight)
		{
			s.events = "event6";
			s.eVar6 = "Weight Tracker";
		}
		else
		{
			s.events = "event11";
			s.eVar22 = "Goal Weight";
		}
		
		s.t();
	},
	couponUserCreated: function() {
		if(JC.isLoggedIn) {
			
			var justRegistered = $F("couponJustRegistered") ;
			
			
			if(justRegistered== "true" || justRegistered == true) {
				s.events = "event4,event10,event16";
			} else {
				s.events = "event4,event16";
			}
			
			//console.log("JUST REGISTERED?: ", justRegistered);
			//console.log("EVENTS: ", s.events);
			s.eVar5 = "Coupon"; //JGB-3733: As per Ryan Haugh/Faizan's request, this has been changed to read "Coupon" instead of "Registration".

			var TID = JC.transactionId;
			var VID = JC.visitorId || Metrics.readVisitorID();
			var CUID = JC.customerId || 0;
			//this.setVariable({transactionID: TID, visitorID: VID, userID: CUID });
			this.commitVars({transactionID: TID, visitorID: VID, userID: CUID });
			s.t();
		} else {
			//Non logged in users shouldn't be here.
			window.location.href = "/";
		}
	},
	closeExperienceFlash: function(secondsOpened)
	{
		s.events = "event6,event19";
		s.eVar27 = "Interactive Experience Flash";
		s.eVar28 = secondsOpened;
		
		s.t();
	},
	whatMotivatesYouSubmission: function()
	{
		s.events = "event6";
		s.eVar6 = "Experience - What Motivates You? - Submit Story";
		
		s.t();
	},
	
	menuCreated: function()
	{
		s.events = "event5";
		s.eVar6 = "Menu Planner";
		
		s.t();
	},
		
	menuCompleted: function()
	{
		s.events = "event6";
		s.eVar6 = "Menu Planner";
		
		s.t();
	},
	submitClickToCall: function()
	{
		//console.log("Click to call activated.");
		s.eVar5 = "Click to Call";
		s.t();
	},
	yourStyleStart: function()
	{
		//alert("yourStyleStart");
		s.events = "event3,event20";
		s.eVar5 = "Your Style";
		s.eVar6 = "Your Style";
		s.eVar26 = "Your Style - Start";

		s.eVar11 = this.userLevel;
		s.t();
	},
	yourStyleUserCreated: function() {
		//alert("yourStyleUserCreated");
		s.events = "event4,event10,event20";
		s.eVar6 = "Your Style";
		s.eVar5 = "Your Style";
		s.eVar11 = this.userLevel;
		s.eVar26 = "Your Style - Completed";
		
		this.setVariable({transactionID: Uuid.create(), visitorID: Metrics.readVisitorID()});
		
		s.t();
	},
	yourStyleCompleted: function()
	{
		//alert("yourStyleCompleted");
		s.events = "event4,event10,event20";
		s.eVar6 = "Your Style";
		s.eVar5 = "Your Style";
		s.eVar11 = this.userLevel;
		s.eVar26 = "Your Style - Completed";
		
		this.setVariable({transactionID: Uuid.create(), visitorID: Metrics.readVisitorID()});
		
		s.t();
	},
	
	// Basing new Find A Centre tracking on yourstyle stuff above
	findACentreStart: function()
	{
    s.prop9 = "Find A Centre Search";
	},
	findACentreCompleted: function()
	{
    s.prop10 = "Find A Centre Results";
	},
	
	// tracking for A/B testing
	abTesting: function(option) {
		if (option == 'default') {
			return;
		} else {
			s.eVar35 = option;
			s.prop35 = option;
		}
	},

	//adds the new variable declaration to the varsHash
	setVariable: function(var_hash) {
		this.mergeVars(var_hash);
	},
	
	setVariables: function(var_hash) {
		this.setVariable(var_hash);
	},
	
	//merges new pairs into the varsHash
	mergeVars: function(var_hash){	
		var vars = $H(var_hash);			//cast to prototype hash object	
		this.varsHash.merge(vars);			//merge with varsHash
	},
	

	//for use when constructing a new tl() request
	//clear all of the necessary variable in preparation for a new image request
	clearVars: function(object) {
		container = $H(object);
		container.each(function(pair) {	
			if (pair.key.match('prop')) {
				container[pair.key] = '';
			} else if (pair.key.match('eVar')) {
				container[pair.key] = '';
			}
		});
	},
	
	analyzePage: function(type){
		var currentUrl = this.getCurrentUrl();
		var uri = new Uri(currentUrl);

		//get&set information from dissecting the page name
		this.dissectPageName(uri);
		//then check to see if this is a campaign landing page
		this.checkCampaign();
		
		this.handleSpecificPage(uri, type);
	},

	dissectPageName: function(uri){
		var namifiedLevels;

		if (this.varsHash['pageName'])
		{
			namifiedLevels = this.varsHash['pageName'].split(/ : /);
		}
		else
		{
			namifiedLevels = this.namifyPathLevels(uri);
			this.varsHash['pageName'] = namifiedLevels.join(' : ');
		}
		
		this.varsHash['section'] = namifiedLevels[0];
		
		if (namifiedLevels.length > 1)
			this.varsHash['section2'] = namifiedLevels[1];
		
		if (namifiedLevels.length > 2)
			this.varsHash['section3'] = namifiedLevels[2];
	},

	namifyPathLevels: function(uri) {
		// special cases
		if (uri.Path == "" || uri.Path == "home")
			return ["Homepage"];
		else if (uri.Path == "login/registration")
			return ["Registration"];

		return uri.PathLevels.collect(function(item) {
			if (item == "login")
				return "Registration";
				
			return item.replace(/_/g, " ").toTitleCase();
		});
	},
	
	getCurrentUrl: function() {
		return window.location.href;
	},
	
	checkCampaign: function() {
		campaign_id = s.getQueryParam(this.campaign_var);
		if (campaign_id != '' && campaign_id != null) {
			campaign_type = this.checkCampaignType(campaign_id);
			this.setVariables({campaignType: campaign_type, campaign: campaign_id});
		}
	},
	
	handleSpecificPage: function(uri, type) {
		if (uri.PathLevels.length > 1 && uri.PathLevels[0] == "login" && uri.PathLevels[1] == "thankyou")
		{
			if(JC.isLoggedIn == true) {
				s.events = "event4,event10";
				s.eVar5 = "eTools Registration"; //This should say Registration.  Changed to 'eTools Registration' April 11 2008
											//JGB-3733: As per Ryan Haugh/Faizan's request, this has been changed to read "Coupon" instead of "Registration".
				s.eVar19 = new Date().getShortDate();		

				//if(!TID || TID == 'undefined') {
		
				var TID = JC.transactionId;
				var VID = JC.visitorId || Metrics.readVisitorID();
				var CUID = JC.customerId || 0;
				this.setVariable({transactionID: TID, visitorID: VID, userID: CUID, userLevel: null })
		
				
			
			} else {
				window.location.href = "/"; //Boot them out.
			}
			
			
		}
		else if (uri.PathLevels.length > 1 && uri.PathLevels[0] == "login" && uri.PathLevels[1] == "registration")
		{
			s.events = "event3";
			s.eVar5 = "eTools Registration"; //This should say Registration.  Changed to 'eTools Registration' April 11 2008
										//JGB-3733: As per Ryan Haugh/Faizan's request, this has been changed to read "Coupon" instead of "Registration".
			s.eVar19 = new Date().getShortDate();		
			
			var TID = Uuid.create();
			var VID = JC.visitorId || Metrics.readVisitorID();
			var CUID = JC.customerId || 0;
			this.setVariable({transactionID: TID, visitorID: VID, userID: CUID });
			
			
		}
		else if (uri.PathLevels.length == 1 && uri.PathLevels[0] == "clicktocall")
		{
			s.events = "event3";
			s.eVar5 = "Click to Call";
			

			var TID = Uuid.create();
			var VID = JC.visitorId || Metrics.readVisitorID(); 
			var CUID = JC.customerId || 0;
			this.setVariable({transactionID: TID, visitorID: VID, userID: CUID });
	
			
		}
		else if (uri.PathLevels.length == 1 && uri.PathLevels[0] == "callconfirm")
		{
			s.events = "event4,event9";
			s.eVar5 = "Click to Call";
			

			var TID = JC.transactionId;
			var VID = JC.visitorId || Metrics.readVisitorID(); 
			var CUID = JC.customerId || 0;
			this.setVariable({transactionID: TID, visitorID: VID, userID: CUID });
	
			
		}
		else if ((uri.PathLevels.length == 3 && uri.PathLevels[0] == "coupon" && uri.PathLevels[1] == "registration"))
		{
			s.events = "event3";
			s.eVar5 = "Coupon"; //JGB-3733: Instead of saying Registration for eVar5, Ryan Haugh/Faizan has requested that this be changed to 'Coupon'.
			
			var TID = Uuid.create();
			var VID = JC.visitorId || Metrics.readVisitorID(); 
			var CUID = JC.customerId || 0;
			this.setVariable({transactionID: TID, visitorID: VID, userID: CUID });
		}
		else if (uri.PathLevels.length > 1 && uri.PathLevels[0] == "coupon" && uri.PathLevels[1] == "print")
		{
			this.isCoupon = true;
			/*
			
			Due to the fact that event10 has been added to this section of coupon/print, 
			we cannot have the metrics system automatically handle this metric by URL. Instead,
			we'll move it to a helper function.
			
			if(JC.isLoggedIn) {
				
				var x = $F("couponJustRegistered");
				
				setTimeout(function() {
					try {
						if(x == "true" || x == true) {
							s.events = "event4,event10,event16";
						} else {
							s.events = "event4,event16";
						}
					} catch(err) {}
				}, 3000);
				
				s.eVar5 = "Coupon"; //JGB-3733: As per Ryan Haugh/Faizan's request, this has been changed to read "Coupon" instead of "Registration".
	
				var TID = JC.transactionId || Uuid.create();
				var VID = JC.visitorId || Metrics.readVisitorID();
				var CUID = JC.customerId || 0;
				this.setVariable({transactionID: TID, visitorID: VID, userID: CUID });
			} else {
				window.location.href = "/";
			}*/
			//this.setVariable({transactionID: Uuid.create(), visitorID: Metrics.readVisitorID()});
		}
		else if (this.varsHash['pageName'] == "Interactive Flash")
		{
			s.events = "event5,event18";
			s.eVar6 = "Interactive Flash";
			s.eVar27 = "Interactive Experience Flash";
		}
		else if (typeof(this.varsHash['pageName']) == 'string' && (this.varsHash['pageName'].match(/^Tabbed Experience Flash \:/) || this.varsHash['pageName'].match(/^Interactive Experience Flash \:/)))
		{
			var nameParts = this.varsHash['pageName'].split(/ : /);
			s.events = "event18";
			s.eVar27 = "{0} - {1}".format(nameParts[0], nameParts[1]);
		}
		/*else if (uri.PathLevels.length == 2 && uri.PathLevels[0] == "etools" && uri.PathLevels[1] == "yourstyle")
		{
			s.events = "event3,event20";
			s.eVar5 = "Your Style";
			s.eVar6 = "Your Style";
			s.eVar26 = "Your Style - Start";
		}*/		
	},
	
	checkCampaignType: function(c_id) {
		//check the campaign id to determine if it's internal/external
		//following looks for the int_ prefix on a campaign id. if it's there, then mark as internal
		if (c_id.split('_')[0] == 'int') { 
			c_type = 'internal';
			this.setVariable({findingMethod: 'internal campaign'});
		} else { //otherwise, it's assumed to be external
			c_type = 'external';
		}
		return c_type;
	},
	
	commitVars: function(options) {
//alert("commitVars");		
		//gather the Object info
		options = $H(options);
		
		/*****************************
		EVENTS LIST
		******************************
		prodView		Product Views 
		event1		Searches
		event2		Product Views (custom)
		event3		Leads initiated
		event4		Leads Completed
		event5		Tool initiated
		event6		Tool complete
		event7		self-service event
		event8		Product/Recipe actions success
		*/
				
		/***************************************************VAR HASH*******************************************************/
		


		
		options.each(function(pair) {
			var index = pair.key;
			var value = pair.value;
			
		
			////console.log(pair);
			switch(index) {
					
				/*****************************
				GENERAL PAGE VARIABLES
				*****************************/
				//pageType				mostly intended for error pages
				//prop3					Site Sub Sections
				//prop4					Site Sub Sub Sections
				//events					page tracking events
				
				case 'pageName': 		
					s.pageName = value;
					s.eVar23 = value;
					break;
				case 'section': 	
					if (value == "Yourstyle") {
						value = "Etools";
					}
					s.channel = value;
					break;
				case 'pageType':
					s.pageType = value;
					break;
				case 'section2': 		
					s.prop3 = value;
					break;
				case 'section3':		
					s.prop4 = value;
					break;
				case 'events': 		
					s.events = value;			
					break;
				case 'action':
					s.eVar28 = value;
					break;
				case 'accountId':
					if (value > 0)
						s.eVar12 = value;
					break;
				
				/*****************************
				USER DATA
				*****************************/
				//eVar11				User Type
				//eVar12				User Id
				//eVar18, prop18	Days since last visit
				//eVar17, prop17	Days since last visit
				case 'userLevel': 	
					if (value != null) {
						s.eVar11 = value;
					}
					break;
				case 'userID': 		
					s.eVar12 = value;
					break;
				case 'totalVisits': 	
					s.prop18 = value;
					s.eVar18 = value;
					break;
				case 'lastVisit': 	
					s.prop17 = value;
					s.eVar17 = value;
					break;
					
				/*****************************
				KEY CONTENT
				*****************************/
				//prop11				Key Program Content
				//prop12				Key Brand Content
				//prop13				Medical Efficacy Content
				case 'programContent': 	
				case 'brandContent': 	
				case 'medicalContent': 	
					break;
					
				/*****************************
				FINDING METHODS
				*****************************/
				//eVar3	Key Content Finding Methods	(browse, search, internal campaign)
				case 'findingMethod': 
					s.eVar3 = value;
					break;
					
				/*****************************
				DETAIL PAGES
				*****************************/
				//eVar4 				Asset Category
				//eVar14				Asset Friendly Name (s.products)
				//eVar15				Asset Type (article, recipe, etc.)
				//products			
				case 'recipeName':  		
					s.evar14 = value;
					s.evar15 = 'recipe';
					s.products = value;
					break;
				case 'articleName':
					s.evar14 = value;
					s.evar15 = 'article';
					break;
				case 'foodName':
					s.eVar14 = value;
					s.eVar15 = 'food';
					break;
				case 'category':
					s.eVar4 = value;
					
				/*****************************
				CAMPAIGNS
				*****************************/	
				//campaign, eVar2		External, Internal Campaigns
				case 'campaign': 
					switch(options['campaignType']) { 
						case 'internal':
							s.eVar2 = value;
							break;
						case 'external':
							s.campaign = value;
							break;
					}
					break;
				
				/*****************************
				CENTER SEARCH
				*****************************/				
				//prop9,eVar9		CL Search Entry
				//prop10,eVar10	CL Filter (not sure what this is yet)
				case 'centerZip': 	
					s.prop9 = value;
					s.eVar9 = value;
					break;
				
				/*****************************
				SECTION SEARCHES
				*****************************/
				//prop1,eVar1		Internal Search Terms
				//prop8,eVar8		Search Type
				//prop2				# Search results		if none, value should be "zero", not 0	
				case 'searchTerm': 	
					s.prop1 = value;
					s.eVar1 = value;
					break;
				case 'searchTypes': 	
					s.prop8 = value;
					s.eVar8 = value;
					break;
				case 'searchResults': 
					s.prop2 = value;
					break;
					
				/*****************************
				LINK REQUESTS
				*****************************/
				//linkTrackVars	specify s.vars to track on link tracks ie. {value = "prop1,eVar1,events"}. a '' value for this parameter will pass all s.vars
				//linkTrackEvents specify events to track on link tracks ie. {value = "prodView, event2"}. a '' value for this parameter will pass all s.events
				case 'linkVars': 					
					s.linkTrackVars = value;
               /*
					//translate the variables
					englishVars = value.split(',');
					translatedVars = '';
               if (index < englishVars.length - 1) {
                  translatedVars = translatedVars + ',';
               } else {
                  englishVars.each(function(value, index) {
                     switch(value) {
   //----->					//cases pending Solution Design Document
                        case 'actionName':
                           translatedVars = translatedVars + 'prop#/ever# or whatever the Omniture name is';
                           break;
                        default:
                           break;
                     }
                  });
               }
               */
					break;
				case 'linkEvents': 				
					s.linkTrackEvents = value;
               /*
					//translate the events
					englishEvents = value.split(',');
					translatedEvents = '';
               if (index < englishEvents.length - 1) {
                  translatedEvents = translatedEvents + ',';
               } else {
                  englishEvents.each(function(value, index) {
                     switch(value) {
   //----->				//cases pending Solution Design Document
                        case 'email':
                           translatedEvents = translatedEvents + 'whatever event# this corresponds to';
                           break;
                        case 'print':
                           translatedEvents = translatedEvents + 'whatever event# this corresponds to';
                           break;
                        default:
                           break;
                     }
                  });
               }
               */
					break;
				case 'linkName':
					linkName = value;
				case 'linkType':
					switch (value) {
						case 'exit':
							linkType = 'e';
							break;
						case 'download':
							linkType = 'd';
							break;
						case 'custom':
							linkType = 'o';
							break;
						default:
							//console.log('no event type was specified');
					}
					break;
				
				/*****************************
				COMMUNITY
				*****************************/
				//prop14	Community
				case 'community': 
					s.prop14 = value;
					break;
				
				case 'transactionID':
					s.transactionID = value;
					s.prop11 = value;
					break;
				
				/*****************************
				CR: VISITOR ID
				*****************************/
				case 'visitorID':
					
					//Omniture hook
					s.eVar31 = value;
					s.visitorID = value;
					
					break;
				
				/*****************************
				OTHERWISE
				*****************************/
				default:
					//console.log('Param matched no criteria: ' + index + ' = ' + value);
					break;
			}
		}.bind(this));
		
		/***********************************************END VAR HASH*******************************************************/
	}
};

var Uri = Class.create();

Uri.prototype = {

	initialize: function(uri) {



		// remove leading http://

		uri = uri.replace(/^http:\/\//, "");

		var base = uri.split(/\?/)[0];

		var parts = base.split(/\//);
		parts.splice(0, 1);
		
		this.Path = parts.join('/').replace(/\/$/, "").toLowerCase();
		this.PathLevels = this.Path.split(/\//).findAll(function(p) { return typeof(p) == 'string' && p != ''; });
	}
};	

Object.extend(String.prototype, {
  toTitleCase: function() 

    {

		var parts = this.toLowerCase().split(/ /);

		return parts.collect(function(item) {

			return item.capitalize();

		}).join(" ");

    },


 

  format: function() 

    {

      var result = this;

      for (var index=0, len = arguments.length; index < len; index++)

      {

        result = result.replace("{" + index + "}", arguments[index]);

      }



      return result;    

    }    

});

Object.extend(Date.prototype, {
  getShortDate: function() 

    {

		return "{0}/{1}/{2}".format(this.getMonth() + 1, this.getDate(), this.getFullYear());

    }

});

/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

var Uuid = {
	create: function() {
		return this.TimeBasedGenerator.generate();
	},
	
	TimeBasedGenerator: {
		GREGORIAN_CHANGE_OFFSET_IN_HOURS: 3394248,
		_uuidPseudoNodeString: null,
		_uuidClockSeqString: null,
		_dateValueOfPreviousUuid: null,
		_nextIntraMillisecondIncrement: 0,
		_cachedMillisecondsBetween1582and1970: null,
		_cachedHundredNanosecondIntervalsPerMillisecond: null,
		HEX_RADIX: 16,
		
		_carry: function(arrayA) {
			arrayA[2] += arrayA[3] >>> 16;
			arrayA[3] &= 65535;
			arrayA[1] += arrayA[2] >>> 16;
			arrayA[2] &= 65535;
			arrayA[0] += arrayA[1] >>> 16;
			arrayA[1] &= 65535;
		},
		
		_get64bitArrayFromFloat: function(x) {
			var result = new Array(0, 0, 0, 0);
			result[3] = x % 65536;
			x -= result[3];
			x /= 65536;
			result[2] = x % 65536;
			x -= result[2];
			x /= 65536;
			result[1] = x % 65536;
			x -= result[1];
			x /= 65536;
			result[0] = x;
			return result;
		},
		
		_addTwo64bitArrays: function(arrayA, arrayB) {
			var result = new Array(0, 0, 0, 0);
			result[3] = arrayA[3] + arrayB[3];
			result[2] = arrayA[2] + arrayB[2];
			result[1] = arrayA[1] + arrayB[1];
			result[0] = arrayA[0] + arrayB[0];
			this._carry(result);
			return result;
		},
		
		_multiplyTwo64bitArrays: function(arrayA, arrayB) {
			var overflow = false;
			if (arrayA[0] * arrayB[0] !== 0) {
				overflow = true;
			}
			if (arrayA[0] * arrayB[1] !== 0) {
				overflow = true;
			}
			if (arrayA[0] * arrayB[2] !== 0) {
				overflow = true;
			}
			if (arrayA[1] * arrayB[0] !== 0) {
				overflow = true;
			}
			if (arrayA[1] * arrayB[1] !== 0) {
				overflow = true;
			}
			if (arrayA[2] * arrayB[0] !== 0) {
				overflow = true;
			}

			var result = new Array(0, 0, 0, 0);
			result[0] += arrayA[0] * arrayB[3];
			this._carry(result);
			result[0] += arrayA[1] * arrayB[2];
			this._carry(result);
			result[0] += arrayA[2] * arrayB[1];
			this._carry(result);
			result[0] += arrayA[3] * arrayB[0];
			this._carry(result);
			result[1] += arrayA[1] * arrayB[3];
			this._carry(result);
			result[1] += arrayA[2] * arrayB[2];
			this._carry(result);
			result[1] += arrayA[3] * arrayB[1];
			this._carry(result);
			result[2] += arrayA[2] * arrayB[3];
			this._carry(result);
			result[2] += arrayA[3] * arrayB[2];
			this._carry(result);
			result[3] += arrayA[3] * arrayB[3];
			this._carry(result);
			return result;
		},
		
		_padWithLeadingZeros: function(string, desiredLength) {
			while (string.length < desiredLength) {
				string = "0" + string;
			}
			return string;
		},
		
		_generateRandomEightCharacterHexString: function() {
			var random32bitNumber = Math.floor((Math.random() % 1) * Math.pow(2, 32));
			var eightCharacterString = random32bitNumber.toString(this.HEX_RADIX);
			while (eightCharacterString.length < 8) {
				eightCharacterString = "0" + eightCharacterString;
			}
			return eightCharacterString;
		},
		
		generate: function() {
			if (!this._uuidPseudoNodeString) {
				var pseudoNodeIndicatorBit = 32768;
				var random15bitNumber = Math.floor((Math.random() % 1) * Math.pow(2, 15));
				var leftmost4HexCharacters = (pseudoNodeIndicatorBit | random15bitNumber).toString(this.HEX_RADIX);
				this._uuidPseudoNodeString = leftmost4HexCharacters + this._generateRandomEightCharacterHexString();
			}

			node = this._uuidPseudoNodeString;

			if (!this._uuidClockSeqString) {
				var variantCodeForDCEUuids = 32768;
				var random14bitNumber = Math.floor((Math.random() % 1) * Math.pow(2, 14));
				this._uuidClockSeqString = (variantCodeForDCEUuids | random14bitNumber).toString(this.HEX_RADIX);
			}
			var now = new Date();
			var millisecondsSince1970 = now.valueOf();
			var nowArray = this._get64bitArrayFromFloat(millisecondsSince1970);
			if (!this._cachedMillisecondsBetween1582and1970) {
				var arraySecondsPerHour = this._get64bitArrayFromFloat(60 * 60);
				var arrayHoursBetween1582and1970 = this._get64bitArrayFromFloat(this.GREGORIAN_CHANGE_OFFSET_IN_HOURS);
				var arraySecondsBetween1582and1970 = this._multiplyTwo64bitArrays(arrayHoursBetween1582and1970, arraySecondsPerHour);
				var arrayMillisecondsPerSecond = this._get64bitArrayFromFloat(1000);
				this._cachedMillisecondsBetween1582and1970 = this._multiplyTwo64bitArrays(arraySecondsBetween1582and1970, arrayMillisecondsPerSecond);
				this._cachedHundredNanosecondIntervalsPerMillisecond = this._get64bitArrayFromFloat(10000);
			}
			var arrayMillisecondsSince1970 = nowArray;
			var arrayMillisecondsSince1582 = this._addTwo64bitArrays(this._cachedMillisecondsBetween1582and1970, arrayMillisecondsSince1970);
			var arrayHundredNanosecondIntervalsSince1582 = this._multiplyTwo64bitArrays(arrayMillisecondsSince1582, this._cachedHundredNanosecondIntervalsPerMillisecond);
			if (now.valueOf() == this._dateValueOfPreviousUuid) {
				arrayHundredNanosecondIntervalsSince1582[3] += this._nextIntraMillisecondIncrement;
				this._carry(arrayHundredNanosecondIntervalsSince1582);
				this._nextIntraMillisecondIncrement += 1;
				if (this._nextIntraMillisecondIncrement == 10000) {
					while (now.valueOf() == this._dateValueOfPreviousUuid) {
						now = new Date();
					}
				}
			} else {
				this._dateValueOfPreviousUuid = now.valueOf();
				this._nextIntraMillisecondIncrement = 1;
			}
			var hexTimeLowLeftHalf = arrayHundredNanosecondIntervalsSince1582[2].toString(this.HEX_RADIX);
			var hexTimeLowRightHalf = arrayHundredNanosecondIntervalsSince1582[3].toString(this.HEX_RADIX);
			var hexTimeLow = this._padWithLeadingZeros(hexTimeLowLeftHalf, 4) + this._padWithLeadingZeros(hexTimeLowRightHalf, 4);
			var hexTimeMid = arrayHundredNanosecondIntervalsSince1582[1].toString(this.HEX_RADIX);
			hexTimeMid = this._padWithLeadingZeros(hexTimeMid, 4);
			var hexTimeHigh = arrayHundredNanosecondIntervalsSince1582[0].toString(this.HEX_RADIX);
			hexTimeHigh = this._padWithLeadingZeros(hexTimeHigh, 3);
			var hyphen = "-";
			var versionCodeForTimeBasedUuids = "1";
			var resultUuid = hexTimeLow + hyphen + hexTimeMid + hyphen + versionCodeForTimeBasedUuids + hexTimeHigh + hyphen + this._uuidClockSeqString + hyphen + node;
			resultUuid = resultUuid.toLowerCase();
			return resultUuid;
		}
	}
};
function videoPop(file) {
	VideoPlayer.popup.open(file, 450, 370);
}