

/* ===================================================
	Copyright (c) 2007 Campus Medica
	global JavaScript functions 
	$Revision: 1.75 $
==================================================== */
if( typeof com == "undefined" ) var com = new Object();
if( typeof com.campusmedica == "undefined" ) com.campusmedica = new Object();
if( typeof com.campusmedica.util == "undefined" ) com.campusmedica.util = new Object();
if( typeof com.campusmedica.www == "undefined" ) com.campusmedica.www = {
is: true,
isSecure: document.location.href.indexOf("https:") == 0
};
function OpenWindow( url, width, height, opt , name ) {
window.open( url, (name || "OutsideWindow"), "width="+(width || 714)+",height="+(height || 536)+","+(opt ||  "scrollbars=yes,menubar=yes,toolbar=yes,location=yes,status=yes,resizable=yes")).focus();
}
PNG = function (id,src,altsrc) {
var png = document.createElement('img');
png.setAttribute('id',id);
if (browser.ua.indexOf('msie 5.0') != -1) {
if (altsrc != null) png.src = altsrc;
else return;
} else if ((browser.appN.indexOf('microsoft') != -1) && (browser.ua.indexOf('mac') == -1)) {
png.src = '/images/alpha/blank.gif';
png.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+src+"',sizingMethod='scale');";
} else {
png.src = src;
}
return png;
}
Randomize = function() { 
this.method = Math.random;
this.alphabet = "abcdefghijklmnopqrstuvwxyz";
return this;
}
Randomize.prototype = {
toNumber: function(num)
{
return Math.floor( this.method()*( Math.pow( 10, num || 1 ) ) );
},
inNumberRange: function( lo, hi)
{
return ( Math.floor( this.method()*(hi*2) )%( hi-lo+1 ) )+lo; 
},
toAlpha: function()
{
var i = this.inNumberRange( 0, this.alphabet.length-1);
return this.alphabet.charAt(i);
},
inAlphaRange: function(lo, hi)
{
var i = this.inNumberRange( this.alphabet.indexOf(lo), this.alphabet.indexOf(hi) );
return this.alphabet.charAt(i);
},
toId: function(num)
{
return this.toAlpha()+this.toNumber( num || 3 );
}
}
var randomize = new Randomize();
Function.prototype.method = function (name, func) {
this.prototype[name] = func;
return this;
};
function isAlien(a) {
return isObject(a) && typeof a.constructor != 'function';
}
function isArray(a) {
return isObject(a) && a.constructor == Array;
}
function isBoolean(a) {
return typeof a == 'boolean';
}
function isEmpty(o) {
var i, v;
if (isObject(o)) {
for (i in o) {
v = o[i];
if (isUndefined(v) && isFunction(v)) {
return false;
}
}
}
return true;
}
function isFunction(a) {
return typeof a == 'function';
}
function isNull(a) {
return typeof a == 'object' && !a;
}
function isNumber(a) {
return typeof a == 'number' && isFinite(a);
}
function isObject(a) {
return (a && typeof a == 'object') || isFunction(a);
}
function isString(a) {
return typeof a == 'string';
}
function isTag(a) {
return (a.nodeType && a.nodeType == 1);
}
function isUndefined(a) {
return typeof a == 'undefined';
} 
if (!isFunction(Function.apply)) {
Function.method('apply', function (o, a) {
var s = [], r, call;
if (!o) o = window;
if (!a) a = [];
for (var i = 0; i < a.length; i++) {
s[i] = "a["+i+"]";
}
call = "o.__method(" + s.join(",") + ");";
o.__method = this;
r = eval(call);
o.__method = null;
return r;
});
};
if (!isFunction(Array.prototype.pop)) {
Array.method('pop', function () {
return this.splice(this.length - 1, 1)[0];
});
};
if (!isFunction(Array.prototype.push)) {
Array.method('push', function () {
this.splice.apply(this,
[this.length, 0].concat(Array.prototype.slice.apply(arguments)));
return this.length;
});
};
if (!isFunction(Array.prototype.shift)) {
Array.method('shift', function () {
return this.splice(0, 1)[0];
});
};
if (!isFunction(Array.prototype.splice)) {
Array.method('splice', function (s, d) {
var max = Math.max,
min = Math.min,
a = [], 
e,  
i = max(arguments.length - 2, 0),   
k = 0,
l = this.length,
n,  
v,  
x;  
s = s || 0;
if (s < 0) {
s += l;
}
s = max(min(s, l), 0);  
d = max(min(isNumber(d) ? d : l, l - s), 0);    
v = i - d;
n = l + v;
while (k < d) {
e = this[s + k];
if (!isUndefined(e)) {
a[k] = e;
}
k += 1;
}
x = l - s - d;
if (v < 0) {
k = s + i;
while (x) {
this[k] = this[k - v];
k += 1;
x -= 1;
}
this.length = n;
} else if (v > 0) {
k = 1;
while (x) {
this[n - k] = this[l - k];
k += 1;
x -= 1;
}
}
for (k = 0; k < i; ++k) {
this[s + k] = arguments[k + 2];
}
return a;
});
};
if (!isFunction(Array.prototype.unshift)) {
Array.method('unshift', function () {
this.splice.apply(this,
[0, 0].concat(Array.prototype.slice.apply(arguments)));
return this.length;
});
};
if (!isFunction(Function.call)) {
Function.method('call', function () {
var o = arguments[0], s = [];
for (var i=1, len=arguments.length; i<len; i++) {
s.push("arguments["+i+"]");
}
o.__method = this;
r = eval("o.__method("+s.join(",")+")");
o.__method = null;
return r;
});
};
function $(s)
{
return document.getElementById(s);
}
function removeElementFromDOM (id) {
var element = $(id);
return element.parentNode.removeChild(element);
}
function resolveElemId(elem)
{
if(elem)
{
var id = elem.getAttribute('id');
if(!id) 
{			
id = randomize.toId();
while($(id))
{
id = randomize.toId();
}
elem.setAttribute('id', id);
}
return id;
}
return "";
}
var CachedElement = {
uberElements:{},
cacheElement:function(name) {
return CachedElement.uberElements[name]=document.createElement(name);
},
create:function(name) {
var query = CachedElement.uberElements[name] || CachedElement.cacheElement(name);
return query.cloneNode(false);
}
}
function getFirstTag(parent,tagname)
{
if(!parent) return null;
var nodes = parent.childNodes;
for(var i=0,len=nodes.length;i<len;i++)
{
var node = nodes[i];
if(node && node.nodeType == 1)
{
if(!tagname) return node;
else if(node.nodeName == tagname) return node;
else continue;	
}
}
return null;
}
function getChildTags(parent, tagname)
{
if(!parent) return null;
var output = new Array();
var nodes = parent.childNodes;
for(var i=0,len=nodes.length;i<len;i++)
{
var node = nodes[i];
if(node && node.nodeType == 1)
{
if(!tagname) output.push(node);
else if(node.nodeName == tagname) output.push(node);
else continue;
}
}
return output;
}
function attrExp(s)
{
return new RegExp("(^| )"+s+"( |$)"); 
}
function getAttrValue(node, attr)
{
if(node[attr] != null) return node[attr];
if(node.getAttribute(attr) != null) return node.getAttribute(attr);
return "";
}
function getAttributesAtMarker(attr,marker,name)
{
var output;
if(!attr) return output;
var params = attr.split(" ");
for(var i = 0, output, len=params.length; i<len; i++)
{
var p = params[i];
var m = (p.indexOf(marker) > -1);
var n = (p.indexOf(name) > -1);
if(m && n)
{
output = [];
continue;
}
else if(output)
{
if(m)
{
break;
}
else
{
output.push(p);
continue;
}
}
}
return output;
}
if( typeof com.campusmedica.css == "undefined" ) com.campusmedica.css = new Object();
com.campusmedica.css.makeLink = function( href, id, title, media, disabled )
{
var 
lk = document.createElement('link'),
i = arguments.length-1;
do
{
switch(i)
{
case 0: lk.setAttribute('href', arguments[0]); break;
case 1: lk.setAttribute('id', arguments[1]); break;
case 2: lk.setAttribute('title', arguments[2]); break;
case 3: lk.setAttribute('media', arguments[3]); break;
case 4: lk.setAttribute('disabled', arguments[4]); break;
}
}
while(i--);
lk.setAttribute('rel','stylesheet');
lk.setAttribute('type','text/css');
return lk;
}
com.campusmedica.css.getElementStyle = function( elem, attrstyle, propstyle )
{
if(typeof elem == 'string') elem = $(elem);
if(!elem) return "";
if(!propstyle) propstyle = attrstyle;
if (elem.style[propstyle]) 
{
return elem.style[propstyle];
}
else if(elem.currentStyle) 
{
return elem.currentStyle[propstyle];
}
else if(window.getComputedStyle) 
{
return window.getComputedStyle(elem,"").getPropertyValue(attrstyle);
}
else if (document.defaultView && document.defaultView.getComputedStyle) 
{
return document.defaultView.getComputedStyle(elem,"").getPropertyValue(attrstyle);
}
return "";
}
com.campusmedica.css.putRule = function( cssIndex,selectorIndex,selector,prop )
{
try
{
if(cssIndex.insertRule)
{
cssIndex.insertRule(selector+"{"+prop+"}",selectorIndex);
}
else if(css.addRule)
{
cssIndex.addRule(selector,prop,selectorIndex);
}
return selectorIndex;
}
catch(e)
{
return -1;
}
}
com.campusmedica.css.attachCssToDOM = function ( paths,dom )
{
if(!dom || !paths.length) return false;
var i = paths.length-1;
if(document.createStyleSheet)
{
do {
document.createStyleSheet(paths[i]);
} while (i--);
}
else if(document.createDocumentFragment)
{
var links = document.createDocumentFragment();
do {
links.appendChild(this.makeLink(paths[i]));
} while (i--);
dom.appendChild(links);
}
return true;
}
CSSProfile = function()
{
this.features = {};
this.seekfeatures = function() { return this};
return this;
}
CSSProfile.prototype.init = function()
{
var testready = this.buildtest.call(this.seekfeatures);
if(testready)
{
for(feature in this.featuretests)
{
this.features[feature] = this.featuretests[feature].call(this.seekfeatures);
}
this.isIE7 = (this.features.layout == true && this.features.stretch == false);
this.isIE5 = (this.features.layout == false && this.features.stretch == true);
}
this.removetest.call(this.seekfeatures);
}
CSSProfile.prototype.trace = function()
{
var str = "";
for(var i=0;i<arguments.length;i++)
{
var prop = this[arguments[i]];
if(prop && isObject(prop))
{
var sep = "";
for(v in prop)
{
str += (sep+v+"="+prop[v]);
sep = ", ";
}
}
}
alert(str);
}
CSSProfile.prototype.featuretests = {
base: function()
{
return com.campusmedica.css.getElementStyle(this.testelements[0],'position') == "absolute";
},
after: function()
{
return this.testelements[3].offsetHeight >= 4;
},
before: function()
{
var h = this.testelements[3].offsetHeight;
return h==4 || h > 5;
},
stretch: function()
{
return this.testelements[1].offsetHeight > 2; 
},
w3box: function()
{
return this.testelements[2].offsetWidth == 4;
},
iebox: function()
{
return this.testelements[2].offsetWidth == 2;
},
isIE6: function()
{
	ua = navigator.userAgent.toLowerCase();
	if (ua.indexOf('msie 6') != -1) {return true;} else  {return false;}
},
layout: function()
{
return com.campusmedica.css.getElementStyle(this.testelements[2],'hasLayout') == true; 
},
directchild: function()
{
return com.campusmedica.css.getElementStyle(this.testelements[2],'overflow') == 'hidden';
},
firstchild: function()
{
return com.campusmedica.css.getElementStyle(this.testelements[2],'direction') == 'rtl';
},
lastchild: function()
{
return com.campusmedica.css.getElementStyle(this.testelements[3],'direction') == 'rtl';
},
adjacent: function()
{
return com.campusmedica.css.getElementStyle(this.testelements[3],'clear') == 'right';
},
attribute: function()
{
return com.campusmedica.css.getElementStyle(this.testelements[1],'cursor') == 'crosshair';
}
}
CSSProfile.prototype.buildtest = function()
{
this.testelements = [];
var i=0;
while(i<5)
{
var div = CachedElement.create("div");
div.id = "testelem"+i;
this.testelements[i] = div;
i++
}		
this.testelements[0].appendChild(this.testelements[1]);
this.testelements[1].appendChild(this.testelements[2]);
this.testelements[1].appendChild(this.testelements[3]);
this.testelements[3].appendChild(this.testelements[4]);
document.body.appendChild(this.testelements[0]);
return true;
}
CSSProfile.prototype.removetest = function()
{
return this.testelements[0].parentNode.removeChild(this.testelements[0]);
}
com.campusmedica.cssprofile = new CSSProfile();
StyleEvent = function(elem)
{
this.elem = elem;
this.elem.styleEvent = this;
this.styles = new Object();
var styles = this.elem.className.split(' ');
for(var i=0, style; style=styles[i]; i++)
{
this.styles[style] = true;
}
this.add = function()
{
for(var i=0, argument; argument=arguments[i]; i++)
{
this.styles[argument] = (this.styles[argument]) ? true : false;
}
}
this.remove = function(stylename)
{
delete this.styles[stylename];
}
this.enable = function(stylename)
{
if(this.styles[stylename]) return;
if(this.styles[stylename] == 'undefined') return;
this.styles[stylename] = true;
this.elem.className = this.compile();
return;
}
this.disable = function(stylename)
{
if(!this.styles[stylename]) return;
this.styles[stylename] = false;
this.elem.className = this.compile();
return;
}
this.toggle = function(newstyle, currstyle)
{
if(this.styles[newstyle]) return false;
if(this.styles[currstyle]) this.styles[currstyle] = false;
this.styles[newstyle] = true;
this.elem.className = this.compile();
}
this.compile = function()
{
var output = "";
for(prop in this.styles)
{
if(this.styles[prop])
{
output += (prop+' ');
}
}
return output;
}
return this;
}	
var cookies;
function parseCookies() {
var cookiesHash = new Object();
var cookiesArray = document.cookie.split(';');
for (i=0; i < cookiesArray.length; i++) {
cookie = cookiesArray[i];
cookie = cookie.split('=');
cookiesHash[cookie[0]] = cookie[1];
}
return cookiesHash;
}
function getCookie (name) {
var value = null;
if (name != null) {
name = name.toUpperCase();
cookies = (cookies) ? cookies : parseCookies();
for (key in cookies) {
if (key.toUpperCase().match(name)) {
value = decodeURI(cookies[key]);
if (value.indexOf('%') != -1) value = unescape(value);
break;
}
}
}
return value;
}
function cookiesToString () { 
cookies = (cookies) ? cookies : parseCookies();
var fvString = new String();
if (arguments.length != 0) {
for (var i=0; i < arguments.length; i++) {
cookieName = arguments[i];
fvString += cookieName +'='+ getCookie(cookieName) +';';
}
} else {
for (cookie in cookies) {
fvString += cookie +'='+ cookies[cookie] +';';
}
}
return fvString;
}
function setCookie (name,value,msec,path,domain,secure) {
if (name != null) {
var now = new Date();
var exp_date = new Date(now.getTime()+(msec?msec:0));
var cookie = name+'='+escape(value)+';';
if (msec) cookie += 'expires='+exp_date.toUTCString()+';';
if (path) cookie += 'path='+path+';';
if (domain) cookie += 'domain='+domain+';';
if (secure) cookie += 'secure;';
document.cookie = cookie;
}
}
function selectFormAction (formID,dropdownID) { 
var selectedLink = document[formID][dropdownID].options[document[formID][dropdownID].selectedIndex].value;
if (selectedLink != '#') {
window.location=document[formID][dropdownID].options[document[formID][dropdownID].selectedIndex].value;
} else if (selectedLink == '#') {
document[formID][dropdownID].selectedIndex = 0;
}
}
Dimensions = function (w,h) { 
this.width = w || 0;
this.height = h || 0;
return this;
}
XYCoords = function (x,y) { 
this.x = x || 0;
this.y = y || 0;	
return this;
}
BoxCoords = function (x1,y1,x2,y2) {
this.x1 = x1 || 0;
this.y1 = y1 || 0;
this.x2 = x2 || 0;
this.y2 = y2 || 0;
return this;
}
function getEventCoords (e) {
var coords = new XYCoords();
if (e.pageX && e.pageY) {
coords.x = e.pageX;
coords.y = e.pageY;
} else if (e.clientX && e.clientY) {
coords.x = e.clientX + document.body.scrollLeft;
coords.y = e.clientY + document.body.scrollTop;
}
return coords;
}
function getElementBoxCoords(domElement) {
this.element = domElement;
this.calculated_offset;
this.calcOffsetFrom = function (element,from,reset) {
if (reset != false) this.calculated_offset = 0;
if (element != null)	{
switch (from) {
case 'top': 
this.calculated_offset += element.offsetTop;
break;
case 'left': 
this.calculated_offset += element.offsetLeft;
break;
}
if ((element.offsetParent == document.body) || (element.offsetParent.tagName == ('HTML'||'BODY'))) {				
return this.calculated_offset;
} else {
return this.calcOffsetFrom(element.offsetParent,from,false);
}
}
}
this.w = this.element.offsetWidth;
this.h = this.element.offsetHeight;
var coords = new BoxCoords();
coords.x1 = this.calcOffsetFrom(this.element,'left',true);
coords.y1 = this.calcOffsetFrom(this.element,'top',true);
coords.x2 = coords.x1 + this.w;
coords.y2 = coords.y1 + this.h;
return coords;
}
function getElementBoxCoordsById(elementID) {
var element = document.getElementById(elementID);
if (element != null) {
return getElementBoxCoords(element);
}
}
function getWindowDimensions () {
var width = (window.innerWidth) ? window.innerWidth : document.body.clientWidth;
var height = (window.innerHeight) ? window.innerHeight : document.body.clientHeight;
return new Dimensions(width,height);
}
function getContentDimensions () {
var width = Math.max(document.body.offsetWidth,document.body.scrollWidth);
var height = Math.max(document.body.offsetHeight,document.body.scrollHeight);
return new Dimensions(width,height);
}
function getScrollPosition () {
var scrollPosition = new XYCoords();
if (window.scrollX && window.scrollY) {
scrollPosition.x = window.scrollX;
scrollPosition.y = window.scrollY;
} else {
var docBody = document.body;
var parent_scrollLeft = (docBody.parentNode.scrollLeft) ? docBody.parentNode.scrollLeft : 0;
var parent_scrollTop = (docBody.parentNode.scrollTop) ? docBody.parentNode.scrollTop : 0;
scrollPosition.x = Math.max(docBody.scrollLeft,parent_scrollLeft);
scrollPosition.y = Math.max(docBody.scrollTop,parent_scrollTop);
}
return scrollPosition;
}
DropDownCollisionManager = function()
{
this.listcount = 0;
this.menuElements = new Array();
this.attr = attrExp('d-dropdown');
return this;
}
DropDownCollisionManager.prototype.getCollision = function(id,buffer)
{
var idpos = getElementBoxCoordsById(id);
var ddcount = this.updateMenuArray();
buffer = (buffer || 0);
for(var i = ddcount - 1; i > -1; i--) 
{
var menupos = this.menuElements[i].coords;
if((((menupos.y2+buffer)-idpos.y1) > 0) && (idpos.y1 > menupos.y2))
{
return this.menuElements[i].id; 
}
else
{
continue; 
}
}	
return ""; 
}
DropDownCollisionManager.prototype.updateMenuArray = function()
{
for(var i=this.listcount;(list = document.getElementsByTagName('UL')[i]);i++)
{
if(getAttrValue(list,"className").search(this.attr) > -1)
{
this.menuElements.push({id:resolveElemId(list),coords:getElementBoxCoords(list)});
}
this.listcount++;
}
return this.menuElements.length;
}
var ddmanager = new DropDownCollisionManager();
function getWM(id) 
{
return (ddmanager.getCollision(id,360)) ? 'transparent' : 'window';
}
function getOverlapId(id)
{
return (ddmanager.getCollision(id,360));
}
function defineEventHandler (element,eventName,handler,capture) {
try {
if (document.addEventListener) {
element.addEventListener(eventName,handler,capture);
} else if (document.attachEvent) {
eventName = 'on'+eventName;
element.attachEvent(eventName,handler);
}
} catch (ex) {
return;
}
}
function removeEventHandler (element,eventName,handler,capture) {
try {
if (document.removeEventListener) {
element.removeEventListener(eventName,handler,capture);
} else if (document.detachEvent) {
element.detachEvent('on'+eventName,handler);
}	
} catch (ex) {
return;
}
}
var onload_queue = new Array();
function execute_onload () {
for (var i=0; i < onload_queue.length; i++) {
onload_queue[i]();
}
}
function registerOnLoadFunc () {
for (var i=0; i < arguments.length; i++) {
if (typeof arguments[i] == 'function') onload_queue[onload_queue.length] = arguments[i];
}
if (document.addEventListener || document.attachEvent) {
var domElement = (window.opera) ? document : window;
removeEventHandler(domElement,'load',execute_onload,false);
defineEventHandler(domElement,'load',execute_onload,false);
} else {
onload = execute_onload;
}
}
var unload_queue = new Array();
function execute_unload () {
for (var i=0; i < unload_queue.length; i++) {
unload_queue[i]();
}
}
function registerUnLoadFunc () {
for (var i=0; i < arguments.length; i++) {
if (typeof arguments[i] == 'function') unload_queue[unload_queue.length] = arguments[i];
}
if (document.addEventListener || document.attachEvent) {
var domElement = (window.opera) ? document : window;
defineEventHandler(domElement,'unload',execute_unload,false);
} else {
onunload = execute_unload;
}
}
var onReadyQueue = new Array();
function registerOnReady()
{
for (var i=0; i < arguments.length; i++) {
if (typeof arguments[i] == 'function') onReadyQueue.push(arguments[i]);
}
}
function executeOnReady () {
if (arguments.callee.done) return; 
arguments.callee.done = true; 
for (var i=0, len = onReadyQueue.length; i < len; i++) {
onReadyQueue[i]();
}
onReadyQueue = new Array(0);
}
if (document.addEventListener) {
document.addEventListener("DOMContentLoaded", executeOnReady, false);
}
if (/WebKit/i.test(navigator.userAgent)) { 
var $timer = setInterval(function() {
if (/loaded|complete/.test(document.readyState)) {
clearInterval($timer);
$timer = null;
executeOnReady(); 
}
}, 10);
}
registerOnLoadFunc(executeOnReady);
BrowserDescription = function () {
this.appN = navigator.appName.toLowerCase();
this.appV = parseInt(navigator.appVersion);
this.ua = navigator.userAgent.toLowerCase();
this.plt = navigator.platform.toLowerCase();
this.lang = (navigator.language || navigator.userLanguage).substring(0,2); 
if (this.ua.indexOf('opera/7') != -1 || this.ua.indexOf('opera 7') != -1) {
this.appV = 7;
}
this.ax = window.ActiveXObject != "undefined";
this.isSafari = (this.ua.indexOf('safari') != -1); 
if(this.ua.indexOf('safari') != -1) 
{
var wk = 'applewebkit/';
var kitpos = this.ua.indexOf(wk);
if(kitpos == -1) return null;
var kit = this.ua.substring(kitpos+wk.length);
kit = kit.substring(0,kit.indexOf(" "));
this.kitV = parseInt(kit);
}
return this;
}
var browser = new BrowserDescription();
var fobjs = [];
function registerSWFObject(fobj,domtarg)
{
if(browser.ax && !browser.isSafari)
{
$(domtarg).style.visibility="hidden";
fobjs.push({ob:fobj,dm:domtarg});
}
else
{
fobj.write(domtarg);
}
}
function writeFOArr()
{
if(!fobjs) return 0;
for(var i=0,len=fobjs.length;i<len;i++)
{
var fobj = fobjs[i];
$(fobj.dm).style.visibility="visible";
fobj.ob.write(fobj.dm);
fobj=null;
}
return 1;
}
if(typeof com=="undefined"){var com=new Object();}
if(typeof com.deconcept=="undefined"){com.deconcept=new Object();}
if(typeof com.deconcept.util=="undefined"){com.deconcept.util=new Object();}
if(typeof com.deconcept.SWFObjectUtil=="undefined"){com.deconcept.SWFObjectUtil=new Object();}
com.deconcept.SWFObject = function( obj ){
if (!document.createElement || !document.getElementById) return;
if( typeof obj.swf == "undefined" ) return;
var swf = obj.swf;
if( typeof obj.id == "undefined" ) return;
var id = obj.id;
if( typeof obj.w == "undefined" ) return;
var w = obj.w;
if( typeof obj.h == "undefined" ) return;
var h = obj.h;
var ver 		= ( typeof obj.ver == "undefined" ) ? "6" : obj.ver;
var c			= ( typeof obj.c == "undefined" ) ? "#ffffff" : obj.c;
var q			= ( typeof obj.q == "undefined" ) ? "high" : obj.q;
var useExpressInstall = ( typeof obj.useExpressInstall == "undefined" ) ? false : obj.useExpressInstall;
var xir 		= ( typeof obj.xiRedirectUrl == "undefined" ) ? window.location : obj.xiRedirectUrl;
var redirectUrl = ( typeof obj.redirectUrl == "undefined" ) ? "" : obj.redirectUrl;
var salign 		= ( typeof obj.salign == "undefined" ) ? "tl" : obj.salign;
var wmode 		= ( typeof obj.wmode == "undefined" ) ? "window" : obj.wmode;
var menu 		= ( typeof obj.menu == "undefined" ) ? "false" : obj.menu;
var onFailFunc 	= ( typeof obj.onFailFunc == "undefined" ) ? "" : obj.onFailFunc;
var objID 		= ( typeof obj.objID == "undefined" ) ? "" : obj.objID;
var embedID 	= ( typeof obj.embedID == "undefined" ) ? "" : obj.embedID;
var name 		= ( typeof obj.name == "undefined" ) ? "" : obj.name;
var pluginspage = ( typeof obj.pluginspage == "undefined" ) ? "" : obj.pluginspage;
var codebase	= ( typeof obj.codebase == "undefined" ) ? "" : obj.codebase;
this.DETECT_KEY = ( typeof obj.detectKey == "undefined" ) ? "detectflash" : obj.detectKey ;
this.skipDetect = com.deconcept.util.getRequestParameter(this.DETECT_KEY);
this.params = new Object();
this.variables = new Object();
this.attributes = new Array();
this.useExpressInstall = useExpressInstall;
this.isInlineInstall = ( obj.isInlineInstall == "true" );
this.setAttribute( 'swf', swf );
this.setAttribute( 'id', id );
this.setAttribute( 'width', w );
this.setAttribute( 'height', h );
this.setAttribute( 'version', new com.deconcept.PlayerVersion(ver.toString().split(".")) );
this.installedVer = com.deconcept.SWFObjectUtil.getPlayerVersion(this.getAttribute('version'), useExpressInstall);
this.addParam( 'bgcolor', c );
this.addParam( 'quality', q );
this.setAttribute( 'redirectUrl', redirectUrl );
if( typeof obj.scale != "undefined" )
this.addParam( 'scale', obj.scale ); 
this.addParam( 'salign', salign );
this.addParam( 'wmode', wmode );
this.addParam( 'menu', menu );
this.setAttribute( 'onFailFunc', onFailFunc );
this.setAttribute( 'objID', objID );
this.setAttribute( 'embedID', embedID );
this.setAttribute( 'name', name );
this.setAttribute( 'codebase', codebase );
if( pluginspage != "" )
this.addParam( 'pluginspage', pluginspage );
}
com.deconcept.SWFObject.prototype = {
setAttribute: function(name, value){
this.attributes[name] = value;
},
getAttribute: function(name){
return this.attributes[name];
},
addParam: function(name, value){
this.params[name] = value;
},
getParams: function(){
return this.params;
},
addVariable: function(name, value){
this.variables[name] = value;
},
getVariable: function(name){
return this.variables[name];
},
getVariables: function(){
return this.variables;
},
createParamTag: function(n, v){
var p = document.createElement('param');
p.setAttribute('name', n);
p.setAttribute('value', v);
return p;
},
getVariablePairs: function(){
var variablePairs = new Array();
var key;
var variables = this.getVariables();
for(key in variables){
variablePairs.push(key +"="+ variables[key]);
}
return variablePairs;
},
getFlashHTML: function() {
var flashNode = "";
if (navigator.plugins && navigator.mimeTypes && navigator.mimeTypes.length) { 
var $ID = this.getAttribute( 'embedID' );
if( $ID == "" ) $ID = this.getAttribute( 'id' );
var $name = this.getAttribute( 'name' );
if( $name == "" ) $name = $ID;
if (this.getAttribute("doExpressInstall")) this.addVariable("MMplayerType", "PlugIn");
if( browser.isSafari && browser.kitV < 420 )
flashNode = '<img src="/images/pixel.gif" name="objectMask" width="'+this.getAttribute( 'width' )+'" height="'+this.getAttribute( 'height' ) + '" class="off" />';
flashNode += '<embed type="application/x-shockwave-flash" src="'+ this.getAttribute('swf') +'" width="'+ this.getAttribute('width') +'" height="'+ this.getAttribute('height') +'"';
flashNode += ' id="'+ $ID +'" name="'+ $name +'" ';
var params = this.getParams();
for(var key in params){ flashNode += [key] +'="'+ params[key] +'" '; }
if( this.isInlineInstall ) this.addVariable( "MMPlayerType", "PlugIn" );
var pairs = this.getVariablePairs().join("&");
if (pairs.length > 0){ flashNode += 'flashvars="'+ pairs +'"'; }
flashNode += '/>';
} else { 
var $ID = this.getAttribute( 'objID' );
if( $ID == "" ) $ID = this.getAttribute( 'id' );
if (this.getAttribute("doExpressInstall")) this.addVariable("MMplayerType", "ActiveX");
if( browser.isSafari && browser.kitV < 420  )
flashNode = '<img src="/images/pixel.gif" name="objectMask" width="'+this.getAttribute( 'width' )+'" height="'+this.getAttribute( 'height' ) + '" class="off" />';
flashNode += '<object id="'+ $ID +'" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="'+ this.getAttribute('width') +'" height="'+ this.getAttribute('height') + '"';
if( this.getAttribute('codebase') == "" )
flashNode += '>';
else
flashNode += ' codebase="'+ this.getAttribute('codebase') + '">';
flashNode += '<param name="movie" value="'+ this.getAttribute('swf') +'" />"';
var params = this.getParams();
for(var key in params) {
flashNode += '<param name="'+ key +'" value="'+ params[key] +'">';
}
if( this.isInlineInstall ) this.addVariable( "MMPlayerType", "ActiveX" );
var pairs = this.getVariablePairs().join("&");
if(pairs.length > 0) flashNode += '<param name="flashvars" value="'+ pairs +'">';
flashNode += "</object>";
}
if( getQueryParamValue( 'alert' ) == "true" )
alert( "writing:\n"+flashNode);
return flashNode;
},
write: function(elementId){
var m = getQueryParamValue("m");
var nf = getQueryParamValue("nf");
if( getCookie( 'mediapref' ) == "gif" || m == 'g' || m=="gif" || nf == "1" )
return;
if(this.useExpressInstall) {
var expressInstallReqVer = new com.deconcept.PlayerVersion([6,0,65]);
if (this.installedVer.versionIsValid(expressInstallReqVer) && !this.installedVer.versionIsValid(this.getAttribute('version'))) {
this.setAttribute('doExpressInstall', true);
this.addVariable("MMredirectURL", escape(this.getAttribute('xiRedirectUrl')));
document.title = document.title.slice(0, 47) + " - Flash Player Installation";
this.addVariable("MMdoctitle", document.title);
}
} else {
this.setAttribute('doExpressInstall', false);
}
if(this.skipDetect || this.getAttribute('doExpressInstall') || this.installedVer.versionIsValid(this.getAttribute('version'))){
var n = (typeof elementId == 'string') ? document.getElementById(elementId) : elementId;
n.innerHTML = this.getFlashHTML();
}else{
if(this.getAttribute('redirectUrl') != "") {
document.location.replace(this.getAttribute('redirectUrl'));
}
if( this.getAttribute('onFailFunc') != "" )
{
var func = this.getAttribute( 'onFailFunc' );
func();
}
}
}
}
com.deconcept.SWFObjectUtil.getPlayerVersion = function(reqVer, xiInstall){
var PlayerVersion = new com.deconcept.PlayerVersion(0,0,0);
if(navigator.plugins && navigator.mimeTypes.length){
var x = navigator.plugins["Shockwave Flash"];
if(x && x.description) {
PlayerVersion = new com.deconcept.PlayerVersion(x.description.replace(/([a-z]|[A-Z]|\s)+/, "").replace(/(\s+r|\s+b[0-9]+)/, ".").split("."));
}
}else{
try{
var axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash");
for (var i=3; axo!=null; i++) {
axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash."+i);
PlayerVersion = new com.deconcept.PlayerVersion([i,0,0]);
}
}catch(e){}
if (reqVer && PlayerVersion.major > reqVer.major) return PlayerVersion; 
if (!reqVer || ((reqVer.minor != 0 || reqVer.rev != 0) && PlayerVersion.major == reqVer.major) || PlayerVersion.major != 6 || xiInstall) {
try{
PlayerVersion = new com.deconcept.PlayerVersion(axo.GetVariable("$version").split(" ")[1].split(","));
}catch(e){}
}
}
return PlayerVersion;
}
com.deconcept.PlayerVersion = function(arrVersion){
this.major = parseInt(arrVersion[0]) || 0;
this.minor = parseInt(arrVersion[1]) || 0;
this.rev = parseInt(arrVersion[2]) || 0;
}
com.deconcept.PlayerVersion.prototype.versionIsValid = function(fv){
if(this.major < fv.major) return false;
if(this.major > fv.major) return true;
if(this.minor < fv.minor) return false;
if(this.minor > fv.minor) return true;
if(this.rev < fv.rev) return false;
return true;
}
com.deconcept.util = {
getRequestParameter: function(param){
var q = document.location.search || document.location.href.hash;
if(q){
var startIndex = q.indexOf(param +"=");
var endIndex = (q.indexOf("&", startIndex) > -1) ? q.indexOf("&", startIndex) : q.length;
if (q.length > 1 && startIndex > -1) {
return q.substring(q.indexOf("=", startIndex)+1, endIndex);
}
}
return "";
},
removeChildren: function(n){
while (n.hasChildNodes()) n.removeChild(n.firstChild);
}
}
if (Array.prototype.push == null) { Array.prototype.push = function(item) { this[this.length] = item; return this.length; }}
var getQueryParamValue = com.deconcept.util.getRequestParameter;
var SWFObject = com.deconcept.SWFObject;
var SWFObjectUtil = com.deconcept.SWFObjectUtil;


/* Copyright (c) 2006 campusmedica Systems Inc. $Revision: 1.60 $ */
function initMembership() {
if(!$("globalnav") && !$('user-menu') && window.location.hostname.indexOf('campusmedica.com') == -1) return;
var membershipElements = {
'greeting': $('greeting'),
'screen_name': $('screenName'),
'account_link': $('account'),
'signout': $('signout')
}
for (var prop in membershipElements) {
if (membershipElements[prop] == null) return;
}
function showScreenName () {
var name = getCookie('SCREENNAME');
if (name != null && (name != '' || name != 'undefined')) {
membershipElements['screen_name'].innerHTML = name;
}
}
var authLevel = 0;
authLevel = (getCookie('RMID') != null) ? 1 : authLevel;
authLevel = (getCookie('AUID') != null) ? 2 : authLevel;
var listitem = ((browser.ua.indexOf('mac') != -1) && (browser.appN.indexOf('microsoft') != -1)) ? 'inline-block' : 'block';
switch (authLevel) {
case 0:
membershipElements.greeting.style.display = 'none';
membershipElements.account_link.style.display = listitem;
break;
case 1:
showScreenName();
membershipElements.greeting.style.display = listitem;
break;
case 2:
showScreenName();
membershipElements.greeting.style.display = listitem;
membershipElements.signout.style.display = listitem;
break;
default: break;
}
}
browser = browser || new BrowserDescription();
if ((!window.opera && browser.ua.indexOf('netscape6') == -1) || (window.opera && browser.appV >= 7)) { 
registerOnReady(initMembership);
}


/*	
	Copyright 2007 Campus Medica
	Dynamic UI Javascript (in development)
	$Revision: 1.25 $
*/
UI = function() {
this.components = {};
this.registered = {};
return this;
}
UI.prototype = {
init: function(configs) {
for(prop in configs) {
if(!this.registered[prop]) continue;
var config = configs[prop];
var component = new UIComponent();
if(config.tags) {
var subscribers = component.getDomSubscribers(config.tags, config.key, config.value);
if(subscribers && config.method) {
component.applyConfigMethod(config.method);
}
}			
this.components[prop] = component;
}
},
register: function() {
for(var i=0,len=arguments.length;i<len;i++) {
this.registered[arguments[i]] = 1;
}
}
}
UIComponent = function() {
this.members = [];
return this;
}
UIComponent.prototype = {
getDomSubscribers: function(tags, attr, value) {
var len = tags.length-1,
value = attrExp(value);
do 
{
var name = tags[len];
for(var i = 0; (t = document.getElementsByTagName(name)[i]); i++)
{
if(getAttrValue(t, attr).search(value) == -1) continue;
this.members.push({id:resolveElemId(t)});
}
}
while (len--);
return this.members.length;
},
applyConfigMethod: function(method) {
method = eval(method);
var i = this.members.length-1;
do {
method.call(this, this.members[i]);
} while(i--);
}
};
function buildPodComponent(member)
{
var handleContentAsText = (browser.ax);
var stylefirst = (com.campusmedica.cssprofile.features.firstchild == false); 
var id = member.id;
var pod = makePodElem($(id), id+'-body', stylefirst, handleContentAsText);
$(id).parentNode.replaceChild(pod.rootelem,$(id));
function makePodElem(elem,bodyID,stylefirst,handleContentAsText)
{
var
prevElem = null,
skinElements = {
'nw':{"elem":elem.cloneNode(false),"cssname":(elem.className.replace("dyn-pod","pod")+' nw')},
'ne':{"elem":CachedElement.create('div'),"cssname":'ne'},
'se':{"elem":CachedElement.create('div'),"cssname":'se'},
'sw':{"elem":CachedElement.create('div'),"cssname":'sw'},
'n':{"elem":CachedElement.create('div'),"cssname":'n'},
's':{"elem":CachedElement.create('div'),"cssname":'s'},
'w':{"elem":CachedElement.create('div'),"cssname":'w'},
'e':{"elem":((handleContentAsText)? CachedElement.create('DIV') : elem.cloneNode(true)),"cssname":'pod-body e'}
};
if(!handleContentAsText)
{
for(var i=0,len=skinElements.e.elem.attributes.length;i<len;i++)
{
skinElements.e.elem.removeAttribute(skinElements.e.elem.attributes[i].nodeName);
}
}
if(bodyID) 
{
skinElements.e.elem.setAttribute('id',bodyID);
}	
if(stylefirst)
{
var firsttag = getFirstTag(((handleContentAsText) ? elem : skinElements.e.elem));
var str = (!firsttag.className) ? 'first-child' : firsttag.className+' first-child';
firsttag.className = str;
if(firsttag.nodeName == 'DL' || firsttag.nodeName == 'UL'  || firsttag.nodeName == 'OL')
{
var firstItem = getFirstTag(firsttag);
var str = (!firstItem.className) ? 'first-child' : (firstItem.className+' first-child');
firstItem.className = str;
}
}
if(handleContentAsText) skinElements.e.elem.innerHTML = elem.innerHTML;
for(prop in skinElements)
{	 
skinElements[prop].elem.className =  skinElements[prop].cssname;
if(prevElem) prevElem.elem.appendChild(skinElements[prop].elem); 
prevElem = skinElements[prop];
}
return { rootelem:skinElements.nw.elem, bodyelem:skinElements.e.elem };
}
}
function balanceContentToPod()
{
var 
C1 = $('C1'),
C1b = $('C1-body'),
C2 = $('C2');
if(C1&&C1b&&C2)
{
var 
C1h = C1.offsetHeight,
C1bh = C1b.offsetHeight,
C2h = C2.offsetHeight,
isTabContent;
if (isTabContent=1) C1bh = C1bh-10;		
if(C1h<C2h) {
var h = ((C1bh-C1h)+C2h)+"px";
if(com.campusmedica.cssprofile.features.layout && !com.campusmedica.cssprofile.isIE7) {
C1b.style.height = h;
}
else {
C1b.style.minHeight = h;
}
}
return true;
}	
return false;
}
function DropDownBehavior(member)
{
var elem = $(member.id);
if(!elem) return;
elem.styles = new StyleEvent(elem);
elem.styles.add('keymode','mousemode');
elem.onkeyup = function() {	this.styles.toggle('keymode','mousemode')};
elem.onmousemove = function() { this.styles.toggle('mousemode','keymode')};
masks = new Masks();
for(var i = 0; (mask = document.getElementsByName('objectMask')[i]); i++)
{
masks.add(mask);
}
var fc = com.campusmedica.cssprofile.features.firstchild;
for(var i=0,len = elem.childNodes.length;i<len;i++)
{
var node = elem.childNodes[i];
if(!node || node.nodeType != 1) continue;
var menu = getFirstTag(node,'UL');
menu = (menu) ? menu : getFirstTag(node,'DL');
if(!menu) continue;
if(masks.elements.length)
{
menu.hasMask = true;
menu.onmouseover = function(evt)
{
masks.setState(1);
}
menu.onmouseout = function(evt)
{
masks.setState(0);
}
}
if(!fc)
{
var f = getFirstTag(menu);
if(f)
{
f.styles = new StyleEvent(getFirstTag(menu));
f.styles.add('first-child');
f.styles.enable('first-child');
}
}
node.styles = new StyleEvent(node);
if(com.campusmedica.cssprofile.features.directchild == false) 
{
node.styles.add('over');
var mouseIN = (typeof document.body.onmouseenter == 'object') ? 'onmouseenter' : 'onmouseover';
var mouseOUT = (typeof document.body.onmouseleave == 'object') ? 'onmouseleave' : 'onmouseout';
node[mouseIN] = function()
{
this.styles.enable('over');
}
node[mouseOUT] = function()
{
this.styles.disable('over');
}
}
node.styles.add('focus');
var anchors = node.getElementsByTagName('A');
for(var a=0,len=anchors.length;a<len;a++)
{
var atag = anchors[a];
atag.ref = node.styles;
atag.onfocus = function()
{
this.ref.enable('focus');
}
atag.onblur = function()
{
this.ref.disable('focus');
}
}
}
return;
}
Masks = function(){return this;};
Masks.prototype = {
elements : [],
stateStyles : ['off','on'],
add : function(mask)
{
var maskobj = new StyleEvent(mask);
maskobj.add('on');
this.elements.push(maskobj);
return this.elements.length;
},
setState : function(state)
{
switch(state)
{
case 0:
this.doStyle(this.stateStyles[0],this.stateStyles[1]);
break;
case 1:
this.doStyle(this.stateStyles[1],this.stateStyles[0]);
break;
default: return;
}
},
doStyle : function(s0,s1)
{
var i=this.elements.length-1;
do 
{
this.elements[i].toggle(s0,s1);
}
while (i--);
}	
};
ToggleState = function(num)
{
this.state = (num || 0);
this.toggle = function()
{
this.state = (this.state) ? 0 : 1;
return this.state;
}
return this;
}
function buildTreeList(member) {
var styleObjects = {};
var elem = $(member.id);
for(var i=0,node; node = elem.childNodes[i]; i++) {	
if(node.nodeType==3) continue; 
switch(node.nodeName) {
case "DT":
dtID = resolveElemId(node);
styleObjects[dtID] = new Array();
var styles = new StyleEvent(node);
styles.add('on','off');
styleObjects[dtID].push(styles);
if(node.firstChild && (node.firstChild.nodeType==3)) {
var cloneTXT = node.firstChild.cloneNode(false);
var a = CachedElement.create('a');
var initnum = (styles.styles['on']) ? 1 : 0;
a.togglestate = new ToggleState(initnum);
a.styles = styleObjects[dtID];
a.onclick = function() {
var i;
this.togglestate.toggle();
switch(this.togglestate.state)
{
case 0:
for(var i=0;i<this.styles.length;i++) {
this.styles[i].toggle('off','on');
}
break;
case 1:
for(var i=0;i<this.styles.length;i++) {
this.styles[i].toggle('on','off');
}
break;
}
return void(0);
}
a.appendChild(cloneTXT);
node.replaceChild(a, node.firstChild);
}
break;
case "DD":
var ddID = resolveElemId(node);
var styles = new StyleEvent(node);
styleObjects[dtID].push(styles);
break;
}	
}
elem.className = elem.className.replace("dyn-","");
member.styleObjects = styleObjects;
}
function makeTreeExplode(member) {	
var elem = $(member.id);
var attrIds = getAttributesAtMarker(elem.rel,'dyn-','explodetree');
if(!attrIds.length) return false;
var trees = com.campusmedica.ui.components.trees.members;
var treeobjs = [];
for(var i=0,len=trees.length;i<len;i++)
{
var tree = trees[i];
for(var id=0,idlen=attrIds.length;id<idlen;id++)
{
attrId = attrIds[id];
if(tree.id != attrId) continue;
for(prop in tree.styleObjects)
{
treeobjs = treeobjs.concat(tree.styleObjects[prop]);
}
attrIds.splice(id,1);
}
}
var gg = new ToggleLinkText();
var itxt = gg.init(elem,1);
elem.gg = gg;
if(!elem.firstChild)
{
elem.appendChild(document.createTextNode(itxt));
}
elem.styles = treeobjs;
elem.style.cursor = "pointer";
elem.onclick = function()
{
this.firstChild.nodeValue = this.gg.run();
var s = (this.gg.state) ? ['on','off'] : ['off','on'];
for(var i=0,len=this.styles.length;i<len;i++)
{
var style = this.styles[i];
style.toggle(s[0],s[1]);
}
};
elem.firstChild.nodeValue = elem.gg.run();
return;
};
ToggleLinkText = function()
{
this.state;
this.txt;
this.init = function(a,state)
{
var text = (a.text || ""); 
this.state = (state || 0);
this.txt = [(a.title+text),(a.rev+text)];
a.removeAttribute('rev');
a.removeAttribute('title');
return this.txt[this.state];
}
this.run = function()
{
this.state = (this.state) ? 0 : 1;
return this.txt[this.state];
}
return this;
}
function buildMapHover(member) {
var elem = $(member.id);
var accentIds = getAttributesAtMarker(elem.getAttribute('rel'),'d-','accent');
elem['hovers'] = accentIds;
function dAccentEvent(evt) {
evt = (evt) ? evt : event;
var elem = ( evt.srcElement ) ? evt.srcElement : evt.target;
if(elem.nodeType == 3) { elem = elem.parentNode }
if( elem ) 
{
switch(evt.type)
{
case "mouseover":
state="on";
break;
case "mouseout":
state="";
break;
}
for(var i=0,hover; hover = elem.hovers[i]; i++)
{
$(hover).className=state;
}
}
}
elem.onmouseover = dAccentEvent;
elem.onmouseout = dAccentEvent;
return;
}
function buildTabSection(member) {
var queryPrefix = "tab:";
var newtab, nontab,
elem = $(member.id),
nav = CachedElement.create('ul'),
navstyle = (elem.className.indexOf('microtab') > -1) ? "microtab menu compact" : "tab menu compact",
tabManager = new TabManager(),
subtags = elem.childNodes;
nav.setAttribute('class', navstyle); 
if(!nav.className) nav.className = navstyle; 
for(var s=0,klen = subtags.length;s<klen;s++)
{
var kid=subtags[s];
if(!kid || (kid.nodeType != 1)) continue; 
switch(kid.className)
{
case "tabtitle":
var titleId = resolveElemId(kid); 
var contentDIVtitle = kid.firstChild; 
var menuItem = CachedElement.create('li'); 
var menuLink = CachedElement.create('a'); 
menuItem.setAttribute('id', titleId); 
newtab = tabManager.addTab( titleId, 0 ); 
var referencestyle = new StyleEvent(menuItem); 
referencestyle.add('on','off'); 
tabManager.styleObjects[titleId] = referencestyle; 
menuLink['tabkey'] = titleId; 
menuLink.tab = tabManager; 
menuLink.onclick = function() {
var winUpdate = false;
var total = "tab:"+this.tabkey;
if (window.location.search.indexOf('tab:') > -1) 
{
var a = 'tab:'+this.tab.states.current+'=1';
var b = 'tab:'+this.tabkey+'=1';
winUpdate = updateUrlQuery(a,b);
}
if(!winUpdate) 
{
this.tab.setState(this.tabkey);
}
}
menuLink.appendChild(contentDIVtitle); 
menuItem.appendChild(menuLink); 
nav.appendChild(menuItem); 
break;
case "tabcontent":
var contentId = resolveElemId(kid); 
tabManager.bindContent(newtab,contentId); 
var contentstyle = new StyleEvent(kid); 
contentstyle.add('hide'); 
tabManager.styleObjects[contentId] = contentstyle; 
break;
}
}
elem.parentNode.insertBefore(nav, elem);
elem.className = "";
var pick = 0; 
for (var z=0; z<tabManager.states.items.length; z++) {
var kd = tabManager.states.items[z].key;
var urlQuery = com.deconcept.util.getRequestParameter(queryPrefix+kd);
if (urlQuery) pick = z;
}
if(!tabManager.states.items.length) {
return;
}
var pickID = tabManager.states.items[pick].key;
var isTabContent=1;
balanceContentToPod();
tabManager.setState(pickID);
this[member.id] = tabManager; 
}
TabManager = function()
{
this.styleObjects = {};
this.contents = {};
this.states = new StateSwitch();
this.setState = function(id)
{
var newstate = this.states.setCurrent(id);
if(newstate)
{
this.setStyles(this.states.items);
}
}
this.addTab = function(key, value)
{
this.contents[key] = [];
var result = this.states.addItem(key,value);
return result;
}
this.bindContent = function(obj, contentId)
{
if(!this.contents[obj.key]) return null; 
this.contents[obj.key].push(contentId); 
return this.contents[obj.key].length;
}
this.setStyles = function(elements)
{
for(var i=0,element; element = elements[i]; i++)
{
switch(element.value)
{
case 0: 
this.styleObjects[element.key].toggle('off','on');
for(var c=0,content; content=this.contents[element.key][c]; c++)
{
this.styleObjects[content].enable('hide');
}
break;
case 1: 
this.styleObjects[element.key].toggle('on','off');
for(var c=0,content; content=this.contents[element.key][c]; c++)
{
this.styleObjects[content].disable('hide');
}
break;
}
}
}
}
StateSwitch = function()
{
this.current = '';
this.items = [];
this.addItem = function(id, value)
{
var obj = {'key':id, 'value':value};
this.items.push(obj);
return obj;
}
this.setCurrent = function(id)
{
if(this.current == id) return false;
var len = this.items.length;
for(var i=0;i<len;i++)
{
this.items[i].value = (this.items[i].key == id) ? 1 : 0;
}
this.current = id;
return true;
}
return this;
}
updateUrlQuery = function(currStr,newStr)
{
var tabQueryString = window.location.toString();
if(tabQueryString.indexOf(newStr) > -1) return false; 
if(tabQueryString.indexOf(currStr) == -1) return false; 
var tabQueryString = tabQueryString.replace(window.location.hash,'');
tabQueryString = tabQueryString.replace(currStr,newStr);
return window.location = tabQueryString;
}
TabLocation = function()
{
this.location = window.location.toString();
this.tabsyntax = ['tab:','=1'];
this.initLookup = function(obj)
{
this.lookup = {};
for(prop in obj)
{
var pos = prop.indexOf(this.tabsyntax[0]);
if(pos == -1) continue;
var n = prop.substring(pos+this.tabsyntax[0].length);
var v = obj[prop];
this.lookup[n]=v;
}
return true;
}
this.update = function(currStr,newStr)
{
if(this.location.indexOf(newStr) > -1) return false; 
if(this.location.indexOf(currStr) == -1) return false; 
this.location = this.location.replace(window.location.hash,'');
this.location = this.location.replace(currStr,newStr);
return window.location = this.location;
}
}
function explodeQueryString(str,div,assign)
{
var output={};
var pairs = str.split(div);
for(var i=0;i<pairs.length;i++)
{
var pos = pairs[i].indexOf(assign);
if(pos == -1) continue;
var n = pairs[i].substring(0,pos);
var v = pairs[i].substring(pos+1);
output[n] = v;
}	
return output;
}
var winquery = window.location.search;
if(winquery.length) 
{
var pos = winquery.indexOf('tab:');
if(pos > -1)
{
var winquery = winquery.substring(1);
var queryObject = explodeQueryString(winquery,'&','=');
this['tabparams'] = new TabLocation();
this.tabparams.initLookup(queryObject);
}
}
function contentBefore()
{
var str = arguments[0];	
if(arguments[1])
{
obj = spaceSpan(str);
obj.className = "space";
obj.style.position = "relative";
obj.style.right = arguments[1];
}
else
{
obj = document.createTextNode(str);
}
this.insertBefore(obj,this.firstChild);
return;
}
function contentAfter()
{
var str = arguments[0];
var obj;
if(arguments[1])
{
obj = spaceSpan(str);
obj.className = "space";
obj.style.position = "relative";
obj.style.left = arguments[1];
}
else
{
obj = document.createTextNode(str);
}
this.appendChild(obj);
return;
}
function spaceSpan(str)
{
var span = CachedElement.create('span');
span.appendChild(document.createTextNode(str));
return span;
}
function adjacent()
{
this.shift();
return this;
}
function last()
{
return this[this.length-1];
}
function marker(method,mark,marg)
{
if(isArray(this))
{
for(var i = 0,len=this.length;i<len;i++)
{
method.apply(this[i],[mark,marg]);
}
}
else if(isObject(this))
{
method.apply(this,[mark,marg]);
}
}
Children = function()
{
this.method;
this.setMethod = function(a)
{
return (document.body.children) ? 'children' : 'childNodes'; 
}
this.checkName = function(n,v)
{
return n.nodeName == v;
}
this.checkNone = function()
{
return true;
}
}
Children.prototype._all = function(root,name)
{
if(!this.method) this.method = this.setMethod();
name = (name || "");
var o = new Array();
var checkName = (name) ? this.checkName : this.checkNone;
if(isTag(root))
{
for(var i=0; (node=root[this.method][i]); i++)
{
if(isTag(node) && checkName(node,name)) o.push(node);
}
}
else if(isArray(root) || isNodeList(root))
{
var len=root.length-1;
do
{
if(isTag(root[len]))
{
var n = this._all.apply(this,[root[len], name]);
o = o.concat(n.reverse());
} 
}
while (len--);
}
return o;
}
Children.prototype.first = function(root, name)
{
if(!this.method) this.method = this.setMethod();
name = (name || "");
var checkName = (name) ? this.checkName : this.checkNone;
if(isTag(root))
{
if(this.method=="children")
{
return (checkName(root.children[0],name)) ? root.children[0] : null;
}
else if(this.method=="childNodes")
{
for(var i=0; (node=root.childNodes[i]); i++)
{
if(isTag(node) && checkName(node,name))
{
return node;
}
}
}
}
return null;
}
Children.prototype.last = function(root,name)
{
if(!this.method) this.method = this.setMethod();
name = (name || "");
var checkName = (name) ? this.checkName : this.checkNone;
if(isTag(root))
{
if(this.method=="children")
{
var last = root.children[root.children.length-1];
return (checkName(last,name)) ? last : null;
}
else if(this.method=="childNodes")
{
for(var i=root.childNodes.length-1; (node=root.childNodes[i]); i--)
{
if(isTag(node) && checkName(node,name))
{
return node;
}
}
}
}
}
children = new Children();
com.campusmedica.ui = new UI();
registerOnReady( function() { 
com.campusmedica.ui.init({
"pods": { 
id:'root', 
key: 'className', 
value:'dyn-pod', 
tags: ['div'], 
method: "buildPodComponent"
},
"tabs": { 
id: 'root', 
key: 'className', 
value:'dyn-tabsection', 
tags: ['div'], 
method: "buildTabSection"
},
"trees": { 
id: 'root', 
key: 'className', 
value:'dyn-treelist', 
tags: ['dl'], 
method: "buildTreeList"
},
"explodes": { 
id: 'root', 
key: 'rel', 
value:'dyn-explodetree',
tags: ['a'], 
method: "makeTreeExplode"
},
"maps": { 
id:'root', 
key: 'rel', 
value:'d-accent', 
tags: ['a','area'], 
method: "buildMapHover"
},
"dropdowns": {
id:'root', 
key: 'className', 
value:'d-dropdown', 
tags: ['ul'], 
method: "DropDownBehavior"
}
});
});
registerOnReady(writeFOArr);
registerOnReady(function() {
balanceContentToPod();
var af = com.campusmedica.cssprofile.features.after;
var lc = com.campusmedica.cssprofile.features.lastchild;
var dp = $('depthpath');
if(dp && !af || dp && !lc) {
var paths = children._all(dp,'LI');
if (paths.length != 0) {					
paths[paths.length-1].className = "last-child";
var pathsA = children._all(paths,'A');
marker.apply(pathsA,[contentAfter,"","1ex"]);
}
}
if(com.campusmedica.cssprofile.features.layout) {
for(var i = 0; (s = document.getElementsByTagName("select")[i]); i++) {
var e=getOverlapId(resolveElemId(s));
if(!e) continue;
var dom = $(e);
if(dom.masks) {
dom.masks.push(s);
continue;
}
else
{
dom.masks = new Array(s);
dom.onmouseover = function() {
var i = this.masks.length-1;
if(i<0) return;
do {
this.masks[i].style.visibility = "hidden";
} while(i--);
}
dom.onmouseout = function() {
var i = this.masks.length-1;
if(i<0) return;
do {
this.masks[i].style.visibility = "visible";
} while(i--);
}
}
}
}					 
});


/*
	HTML Template Utility
	$Revision: 1.24 $
*/
if( typeof com.campusmedica.htmltemplate == "undefined" ) com.campusmedica.htmltemplate = {
cssloaded:0,
featureTestReady: function()
{
return ($("test-css") && com.campusmedica.css);
},
loadCondAssets: function()
{
var head = document.getElementsByTagName('HEAD')[0]; 
if(!head) return;
var csspaths = new Array();
if(this.featureTestReady())
{
com.campusmedica.cssprofile.init();
if(browser.ua.indexOf('msie 5.2') == -1 && (browser.ua.indexOf('playstation') == -1) ) {
for(var i=0,len=arguments.length;i<len;i++)
{
var arg = arguments[i];
switch(arg)
{
case "pod": 
csspaths.push("/css/pod.css");
if(com.campusmedica.cssprofile.features.iebox || com.campusmedica.cssprofile.features.isIE6) csspaths.push("/css/pod_ie.css");
com.campusmedica.ui.register('pods');
break;
case "tree": 
csspaths.push("/css/treelist.css");
com.campusmedica.ui.register('trees','explodes');
break;
case "map": 
csspaths.push("/css/map.css");
com.campusmedica.ui.register('maps');
break;
case "tab": 
csspaths.push("/css/tabsection.css");
if(com.campusmedica.cssprofile.features.stretch) csspaths.push("/css/tabsection_ie.css");
com.campusmedica.ui.register('tabs');
break;
case "dropdown": 
if(!com.campusmedica.cssprofile.features.directchild) csspaths.push("/css/dropdown_help.css");
com.campusmedica.ui.register('dropdowns');
break;
case "backcompat": 
var compatmode = true;
break;
}
}
}
if(com.campusmedica.cssprofile.isIE7)
{
csspaths.push("/css/globalnav_ie7.css");
csspaths.push("/css/pod_ie7.css");
}			
if(!com.campusmedica.cssprofile.features.after)
{
csspaths.push("/css/compact_noafter.css");	
com.campusmedica.ui.register('markers');	
}
if(com.campusmedica.cssprofile.features.stretch)
{
csspaths.push("/css/compact_ie.css");
csspaths.push("/css/pullout_ie.css");
}
if(!com.campusmedica.cssprofile.features.adjacent)
{
csspaths.push("/css/markers_help.css");	
}

if(com.campusmedica.cssprofile.features.iebox || com.campusmedica.cssprofile.features.isIE6)
{
csspaths.push("/css/menu_ie.css"); 
if(!compatmode)
{
csspaths.push("/css/master_ie.css"); 
}
}
if(!com.campusmedica.cssprofile.features.directchild) 
{
csspaths.push("/css/globalnav_ie.css");
if(com.campusmedica.www.isSecure == true) csspaths.push("/css/globalnav_ie_secure.css");
}
if(browser.isSafari && browser.kitV < 420)
{
csspaths.push("/css/swfcontent_help.css");	
}
if(browser.ua.indexOf('msie 5.2') != -1) {		
csspaths.push("/css/master_macie.css");
csspaths.push("/css/tabsection.css");
}		
if(browser.ua.indexOf('playstation') != -1) {
document.write('<link href="/css/ps3.css" type="text/css" rel="stylesheet" media="screen" />');
}
}
if(!com.campusmedica.www.is && csspaths.length) 
{
var i = csspaths.length-1;
do 
{
	/*
csspaths[i] = "http://www.campusmedica.com"+csspaths[i];
*/
csspaths[i] = ""+csspaths[i];
}
while (i--);
}
this.cssloaded = com.campusmedica.css.attachCssToDOM(csspaths,head);
return true;
}
};


/*
 balloon.js -- a DHTML library for balloon tooltips

 Sheldon McKay <mckays@cshl.edu>
 $Id: balloon.js,v 1.5 2007/04/02 19:16:43 smckay Exp $

 See http://www.wormbase.org/wiki/index.php/Balloon_Tooltips
 for documentation.

 Copyright (c) 2007 Sheldon McKay, Cold Spring Harbor Laboratory

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.

*/


// Only two global variables.  These are necessary to avoid losing
// scope when setting the balloon timeout and so that multiple instances
// of the balloon class know if a balloon is currently visible on the
// page.
var currentBalloonClass;
var balloonIsVisible;


// constructor for balloon class
// Each instance of this class will be populated with default configuration
// variables that can be overwritten
var Balloon = function() {
  
  // Balloon connector (the triangle part) images
  // Default images are provided, they are 48 px in height
  this.upLeftConnector    = '/images/balloons/balloon_up_bottom_left.png';
  this.upRightConnector   = '/images/balloons/balloon_up_bottom_right.png';
  this.downLeftConnector  = '/images/balloons/balloon_down_top_left.png';
  this.downRightConnector = '/images/balloons/balloon_down_top_right.png';

  // Balloon body background images
  // NOTE: the balloon body height is exaggerated to allow for a sliding
  // non-repeat background image for an arbitrary amount of text. The
  // height of the default balloon images is 900px, but only a small part
  // is usually visible, depending on the content dimensions. 
  this.upBalloon   = '/images/balloons/balloon_up_top.png';
  this.downBalloon = '/images/balloons/balloon_down_bottom.png';

  // Balloon dimensions and text placement
  // the default width 300px images (8 pixel shadow)
  this.balloonWidth     = '308px';
  this.paddingTop       = '20px';
  this.paddingLeft      = '15px';
  this.paddingRight     = '15px';
  this.paddingBottom    = '20px';
  this.paddingConnector = '48px';

  // Horizontal offset: allowed values are 'left' and 'right'
  // the offset will be flipped as required to keep the balloon onscreen
  this.hOffset = 'left';

  // Location of optional ajax handler that returns tooltip contents
  this.helpUrl = null;//'/db/misc/help';

  // Default tooltip text size
  this.balloonTextSize = '90%';

  // Delay (milliseconds) before balloon is displayed
  // Don't set it too low or you may annoy your users!
  this.delayTime = 0;

  this.vOffset = '5px'
  this.isIE    = document.all && !window.opera;
  this.isOpera = window.opera;

  // A random number ID to avoid collisions between different balloon
  // types in the same document
  this.rID = Math.random();
}

/////////////////////////////////////////////////////////////////////////
// This is the function that is called on mouseover.  It has a built-in
// delay time to avoid balloons popping up on rapid mousover events
/////////////////////////////////////////////////////////////////////////

Balloon.prototype.showTooltip = function(evt,caption,sticky) {
  if (balloonIsVisible) return false;
  var el = this.getEventTarget(evt);
  
  // attach a mousout event to the target element
  el.onmouseout = this.hideTooltip;

  // set the active coordinates
  this.setActiveCoordinates(evt);

  // Opera tooltip workaround
  if (this.isOpera && (el.getAttribute('title') || el.getAttribute('href')) ) 
    sticky = true;
 
  this.balloonIsStatic ? this.hideStaticTooltip() : this.hideTooltip();  
  this.balloonIsStatic = sticky;
  this.currentHelpText = caption;
  currentBalloonClass = this;
  this.timeoutTooltip = window.setTimeout(this.doShowTooltip,this.delayTime);
}

/////////////////////////////////////////////////////////////////////
// Tooltip rendering function
/////////////////////////////////////////////////////////////////////

Balloon.prototype.doShowTooltip = function() {
  var bSelf = currentBalloonClass;

  // Stop firing if a balloon is already being displayed
  if (balloonIsVisible) return false;  

  // make sure user-configured numbers are not strings
  bSelf.parseIntAll();

  // actual window dimensions
  var pageWidth  = YAHOO.util.Dom.getViewportWidth();
  var pageHeight = YAHOO.util.Dom.getViewportHeight();
  var pageTop    = bSelf.isIE ? document.body.scrollTop : window.pageYOffset;
  var pageMid    = pageTop + pageHeight/2;
  var pageBottom = pageTop + pageHeight;

  // balloon placement tied to onmouseover element
  var left,hOrient;
  if (bSelf.activeLeft < bSelf.balloonWidth) {
    hOrient = 'right';
    left = bSelf.activeRight;
  }
  else if ((bSelf.activeRight + bSelf.balloonWidth) > pageWidth) {
    hOrient = 'left';
    left = bSelf.activeLeft - bSelf.balloonWidth;
  }
  else {
    hOrient = bSelf.hOffset;
    left = hOrient == 'left' ? (bSelf.activeLeft - bSelf.balloonWidth) : bSelf.activeRight;
  }

  // balloon is up if below midline, down otherwise
  var top,vOrient;
  if (bSelf.activeTop > pageMid) {
    vOrient = 'up';
    top = bSelf.activeTop - Math.abs(bSelf.vOffset);
  }
  else {
    vOrient = 'down';
    top = bSelf.activeBottom + Math.abs(bSelf.vOffset);
  }

  // Get or create the balloon layer
  bSelf.activeBalloon = bSelf.getElement('balloon') || bSelf.createAndAppend('balloon');
  bSelf.setStyle(bSelf.activeBalloon,'display','none');
  bSelf.setStyle(bSelf.activeBalloon,'position','absolute');
  bSelf.activeBody = bSelf.getElement('caption') || bSelf.createAndAppend('caption',bSelf.activeBalloon);
  bSelf.activeText = bSelf.getElement('text')    || bSelf.createAndAppend('text',bSelf.activeBody);

  // look for url 
  if (bSelf.currentHelpText.match(/url:/i)) {
    var urlArray = bSelf.currentHelpText.split(':');
    bSelf.currentHelpText = '';
    bSelf.activeUrl = urlArray[1];
  }
  // or if the text is a bare hyperlink
  else if (bSelf.currentHelpText.match(/^(http:|\/)\S+$/i)) {
    bSelf.activeUrl = bSelf.currentHelpText;
    bSelf.currentHelpText = '';
  }	

  // request the contents synchronously (ie wait for result)
  var helpText = bSelf.getContents(bSelf.currentHelpText);

  // configure for up or down orientation
  if (vOrient == 'up') {
    var upConnector = hOrient == 'left' ?  bSelf.upLeftConnector : bSelf.upRightConnector; 
    bSelf.setStyle(bSelf.activeBalloon,'background','url('+upConnector+') bottom left no-repeat');
    bSelf.setStyle(bSelf.activeBalloon,'padding-bottom',bSelf.paddingConnector);
    bSelf.setStyle(bSelf.activeBalloon,'padding-top',bSelf.paddingTop);
    bSelf.setStyle(bSelf.activeBody,'background','url('+bSelf.upBalloon+') top left no-repeat');
    bSelf.setStyle(bSelf.activeBody,'padding-top',bSelf.paddingTop);    
    bSelf.setStyle(bSelf.activeBody,'padding-bottom',1);
  }
  else {
    var downConnector = hOrient == 'left' ?  bSelf.downLeftConnector : bSelf.downRightConnector;
    bSelf.setStyle(bSelf.activeBalloon,'background','url('+downConnector+') top left no-repeat');
    bSelf.setStyle(bSelf.activeBalloon,'padding-bottom',bSelf.paddingBottom);
    bSelf.setStyle(bSelf.activeBalloon,'padding-top',bSelf.paddingConnector);
    bSelf.setStyle(bSelf.activeBody,'background','url('+bSelf.downBalloon+') bottom left no-repeat');
    bSelf.setStyle(bSelf.activeBody,'padding-top',1);
    bSelf.setStyle(bSelf.activeBody,'padding-bottom',bSelf.paddingBottom);
  }
  
  // text boundaries
  bSelf.setStyle(bSelf.activeBody,'padding-left',bSelf.paddingLeft);
  bSelf.setStyle(bSelf.activeBody,'width',bSelf.balloonWidth);
  bSelf.setStyle(bSelf.activeBody,'z-index',10000);
  bSelf.setStyle(bSelf.activeText,'width',bSelf.balloonWidth - (bSelf.paddingLeft + bSelf.paddingRight));
  bSelf.setStyle(bSelf.activeText,'font-size',bSelf.balloonTextSize);

  // persistent balloons need a close control
  if (bSelf.balloonIsStatic) {
    if (vOrient == 'up') {
      bSelf.setStyle(bSelf.activeBody,'padding-top',7);
    }
    else {
      var margin = bSelf.isIE ? -4 : -8;
      bSelf.setStyle(bSelf.activeText,'margin-top',margin);
      bSelf.setStyle(bSelf.activeBody,'padding-top',1);
    }

    helpText = '\
    <a onClick="Balloon.prototype.hideStaticTooltip()" title="close this balloon" \
    style="float:right;font-size:12px;text-decoration:none">\
    Close [X]</a><br>' + helpText;
  }
  else {
    if (vOrient == 'up') {
      bSelf.setStyle(bSelf.activeBody,'padding-top',bSelf.paddingTop);
    }
    else { 
      bSelf.setStyle(bSelf.activeBody,'padding-top',1);
      bSelf.setStyle(bSelf.activeText,'margin-top',0);
    }
  }


  // add the text to the caption layer
  bSelf.activeText.innerHTML = helpText;

  bSelf.showBalloon(vOrient,left,top,pageTop,pageBottom);
}

/////////////////////////////////////////////////////////////////////
// Convenience functions
/////////////////////////////////////////////////////////////////////

Balloon.prototype.getElement = function(id) {
  return document.getElementById(id);
}

// Set the active mouseover coordinates
Balloon.prototype.setActiveCoordinates = function(evt) {
  var el = this.getEventTarget(evt);
  var XY = this.eventXY(evt);

  // is this an image map area?
  var area = el.getAttribute('coords');
  var isImage = el.tagName.match('img', 'i');

  // prefer element vertical bounds if available
  // otherwise, use event's
  this.activeTop  = (!area && !isImage && this.getLoc(el,'y1')) || XY[1];
  this.activeTop -= 10;
  
  this.activeLeft = XY[0] - 10;
  this.activeRight = this.activeLeft + 20;

  this.activeBottom = !area && this.getLoc(el,'y2');
  if (this.activeBottom) this.activeBottom += 10;
  else this.activeBottom = this.activeTop + 20;
}


// event XY and getEventTarget Functions based on examples by Peter-Paul
// Koch http://www.quirksmode.org/js/events_properties.html
Balloon.prototype.eventXY = function(event) {
  var XY = new Array(2);
  var e = event || window.event;
  XY[0] = e.pageX || e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
  XY[1] = e.pageY || e.clientY + document.body.scrollTop  + document.documentElement.scrollTop;
  return XY;
}

Balloon.prototype.getEventTarget = function(event) {
  var targ;
  var e = event || window.event;
  if (e.target) targ = e.target;
  else if (e.srcElement) targ = e.srcElement;
  if (targ.nodeType == 3) targ = targ.parentNode; // Safari
  return targ;
}


Balloon.prototype.setStyle = function(el,att,val) {
  if (att.match(/left|top|width|height|padding|margin/)) val += 'px'; 
  if (el) YAHOO.util.Dom.setStyle(el,att,val);
}

Balloon.prototype.getLoc = function(el,request) {
  var region = YAHOO.util.Dom.getRegion(el);
  switch(request) {
    case ('y1') : return region.top;
    case ('y2') : return region.bottom;
    case ('x1') : return region.left;
    case ('x2') : return region.right;
    case ('width')  : return (region.right - region.left);
    case ('height') : return (region.bottom - region.top);
    case ('region') : return region; 
 }
}

// We don't know if numbers are overridden with strings
Balloon.prototype.parseIntAll = function() {
  this.balloonWidth     = parseInt(this.balloonWidth);
  this.paddingTop       = parseInt(this.paddingTop);
  this.paddingLeft      = parseInt(this.paddingLeft);
  this.paddingRight     = parseInt(this.paddingRight);
  this.paddingBottom    = parseInt(this.paddingBottom);
  this.paddingConnector = parseInt(this.paddingConnector);
  this.vOffset          = parseInt(this.vOffset);
}

/////////////////////////////////////////////////////////////////////
// Create/append  balloon elements
/////////////////////////////////////////////////////////////////////

Balloon.prototype.createAndAppend = function(id,parent,elTag) {
  var node = this.justCreate(id,elTag);
  this.justAppend(node,parent);
  return node;
}

Balloon.prototype.justCreate = function(id,elTag) {
  var tag = elTag || 'div';
  var node = document.createElement(tag);
  node.setAttribute('id', id);  
  return node;
}

Balloon.prototype.justAppend = function(child,parent) {
  var parentNode = parent || document.body;
  parentNode.appendChild(child);
}


/////////////////////////////////////////////////////////////////////
// Balloon visibility controls
/////////////////////////////////////////////////////////////////////

Balloon.prototype.showBalloon = function(orient,left,top)  {
  YAHOO.util.Dom.setY(this.activeBalloon,999999999);
  this.setStyle(this.activeBalloon,'display','inline');

  if (orient == 'up') {
    var height = this.getLoc(this.activeBalloon,'height');
    top -= height;
  }

  YAHOO.util.Dom.setY(this.activeBalloon,top);
  YAHOO.util.Dom.setX(this.activeBalloon,left);
  balloonIsVisble = true;
  this.showHideSelect();
}

Balloon.prototype.hideTooltip = function() {
  var bSelf = currentBalloonClass;
  if (!bSelf) return;
  currentBalloonClass = null;
  window.clearTimeout(bSelf.timeoutTooltip);
  if (bSelf.balloonIsStatic) return false;
  balloonIsVisible = false;
  if (bSelf.activeBalloon) {
    bSelf.showHideSelect(1);
    bSelf.setStyle(bSelf.activeBalloon,'display','none');
  }
}

Balloon.prototype.hideStaticTooltip = function() {
  var bSelf = currentBalloonClass;
  currentBalloonClass = null;

  if (!bSelf) {
    var hideBalloon  = document.getElementById('balloon');
    if (hideBalloon) Balloon.prototype.setStyle(hideBalloon,'display','none');
  }
  else if (bSelf.activeBalloon) {
      bSelf.showHideSelect(1);
      bSelf.setStyle(bSelf.activeBalloon,'display','none');
  }	

  balloonIsVisible = false;
}

// this function is meant to be called externally tp clear
// any open balloons
hideAllTooltips = function() {
  var bSelf = currentBalloonClass;
  if (!bSelf) return;
  window.clearTimeout(bSelf.timeoutTooltip);
  if (bSelf.activeBalloon) bSelf.setStyle(bSelf.activeBalloon,'display','none');
  balloonIsVisble = false;
  currentBalloonClass = null;
}

// IE select z-index bug
Balloon.prototype.showHideSelect = function(visible) {
  if (!this.isIE) return false;
  var sel = document.getElementsByTagName('select');
  if (!sel) return false;
  visible = visible ? 'visible' : 'hidden';
  for (var i=0; i<sel.length; i++) {
    if (this.isOverlap(sel[i]))
      this.setStyle(sel[i],'visibility',visible);
  }
}

// Try to find overlap 
Balloon.prototype.isOverlap = function(sel) {
  if (!this.activeBalloon) return false;
  var R1 = this.getLoc(this.activeBalloon,'region');
  var R2 = this.getLoc(sel,'region');
  var t1=R1.top,b1=R1.bottom,l1=R1.left,r1=R1.right;
  var t2=R2.top,b2=R2.bottom,l2=R2.left,r2=R2.right;

  if ( ((t2 < b1) && (t2 > t1)) 
      && (((l2 > l1) && (l2 < r1)) || (r2 < r1) && (r2 > l1))) return true;

  if ( ((b2 < b1) && (b2 > t1))
      && (((l2 > l1) && (l2 < r1)) || (r2 < r1) && (r2 > l1))) return true;

  return false;
}


///////////////////////////////////////////////////////
// AJAX widget to fill the balloons
// requires prototype.js
///////////////////////////////////////////////////////
Balloon.prototype.getContents = function(section) {
  // just pass it back if no AJAX handler is required.
  if (!this.helpUrl && !this.activeUrl) return section;

  // inline URL takes precedence
  var url = this.activeUrl || this.helpUrl;

  var pars = this.activeUrl ? '' : 'section='+section;
  var ajax  = new Ajax.Request( url,
                           { method:   'get',
                             asynchronous: false,
		             parameters:  pars,
                             onSuccess: function(t) { currentBalloonClass.updateResult(t.responseText) },
                             onFailure: function(t) { alert('AJAX Failure! '+t.statusText)}});

  // activeUrl is meant to be single-use only
  this.activeUrl = null;

  return this.helpText || section;
}

Balloon.prototype.updateResult = function(text) {
  this.helpText = text;
}

 var balloon = new Balloon;


/***********************************************
* Bookmark site script- © Dynamic Drive DHTML code library (www.dynamicdrive.com)
* This notice MUST stay intact for legal use
* Visit Dynamic Drive at http://www.dynamicdrive.com/ for full source code
***********************************************/

/* Modified to support Opera */
function bookmarksite(title,url){
if (window.sidebar) // firefox
	window.sidebar.addPanel(title, url, "");
else if(window.opera && window.print){ // opera
	var elem = document.createElement('a');
	elem.setAttribute('href',url);
	elem.setAttribute('title',title);
	elem.setAttribute('rel','sidebar');
	elem.click();
} 
else if(document.all)// ie
	window.external.AddFavorite(url, title);
}

function togglemenu(image,list){
var listElementStyle=document.getElementById(list).style;
if (listElementStyle.display=="none"){
listElementStyle.display="block";
document.getElementById(image).src="/images/minus.gif";
document.getElementById(image).alt="Close list"; }
else{ listElementStyle.display="none";
document.getElementById(image).src="/images/add.gif";
document.getElementById(image).alt="Open list";
 }
}

if (top.location!= self.location) {
	top.location = self.location.href
}



/*
Copyright (c) 2007, Yahoo! Inc. All rights reserved.
Code licensed under the BSD License:
http://developer.yahoo.net/yui/license.txt
version: 2.2.0
*/

if(typeof YAHOO=="undefined"){var YAHOO={};}
YAHOO.namespace=function(){var a=arguments,o=null,i,j,d;for(i=0;i<a.length;i=i+1){d=a[i].split(".");o=YAHOO;for(j=(d[0]=="YAHOO")?1:0;j<d.length;j=j+1){o[d[j]]=o[d[j]]||{};o=o[d[j]];}}
return o;};YAHOO.log=function(msg,cat,src){var l=YAHOO.widget.Logger;if(l&&l.log){return l.log(msg,cat,src);}else{return false;}};YAHOO.init=function(){this.namespace("util","widget","example");if(typeof YAHOO_config!="undefined"){var l=YAHOO_config.listener,ls=YAHOO.env.listeners,unique=true,i;if(l){for(i=0;i<ls.length;i=i+1){if(ls[i]==l){unique=false;break;}}
if(unique){ls.push(l);}}}};YAHOO.register=function(name,mainClass,data){var mods=YAHOO.env.modules;if(!mods[name]){mods[name]={versions:[],builds:[]};}
var m=mods[name],v=data.version,b=data.build,ls=YAHOO.env.listeners;m.name=name;m.version=v;m.build=b;m.versions.push(v);m.builds.push(b);m.mainClass=mainClass;for(var i=0;i<ls.length;i=i+1){ls[i](m);}
if(mainClass){mainClass.VERSION=v;mainClass.BUILD=b;}else{YAHOO.log("mainClass is undefined for module "+name,"warn");}};YAHOO.env=YAHOO.env||{modules:[],listeners:[],getVersion:function(name){return YAHOO.env.modules[name]||null;}};YAHOO.lang={isArray:function(obj){if(obj.constructor&&obj.constructor.toString().indexOf('Array')>-1){return true;}else{return YAHOO.lang.isObject(obj)&&obj.constructor==Array;}},isBoolean:function(obj){return typeof obj=='boolean';},isFunction:function(obj){return typeof obj=='function';},isNull:function(obj){return obj===null;},isNumber:function(obj){return typeof obj=='number'&&isFinite(obj);},isObject:function(obj){return typeof obj=='object'||YAHOO.lang.isFunction(obj);},isString:function(obj){return typeof obj=='string';},isUndefined:function(obj){return typeof obj=='undefined';},hasOwnProperty:function(obj,prop){if(Object.prototype.hasOwnProperty){return obj.hasOwnProperty(prop);}
return!YAHOO.lang.isUndefined(obj[prop])&&obj.constructor.prototype[prop]!==obj[prop];},extend:function(subc,superc,overrides){var F=function(){};F.prototype=superc.prototype;subc.prototype=new F();subc.prototype.constructor=subc;subc.superclass=superc.prototype;if(superc.prototype.constructor==Object.prototype.constructor){superc.prototype.constructor=superc;}
if(overrides){for(var i in overrides){subc.prototype[i]=overrides[i];}}},augment:function(r,s){var rp=r.prototype,sp=s.prototype,a=arguments,i,p;if(a[2]){for(i=2;i<a.length;i=i+1){rp[a[i]]=sp[a[i]];}}else{for(p in sp){if(!rp[p]){rp[p]=sp[p];}}}}};YAHOO.init();YAHOO.util.Lang=YAHOO.lang;YAHOO.augment=YAHOO.lang.augment;YAHOO.extend=YAHOO.lang.extend;YAHOO.register("yahoo",YAHOO,{version:"2.2.0",build:"127"});
(function(){var Y=YAHOO.util,getStyle,setStyle,id_counter=0,propertyCache={};var ua=navigator.userAgent.toLowerCase(),isOpera=(ua.indexOf('opera')>-1),isSafari=(ua.indexOf('safari')>-1),isGecko=(!isOpera&&!isSafari&&ua.indexOf('gecko')>-1),isIE=(!isOpera&&ua.indexOf('msie')>-1);var patterns={HYPHEN:/(-[a-z])/i};var toCamel=function(property){if(!patterns.HYPHEN.test(property)){return property;}
if(propertyCache[property]){return propertyCache[property];}
while(patterns.HYPHEN.exec(property)){property=property.replace(RegExp.$1,RegExp.$1.substr(1).toUpperCase());}
propertyCache[property]=property;return property;};if(document.defaultView&&document.defaultView.getComputedStyle){getStyle=function(el,property){var value=null;var computed=document.defaultView.getComputedStyle(el,'');if(computed){value=computed[toCamel(property)];}
return el.style[property]||value;};}else if(document.documentElement.currentStyle&&isIE){getStyle=function(el,property){switch(toCamel(property)){case'opacity':var val=100;try{val=el.filters['DXImageTransform.Microsoft.Alpha'].opacity;}catch(e){try{val=el.filters('alpha').opacity;}catch(e){}}
return val/100;break;default:var value=el.currentStyle?el.currentStyle[property]:null;return(el.style[property]||value);}};}else{getStyle=function(el,property){return el.style[property];};}
if(isIE){setStyle=function(el,property,val){switch(property){case'opacity':if(typeof el.style.filter=='string'){el.style.filter='alpha(opacity='+val*100+')';if(!el.currentStyle||!el.currentStyle.hasLayout){el.style.zoom=1;}}
break;default:el.style[property]=val;}};}else{setStyle=function(el,property,val){el.style[property]=val;};}
YAHOO.util.Dom={get:function(el){if(!el){return null;}
if(typeof el!='string'&&!(el instanceof Array)){return el;}
if(typeof el=='string'){return document.getElementById(el);}
else{var collection=[];for(var i=0,len=el.length;i<len;++i){collection[collection.length]=Y.Dom.get(el[i]);}
return collection;}
return null;},getStyle:function(el,property){property=toCamel(property);var f=function(element){return getStyle(element,property);};return Y.Dom.batch(el,f,Y.Dom,true);},setStyle:function(el,property,val){property=toCamel(property);var f=function(element){setStyle(element,property,val);};Y.Dom.batch(el,f,Y.Dom,true);},getXY:function(el){var f=function(el){if(el.parentNode===null||el.offsetParent===null||this.getStyle(el,'display')=='none'){return false;}
var parentNode=null;var pos=[];var box;if(el.getBoundingClientRect){box=el.getBoundingClientRect();var doc=document;if(!this.inDocument(el)&&parent.document!=document){doc=parent.document;if(!this.isAncestor(doc.documentElement,el)){return false;}}
var scrollTop=Math.max(doc.documentElement.scrollTop,doc.body.scrollTop);var scrollLeft=Math.max(doc.documentElement.scrollLeft,doc.body.scrollLeft);return[box.left+scrollLeft,box.top+scrollTop];}
else{pos=[el.offsetLeft,el.offsetTop];parentNode=el.offsetParent;if(parentNode!=el){while(parentNode){pos[0]+=parentNode.offsetLeft;pos[1]+=parentNode.offsetTop;parentNode=parentNode.offsetParent;}}
if(isSafari&&this.getStyle(el,'position')=='absolute'){pos[0]-=document.body.offsetLeft;pos[1]-=document.body.offsetTop;}}
if(el.parentNode){parentNode=el.parentNode;}
else{parentNode=null;}
while(parentNode&&parentNode.tagName.toUpperCase()!='BODY'&&parentNode.tagName.toUpperCase()!='HTML')
{if(Y.Dom.getStyle(parentNode,'display')!='inline'){pos[0]-=parentNode.scrollLeft;pos[1]-=parentNode.scrollTop;}
if(parentNode.parentNode){parentNode=parentNode.parentNode;}else{parentNode=null;}}
return pos;};return Y.Dom.batch(el,f,Y.Dom,true);},getX:function(el){var f=function(el){return Y.Dom.getXY(el)[0];};return Y.Dom.batch(el,f,Y.Dom,true);},getY:function(el){var f=function(el){return Y.Dom.getXY(el)[1];};return Y.Dom.batch(el,f,Y.Dom,true);},setXY:function(el,pos,noRetry){var f=function(el){var style_pos=this.getStyle(el,'position');if(style_pos=='static'){this.setStyle(el,'position','relative');style_pos='relative';}
var pageXY=this.getXY(el);if(pageXY===false){return false;}
var delta=[parseInt(this.getStyle(el,'left'),10),parseInt(this.getStyle(el,'top'),10)];if(isNaN(delta[0])){delta[0]=(style_pos=='relative')?0:el.offsetLeft;}
if(isNaN(delta[1])){delta[1]=(style_pos=='relative')?0:el.offsetTop;}
if(pos[0]!==null){el.style.left=pos[0]-pageXY[0]+delta[0]+'px';}
if(pos[1]!==null){el.style.top=pos[1]-pageXY[1]+delta[1]+'px';}
if(!noRetry){var newXY=this.getXY(el);if((pos[0]!==null&&newXY[0]!=pos[0])||(pos[1]!==null&&newXY[1]!=pos[1])){this.setXY(el,pos,true);}}};Y.Dom.batch(el,f,Y.Dom,true);},setX:function(el,x){Y.Dom.setXY(el,[x,null]);},setY:function(el,y){Y.Dom.setXY(el,[null,y]);},getRegion:function(el){var f=function(el){var region=new Y.Region.getRegion(el);return region;};return Y.Dom.batch(el,f,Y.Dom,true);},getClientWidth:function(){return Y.Dom.getViewportWidth();},getClientHeight:function(){return Y.Dom.getViewportHeight();},getElementsByClassName:function(className,tag,root){var method=function(el){return Y.Dom.hasClass(el,className);};return Y.Dom.getElementsBy(method,tag,root);},hasClass:function(el,className){var re=new RegExp('(?:^|\\s+)'+className+'(?:\\s+|$)');var f=function(el){return re.test(el['className']);};return Y.Dom.batch(el,f,Y.Dom,true);},addClass:function(el,className){var f=function(el){if(this.hasClass(el,className)){return;}
el['className']=[el['className'],className].join(' ');};Y.Dom.batch(el,f,Y.Dom,true);},removeClass:function(el,className){var re=new RegExp('(?:^|\\s+)'+className+'(?:\\s+|$)','g');var f=function(el){if(!this.hasClass(el,className)){return;}
var c=el['className'];el['className']=c.replace(re,' ');if(this.hasClass(el,className)){this.removeClass(el,className);}};Y.Dom.batch(el,f,Y.Dom,true);},replaceClass:function(el,oldClassName,newClassName){if(oldClassName===newClassName){return false;}
var re=new RegExp('(?:^|\\s+)'+oldClassName+'(?:\\s+|$)','g');var f=function(el){if(!this.hasClass(el,oldClassName)){this.addClass(el,newClassName);return;}
el['className']=el['className'].replace(re,' '+newClassName+' ');if(this.hasClass(el,oldClassName)){this.replaceClass(el,oldClassName,newClassName);}};Y.Dom.batch(el,f,Y.Dom,true);},generateId:function(el,prefix){prefix=prefix||'yui-gen';el=el||{};var f=function(el){if(el){el=Y.Dom.get(el);}else{el={};}
if(!el.id){el.id=prefix+id_counter++;}
return el.id;};return Y.Dom.batch(el,f,Y.Dom,true);},isAncestor:function(haystack,needle){haystack=Y.Dom.get(haystack);if(!haystack||!needle){return false;}
var f=function(needle){if(haystack.contains&&!isSafari){return haystack.contains(needle);}
else if(haystack.compareDocumentPosition){return!!(haystack.compareDocumentPosition(needle)&16);}
else{var parent=needle.parentNode;while(parent){if(parent==haystack){return true;}
else if(!parent.tagName||parent.tagName.toUpperCase()=='HTML'){return false;}
parent=parent.parentNode;}
return false;}};return Y.Dom.batch(needle,f,Y.Dom,true);},inDocument:function(el){var f=function(el){return this.isAncestor(document.documentElement,el);};return Y.Dom.batch(el,f,Y.Dom,true);},getElementsBy:function(method,tag,root){tag=tag||'*';var nodes=[];if(root){root=Y.Dom.get(root);if(!root){return nodes;}}else{root=document;}
var elements=root.getElementsByTagName(tag);if(!elements.length&&(tag=='*'&&root.all)){elements=root.all;}
for(var i=0,len=elements.length;i<len;++i){if(method(elements[i])){nodes[nodes.length]=elements[i];}}
return nodes;},batch:function(el,method,o,override){var id=el;el=Y.Dom.get(el);var scope=(override)?o:window;if(!el||el.tagName||!el.length){if(!el){return false;}
return method.call(scope,el,o);}
var collection=[];for(var i=0,len=el.length;i<len;++i){if(!el[i]){id=el[i];}
collection[collection.length]=method.call(scope,el[i],o);}
return collection;},getDocumentHeight:function(){var scrollHeight=(document.compatMode!='CSS1Compat')?document.body.scrollHeight:document.documentElement.scrollHeight;var h=Math.max(scrollHeight,Y.Dom.getViewportHeight());return h;},getDocumentWidth:function(){var scrollWidth=(document.compatMode!='CSS1Compat')?document.body.scrollWidth:document.documentElement.scrollWidth;var w=Math.max(scrollWidth,Y.Dom.getViewportWidth());return w;},getViewportHeight:function(){var height=self.innerHeight;var mode=document.compatMode;if((mode||isIE)&&!isOpera){height=(mode=='CSS1Compat')?document.documentElement.clientHeight:document.body.clientHeight;}
return height;},getViewportWidth:function(){var width=self.innerWidth;var mode=document.compatMode;if(mode||isIE){width=(mode=='CSS1Compat')?document.documentElement.clientWidth:document.body.clientWidth;}
return width;}};})();YAHOO.util.Region=function(t,r,b,l){this.top=t;this[1]=t;this.right=r;this.bottom=b;this.left=l;this[0]=l;};YAHOO.util.Region.prototype.contains=function(region){return(region.left>=this.left&&region.right<=this.right&&region.top>=this.top&&region.bottom<=this.bottom);};YAHOO.util.Region.prototype.getArea=function(){return((this.bottom-this.top)*(this.right-this.left));};YAHOO.util.Region.prototype.intersect=function(region){var t=Math.max(this.top,region.top);var r=Math.min(this.right,region.right);var b=Math.min(this.bottom,region.bottom);var l=Math.max(this.left,region.left);if(b>=t&&r>=l){return new YAHOO.util.Region(t,r,b,l);}else{return null;}};YAHOO.util.Region.prototype.union=function(region){var t=Math.min(this.top,region.top);var r=Math.max(this.right,region.right);var b=Math.max(this.bottom,region.bottom);var l=Math.min(this.left,region.left);return new YAHOO.util.Region(t,r,b,l);};YAHOO.util.Region.prototype.toString=function(){return("Region {"+"top: "+this.top+", right: "+this.right+", bottom: "+this.bottom+", left: "+this.left+"}");};YAHOO.util.Region.getRegion=function(el){var p=YAHOO.util.Dom.getXY(el);var t=p[1];var r=p[0]+el.offsetWidth;var b=p[1]+el.offsetHeight;var l=p[0];return new YAHOO.util.Region(t,r,b,l);};YAHOO.util.Point=function(x,y){if(x instanceof Array){y=x[1];x=x[0];}
this.x=this.right=this.left=this[0]=x;this.y=this.top=this.bottom=this[1]=y;};YAHOO.util.Point.prototype=new YAHOO.util.Region();YAHOO.register("dom",YAHOO.util.Dom,{version:"2.2.0",build:"127"});
if(!YAHOO.util.Event){YAHOO.util.Event=function(){var loadComplete=false;var listeners=[];var unloadListeners=[];var legacyEvents=[];var legacyHandlers=[];var retryCount=0;var onAvailStack=[];var legacyMap=[];var counter=0;var lastError=null;return{POLL_RETRYS:200,POLL_INTERVAL:20,EL:0,TYPE:1,FN:2,WFN:3,OBJ:3,ADJ_SCOPE:4,isSafari:(/KHTML/gi).test(navigator.userAgent),webkit:function(){var v=navigator.userAgent.match(/AppleWebKit\/([^ ]*)/);if(v&&v[1]){return v[1];}
return null;}(),isIE:(!this.webkit&&!navigator.userAgent.match(/opera/gi)&&navigator.userAgent.match(/msie/gi)),_interval:null,startInterval:function(){if(!this._interval){var self=this;var callback=function(){self._tryPreloadAttach();};this._interval=setInterval(callback,this.POLL_INTERVAL);}},onAvailable:function(p_id,p_fn,p_obj,p_override){onAvailStack.push({id:p_id,fn:p_fn,obj:p_obj,override:p_override,checkReady:false});retryCount=this.POLL_RETRYS;this.startInterval();},onContentReady:function(p_id,p_fn,p_obj,p_override){onAvailStack.push({id:p_id,fn:p_fn,obj:p_obj,override:p_override,checkReady:true});retryCount=this.POLL_RETRYS;this.startInterval();},addListener:function(el,sType,fn,obj,override){if(!fn||!fn.call){return false;}
if(this._isValidCollection(el)){var ok=true;for(var i=0,len=el.length;i<len;++i){ok=this.on(el[i],sType,fn,obj,override)&&ok;}
return ok;}else if(typeof el=="string"){var oEl=this.getEl(el);if(oEl){el=oEl;}else{this.onAvailable(el,function(){YAHOO.util.Event.on(el,sType,fn,obj,override);});return true;}}
if(!el){return false;}
if("unload"==sType&&obj!==this){unloadListeners[unloadListeners.length]=[el,sType,fn,obj,override];return true;}
var scope=el;if(override){if(override===true){scope=obj;}else{scope=override;}}
var wrappedFn=function(e){return fn.call(scope,YAHOO.util.Event.getEvent(e),obj);};var li=[el,sType,fn,wrappedFn,scope];var index=listeners.length;listeners[index]=li;if(this.useLegacyEvent(el,sType)){var legacyIndex=this.getLegacyIndex(el,sType);if(legacyIndex==-1||el!=legacyEvents[legacyIndex][0]){legacyIndex=legacyEvents.length;legacyMap[el.id+sType]=legacyIndex;legacyEvents[legacyIndex]=[el,sType,el["on"+sType]];legacyHandlers[legacyIndex]=[];el["on"+sType]=function(e){YAHOO.util.Event.fireLegacyEvent(YAHOO.util.Event.getEvent(e),legacyIndex);};}
legacyHandlers[legacyIndex].push(li);}else{try{this._simpleAdd(el,sType,wrappedFn,false);}catch(ex){this.lastError=ex;this.removeListener(el,sType,fn);return false;}}
return true;},fireLegacyEvent:function(e,legacyIndex){var ok=true,le,lh,li,scope,ret;lh=legacyHandlers[legacyIndex];for(var i=0,len=lh.length;i<len;++i){li=lh[i];if(li&&li[this.WFN]){scope=li[this.ADJ_SCOPE];ret=li[this.WFN].call(scope,e);ok=(ok&&ret);}}
le=legacyEvents[legacyIndex];if(le&&le[2]){le[2](e);}
return ok;},getLegacyIndex:function(el,sType){var key=this.generateId(el)+sType;if(typeof legacyMap[key]=="undefined"){return-1;}else{return legacyMap[key];}},useLegacyEvent:function(el,sType){if(this.webkit&&("click"==sType||"dblclick"==sType)){var v=parseInt(this.webkit,10);if(!isNaN(v)&&v<418){return true;}}
return false;},removeListener:function(el,sType,fn){var i,len;if(typeof el=="string"){el=this.getEl(el);}else if(this._isValidCollection(el)){var ok=true;for(i=0,len=el.length;i<len;++i){ok=(this.removeListener(el[i],sType,fn)&&ok);}
return ok;}
if(!fn||!fn.call){return this.purgeElement(el,false,sType);}
if("unload"==sType){for(i=0,len=unloadListeners.length;i<len;i++){var li=unloadListeners[i];if(li&&li[0]==el&&li[1]==sType&&li[2]==fn){unloadListeners.splice(i,1);return true;}}
return false;}
var cacheItem=null;var index=arguments[3];if("undefined"==typeof index){index=this._getCacheIndex(el,sType,fn);}
if(index>=0){cacheItem=listeners[index];}
if(!el||!cacheItem){return false;}
if(this.useLegacyEvent(el,sType)){var legacyIndex=this.getLegacyIndex(el,sType);var llist=legacyHandlers[legacyIndex];if(llist){for(i=0,len=llist.length;i<len;++i){li=llist[i];if(li&&li[this.EL]==el&&li[this.TYPE]==sType&&li[this.FN]==fn){llist.splice(i,1);break;}}}}else{try{this._simpleRemove(el,sType,cacheItem[this.WFN],false);}catch(ex){this.lastError=ex;return false;}}
delete listeners[index][this.WFN];delete listeners[index][this.FN];listeners.splice(index,1);return true;},getTarget:function(ev,resolveTextNode){var t=ev.target||ev.srcElement;return this.resolveTextNode(t);},resolveTextNode:function(node){if(node&&3==node.nodeType){return node.parentNode;}else{return node;}},getPageX:function(ev){var x=ev.pageX;if(!x&&0!==x){x=ev.clientX||0;if(this.isIE){x+=this._getScrollLeft();}}
return x;},getPageY:function(ev){var y=ev.pageY;if(!y&&0!==y){y=ev.clientY||0;if(this.isIE){y+=this._getScrollTop();}}
return y;},getXY:function(ev){return[this.getPageX(ev),this.getPageY(ev)];},getRelatedTarget:function(ev){var t=ev.relatedTarget;if(!t){if(ev.type=="mouseout"){t=ev.toElement;}else if(ev.type=="mouseover"){t=ev.fromElement;}}
return this.resolveTextNode(t);},getTime:function(ev){if(!ev.time){var t=new Date().getTime();try{ev.time=t;}catch(ex){this.lastError=ex;return t;}}
return ev.time;},stopEvent:function(ev){this.stopPropagation(ev);this.preventDefault(ev);},stopPropagation:function(ev){if(ev.stopPropagation){ev.stopPropagation();}else{ev.cancelBubble=true;}},preventDefault:function(ev){if(ev.preventDefault){ev.preventDefault();}else{ev.returnValue=false;}},getEvent:function(e){var ev=e||window.event;if(!ev){var c=this.getEvent.caller;while(c){ev=c.arguments[0];if(ev&&Event==ev.constructor){break;}
c=c.caller;}}
return ev;},getCharCode:function(ev){return ev.charCode||ev.keyCode||0;},_getCacheIndex:function(el,sType,fn){for(var i=0,len=listeners.length;i<len;++i){var li=listeners[i];if(li&&li[this.FN]==fn&&li[this.EL]==el&&li[this.TYPE]==sType){return i;}}
return-1;},generateId:function(el){var id=el.id;if(!id){id="yuievtautoid-"+counter;++counter;el.id=id;}
return id;},_isValidCollection:function(o){return(o&&o.length&&typeof o!="string"&&!o.tagName&&!o.alert&&typeof o[0]!="undefined");},elCache:{},getEl:function(id){return document.getElementById(id);},clearCache:function(){},_load:function(e){loadComplete=true;var EU=YAHOO.util.Event;if(this.isIE){EU._simpleRemove(window,"load",EU._load);}},_tryPreloadAttach:function(){if(this.locked){return false;}
this.locked=true;var tryAgain=!loadComplete;if(!tryAgain){tryAgain=(retryCount>0);}
var notAvail=[];for(var i=0,len=onAvailStack.length;i<len;++i){var item=onAvailStack[i];if(item){var el=this.getEl(item.id);if(el){if(!item.checkReady||loadComplete||el.nextSibling||(document&&document.body)){var scope=el;if(item.override){if(item.override===true){scope=item.obj;}else{scope=item.override;}}
item.fn.call(scope,item.obj);onAvailStack[i]=null;}}else{notAvail.push(item);}}}
retryCount=(notAvail.length===0)?0:retryCount-1;if(tryAgain){this.startInterval();}else{clearInterval(this._interval);this._interval=null;}
this.locked=false;return true;},purgeElement:function(el,recurse,sType){var elListeners=this.getListeners(el,sType);if(elListeners){for(var i=0,len=elListeners.length;i<len;++i){var l=elListeners[i];this.removeListener(el,l.type,l.fn);}}
if(recurse&&el&&el.childNodes){for(i=0,len=el.childNodes.length;i<len;++i){this.purgeElement(el.childNodes[i],recurse,sType);}}},getListeners:function(el,sType){var results=[],searchLists;if(!sType){searchLists=[listeners,unloadListeners];}else if(sType=="unload"){searchLists=[unloadListeners];}else{searchLists=[listeners];}
for(var j=0;j<searchLists.length;++j){var searchList=searchLists[j];if(searchList&&searchList.length>0){for(var i=0,len=searchList.length;i<len;++i){var l=searchList[i];if(l&&l[this.EL]===el&&(!sType||sType===l[this.TYPE])){results.push({type:l[this.TYPE],fn:l[this.FN],obj:l[this.OBJ],adjust:l[this.ADJ_SCOPE],index:i});}}}}
return(results.length)?results:null;},_unload:function(e){var EU=YAHOO.util.Event,i,j,l,len,index;for(i=0,len=unloadListeners.length;i<len;++i){l=unloadListeners[i];if(l){var scope=window;if(l[EU.ADJ_SCOPE]){if(l[EU.ADJ_SCOPE]===true){scope=l[EU.OBJ];}else{scope=l[EU.ADJ_SCOPE];}}
l[EU.FN].call(scope,EU.getEvent(e),l[EU.OBJ]);unloadListeners[i]=null;l=null;scope=null;}}
unloadListeners=null;if(listeners&&listeners.length>0){j=listeners.length;while(j){index=j-1;l=listeners[index];if(l){EU.removeListener(l[EU.EL],l[EU.TYPE],l[EU.FN],index);}
j=j-1;}
l=null;EU.clearCache();}
for(i=0,len=legacyEvents.length;i<len;++i){legacyEvents[i][0]=null;legacyEvents[i]=null;}
legacyEvents=null;EU._simpleRemove(window,"unload",EU._unload);},_getScrollLeft:function(){return this._getScroll()[1];},_getScrollTop:function(){return this._getScroll()[0];},_getScroll:function(){var dd=document.documentElement,db=document.body;if(dd&&(dd.scrollTop||dd.scrollLeft)){return[dd.scrollTop,dd.scrollLeft];}else if(db){return[db.scrollTop,db.scrollLeft];}else{return[0,0];}},regCE:function(){},_simpleAdd:function(){if(window.addEventListener){return function(el,sType,fn,capture){el.addEventListener(sType,fn,(capture));};}else if(window.attachEvent){return function(el,sType,fn,capture){el.attachEvent("on"+sType,fn);};}else{return function(){};}}(),_simpleRemove:function(){if(window.removeEventListener){return function(el,sType,fn,capture){el.removeEventListener(sType,fn,(capture));};}else if(window.detachEvent){return function(el,sType,fn){el.detachEvent("on"+sType,fn);};}else{return function(){};}}()};}();(function(){var EU=YAHOO.util.Event;EU.on=EU.addListener;if(document&&document.body){EU._load();}else{EU._simpleAdd(window,"load",EU._load);}
EU._simpleAdd(window,"unload",EU._unload);EU._tryPreloadAttach();})();}
YAHOO.util.CustomEvent=function(type,oScope,silent,signature){this.type=type;this.scope=oScope||window;this.silent=silent;this.signature=signature||YAHOO.util.CustomEvent.LIST;this.subscribers=[];if(!this.silent){}
var onsubscribeType="_YUICEOnSubscribe";if(type!==onsubscribeType){this.subscribeEvent=new YAHOO.util.CustomEvent(onsubscribeType,this,true);}};YAHOO.util.CustomEvent.LIST=0;YAHOO.util.CustomEvent.FLAT=1;YAHOO.util.CustomEvent.prototype={subscribe:function(fn,obj,override){if(this.subscribeEvent){this.subscribeEvent.fire(fn,obj,override);}
this.subscribers.push(new YAHOO.util.Subscriber(fn,obj,override));},unsubscribe:function(fn,obj){if(!fn){return this.unsubscribeAll();}
var found=false;for(var i=0,len=this.subscribers.length;i<len;++i){var s=this.subscribers[i];if(s&&s.contains(fn,obj)){this._delete(i);found=true;}}
return found;},fire:function(){var len=this.subscribers.length;if(!len&&this.silent){return true;}
var args=[],ret=true,i;for(i=0;i<arguments.length;++i){args.push(arguments[i]);}
var argslength=args.length;if(!this.silent){}
for(i=0;i<len;++i){var s=this.subscribers[i];if(s){if(!this.silent){}
var scope=s.getScope(this.scope);if(this.signature==YAHOO.util.CustomEvent.FLAT){var param=null;if(args.length>0){param=args[0];}
ret=s.fn.call(scope,param,s.obj);}else{ret=s.fn.call(scope,this.type,args,s.obj);}
if(false===ret){if(!this.silent){}
return false;}}}
return true;},unsubscribeAll:function(){for(var i=0,len=this.subscribers.length;i<len;++i){this._delete(len-1-i);}
return i;},_delete:function(index){var s=this.subscribers[index];if(s){delete s.fn;delete s.obj;}
this.subscribers.splice(index,1);},toString:function(){return"CustomEvent: "+"'"+this.type+"', "+"scope: "+this.scope;}};YAHOO.util.Subscriber=function(fn,obj,override){this.fn=fn;this.obj=obj||null;this.override=override;};YAHOO.util.Subscriber.prototype.getScope=function(defaultScope){if(this.override){if(this.override===true){return this.obj;}else{return this.override;}}
return defaultScope;};YAHOO.util.Subscriber.prototype.contains=function(fn,obj){if(obj){return(this.fn==fn&&this.obj==obj);}else{return(this.fn==fn);}};YAHOO.util.Subscriber.prototype.toString=function(){return"Subscriber { obj: "+(this.obj||"")+", override: "+(this.override||"no")+" }";};YAHOO.util.EventProvider=function(){};YAHOO.util.EventProvider.prototype={__yui_events:null,__yui_subscribers:null,subscribe:function(p_type,p_fn,p_obj,p_override){this.__yui_events=this.__yui_events||{};var ce=this.__yui_events[p_type];if(ce){ce.subscribe(p_fn,p_obj,p_override);}else{this.__yui_subscribers=this.__yui_subscribers||{};var subs=this.__yui_subscribers;if(!subs[p_type]){subs[p_type]=[];}
subs[p_type].push({fn:p_fn,obj:p_obj,override:p_override});}},unsubscribe:function(p_type,p_fn,p_obj){this.__yui_events=this.__yui_events||{};var ce=this.__yui_events[p_type];if(ce){return ce.unsubscribe(p_fn,p_obj);}else{return false;}},unsubscribeAll:function(p_type){return this.unsubscribe(p_type);},createEvent:function(p_type,p_config){this.__yui_events=this.__yui_events||{};var opts=p_config||{};var events=this.__yui_events;if(events[p_type]){}else{var scope=opts.scope||this;var silent=opts.silent||null;var ce=new YAHOO.util.CustomEvent(p_type,scope,silent,YAHOO.util.CustomEvent.FLAT);events[p_type]=ce;if(opts.onSubscribeCallback){ce.subscribeEvent.subscribe(opts.onSubscribeCallback);}
this.__yui_subscribers=this.__yui_subscribers||{};var qs=this.__yui_subscribers[p_type];if(qs){for(var i=0;i<qs.length;++i){ce.subscribe(qs[i].fn,qs[i].obj,qs[i].override);}}}
return events[p_type];},fireEvent:function(p_type,arg1,arg2,etc){this.__yui_events=this.__yui_events||{};var ce=this.__yui_events[p_type];if(ce){var args=[];for(var i=1;i<arguments.length;++i){args.push(arguments[i]);}
return ce.fire.apply(ce,args);}else{return null;}},hasEvent:function(type){if(this.__yui_events){if(this.__yui_events[type]){return true;}}
return false;}};YAHOO.util.KeyListener=function(attachTo,keyData,handler,event){if(!attachTo){}else if(!keyData){}else if(!handler){}
if(!event){event=YAHOO.util.KeyListener.KEYDOWN;}
var keyEvent=new YAHOO.util.CustomEvent("keyPressed");this.enabledEvent=new YAHOO.util.CustomEvent("enabled");this.disabledEvent=new YAHOO.util.CustomEvent("disabled");if(typeof attachTo=='string'){attachTo=document.getElementById(attachTo);}
if(typeof handler=='function'){keyEvent.subscribe(handler);}else{keyEvent.subscribe(handler.fn,handler.scope,handler.correctScope);}
function handleKeyPress(e,obj){if(!keyData.shift){keyData.shift=false;}
if(!keyData.alt){keyData.alt=false;}
if(!keyData.ctrl){keyData.ctrl=false;}
if(e.shiftKey==keyData.shift&&e.altKey==keyData.alt&&e.ctrlKey==keyData.ctrl){var dataItem;var keyPressed;if(keyData.keys instanceof Array){for(var i=0;i<keyData.keys.length;i++){dataItem=keyData.keys[i];if(dataItem==e.charCode){keyEvent.fire(e.charCode,e);break;}else if(dataItem==e.keyCode){keyEvent.fire(e.keyCode,e);break;}}}else{dataItem=keyData.keys;if(dataItem==e.charCode){keyEvent.fire(e.charCode,e);}else if(dataItem==e.keyCode){keyEvent.fire(e.keyCode,e);}}}}
this.enable=function(){if(!this.enabled){YAHOO.util.Event.addListener(attachTo,event,handleKeyPress);this.enabledEvent.fire(keyData);}
this.enabled=true;};this.disable=function(){if(this.enabled){YAHOO.util.Event.removeListener(attachTo,event,handleKeyPress);this.disabledEvent.fire(keyData);}
this.enabled=false;};this.toString=function(){return"KeyListener ["+keyData.keys+"] "+attachTo.tagName+
(attachTo.id?"["+attachTo.id+"]":"");};};YAHOO.util.KeyListener.KEYDOWN="keydown";YAHOO.util.KeyListener.KEYUP="keyup";YAHOO.register("event",YAHOO.util.Event,{version:"2.2.0",build:"127"});

/*  Prototype JavaScript framework, version 1.5.0_rc1
 *  (c) 2005 Sam Stephenson <sam@conio.net>
 *
 *  Prototype is freely distributable under the terms of an MIT-style license.
 *  For details, see the Prototype web site: http://prototype.conio.net/
 *
/*--------------------------------------------------------------------------*/

var Prototype = {
  Version: '1.5.0_rc1',
  BrowserFeatures: {
    XPath: !!document.evaluate
  },

  ScriptFragment: '(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)',
  emptyFunction: function() {},
  K: function(x) { return x }
}

var Class = {
  create: function() {
    return function() {
      this.initialize.apply(this, arguments);
    }
  }
}

var Abstract = new Object();

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

Object.extend(Object, {
  inspect: function(object) {
    try {
      if (object === undefined) return 'undefined';
      if (object === null) return 'null';
      return object.inspect ? object.inspect() : object.toString();
    } catch (e) {
      if (e instanceof RangeError) return '...';
      throw e;
    }
  },

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

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

  clone: function(object) {
    return Object.extend({}, object);
  }
});

Function.prototype.bind = function() {
  var __method = this, args = $A(arguments), object = args.shift();
  return function() {
    return __method.apply(object, args.concat($A(arguments)));
  }
}

Function.prototype.bindAsEventListener = function(object) {
  var __method = this, args = $A(arguments), object = args.shift();
  return function(event) {
    return __method.apply(object, [( event || window.event)].concat(args).concat($A(arguments)));
  }
}

Object.extend(Number.prototype, {
  toColorPart: function() {
    var digits = this.toString(16);
    if (this < 16) return '0' + digits;
    return digits;
  },

  succ: function() {
    return this + 1;
  },

  times: function(iterator) {
    $R(0, this, true).each(iterator);
    return this;
  }
});

var Try = {
  these: function() {
    var returnValue;

    for (var i = 0; i < arguments.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.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 += (replacement(match) || '').toString();
        source  = source.slice(match.index + match[0].length);
      } else {
        result += source, source = '';
      }
    }
    return result;
  },

  sub: function(pattern, replacement, count) {
    replacement = this.gsub.prepareReplacement(replacement);
    count = count === undefined ? 1 : count;

    return this.gsub(pattern, function(match) {
      if (--count < 0) return match[0];
      return replacement(match);
    });
  },

  scan: function(pattern, iterator) {
    this.gsub(pattern, iterator);
    return this;
  },

  truncate: function(length, truncation) {
    length = length || 30;
    truncation = truncation === undefined ? '...' : truncation;
    return this.length > length ?
      this.slice(0, length - truncation.length) + truncation : this;
  },

  strip: function() {
    return this.replace(/^\s+/, '').replace(/\s+$/, '');
  },

  stripTags: function() {
    return this.replace(/<\/?[^>]+>/gi, '');
  },

  stripScripts: function() {
    return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
  },

  extractScripts: function() {
    var matchAll = new RegExp(Prototype.ScriptFragment, 'img');
    var matchOne = new RegExp(Prototype.ScriptFragment, 'im');
    return (this.match(matchAll) || []).map(function(scriptTag) {
      return (scriptTag.match(matchOne) || ['', ''])[1];
    });
  },

  evalScripts: function() {
    return this.extractScripts().map(function(script) { return eval(script) });
  },

  escapeHTML: function() {
    var div = document.createElement('div');
    var text = document.createTextNode(this);
    div.appendChild(text);
    return div.innerHTML;
  },

  unescapeHTML: function() {
    var div = document.createElement('div');
    div.innerHTML = this.stripTags();
    return div.childNodes[0] ? div.childNodes[0].nodeValue : '';
  },

  toQueryParams: function() {
    var match = this.strip().match(/[^?]*$/)[0];
    if (!match) return {};
    var pairs = match.split('&');
    return pairs.inject({}, function(params, pairString) {
      var pair  = pairString.split('=');
      var value = pair[1] ? decodeURIComponent(pair[1]) : undefined;
      params[decodeURIComponent(pair[0])] = value;
      return params;
    });
  },

  toArray: function() {
    return this.split('');
  },

  camelize: function() {
    var oStringList = this.split('-');
    if (oStringList.length == 1) return oStringList[0];

    var camelizedString = this.indexOf('-') == 0
      ? oStringList[0].charAt(0).toUpperCase() + oStringList[0].substring(1)
      : oStringList[0];

    for (var i = 1, length = oStringList.length; i < length; i++) {
      var s = oStringList[i];
      camelizedString += s.charAt(0).toUpperCase() + s.substring(1);
    }

    return camelizedString;
  },

  inspect: function(useDoubleQuotes) {
    var escapedString = this.replace(/\\/g, '\\\\');
    if (useDoubleQuotes)
      return '"' + escapedString.replace(/"/g, '\\"') + '"';
    else
      return "'" + escapedString.replace(/'/g, '\\\'') + "'";
  }
});

String.prototype.gsub.prepareReplacement = function(replacement) {
  if (typeof replacement == 'function') return replacement;
  var template = new Template(replacement);
  return function(match) { return template.evaluate(match) };
}

String.prototype.parseQuery = String.prototype.toQueryParams;

var Template = Class.create();
Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
Template.prototype = {
  initialize: function(template, pattern) {
    this.template = template.toString();
    this.pattern  = pattern || Template.Pattern;
  },

  evaluate: function(object) {
    return this.template.gsub(this.pattern, function(match) {
      var before = match[1];
      if (before == '\\') return match[2];
      return before + (object[match[3]] || '').toString();
    });
  }
}

var $break    = new Object();
var $continue = new Object();

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

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

  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(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 || null;
    var results = this.eachSlice(number);
    if (results.length > 0) (number - results.last().length).times(function() {
      results.last().push(fillWith)
    });
    return results;
  },

  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.collect(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.collect(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.collect(Prototype.K);
  },

  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));
    });
  },

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

Object.extend(Enumerable, {
  map:     Enumerable.collect,
  find:    Enumerable.detect,
  select:  Enumerable.findAll,
  member:  Enumerable.include,
  entries: Enumerable.toArray
});
var $A = Array.from = function(iterable) {
  if (!iterable) return [];
  if (iterable.toArray) {
    return iterable.toArray();
  } else {
    var results = [];
    for (var i = 0, length = iterable.length; i < length; i++)
      results.push(iterable[i]);
    return results;
  }
}

Object.extend(Array.prototype, Enumerable);

if (!Array.prototype._reverse)
  Array.prototype._reverse = Array.prototype.reverse;

Object.extend(Array.prototype, {
  _each: function(iterator) {
    for (var i = 0, length = this.length; i < length; i++)
      iterator(this[i]);
  },

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

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

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

  compact: function() {
    return this.select(function(value) {
      return value != undefined || value != null;
    });
  },

  flatten: function() {
    return this.inject([], function(array, value) {
      return array.concat(value && value.constructor == Array ?
        value.flatten() : [value]);
    });
  },

  without: function() {
    var values = $A(arguments);
    return this.select(function(value) {
      return !values.include(value);
    });
  },

  indexOf: function(object) {
    for (var i = 0, length = this.length; i < length; i++)
      if (this[i] == object) return i;
    return -1;
  },

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

  reduce: function() {
    return this.length > 1 ? this : this[0];
  },

  uniq: function() {
    return this.inject([], function(array, value) {
      return array.include(value) ? array : array.concat([value]);
    });
  },

  clone: function() {
    return [].concat(this);
  },

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

Array.prototype.toArray = Array.prototype.clone;
var Hash = {
  _each: function(iterator) {
    for (var key in this) {
      var value = this[key];
      if (typeof value == 'function') 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;
    });
  },

  toQueryString: function() {
    return this.map(function(pair) {
      if (!pair.value && pair.value !== 0) pair[1] = '';
      if (!pair.key) return;
      return pair.map(encodeURIComponent).join('=');
    }).join('&');
  },

  inspect: function() {
    return '#<Hash:{' + this.map(function(pair) {
      return pair.map(Object.inspect).join(': ');
    }).join(', ') + '}>';
  }
}

function $H(object) {
  var hash = Object.extend({}, object || {});
  Object.extend(hash, Enumerable);
  Object.extend(hash, Hash);
  return hash;
}
ObjectRange = Class.create();
Object.extend(ObjectRange.prototype, Enumerable);
Object.extend(ObjectRange.prototype, {
  initialize: function(start, end, exclusive) {
    this.start = start;
    this.end = end;
    this.exclusive = exclusive;
  },

  _each: function(iterator) {
    var value = this.start;
    while (this.include(value)) {
      iterator(value);
      value = value.succ();
    }
  },

  include: function(value) {
    if (value < this.start)
      return false;
    if (this.exclusive)
      return value < this.end;
    return value <= this.end;
  }
});

var $R = function(start, end, exclusive) {
  return new ObjectRange(start, end, exclusive);
}

var Ajax = {
  getTransport: function() {
    return Try.these(
      function() {return new XMLHttpRequest()},
      function() {return new ActiveXObject('Msxml2.XMLHTTP')},
      function() {return new ActiveXObject('Microsoft.XMLHTTP')}
    ) || false;
  },

  activeRequestCount: 0
}

Ajax.Responders = {
  responders: [],

  _each: function(iterator) {
    this.responders._each(iterator);
  },

  register: function(responder) {
    if (!this.include(responder))
      this.responders.push(responder);
  },

  unregister: function(responder) {
    this.responders = this.responders.without(responder);
  },

  dispatch: function(callback, request, transport, json) {
    this.each(function(responder) {
      if (typeof responder[callback] == 'function') {
        try {
          responder[callback].apply(responder, [request, transport, json]);
        } catch (e) {}
      }
    });
  }
};

Object.extend(Ajax.Responders, Enumerable);

Ajax.Responders.register({
  onCreate: function() {
    Ajax.activeRequestCount++;
  },
  onComplete: function() {
    Ajax.activeRequestCount--;
  }
});

Ajax.Base = function() {};
Ajax.Base.prototype = {
  setOptions: function(options) {
    this.options = {
      method:       'post',
      asynchronous: true,
      contentType:  'application/x-www-form-urlencoded',
      encoding:     'UTF-8',
      parameters:   ''
    }
    Object.extend(this.options, options || {});

    this.options.method = this.options.method.toLowerCase();
    this.options.parameters = $H(typeof this.options.parameters == 'string' ?
      this.options.parameters.toQueryParams() : this.options.parameters);
  }
}

Ajax.Request = Class.create();
Ajax.Request.Events =
  ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];

Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
  initialize: function(url, options) {
    this.transport = Ajax.getTransport();
    this.setOptions(options);
    this.request(url);
  },

  request: function(url) {
    var params = this.options.parameters;
    if (params.any()) params['_'] = '';

    if (!['get', 'post'].include(this.options.method)) {
      // simulate other verbs over post
      params['_method'] = this.options.method;
      this.options.method = 'post';
    }

    this.url = url;

    // when GET, append parameters to URL
    if (this.options.method == 'get' && params.any())
      this.url += (this.url.indexOf('?') >= 0 ? '&' : '?') +
        params.toQueryString();

    try {
      Ajax.Responders.dispatch('onCreate', this, this.transport);

      this.transport.open(this.options.method.toUpperCase(), this.url,
        this.options.asynchronous, this.options.username,
        this.options.password);

      if (this.options.asynchronous)
        setTimeout(function() { this.respondToReadyState(1) }.bind(this), 10);

      this.transport.onreadystatechange = this.onStateChange.bind(this);
      this.setRequestHeaders();

      var body = this.options.method == 'post' ?
        (this.options.postBody || params.toQueryString()) : null;

      this.transport.send(body);


      /* Force Firefox to handle ready state 4 for synchronous requests */
      if (!this.options.asynchronous && this.transport.overrideMimeType)
        this.onStateChange();
    }
    catch (e) {
      this.dispatchException(e);
    }
  },

  onStateChange: function() {
    var readyState = this.transport.readyState;
    if (readyState > 1)
      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.options.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; i < extras.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.options['on' + this.transport.status]
         || this.options['on' + (this.success() ? 'Success' : 'Failure')]
         || Prototype.emptyFunction)(transport, json);
      } catch (e) {
        this.dispatchException(e);
      }
    }

    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') {
      if ((this.getHeader('Content-type') || '').strip().
        match(/^(text|application)\/(x-)?(java|ecma)script(;.*)?$/i))
          this.evalResponse();

      // avoid memory leak in MSIE: clean up
      this.transport.onreadystatechange = Prototype.emptyFunction;
    }
  },

  getHeader: function(name) {
    try {
      return this.transport.getResponseHeader(name);
    } catch (e) { return null }
  },

  evalJSON: function() {
    try {
      var json = this.getHeader('X-JSON');
      return json ? eval('(' + json + ')') : null;
    } catch (e) { return null }
  },

  evalResponse: function() {
    try {
      return eval(this.transport.responseText);
    } catch (e) {
      this.dispatchException(e);
    }
  },

  dispatchException: function(exception) {
    (this.options.onException || Prototype.emptyFunction)(this, exception);
    Ajax.Responders.dispatch('onException', this, exception);
  }
});

Ajax.Updater = Class.create();

Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {
  initialize: function(container, url, options) {
    this.container = {
      success: (container.success || container),
      failure: (container.failure || (container.success ? null : container))
    }

    this.transport = Ajax.getTransport();
    this.setOptions(options);

    var onComplete = this.options.onComplete || Prototype.emptyFunction;
    this.options.onComplete = (function(transport, param) {
      this.updateContent();
      onComplete(transport, param);
    }).bind(this);

    this.request(url);
  },

  updateContent: function() {
    var receiver = this.container[this.success() ? 'success' : 'failure'];
    var response = this.transport.responseText;

    if (!this.options.evalScripts) response = response.stripScripts();

    if (receiver = $(receiver)) {
      if (this.options.insertion)
        new this.options.insertion(receiver, response);
      else
        receiver.update(response);
    }

    if (this.success()) {
      if (this.onComplete)
        setTimeout(this.onComplete.bind(this), 10);
    }
  }
});

Ajax.PeriodicalUpdater = Class.create();
Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), {
  initialize: function(container, url, options) {
    this.setOptions(options);
    this.onComplete = this.options.onComplete;

    this.frequency = (this.options.frequency || 2);
    this.decay = (this.options.decay || 1);

    this.updater = {};
    this.container = container;
    this.url = url;

    this.start();
  },

  start: function() {
    this.options.onComplete = this.updateComplete.bind(this);
    this.onTimerEvent();
  },

  stop: function() {
    this.updater.options.onComplete = undefined;
    clearTimeout(this.timer);
    (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
  },

  updateComplete: function(request) {
    if (this.options.decay) {
      this.decay = (request.responseText == this.lastText ?
        this.decay * this.options.decay : 1);

      this.lastText = request.responseText;
    }
    this.timer = setTimeout(this.onTimerEvent.bind(this),
      this.decay * this.frequency * 1000);
  },

  onTimerEvent: function() {
    this.updater = new Ajax.Updater(this.container, this.url, this.options);
  }
});
function $(element) {
  if (arguments.length > 1) {
    for (var i = 0, elements = [], length = arguments.length; i < length; i++)
      elements.push($(arguments[i]));
    return elements;
  }
  if (typeof element == 'string')
    element = document.getElementById(element);
  return Element.extend(element);
}

if (Prototype.BrowserFeatures.XPath) {
  document._getElementsByXPath = function(expression, parentElement) {
    var results = [];
    var query = document.evaluate(expression, $(parentElement) || document,
      null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
    for (var i = 0, len = query.snapshotLength; i < len; i++)
      results.push(query.snapshotItem(i));
    return results;
  }
}

document.getElementsByClassName = function(className, parentElement) {
  if (Prototype.BrowserFeatures.XPath) {
    var q = ".//*[contains(concat(' ', @class, ' '), ' " + className + " ')]";
    return document._getElementsByXPath(q, parentElement);
  } else {
    var children = ($(parentElement) || document.body).getElementsByTagName('*');
    var elements = [], child;
    for (var i = 0, length = children.length; i < length; i++) {
      child = children[i];
      if (Element.hasClassName(child, className))
        elements.push(Element.extend(child));
    }
    return elements;
  }
}

/*--------------------------------------------------------------------------*/

if (!window.Element)
  var Element = new Object();

Element.extend = function(element) {
  if (!element) return;
  if (_nativeExtensions || element.nodeType == 3) return element;

  if (!element._extended && element.tagName && element != window) {
    var methods = Object.clone(Element.Methods), cache = Element.extend.cache;

    if (element.tagName == 'FORM')
      Object.extend(methods, Form.Methods);
    if (['INPUT', 'TEXTAREA', 'SELECT'].include(element.tagName))
      Object.extend(methods, Form.Element.Methods);

    for (var property in methods) {
      var value = methods[property];
      if (typeof value == 'function')
        element[property] = cache.findOrStore(value);
    }

    var methods = Object.clone(Element.Methods.Simulated), cache = Element.extend.cache;
    for (var property in methods) {
      var value = methods[property];
      if ('function' == typeof value && !(property in element))
        element[property] = cache.findOrStore(value);
    }
  }

  element._extended = true;
  return element;
}

Element.extend.cache = {
  findOrStore: function(value) {
    return this[value] = this[value] || function() {
      return value.apply(null, [this].concat($A(arguments)));
    }
  }
}

Element.Methods = {
  visible: function(element) {
    return $(element).style.display != 'none';
  },

  toggle: function(element) {
    element = $(element);
    Element[Element.visible(element) ? 'hide' : 'show'](element);
    return element;
  },

  hide: function(element) {
    $(element).style.display = 'none';
    return element;
  },

  show: function(element) {
    $(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);
    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) {
    element = $(element);
    return $A(element.getElementsByTagName('*'));
  },

  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) {
    element = $(element);
    if (typeof selector == 'string')
      selector = new Selector(selector);
    return selector.match(element);
  },

  up: function(element, expression, index) {
    return Selector.findElement($(element).ancestors(), expression, index);
  },

  down: function(element, expression, index) {
    return Selector.findElement($(element).descendants(), expression, index);
  },

  previous: function(element, expression, index) {
    return Selector.findElement($(element).previousSiblings(), expression, index);
  },

  next: function(element, expression, index) {
    return Selector.findElement($(element).nextSiblings(), expression, index);
  },

  getElementsBySelector: function() {
    var args = $A(arguments), element = $(args.shift());
    return Selector.findChildElements(element, args);
  },

  getElementsByClassName: function(element, className) {
    element = $(element);
    return document.getElementsByClassName(className, element);
  },

  getHeight: function(element) {
    element = $(element);
    return element.offsetHeight;
  },

  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;
  },

  observe: function() {
    Event.observe.apply(Event, arguments);
    return $A(arguments).first();
  },

  stopObserving: function() {
    Event.stopObserving.apply(Event, arguments);
    return $A(arguments).first();
  },

  // removes whitespace-only text node children
  cleanWhitespace: function(element) {
    element = $(element);
    var node = element.firstChild;
    while (node) {
      var nextNode = node.nextSibling;
      if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
        element.removeChild(node);
      node = nextNode;
    }
    return element;
  },

  empty: function(element) {
    return $(element).innerHTML.match(/^\s*$/);
  },

  childOf: function(element, ancestor) {
    element = $(element), ancestor = $(ancestor);
    while (element = element.parentNode)
      if (element == ancestor) return true;
    return false;
  },

  scrollTo: function(element) {
    element = $(element);
    var x = element.x ? element.x : element.offsetLeft,
        y = element.y ? element.y : element.offsetTop;
    window.scrollTo(x, y);
    return element;
  },

  getStyle: function(element, style) {
    element = $(element);
    var value = element.style[style.camelize()];
    if (!value) {
      if (document.defaultView && document.defaultView.getComputedStyle) {
        var css = document.defaultView.getComputedStyle(element, null);
        value = css ? css.getPropertyValue(style) : null;
      } else if (element.currentStyle) {
        value = element.currentStyle[style.camelize()];
      }
    }

    if (window.opera && ['left', 'top', 'right', 'bottom'].include(style))
      if (Element.getStyle(element, 'position') == 'static') value = 'auto';

    return value == 'auto' ? null : value;
  },

  setStyle: function(element, style) {
    element = $(element);
    for (var name in style)
      element.style[name.camelize()] = style[name];
    return element;
  },

  getDimensions: function(element) {
    element = $(element);
    if (Element.getStyle(element, 'display') != 'none')
      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;
    els.visibility = 'hidden';
    els.position = 'absolute';
    els.display = '';
    var originalWidth = element.clientWidth;
    var originalHeight = element.clientHeight;
    els.display = 'none';
    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;
  }
}

Element.Methods.Simulated = {
  hasAttribute: function(element, attribute) {
    return $(element).getAttributeNode(attribute).specified;
  }
}

// IE is missing .innerHTML support for TABLE-related elements
if(document.all){
  Element.Methods.update = function(element, html) {
    element = $(element);
    html = typeof html == 'undefined' ? '' : html.toString();
    var tagName = element.tagName.toUpperCase();
    if (['THEAD','TBODY','TR','TD'].indexOf(tagName) > -1) {
      var div = document.createElement('div');
      switch (tagName) {
        case 'THEAD':
        case 'TBODY':
          div.innerHTML = '<table><tbody>' +  html.stripScripts() + '</tbody></table>';
          depth = 2;
          break;
        case 'TR':
          div.innerHTML = '<table><tbody><tr>' +  html.stripScripts() + '</tr></tbody></table>';
          depth = 3;
          break;
        case 'TD':
          div.innerHTML = '<table><tbody><tr><td>' +  html.stripScripts() + '</td></tr></tbody></table>';
          depth = 4;
      }
      $A(element.childNodes).each(function(node){
        element.removeChild(node)
      });
      depth.times(function(){ div = div.firstChild });

      $A(div.childNodes).each(
        function(node){ element.appendChild(node) });
    } else {
      element.innerHTML = html.stripScripts();
    }
    setTimeout(function() {html.evalScripts()}, 10);
    return element;
  }
}

Object.extend(Element, Element.Methods);

var _nativeExtensions = false;

if(/Konqueror|Safari|KHTML/.test(navigator.userAgent))
  ['', 'Form', 'Input', 'TextArea', 'Select'].each(function(tag) {
    var className = 'HTML' + tag + 'Element';
    if(window[className]) return;
    var klass = window[className] = {};
    klass.prototype = document.createElement(tag ? tag.toLowerCase() : 'div').__proto__;
  });

Element.addMethods = function(methods) {
  Object.extend(Element.Methods, methods || {});

  function copy(methods, destination, onlyIfAbsent) {
    onlyIfAbsent = onlyIfAbsent || false;
    var cache = Element.extend.cache;
    for (var property in methods) {
      var value = methods[property];
      if (!onlyIfAbsent || !(property in destination))
        destination[property] = cache.findOrStore(value);
    }
  }

  if (typeof HTMLElement != 'undefined') {
    copy(Element.Methods, HTMLElement.prototype);
    copy(Element.Methods.Simulated, HTMLElement.prototype, true);
    copy(Form.Methods, HTMLFormElement.prototype);
    [HTMLInputElement, HTMLTextAreaElement, HTMLSelectElement].each(function(klass) {
      copy(Form.Element.Methods, klass.prototype);
    });
    _nativeExtensions = true;
  }
}

var Toggle = new Object();
Toggle.display = Element.toggle;

/*--------------------------------------------------------------------------*/

Abstract.Insertion = function(adjacency) {
  this.adjacency = adjacency;
}

Abstract.Insertion.prototype = {
  initialize: function(element, content) {
    this.element = $(element);
    this.content = content.stripScripts();

    if (this.adjacency && this.element.insertAdjacentHTML) {
      try {
        this.element.insertAdjacentHTML(this.adjacency, this.content);
      } catch (e) {
        var tagName = this.element.tagName.toLowerCase();
        if (tagName == 'tbody' || tagName == 'tr') {
          this.insertContent(this.contentFromAnonymousTable());
        } else {
          throw e;
        }
      }
    } else {
      this.range = this.element.ownerDocument.createRange();
      if (this.initializeRange) this.initializeRange();
      this.insertContent([this.range.createContextualFragment(this.content)]);
    }

    setTimeout(function() {content.evalScripts()}, 10);
  },

  contentFromAnonymousTable: function() {
    var div = document.createElement('div');
    div.innerHTML = '<table><tbody>' + this.content + '</tbody></table>';
    return $A(div.childNodes[0].childNodes[0].childNodes);
  }
}

var Insertion = new Object();

Insertion.Before = Class.create();
Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), {
  initializeRange: function() {
    this.range.setStartBefore(this.element);
  },

  insertContent: function(fragments) {
    fragments.each((function(fragment) {
      this.element.parentNode.insertBefore(fragment, this.element);
    }).bind(this));
  }
});

Insertion.Top = Class.create();
Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), {
  initializeRange: function() {
    this.range.selectNodeContents(this.element);
    this.range.collapse(true);
  },

  insertContent: function(fragments) {
    fragments.reverse(false).each((function(fragment) {
      this.element.insertBefore(fragment, this.element.firstChild);
    }).bind(this));
  }
});

Insertion.Bottom = Class.create();
Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), {
  initializeRange: function() {
    this.range.selectNodeContents(this.element);
    this.range.collapse(this.element);
  },

  insertContent: function(fragments) {
    fragments.each((function(fragment) {
      this.element.appendChild(fragment);
    }).bind(this));
  }
});

Insertion.After = Class.create();
Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), {
  initializeRange: function() {
    this.range.setStartAfter(this.element);
  },

  insertContent: function(fragments) {
    fragments.each((function(fragment) {
      this.element.parentNode.insertBefore(fragment,
        this.element.nextSibling);
    }).bind(this));
  }
});

/*--------------------------------------------------------------------------*/

Element.ClassNames = Class.create();
Element.ClassNames.prototype = {
  initialize: function(element) {
    this.element = $(element);
  },

  _each: function(iterator) {
    this.element.className.split(/\s+/).select(function(name) {
      return name.length > 0;
    })._each(iterator);
  },

  set: function(className) {
    this.element.className = className;
  },

  add: function(classNameToAdd) {
    if (this.include(classNameToAdd)) return;
    this.set($A(this).concat(classNameToAdd).join(' '));
  },

  remove: function(classNameToRemove) {
    if (!this.include(classNameToRemove)) return;
    this.set($A(this).without(classNameToRemove).join(' '));
  },

  toString: function() {
    return $A(this).join(' ');
  }
}

Object.extend(Element.ClassNames.prototype, Enumerable);
var Selector = Class.create();
Selector.prototype = {
  initialize: function(expression) {
    this.params = {classNames: []};
    this.expression = expression.toString().strip();
    this.parseExpression();
    this.compileMatcher();
  },

  parseExpression: function() {
    function abort(message) { throw 'Parse error in selector: ' + message; }

    if (this.expression == '')  abort('empty expression');

    var params = this.params, expr = this.expression, match, modifier, clause, rest;
    while (match = expr.match(/^(.*)\[([a-z0-9_:-]+?)(?:([~\|!]?=)(?:"([^"]*)"|([^\]\s]*)))?\]$/i)) {
      params.attributes = params.attributes || [];
      params.attributes.push({name: match[2], operator: match[3], value: match[4] || match[5] || ''});
      expr = match[1];
    }

    if (expr == '*') return this.params.wildcard = true;

    while (match = expr.match(/^([^a-z0-9_-])?([a-z0-9_-]+)(.*)/i)) {
      modifier = match[1], clause = match[2], rest = match[3];
      switch (modifier) {
        case '#':       params.id = clause; break;
        case '.':       params.classNames.push(clause); break;
        case '':
        case undefined: params.tagName = clause.toUpperCase(); break;
        default:        abort(expr.inspect());
      }
      expr = rest;
    }

    if (expr.length > 0) abort(expr.inspect());
  },

  buildMatchExpression: function() {
    var params = this.params, conditions = [], clause;

    if (params.wildcard)
      conditions.push('true');
    if (clause = params.id)
      conditions.push('element.id == ' + clause.inspect());
    if (clause = params.tagName)
      conditions.push('element.tagName.toUpperCase() == ' + clause.inspect());
    if ((clause = params.classNames).length > 0)
      for (var i = 0; i < clause.length; i++)
        conditions.push('Element.hasClassName(element, ' + clause[i].inspect() + ')');
    if (clause = params.attributes) {
      clause.each(function(attribute) {
        var value = 'element.getAttribute(' + attribute.name.inspect() + ')';
        var splitValueBy = function(delimiter) {
          return value + ' && ' + value + '.split(' + delimiter.inspect() + ')';
        }

        switch (attribute.operator) {
          case '=':       conditions.push(value + ' == ' + attribute.value.inspect()); break;
          case '~=':      conditions.push(splitValueBy(' ') + '.include(' + attribute.value.inspect() + ')'); break;
          case '|=':      conditions.push(
                            splitValueBy('-') + '.first().toUpperCase() == ' + attribute.value.toUpperCase().inspect()
                          ); break;
          case '!=':      conditions.push(value + ' != ' + attribute.value.inspect()); break;
          case '':
          case undefined: conditions.push(value + ' != null'); break;
          default:        throw 'Unknown operator ' + attribute.operator + ' in selector';
        }
      });
    }

    return conditions.join(' && ');
  },

  compileMatcher: function() {
    this.match = new Function('element', 'if (!element.tagName) return false; \
      return ' + this.buildMatchExpression());
  },

  findElements: function(scope) {
    var element;

    if (element = $(this.params.id))
      if (this.match(element))
        if (!scope || Element.childOf(element, scope))
          return [element];

    scope = (scope || document).getElementsByTagName(this.params.tagName || '*');

    var results = [];
    for (var i = 0, length = scope.length; i < length; i++)
      if (this.match(element = scope[i]))
        results.push(Element.extend(element));

    return results;
  },

  toString: function() {
    return this.expression;
  }
}

Object.extend(Selector, {
  matchElements: function(elements, expression) {
    var selector = new Selector(expression);
    return elements.select(selector.match.bind(selector)).collect(Element.extend);
  },

  findElement: function(elements, expression, index) {
    if (typeof expression == 'number') index = expression, expression = false;
    return Selector.matchElements(elements, expression || '*')[index || 0];
  },

  findChildElements: function(element, expressions) {
    return expressions.map(function(expression) {
      return expression.strip().split(/\s+/).inject([null], function(results, expr) {
        var selector = new Selector(expr);
        return results.inject([], function(elements, result) {
          return elements.concat(selector.findElements(result || element));
        });
      });
    }).flatten();
  }
});

function $$() {
  return Selector.findChildElements(document, $A(arguments));
}
var Form = {
  reset: function(form) {
    $(form).reset();
    return form;
  },

  serializeElements: function(elements) {
    return elements.inject([], function(queryComponents, element) {
      var queryComponent = Form.Element.serialize(element);
      if (queryComponent) queryComponents.push(queryComponent);
      return queryComponents;
    }).join('&');
  }
};

Form.Methods = {
  serialize: function(form) {
    return Form.serializeElements($(form).getElements());
  },

  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 inputs;

    var matchingInputs = new Array();
    for (var i = 0, length = inputs.length; i < length; i++) {
      var input = inputs[i];
      if ((typeName && input.type != typeName) ||
          (name && input.name != name))
        continue;
      matchingInputs.push(Element.extend(input));
    }

    return matchingInputs;
  },

  disable: function(form) {
    form = $(form);
    form.getElements().each(function(element) {
      element.blur();
      element.disabled = 'true';
    });
    return form;
  },

  enable: function(form) {
    form = $(form);
    form.getElements().each(function(element) {
      element.disabled = '';
    });
    return form;
  },

  findFirstElement: function(form) {
    return $(form).getElements().find(function(element) {
      return element.type != 'hidden' && !element.disabled &&
        ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
    });
  },

  focusFirstElement: function(form) {
    form = $(form);
    form.findFirstElement().activate();
    return form;
  }
}

Object.extend(Form, Form.Methods);

/*--------------------------------------------------------------------------*/

Form.Element = {
  focus: function(element) {
    $(element).focus();
    return element;
  },

  select: function(element) {
    $(element).select();
    return element;
  }
}

Form.Element.Methods = {
  serialize: function(element) {
    element = $(element);
    if (element.disabled) return '';
    var method = element.tagName.toLowerCase();
    var parameter = Form.Element.Serializers[method](element);

    if (parameter) {
      var key = encodeURIComponent(parameter[0]);
      if (key.length == 0) return;

      if (parameter[1].constructor != Array)
        parameter[1] = [parameter[1]];

      return parameter[1].map(function(value) {
        return key + '=' + encodeURIComponent(value);
      }).join('&');
    }
  },

  getValue: function(element) {
    element = $(element);
    var method = element.tagName.toLowerCase();
    var parameter = Form.Element.Serializers[method](element);

    if (parameter)
      return parameter[1];
  },

  clear: function(element) {
    $(element).value = '';
    return element;
  },

  present: function(element) {
    return $(element).value != '';
  },

  activate: function(element) {
    element = $(element);
    element.focus();
    if (element.select)
      element.select();
    return element;
  },

  disable: function(element) {
    element = $(element);
    element.disabled = true;
    return element;
  },

  enable: function(element) {
    element = $(element);
    element.blur();
    element.disabled = false;
    return element;
  }
}

Object.extend(Form.Element, Form.Element.Methods);
var Field = Form.Element;

/*--------------------------------------------------------------------------*/

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);
    }
    return false;
  },

  inputSelector: function(element) {
    if (element.checked)
      return [element.name, element.value];
  },

  textarea: function(element) {
    return [element.name, element.value];
  },

  select: function(element) {
    return Form.Element.Serializers[element.type == 'select-one' ?
      'selectOne' : 'selectMany'](element);
  },

  selectOne: function(element) {
    var value = '', opt, index = element.selectedIndex;
    if (index >= 0) {
      opt = Element.extend(element.options[index]);
      // Uses the new potential extension if hasAttribute isn't native.
      value = opt.hasAttribute('value') ? opt.value : opt.text;
    }
    return [element.name, value];
  },

  selectMany: function(element) {
    var value = [];
    for (var i = 0; i < element.length; i++) {
      var opt = Element.extend(element.options[i]);
      if (opt.selected)
        // Uses the new potential extension if hasAttribute isn't native.
        value.push(opt.hasAttribute('value') ? opt.value : opt.text);
    }
    return [element.name, value];
  }
}

/*--------------------------------------------------------------------------*/

var $F = Form.Element.getValue;

/*--------------------------------------------------------------------------*/

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();
    if (this.lastValue != value) {
      this.callback(this.element, value);
      this.lastValue = value;
    }
  }
}

Form.Element.Observer = Class.create();
Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
  getValue: function() {
    return Form.Element.getValue(this.element);
  }
});

Form.Observer = Class.create();
Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
  getValue: function() {
    return Form.serialize(this.element);
  }
});

/*--------------------------------------------------------------------------*/

Abstract.EventObserver = function() {}
Abstract.EventObserver.prototype = {
  initialize: function(element, callback) {
    this.element  = $(element);
    this.callback = callback;

    this.lastValue = this.getValue();
    if (this.element.tagName.toLowerCase() == 'form')
      this.registerFormCallbacks();
    else
      this.registerCallback(this.element);
  },

  onElementEvent: function() {
    var value = this.getValue();
    if (this.lastValue != value) {
      this.callback(this.element, value);
      this.lastValue = value;
    }
  },

  registerFormCallbacks: function() {
    Form.getElements(this.element).each(this.registerCallback.bind(this));
  },

  registerCallback: function(element) {
    if (element.type) {
      switch (element.type.toLowerCase()) {
        case 'checkbox':
        case 'radio':
          Event.observe(element, 'click', this.onElementEvent.bind(this));
          break;
        default:
          Event.observe(element, 'change', this.onElementEvent.bind(this));
          break;
      }
    }
  }
}

Form.Element.EventObserver = Class.create();
Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
  getValue: function() {
    return Form.Element.getValue(this.element);
  }
});

Form.EventObserver = Class.create();
Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
  getValue: function() {
    return Form.serialize(this.element);
  }
});
if (!window.Event) {
  var Event = new Object();
}

Object.extend(Event, {
  KEY_BACKSPACE: 8,
  KEY_TAB:       9,
  KEY_RETURN:   13,
  KEY_ESC:      27,
  KEY_LEFT:     37,
  KEY_UP:       38,
  KEY_RIGHT:    39,
  KEY_DOWN:     40,
  KEY_DELETE:   46,
  KEY_HOME:     36,
  KEY_END:      35,
  KEY_PAGEUP:   33,
  KEY_PAGEDOWN: 34,

  element: function(event) {
    return event.target || event.srcElement;
  },

  isLeftClick: function(event) {
    return (((event.which) && (event.which == 1)) ||
            ((event.button) && (event.button == 1)));
  },

  pointerX: function(event) {
    return event.pageX || (event.clientX +
      (document.documentElement.scrollLeft || document.body.scrollLeft));
  },

  pointerY: function(event) {
    return event.pageY || (event.clientY +
      (document.documentElement.scrollTop || document.body.scrollTop));
  },

  stop: function(event) {
    if (event.preventDefault) {
      event.preventDefault();
      event.stopPropagation();
    } else {
      event.returnValue = false;
      event.cancelBubble = true;
    }
  },

  // find the first node with the given tagName, starting from the
  // node the event was triggered on; traverses the DOM upwards
  findElement: function(event, tagName) {
    var element = Event.element(event);
    while (element.parentNode && (!element.tagName ||
        (element.tagName.toUpperCase() != tagName.toUpperCase())))
      element = element.parentNode;
    return element;
  },

  observers: false,

  _observeAndCache: function(element, name, observer, useCapture) {
    if (!this.observers) this.observers = [];
    if (element.addEventListener) {
      this.observers.push([element, name, observer, useCapture]);
      element.addEventListener(name, observer, useCapture);
    } else if (element.attachEvent) {
      this.observers.push([element, name, observer, useCapture]);
      element.attachEvent('on' + name, observer);
    }
  },

  unloadCache: function() {
    if (!Event.observers) return;
    for (var i = 0, length = Event.observers.length; i < length; i++) {
      Event.stopObserving.apply(this, Event.observers[i]);
      Event.observers[i][0] = null;
    }
    Event.observers = false;
  },

  observe: function(element, name, observer, useCapture) {
    element = $(element);
    useCapture = useCapture || false;

    if (name == 'keypress' &&
        (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
        || element.attachEvent))
      name = 'keydown';

    Event._observeAndCache(element, name, observer, useCapture);
  },

  stopObserving: function(element, name, observer, useCapture) {
    element = $(element);
    useCapture = useCapture || false;

    if (name == 'keypress' &&
        (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
        || element.detachEvent))
      name = 'keydown';

    if (element.removeEventListener) {
      element.removeEventListener(name, observer, useCapture);
    } else if (element.detachEvent) {
      try {
        element.detachEvent('on' + name, observer);
      } catch (e) {}
    }
  }
});

/* prevent memory leaks in IE */
if (navigator.appVersion.match(/\bMSIE\b/))
  Event.observe(window, 'unload', Event.unloadCache, false);
var Position = {
  // set to true if needed, warning: firefox performance problems
  // NOT neeeded for page scrolling, only if draggable contained in
  // scrollable elements
  includeScrollOffsets: false,

  // must be called before calling withinIncludingScrolloffset, every time the
  // page is scrolled
  prepare: function() {
    this.deltaX =  window.pageXOffset
                || document.documentElement.scrollLeft
                || document.body.scrollLeft
                || 0;
    this.deltaY =  window.pageYOffset
                || document.documentElement.scrollTop
                || document.body.scrollTop
                || 0;
  },

  realOffset: function(element) {
    var valueT = 0, valueL = 0;
    do {
      valueT += element.scrollTop  || 0;
      valueL += element.scrollLeft || 0;
      element = element.parentNode;
    } while (element);
    return [valueL, valueT];
  },

  cumulativeOffset: function(element) {
    var valueT = 0, valueL = 0;
    do {
      valueT += element.offsetTop  || 0;
      valueL += element.offsetLeft || 0;
      element = element.offsetParent;
    } while (element);
    return [valueL, valueT];
  },

  positionedOffset: function(element) {
    var valueT = 0, valueL = 0;
    do {
      valueT += element.offsetTop  || 0;
      valueL += element.offsetLeft || 0;
      element = element.offsetParent;
      if (element) {
        if(element.tagName=='BODY') break;
        var p = Element.getStyle(element, 'position');
        if (p == 'relative' || p == 'absolute') break;
      }
    } while (element);
    return [valueL, valueT];
  },

  offsetParent: function(element) {
    if (element.offsetParent) return element.offsetParent;
    if (element == document.body) return element;

    while ((element = element.parentNode) && element != document.body)
      if (Element.getStyle(element, 'position') != 'static')
        return element;

    return document.body;
  },

  // caches x/y coordinate pair to use with overlap
  within: function(element, x, y) {
    if (this.includeScrollOffsets)
      return this.withinIncludingScrolloffsets(element, x, y);
    this.xcomp = x;
    this.ycomp = y;
    this.offset = this.cumulativeOffset(element);

    return (y >= this.offset[1] &&
            y <  this.offset[1] + element.offsetHeight &&
            x >= this.offset[0] &&
            x <  this.offset[0] + element.offsetWidth);
  },

  withinIncludingScrolloffsets: function(element, x, y) {
    var offsetcache = this.realOffset(element);

    this.xcomp = x + offsetcache[0] - this.deltaX;
    this.ycomp = y + offsetcache[1] - this.deltaY;
    this.offset = this.cumulativeOffset(element);

    return (this.ycomp >= this.offset[1] &&
            this.ycomp <  this.offset[1] + element.offsetHeight &&
            this.xcomp >= this.offset[0] &&
            this.xcomp <  this.offset[0] + element.offsetWidth);
  },

  // within must be called directly before
  overlap: function(mode, element) {
    if (!mode) return 0;
    if (mode == 'vertical')
      return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
        element.offsetHeight;
    if (mode == 'horizontal')
      return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
        element.offsetWidth;
  },

  page: function(forElement) {
    var valueT = 0, valueL = 0;

    var element = forElement;
    do {
      valueT += element.offsetTop  || 0;
      valueL += element.offsetLeft || 0;

      // Safari fix
      if (element.offsetParent==document.body)
        if (Element.getStyle(element,'position')=='absolute') break;

    } while (element = element.offsetParent);

    element = forElement;
    do {
      if (!window.opera || element.tagName=='BODY') {
        valueT -= element.scrollTop  || 0;
        valueL -= element.scrollLeft || 0;
      }
    } while (element = element.parentNode);

    return [valueL, valueT];
  },

  clone: function(source, target) {
    var options = Object.extend({
      setLeft:    true,
      setTop:     true,
      setWidth:   true,
      setHeight:  true,
      offsetTop:  0,
      offsetLeft: 0
    }, arguments[2] || {})

    // find page position of source
    source = $(source);
    var p = Position.page(source);

    // find coordinate system to use
    target = $(target);
    var delta = [0, 0];
    var parent = null;
    // delta [0,0] will do fine with position: fixed elements,
    // position:absolute needs offsetParent deltas
    if (Element.getStyle(target,'position') == 'absolute') {
      parent = Position.offsetParent(target);
      delta = Position.page(parent);
    }

    // correct by body offsets (fixes Safari)
    if (parent == document.body) {
      delta[0] -= document.body.offsetLeft;
      delta[1] -= document.body.offsetTop;
    }

    // set position
    if(options.setLeft)   target.style.left  = (p[0] - delta[0] + options.offsetLeft) + 'px';
    if(options.setTop)    target.style.top   = (p[1] - delta[1] + options.offsetTop) + 'px';
    if(options.setWidth)  target.style.width = source.offsetWidth + 'px';
    if(options.setHeight) target.style.height = source.offsetHeight + 'px';
  },

  absolutize: function(element) {
    element = $(element);
    if (element.style.position == 'absolute') return;
    Position.prepare();

    var offsets = Position.positionedOffset(element);
    var top     = offsets[1];
    var left    = offsets[0];
    var width   = element.clientWidth;
    var height  = element.clientHeight;

    element._originalLeft   = left - parseFloat(element.style.left  || 0);
    element._originalTop    = top  - parseFloat(element.style.top || 0);
    element._originalWidth  = element.style.width;
    element._originalHeight = element.style.height;

    element.style.position = 'absolute';
    element.style.top    = top + 'px';;
    element.style.left   = left + 'px';;
    element.style.width  = width + 'px';;
    element.style.height = height + 'px';;
  },

  relativize: function(element) {
    element = $(element);
    if (element.style.position == 'relative') return;
    Position.prepare();

    element.style.position = 'relative';
    var top  = parseFloat(element.style.top  || 0) - (element._originalTop || 0);
    var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);

    element.style.top    = top + 'px';
    element.style.left   = left + 'px';
    element.style.height = element._originalHeight;
    element.style.width  = element._originalWidth;
  }
}

// Safari returns margins on body which is incorrect if the child is absolutely
// positioned.  For performance reasons, redefine Position.cumulativeOffset for
// KHTML/WebKit only.
if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) {
  Position.cumulativeOffset = function(element) {
    var valueT = 0, valueL = 0;
    do {
      valueT += element.offsetTop  || 0;
      valueL += element.offsetLeft || 0;
      if (element.offsetParent == document.body)
        if (Element.getStyle(element, 'position') == 'absolute') break;

      element = element.offsetParent;
    } while (element);

    return [valueL, valueT];
  }
}

Element.addMethods();

// script.aculo.us builder.js v1.6.5, Wed Nov 08 14:17:49 CET 2006

// Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
//
// 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/

var Builder = {
  NODEMAP: {
    AREA: 'map',
    CAPTION: 'table',
    COL: 'table',
    COLGROUP: 'table',
    LEGEND: 'fieldset',
    OPTGROUP: 'select',
    OPTION: 'select',
    PARAM: 'object',
    TBODY: 'table',
    TD: 'table',
    TFOOT: 'table',
    TH: 'table',
    THEAD: 'table',
    TR: 'table'
  },
  // note: For Firefox < 1.5, OPTION and OPTGROUP tags are currently broken,
  //       due to a Firefox bug
  node: function(elementName) {
    elementName = elementName.toUpperCase();
    
    // try innerHTML approach
    var parentTag = this.NODEMAP[elementName] || 'div';
    var parentElement = document.createElement(parentTag);
    try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707
      parentElement.innerHTML = "<" + elementName + "></" + elementName + ">";
    } catch(e) {}
    var element = parentElement.firstChild || null;
      
    // see if browser added wrapping tags
    if(element && (element.tagName != elementName))
      element = element.getElementsByTagName(elementName)[0];
    
    // fallback to createElement approach
    if(!element) element = document.createElement(elementName);
    
    // abort if nothing could be created
    if(!element) return;

    // attributes (or text)
    if(arguments[1])
      if(this._isStringOrNumber(arguments[1]) ||
        (arguments[1] instanceof Array)) {
          this._children(element, arguments[1]);
        } else {
          var attrs = this._attributes(arguments[1]);
          if(attrs.length) {
            try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707
              parentElement.innerHTML = "<" +elementName + " " +
                attrs + "></" + elementName + ">";
            } catch(e) {}
            element = parentElement.firstChild || null;
            // workaround firefox 1.0.X bug
            if(!element) {
              element = document.createElement(elementName);
              for(attr in arguments[1]) 
                element[attr == 'class' ? 'className' : attr] = arguments[1][attr];
            }
            if(element.tagName != elementName)
              element = parentElement.getElementsByTagName(elementName)[0];
            }
        } 

    // text, or array of children
    if(arguments[2])
      this._children(element, arguments[2]);

     return element;
  },
  _text: function(text) {
     return document.createTextNode(text);
  },

  ATTR_MAP: {
    'className': 'class',
    'htmlFor': 'for'
  },

  _attributes: function(attributes) {
    var attrs = [];
    for(attribute in attributes)
      attrs.push((attribute in this.ATTR_MAP ? this.ATTR_MAP[attribute] : attribute) +
          '="' + attributes[attribute].toString().escapeHTML() + '"');
    return attrs.join(" ");
  },
  _children: function(element, children) {
    if(typeof children=='object') { // array can hold nodes and text
      children.flatten().each( function(e) {
        if(typeof e=='object')
          element.appendChild(e)
        else
          if(Builder._isStringOrNumber(e))
            element.appendChild(Builder._text(e));
      });
    } else
      if(Builder._isStringOrNumber(children)) 
         element.appendChild(Builder._text(children));
  },
  _isStringOrNumber: function(param) {
    return(typeof param=='string' || typeof param=='number');
  },
  build: function(html) {
    var element = this.node('div');
    $(element).update(html.strip());
    return element.down();
  },
  dump: function(scope) { 
    if(typeof scope != 'object' && typeof scope != 'function') scope = window; //global scope 
  
    var tags = ("A ABBR ACRONYM ADDRESS APPLET AREA B BASE BASEFONT BDO BIG BLOCKQUOTE BODY " +
      "BR BUTTON CAPTION CENTER CITE CODE COL COLGROUP DD DEL DFN DIR DIV DL DT EM FIELDSET " +
      "FONT FORM FRAME FRAMESET H1 H2 H3 H4 H5 H6 HEAD HR HTML I IFRAME IMG INPUT INS ISINDEX "+
      "KBD LABEL LEGEND LI LINK MAP MENU META NOFRAMES NOSCRIPT OBJECT OL OPTGROUP OPTION P "+
      "PARAM PRE Q S SAMP SCRIPT SELECT SMALL SPAN STRIKE STRONG STYLE SUB SUP TABLE TBODY TD "+
      "TEXTAREA TFOOT TH THEAD TITLE TR TT U UL VAR").split(/\s+/);
  
    tags.each( function(tag){ 
      scope[tag] = function() { 
        return Builder.node.apply(Builder, [tag].concat($A(arguments)));  
      } 
    });
  }
}


// script.aculo.us effects.js v1.6.5, Wed Nov 08 14:17:49 CET 2006

// Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
// Contributors:
//  Justin Palmer (http://encytemedia.com/)
//  Mark Pilgrim (http://diveintomark.org/)
//  Martin Bialasinki
// 
// script.aculo.us is freely distributable under the terms of an MIT-style license.
// For details, see the script.aculo.us web site: http://script.aculo.us/ 

// converts rgb() and #xxx to #xxxxxx format,  
// returns self (or first argument) if not convertable  
String.prototype.parseColor = function() {  
  var color = '#';  
  if(this.slice(0,4) == 'rgb(') {  
    var cols = this.slice(4,this.length-1).split(',');  
    var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3);  
  } else {  
    if(this.slice(0,1) == '#') {  
      if(this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase();  
      if(this.length==7) color = this.toLowerCase();  
    }  
  }  
  return(color.length==7 ? color : (arguments[0] || this));  
}

/*--------------------------------------------------------------------------*/

Element.collectTextNodes = function(element) {  
  return $A($(element).childNodes).collect( function(node) {
    return (node.nodeType==3 ? node.nodeValue : 
      (node.hasChildNodes() ? Element.collectTextNodes(node) : ''));
  }).flatten().join('');
}

Element.collectTextNodesIgnoreClass = function(element, className) {  
  return $A($(element).childNodes).collect( function(node) {
    return (node.nodeType==3 ? node.nodeValue : 
      ((node.hasChildNodes() && !Element.hasClassName(node,className)) ? 
        Element.collectTextNodesIgnoreClass(node, className) : ''));
  }).flatten().join('');
}

Element.setContentZoom = function(element, percent) {
  element = $(element);  
  element.setStyle({fontSize: (percent/100) + 'em'});   
  if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);
  return element;
}

Element.getOpacity = function(element){
  element = $(element);
  var opacity;
  if (opacity = element.getStyle('opacity'))  
    return parseFloat(opacity);  
  if (opacity = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/))  
    if(opacity[1]) return parseFloat(opacity[1]) / 100;  
  return 1.0;  
}

Element.setOpacity = function(element, value){  
  element= $(element);  
  if (value == 1){
    element.setStyle({ opacity: 
      (/Gecko/.test(navigator.userAgent) && !/Konqueror|Safari|KHTML/.test(navigator.userAgent)) ? 
      0.999999 : 1.0 });
    if(/MSIE/.test(navigator.userAgent) && !window.opera)  
      element.setStyle({filter: Element.getStyle(element,'filter').replace(/alpha\([^\)]*\)/gi,'')});  
  } else {  
    if(value < 0.00001) value = 0;  
    element.setStyle({opacity: value});
    if(/MSIE/.test(navigator.userAgent) && !window.opera)  
      element.setStyle(
        { filter: element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,'') +
            'alpha(opacity='+value*100+')' });  
  }
  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(/MSIE/.test(navigator.userAgent) && !window.opera) tagifyStyle += ';zoom:1';
    
    element = $(element);
    $A(element.childNodes).each( function(child) {
      if(child.nodeType==3) {
        child.nodeValue.toArray().each( function(character) {
          element.insertBefore(
            Builder.node('span',{style: tagifyStyle},
              character == ' ' ? String.fromCharCode(160) : character), 
              child);
        });
        Element.remove(child);
      }
    });
  },
  multiple: function(element, effect) {
    var elements;
    if(((typeof element == 'object') || 
        (typeof element == 'function')) && 
       (element.length))
      elements = element;
    else
      elements = $(element).childNodes;
      
    var options = Object.extend({
      speed: 0.1,
      delay: 0.0
    }, arguments[2] || {});
    var masterDelay = options.delay;

    $A(elements).each( function(element, index) {
      new effect(element, Object.extend(options, { delay: index * options.speed + masterDelay }));
    });
  },
  PAIRS: {
    'slide':  ['SlideDown','SlideUp'],
    'blind':  ['BlindDown','BlindUp'],
    'appear': ['Appear','Fade']
  },
  toggle: function(element, effect) {
    element = $(element);
    effect = (effect || 'appear').toLowerCase();
    var options = Object.extend({
      queue: { position:'end', scope:(element.id || 'global'), limit: 1 }
    }, arguments[2] || {});
    Effect[element.visible() ? 
      Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options);
  }
};

var Effect2 = Effect; // deprecated

/* ------------- transitions ------------- */

Effect.Transitions = {
  linear: Prototype.K,
  sinoidal: function(pos) {
    return (-Math.cos(pos*Math.PI)/2) + 0.5;
  },
  reverse: function(pos) {
    return 1-pos;
  },
  flicker: function(pos) {
    return ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4;
  },
  wobble: function(pos) {
    return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5;
  },
  pulse: function(pos, pulses) { 
    pulses = pulses || 5; 
    return (
      Math.round((pos % (1/pulses)) * pulses) == 0 ? 
            ((pos * pulses * 2) - Math.floor(pos * pulses * 2)) : 
        1 - ((pos * pulses * 2) - Math.floor(pos * pulses * 2))
      );
  },
  none: function(pos) {
    return 0;
  },
  full: function(pos) {
    return 1;
  }
};

/* ------------- core effects ------------- */

Effect.ScopedQueue = Class.create();
Object.extend(Object.extend(Effect.ScopedQueue.prototype, Enumerable), {
  initialize: function() {
    this.effects  = [];
    this.interval = null;
  },
  _each: function(iterator) {
    this.effects._each(iterator);
  },
  add: function(effect) {
    var timestamp = new Date().getTime();
    
    var position = (typeof effect.options.queue == 'string') ? 
      effect.options.queue : effect.options.queue.position;
    
    switch(position) {
      case 'front':
        // move unstarted effects after this effect  
        this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) {
            e.startOn  += effect.finishOn;
            e.finishOn += effect.finishOn;
          });
        break;
      case 'with-last':
        timestamp = this.effects.pluck('startOn').max() || timestamp;
        break;
      case 'end':
        // start effect after last queued effect has finished
        timestamp = this.effects.pluck('finishOn').max() || timestamp;
        break;
    }
    
    effect.startOn  += timestamp;
    effect.finishOn += timestamp;

    if(!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit))
      this.effects.push(effect);
    
    if(!this.interval) 
      this.interval = setInterval(this.loop.bind(this), 40);
  },
  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();
    this.effects.invoke('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:        25.0,  // max. 25fps due to Effect.Queue implementation
  sync:       false, // true for combining
  from:       0.0,
  to:         1.0,
  delay:      0.0,
  queue:      'parallel'
}

Effect.Base = function() {};
Effect.Base.prototype = {
  position: null,
  start: function(options) {
    this.options      = Object.extend(Object.extend({},Effect.DefaultOptions), options || {});
    this.currentFrame = 0;
    this.state        = 'idle';
    this.startOn      = this.options.delay*1000;
    this.finishOn     = this.startOn + (this.options.duration*1000);
    this.event('beforeStart');
    if(!this.options.sync)
      Effect.Queues.get(typeof this.options.queue == 'string' ? 
        'global' : this.options.queue.scope).add(this);
  },
  loop: function(timePos) {
    if(timePos >= this.startOn) {
      if(timePos >= this.finishOn) {
        this.render(1.0);
        this.cancel();
        this.event('beforeFinish');
        if(this.finish) this.finish(); 
        this.event('afterFinish');
        return;  
      }
      var pos   = (timePos - this.startOn) / (this.finishOn - this.startOn);
      var frame = Math.round(pos * this.options.fps * this.options.duration);
      if(frame > this.currentFrame) {
        this.render(pos);
        this.currentFrame = frame;
      }
    }
  },
  render: function(pos) {
    if(this.state == 'idle') {
      this.state = 'running';
      this.event('beforeSetup');
      if(this.setup) this.setup();
      this.event('afterSetup');
    }
    if(this.state == 'running') {
      if(this.options.transition) pos = this.options.transition(pos);
      pos *= (this.options.to-this.options.from);
      pos += this.options.from;
      this.position = pos;
      this.event('beforeUpdate');
      if(this.update) this.update(pos);
      this.event('afterUpdate');
    }
  },
  cancel: function() {
    if(!this.options.sync)
      Effect.Queues.get(typeof this.options.queue == 'string' ? 
        'global' : this.options.queue.scope).remove(this);
    this.state = 'finished';
  },
  event: function(eventName) {
    if(this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this);
    if(this.options[eventName]) this.options[eventName](this);
  },
  inspect: function() {
    return '#<Effect:' + $H(this).inspect() + ',options:' + $H(this.options).inspect() + '>';
  }
}

Effect.Parallel = Class.create();
Object.extend(Object.extend(Effect.Parallel.prototype, Effect.Base.prototype), {
  initialize: function(effects) {
    this.effects = effects || [];
    this.start(arguments[1]);
  },
  update: function(position) {
    this.effects.invoke('render', position);
  },
  finish: function(position) {
    this.effects.each( function(effect) {
      effect.render(1.0);
      effect.cancel();
      effect.event('beforeFinish');
      if(effect.finish) effect.finish(position);
      effect.event('afterFinish');
    });
  }
});

Effect.Event = Class.create();
Object.extend(Object.extend(Effect.Event.prototype, Effect.Base.prototype), {
  initialize: function() {
    var options = Object.extend({
      duration: 0
    }, arguments[0] || {});
    this.start(options);
  },
  update: Prototype.emptyFunction
});

Effect.Opacity = Class.create();
Object.extend(Object.extend(Effect.Opacity.prototype, Effect.Base.prototype), {
  initialize: function(element) {
    this.element = $(element);
    if(!this.element) throw(Effect._elementDoesNotExistError);
    // make this work on IE on elements without 'layout'
    if(/MSIE/.test(navigator.userAgent) && !window.opera && (!this.element.currentStyle.hasLayout))
      this.element.setStyle({zoom: 1});
    var options = Object.extend({
      from: this.element.getOpacity() || 0.0,
      to:   1.0
    }, arguments[1] || {});
    this.start(options);
  },
  update: function(position) {
    this.element.setOpacity(position);
  }
});

Effect.Move = Class.create();
Object.extend(Object.extend(Effect.Move.prototype, Effect.Base.prototype), {
  initialize: function(element) {
    this.element = $(element);
    if(!this.element) throw(Effect._elementDoesNotExistError);
    var options = Object.extend({
      x:    0,
      y:    0,
      mode: 'relative'
    }, arguments[1] || {});
    this.start(options);
  },
  setup: function() {
    // Bug in Opera: Opera returns the "real" position of a static element or
    // relative element that does not have top/left explicitly set.
    // ==> Always set top and left for position relative elements in your stylesheets 
    // (to 0 if you do not need them) 
    this.element.makePositioned();
    this.originalLeft = parseFloat(this.element.getStyle('left') || '0');
    this.originalTop  = parseFloat(this.element.getStyle('top')  || '0');
    if(this.options.mode == 'absolute') {
      // absolute movement, so we need to calc deltaX and deltaY
      this.options.x = this.options.x - this.originalLeft;
      this.options.y = this.options.y - this.originalTop;
    }
  },
  update: function(position) {
    this.element.setStyle({
      left: Math.round(this.options.x  * position + this.originalLeft) + 'px',
      top:  Math.round(this.options.y  * position + this.originalTop)  + 'px'
    });
  }
});

// for backwards compatibility
Effect.MoveBy = function(element, toTop, toLeft) {
  return new Effect.Move(element, 
    Object.extend({ x: toLeft, y: toTop }, arguments[3] || {}));
};

Effect.Scale = Class.create();
Object.extend(Object.extend(Effect.Scale.prototype, Effect.Base.prototype), {
  initialize: function(element, percent) {
    this.element = $(element);
    if(!this.element) throw(Effect._elementDoesNotExistError);
    var options = Object.extend({
      scaleX: true,
      scaleY: true,
      scaleContent: true,
      scaleFromCenter: false,
      scaleMode: 'box',        // 'box' or 'contents' or {} with provided values
      scaleFrom: 100.0,
      scaleTo:   percent
    }, arguments[2] || {});
    this.start(options);
  },
  setup: function() {
    this.restoreAfterFinish = this.options.restoreAfterFinish || false;
    this.elementPositioning = this.element.getStyle('position');
    
    this.originalStyle = {};
    ['top','left','width','height','fontSize'].each( function(k) {
      this.originalStyle[k] = this.element.style[k];
    }.bind(this));
      
    this.originalTop  = this.element.offsetTop;
    this.originalLeft = this.element.offsetLeft;
    
    var fontSize = this.element.getStyle('font-size') || '100%';
    ['em','px','%','pt'].each( function(fontSizeType) {
      if(fontSize.indexOf(fontSizeType)>0) {
        this.fontSize     = parseFloat(fontSize);
        this.fontSizeType = fontSizeType;
      }
    }.bind(this));
    
    this.factor = (this.options.scaleTo - this.options.scaleFrom)/100;
    
    this.dims = null;
    if(this.options.scaleMode=='box')
      this.dims = [this.element.offsetHeight, this.element.offsetWidth];
    if(/^content/.test(this.options.scaleMode))
      this.dims = [this.element.scrollHeight, this.element.scrollWidth];
    if(!this.dims)
      this.dims = [this.options.scaleMode.originalHeight,
                   this.options.scaleMode.originalWidth];
  },
  update: function(position) {
    var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position);
    if(this.options.scaleContent && this.fontSize)
      this.element.setStyle({fontSize: this.fontSize * currentScale + this.fontSizeType });
    this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale);
  },
  finish: function(position) {
    if(this.restoreAfterFinish) this.element.setStyle(this.originalStyle);
  },
  setDimensions: function(height, width) {
    var d = {};
    if(this.options.scaleX) d.width = Math.round(width) + 'px';
    if(this.options.scaleY) d.height = Math.round(height) + 'px';
    if(this.options.scaleFromCenter) {
      var topd  = (height - this.dims[0])/2;
      var leftd = (width  - this.dims[1])/2;
      if(this.elementPositioning == 'absolute') {
        if(this.options.scaleY) d.top = this.originalTop-topd + 'px';
        if(this.options.scaleX) d.left = this.originalLeft-leftd + 'px';
      } else {
        if(this.options.scaleY) d.top = -topd + 'px';
        if(this.options.scaleX) d.left = -leftd + 'px';
      }
    }
    this.element.setStyle(d);
  }
});

Effect.Highlight = Class.create();
Object.extend(Object.extend(Effect.Highlight.prototype, Effect.Base.prototype), {
  initialize: function(element) {
    this.element = $(element);
    if(!this.element) throw(Effect._elementDoesNotExistError);
    var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || {});
    this.start(options);
  },
  setup: function() {
    // Prevent executing on elements not in the layout flow
    if(this.element.getStyle('display')=='none') { this.cancel(); return; }
    // Disable background image during the effect
    this.oldStyle = {
      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] || {}));
};

['setOpacity','getOpacity','getInlineOpacity','forceRerendering','setContentZoom',
 'collectTextNodes','collectTextNodesIgnoreClass'].each( 
  function(f) { Element.Methods[f] = Element[f]; }
);

Element.Methods.visualEffect = function(element, effect, options) {
  s = effect.gsub(/_/, '-').camelize();
  effect_class = s.charAt(0).toUpperCase() + s.substring(1);
  new Effect[effect_class](element, options);
  return $(element);
};

Element.addMethods();

// script.aculo.us dragdrop.js v1.6.5, Wed Nov 08 14:17:49 CET 2006

// Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
//           (c) 2005, 2006 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz)
// 
// 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/

if(typeof Effect == 'undefined')
  throw("dragdrop.js requires including script.aculo.us' effects.js library");

var Droppables = {
  drops: [],

  remove: function(element) {
    this.drops = this.drops.reject(function(d) { return d.element==$(element) });
  },

  add: function(element) {
    element = $(element);
    var options = Object.extend({
      greedy:     true,
      hoverclass: null,
      tree:       false
    }, arguments[1] || {});

    // cache containers
    if(options.containment) {
      options._containers = [];
      var containment = options.containment;
      if((typeof containment == 'object') && 
        (containment.constructor == Array)) {
        containment.each( function(c) { options._containers.push($(c)) });
      } else {
        options._containers.push($(containment));
      }
    }
    
    if(options.accept) options.accept = [options.accept].flatten();

    Element.makePositioned(element); // fix IE
    options.element = element;

    this.drops.push(options);
  },
  
  findDeepestChild: function(drops) {
    deepest = drops[0];
      
    for (i = 1; i < drops.length; ++i)
      if (Element.isParent(drops[i].element, deepest.element))
        deepest = drops[i];
    
    return deepest;
  },

  isContained: function(element, drop) {
    var containmentNode;
    if(drop.tree) {
      containmentNode = element.treeNode; 
    } else {
      containmentNode = element.parentNode;
    }
    return drop._containers.detect(function(c) { return containmentNode == c });
  },
  
  isAffected: function(point, element, drop) {
    return (
      (drop.element!=element) &&
      ((!drop._containers) ||
        this.isContained(element, drop)) &&
      ((!drop.accept) ||
        (Element.classNames(element).detect( 
          function(v) { return drop.accept.include(v) } ) )) &&
      Position.within(drop.element, point[0], point[1]) );
  },

  deactivate: function(drop) {
    if(drop.hoverclass)
      Element.removeClassName(drop.element, drop.hoverclass);
    this.last_active = null;
  },

  activate: function(drop) {
    if(drop.hoverclass)
      Element.addClassName(drop.element, drop.hoverclass);
    this.last_active = drop;
  },

  show: function(point, element) {
    if(!this.drops.length) return;
    var affected = [];
    
    if(this.last_active) this.deactivate(this.last_active);
    this.drops.each( function(drop) {
      if(Droppables.isAffected(point, element, drop))
        affected.push(drop);
    });
        
    if(affected.length>0) {
      drop = Droppables.findDeepestChild(affected);
      Position.within(drop.element, point[0], point[1]);
      if(drop.onHover)
        drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element));
      
      Droppables.activate(drop);
    }
  },

  fire: function(event, element) {
    if(!this.last_active) return;
    Position.prepare();

    if (this.isAffected([Event.pointerX(event), Event.pointerY(event)], element, this.last_active))
      if (this.last_active.onDrop) 
        this.last_active.onDrop(element, this.last_active.element, event);
  },

  reset: function() {
    if(this.last_active)
      this.deactivate(this.last_active);
  }
}

var Draggables = {
  drags: [],
  observers: [],
  
  register: function(draggable) {
    if(this.drags.length == 0) {
      this.eventMouseUp   = this.endDrag.bindAsEventListener(this);
      this.eventMouseMove = this.updateDrag.bindAsEventListener(this);
      this.eventKeypress  = this.keyPress.bindAsEventListener(this);
      
      Event.observe(document, "mouseup", this.eventMouseUp);
      Event.observe(document, "mousemove", this.eventMouseMove);
      Event.observe(document, "keypress", this.eventKeypress);
    }
    this.drags.push(draggable);
  },
  
  unregister: function(draggable) {
    this.drags = this.drags.reject(function(d) { return d==draggable });
    if(this.drags.length == 0) {
      Event.stopObserving(document, "mouseup", this.eventMouseUp);
      Event.stopObserving(document, "mousemove", this.eventMouseMove);
      Event.stopObserving(document, "keypress", this.eventKeypress);
    }
  },
  
  activate: function(draggable) {
    if(draggable.options.delay) { 
      this._timeout = setTimeout(function() { 
        Draggables._timeout = null; 
        window.focus(); 
        Draggables.activeDraggable = draggable; 
      }.bind(this), draggable.options.delay); 
    } else {
      window.focus(); // allows keypress events if window isn't currently focused, fails for Safari
      this.activeDraggable = draggable;
    }
  },
  
  deactivate: function() {
    this.activeDraggable = null;
  },
  
  updateDrag: function(event) {
    if(!this.activeDraggable) return;
    var pointer = [Event.pointerX(event), Event.pointerY(event)];
    // Mozilla-based browsers fire successive mousemove events with
    // the same coordinates, prevent needless redrawing (moz bug?)
    if(this._lastPointer && (this._lastPointer.inspect() == pointer.inspect())) return;
    this._lastPointer = pointer;
    
    this.activeDraggable.updateDrag(event, pointer);
  },
  
  endDrag: function(event) {
    if(this._timeout) { 
      clearTimeout(this._timeout); 
      this._timeout = null; 
    }
    if(!this.activeDraggable) return;
    this._lastPointer = null;
    this.activeDraggable.endDrag(event);
    this.activeDraggable = null;
  },
  
  keyPress: function(event) {
    if(this.activeDraggable)
      this.activeDraggable.keyPress(event);
  },
  
  addObserver: function(observer) {
    this.observers.push(observer);
    this._cacheObserverCallbacks();
  },
  
  removeObserver: function(element) {  // element instead of observer fixes mem leaks
    this.observers = this.observers.reject( function(o) { return o.element==element });
    this._cacheObserverCallbacks();
  },
  
  notify: function(eventName, draggable, event) {  // 'onStart', 'onEnd', 'onDrag'
    if(this[eventName+'Count'] > 0)
      this.observers.each( function(o) {
        if(o[eventName]) o[eventName](eventName, draggable, event);
      });
    if(draggable.options[eventName]) draggable.options[eventName](draggable, event);
  },
  
  _cacheObserverCallbacks: function() {
    ['onStart','onEnd','onDrag'].each( function(eventName) {
      Draggables[eventName+'Count'] = Draggables.observers.select(
        function(o) { return o[eventName]; }
      ).length;
    });
  }
}

/*--------------------------------------------------------------------------*/

var Draggable = Class.create();
Draggable._dragging    = {};

Draggable.prototype = {
  initialize: function(element) {
    var defaults = {
      handle: false,
      reverteffect: function(element, top_offset, left_offset) {
        var dur = Math.sqrt(Math.abs(top_offset^2)+Math.abs(left_offset^2))*0.02;
        new Effect.Move(element, { x: -left_offset, y: -top_offset, duration: dur,
          queue: {scope:'_draggable', position:'end'}
        });
      },
      endeffect: function(element) {
        var toOpacity = typeof element._opacity == 'number' ? element._opacity : 1.0;
        new Effect.Opacity(element, {duration:0.2, from:0.7, to:toOpacity, 
          queue: {scope:'_draggable', position:'end'},
          afterFinish: function(){ 
            Draggable._dragging[element] = false 
          }
        }); 
      },
      zindex: 1000,
      revert: false,
      scroll: false,
      scrollSensitivity: 20,
      scrollSpeed: 15,
      snap: false,  // false, or xy or [x,y] or function(x,y){ return [x,y] }
      delay: 0
    };
    
    if(!arguments[1] || typeof arguments[1].endeffect == 'undefined')
      Object.extend(defaults, {
        starteffect: function(element) {
          element._opacity = Element.getOpacity(element);
          Draggable._dragging[element] = true;
          new Effect.Opacity(element, {duration:0.2, from:element._opacity, to:0.7}); 
        }
      });
    
    var options = Object.extend(defaults, arguments[1] || {});

    this.element = $(element);
    
    if(options.handle && (typeof options.handle == 'string'))
      this.handle = this.element.down('.'+options.handle, 0);
    
    if(!this.handle) this.handle = $(options.handle);
    if(!this.handle) this.handle = this.element;
    
    if(options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML) {
      options.scroll = $(options.scroll);
      this._isScrollChild = Element.childOf(this.element, options.scroll);
    }

    Element.makePositioned(this.element); // fix IE    

    this.delta    = this.currentDelta();
    this.options  = options;
    this.dragging = false;   

    this.eventMouseDown = this.initDrag.bindAsEventListener(this);
    Event.observe(this.handle, "mousedown", this.eventMouseDown);
    
    Draggables.register(this);
  },
  
  destroy: function() {
    Event.stopObserving(this.handle, "mousedown", this.eventMouseDown);
    Draggables.unregister(this);
  },
  
  currentDelta: function() {
    return([
      parseInt(Element.getStyle(this.element,'left') || '0'),
      parseInt(Element.getStyle(this.element,'top') || '0')]);
  },
  
  initDrag: function(event) {
    if(typeof Draggable._dragging[this.element] != 'undefined' &&
      Draggable._dragging[this.element]) return;
    if(Event.isLeftClick(event)) {    
      // abort on form elements, fixes a Firefox issue
      var src = Event.element(event);
      if(src.tagName && (
        src.tagName=='INPUT' ||
        src.tagName=='SELECT' ||
        src.tagName=='OPTION' ||
        src.tagName=='BUTTON' ||
        src.tagName=='TEXTAREA')) return;
        
      var pointer = [Event.pointerX(event), Event.pointerY(event)];
      var pos     = Position.cumulativeOffset(this.element);
      this.offset = [0,1].map( function(i) { return (pointer[i] - pos[i]) });
      
      Draggables.activate(this);
      Event.stop(event);
    }
  },
  
  startDrag: function(event) {
    this.dragging = true;
    
    if(this.options.zindex) {
      this.originalZ = parseInt(Element.getStyle(this.element,'z-index') || 0);
      this.element.style.zIndex = this.options.zindex;
    }
    
    if(this.options.ghosting) {
      this._clone = this.element.cloneNode(true);
      Position.absolutize(this.element);
      this.element.parentNode.insertBefore(this._clone, this.element);
    }
    
    if(this.options.scroll) {
      if (this.options.scroll == window) {
        var where = this._getWindowScroll(this.options.scroll);
        this.originalScrollLeft = where.left;
        this.originalScrollTop = where.top;
      } else {
        this.originalScrollLeft = this.options.scroll.scrollLeft;
        this.originalScrollTop = this.options.scroll.scrollTop;
      }
    }
    
    Draggables.notify('onStart', this, event);
        
    if(this.options.starteffect) this.options.starteffect(this.element);
  },
  
  updateDrag: function(event, pointer) {
    if(!this.dragging) this.startDrag(event);
    Position.prepare();
    Droppables.show(pointer, this.element);
    Draggables.notify('onDrag', this, event);
    
    this.draw(pointer);
    if(this.options.change) this.options.change(this);
    
    if(this.options.scroll) {
      this.stopScrolling();
      
      var p;
      if (this.options.scroll == window) {
        with(this._getWindowScroll(this.options.scroll)) { p = [ left, top, left+width, top+height ]; }
      } else {
        p = Position.page(this.options.scroll);
        p[0] += this.options.scroll.scrollLeft + Position.deltaX;
        p[1] += this.options.scroll.scrollTop + Position.deltaY;
        p.push(p[0]+this.options.scroll.offsetWidth);
        p.push(p[1]+this.options.scroll.offsetHeight);
      }
      var speed = [0,0];
      if(pointer[0] < (p[0]+this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[0]+this.options.scrollSensitivity);
      if(pointer[1] < (p[1]+this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[1]+this.options.scrollSensitivity);
      if(pointer[0] > (p[2]-this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[2]-this.options.scrollSensitivity);
      if(pointer[1] > (p[3]-this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[3]-this.options.scrollSensitivity);
      this.startScrolling(speed);
    }
    
    // fix AppleWebKit rendering
    if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);
    
    Event.stop(event);
  },
  
  finishDrag: function(event, success) {
    this.dragging = false;

    if(this.options.ghosting) {
      Position.relativize(this.element);
      Element.remove(this._clone);
      this._clone = null;
    }

    if(success) Droppables.fire(event, this.element);
    Draggables.notify('onEnd', this, event);

    var revert = this.options.revert;
    if(revert && typeof revert == 'function') revert = revert(this.element);
    
    var d = this.currentDelta();
    if(revert && this.options.reverteffect) {
      this.options.reverteffect(this.element, 
        d[1]-this.delta[1], d[0]-this.delta[0]);
    } else {
      this.delta = d;
    }

    if(this.options.zindex)
      this.element.style.zIndex = this.originalZ;

    if(this.options.endeffect) 
      this.options.endeffect(this.element);
      
    Draggables.deactivate(this);
    Droppables.reset();
  },
  
  keyPress: function(event) {
    if(event.keyCode!=Event.KEY_ESC) return;
    this.finishDrag(event, false);
    Event.stop(event);
  },
  
  endDrag: function(event) {
    if(!this.dragging) return;
    this.stopScrolling();
    this.finishDrag(event, true);
    Event.stop(event);
  },
  
  draw: function(point) {
    var pos = Position.cumulativeOffset(this.element);
    if(this.options.ghosting) {
      var r   = Position.realOffset(this.element);
      pos[0] += r[0] - Position.deltaX; pos[1] += r[1] - Position.deltaY;
    }
    
    var d = this.currentDelta();
    pos[0] -= d[0]; pos[1] -= d[1];
    
    if(this.options.scroll && (this.options.scroll != window && this._isScrollChild)) {
      pos[0] -= this.options.scroll.scrollLeft-this.originalScrollLeft;
      pos[1] -= this.options.scroll.scrollTop-this.originalScrollTop;
    }
    
    var p = [0,1].map(function(i){ 
      return (point[i]-pos[i]-this.offset[i]) 
    }.bind(this));
    
    if(this.options.snap) {
      if(typeof this.options.snap == 'function') {
        p = this.options.snap(p[0],p[1],this);
      } else {
      if(this.options.snap instanceof Array) {
        p = p.map( function(v, i) {
          return Math.round(v/this.options.snap[i])*this.options.snap[i] }.bind(this))
      } else {
        p = p.map( function(v) {
          return Math.round(v/this.options.snap)*this.options.snap }.bind(this))
      }
    }}
    
    var style = this.element.style;
    if((!this.options.constraint) || (this.options.constraint=='horizontal'))
      style.left = p[0] + "px";
    if((!this.options.constraint) || (this.options.constraint=='vertical'))
      style.top  = p[1] + "px";
    
    if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering
  },
  
  stopScrolling: function() {
    if(this.scrollInterval) {
      clearInterval(this.scrollInterval);
      this.scrollInterval = null;
      Draggables._lastScrollPointer = null;
    }
  },
  
  startScrolling: function(speed) {
    if(!(speed[0] || speed[1])) return;
    this.scrollSpeed = [speed[0]*this.options.scrollSpeed,speed[1]*this.options.scrollSpeed];
    this.lastScrolled = new Date();
    this.scrollInterval = setInterval(this.scroll.bind(this), 10);
  },
  
  scroll: function() {
    var current = new Date();
    var delta = current - this.lastScrolled;
    this.lastScrolled = current;
    if(this.options.scroll == window) {
      with (this._getWindowScroll(this.options.scroll)) {
        if (this.scrollSpeed[0] || this.scrollSpeed[1]) {
          var d = delta / 1000;
          this.options.scroll.scrollTo( left + d*this.scrollSpeed[0], top + d*this.scrollSpeed[1] );
        }
      }
    } else {
      this.options.scroll.scrollLeft += this.scrollSpeed[0] * delta / 1000;
      this.options.scroll.scrollTop  += this.scrollSpeed[1] * delta / 1000;
    }
    
    Position.prepare();
    Droppables.show(Draggables._lastPointer, this.element);
    Draggables.notify('onDrag', this);
    if (this._isScrollChild) {
      Draggables._lastScrollPointer = Draggables._lastScrollPointer || $A(Draggables._lastPointer);
      Draggables._lastScrollPointer[0] += this.scrollSpeed[0] * delta / 1000;
      Draggables._lastScrollPointer[1] += this.scrollSpeed[1] * delta / 1000;
      if (Draggables._lastScrollPointer[0] < 0)
        Draggables._lastScrollPointer[0] = 0;
      if (Draggables._lastScrollPointer[1] < 0)
        Draggables._lastScrollPointer[1] = 0;
      this.draw(Draggables._lastScrollPointer);
    }
    
    if(this.options.change) this.options.change(this);
  },
  
  _getWindowScroll: function(w) {
    var T, L, W, H;
    with (w.document) {
      if (w.document.documentElement && documentElement.scrollTop) {
        T = documentElement.scrollTop;
        L = documentElement.scrollLeft;
      } else if (w.document.body) {
        T = body.scrollTop;
        L = body.scrollLeft;
      }
      if (w.innerWidth) {
        W = w.innerWidth;
        H = w.innerHeight;
      } else if (w.document.documentElement && documentElement.clientWidth) {
        W = documentElement.clientWidth;
        H = documentElement.clientHeight;
      } else {
        W = body.offsetWidth;
        H = body.offsetHeight
      }
    }
    return { top: T, left: L, width: W, height: H };
  }
}

/*--------------------------------------------------------------------------*/

var SortableObserver = Class.create();
SortableObserver.prototype = {
  initialize: function(element, observer) {
    this.element   = $(element);
    this.observer  = observer;
    this.lastValue = Sortable.serialize(this.element);
  },
  
  onStart: function() {
    this.lastValue = Sortable.serialize(this.element);
  },
  
  onEnd: function() {
    Sortable.unmark();
    if(this.lastValue != Sortable.serialize(this.element))
      this.observer(this.element)
  }
}

var Sortable = {
  SERIALIZE_RULE: /^[^_\-](?:[A-Za-z0-9\-\_]*)[_](.*)$/,
  
  sortables: {},
  
  _findRootElement: function(element) {
    while (element.tagName != "BODY") {  
      if(element.id && Sortable.sortables[element.id]) return element;
      element = element.parentNode;
    }
  },

  options: function(element) {
    element = Sortable._findRootElement($(element));
    if(!element) return;
    return Sortable.sortables[element.id];
  },
  
  destroy: function(element){
    var s = Sortable.options(element);
    
    if(s) {
      Draggables.removeObserver(s.element);
      s.droppables.each(function(d){ Droppables.remove(d) });
      s.draggables.invoke('destroy');
      
      delete Sortable.sortables[s.element.id];
    }
  },

  create: function(element) {
    element = $(element);
    var options = Object.extend({ 
      element:     element,
      tag:         'li',       // assumes li children, override with tag: 'tagname'
      dropOnEmpty: false,
      tree:        false,
      treeTag:     'ul',
      overlap:     'vertical', // one of 'vertical', 'horizontal'
      constraint:  'vertical', // one of 'vertical', 'horizontal', false
      containment: element,    // also takes array of elements (or id's); or false
      handle:      false,      // or a CSS class
      only:        false,
      delay:       0,
      hoverclass:  null,
      ghosting:    false,
      scroll:      false,
      scrollSensitivity: 20,
      scrollSpeed: 15,
      format:      this.SERIALIZE_RULE,
      onChange:    Prototype.emptyFunction,
      onUpdate:    Prototype.emptyFunction
    }, arguments[1] || {});

    // clear any old sortable with same element
    this.destroy(element);

    // build options for the draggables
    var options_for_draggable = {
      revert:      true,
      scroll:      options.scroll,
      scrollSpeed: options.scrollSpeed,
      scrollSensitivity: options.scrollSensitivity,
      delay:       options.delay,
      ghosting:    options.ghosting,
      constraint:  options.constraint,
      handle:      options.handle };

    if(options.starteffect)
      options_for_draggable.starteffect = options.starteffect;

    if(options.reverteffect)
      options_for_draggable.reverteffect = options.reverteffect;
    else
      if(options.ghosting) options_for_draggable.reverteffect = function(element) {
        element.style.top  = 0;
        element.style.left = 0;
      };

    if(options.endeffect)
      options_for_draggable.endeffect = options.endeffect;

    if(options.zindex)
      options_for_draggable.zindex = options.zindex;

    // build options for the droppables  
    var options_for_droppable = {
      overlap:     options.overlap,
      containment: options.containment,
      tree:        options.tree,
      hoverclass:  options.hoverclass,
      onHover:     Sortable.onHover
    }
    
    var options_for_tree = {
      onHover:      Sortable.onEmptyHover,
      overlap:      options.overlap,
      containment:  options.containment,
      hoverclass:   options.hoverclass
    }

    // fix for gecko engine
    Element.cleanWhitespace(element); 

    options.draggables = [];
    options.droppables = [];

    // drop on empty handling
    if(options.dropOnEmpty || options.tree) {
      Droppables.add(element, options_for_tree);
      options.droppables.push(element);
    }

    (this.findElements(element, options) || []).each( function(e) {
      // handles are per-draggable
      var handle = options.handle ? 
        $(e).down('.'+options.handle,0) : e;    
      options.draggables.push(
        new Draggable(e, Object.extend(options_for_draggable, { handle: handle })));
      Droppables.add(e, options_for_droppable);
      if(options.tree) e.treeNode = element;
      options.droppables.push(e);      
    });
    
    if(options.tree) {
      (Sortable.findTreeElements(element, options) || []).each( function(e) {
        Droppables.add(e, options_for_tree);
        e.treeNode = element;
        options.droppables.push(e);
      });
    }

    // keep reference
    this.sortables[element.id] = options;

    // for onupdate
    Draggables.addObserver(new SortableObserver(element, options.onUpdate));

  },

  // return all suitable-for-sortable elements in a guaranteed order
  findElements: function(element, options) {
    return Element.findChildren(
      element, options.only, options.tree ? true : false, options.tag);
  },
  
  findTreeElements: function(element, options) {
    return Element.findChildren(
      element, options.only, options.tree ? true : false, options.treeTag);
  },

  onHover: function(element, dropon, overlap) {
    if(Element.isParent(dropon, element)) return;

    if(overlap > .33 && overlap < .66 && Sortable.options(dropon).tree) {
      return;
    } else if(overlap>0.5) {
      Sortable.mark(dropon, 'before');
      if(dropon.previousSibling != element) {
        var oldParentNode = element.parentNode;
        element.style.visibility = "hidden"; // fix gecko rendering
        dropon.parentNode.insertBefore(element, dropon);
        if(dropon.parentNode!=oldParentNode) 
          Sortable.options(oldParentNode).onChange(element);
        Sortable.options(dropon.parentNode).onChange(element);
      }
    } else {
      Sortable.mark(dropon, 'after');
      var nextElement = dropon.nextSibling || null;
      if(nextElement != element) {
        var oldParentNode = element.parentNode;
        element.style.visibility = "hidden"; // fix gecko rendering
        dropon.parentNode.insertBefore(element, nextElement);
        if(dropon.parentNode!=oldParentNode) 
          Sortable.options(oldParentNode).onChange(element);
        Sortable.options(dropon.parentNode).onChange(element);
      }
    }
  },
  
  onEmptyHover: function(element, dropon, overlap) {
    var oldParentNode = element.parentNode;
    var droponOptions = Sortable.options(dropon);
        
    if(!Element.isParent(dropon, element)) {
      var index;
      
      var children = Sortable.findElements(dropon, {tag: droponOptions.tag, only: droponOptions.only});
      var child = null;
            
      if(children) {
        var offset = Element.offsetSize(dropon, droponOptions.overlap) * (1.0 - overlap);
        
        for (index = 0; index < children.length; index += 1) {
          if (offset - Element.offsetSize (children[index], droponOptions.overlap) >= 0) {
            offset -= Element.offsetSize (children[index], droponOptions.overlap);
          } else if (offset - (Element.offsetSize (children[index], droponOptions.overlap) / 2) >= 0) {
            child = index + 1 < children.length ? children[index + 1] : null;
            break;
          } else {
            child = children[index];
            break;
          }
        }
      }
      
      dropon.insertBefore(element, child);
      
      Sortable.options(oldParentNode).onChange(element);
      droponOptions.onChange(element);
    }
  },

  unmark: function() {
    if(Sortable._marker) Sortable._marker.hide();
  },

  mark: function(dropon, position) {
    // mark on ghosting only
    var sortable = Sortable.options(dropon.parentNode);
    if(sortable && !sortable.ghosting) return; 

    if(!Sortable._marker) {
      Sortable._marker = 
        ($('dropmarker') || Element.extend(document.createElement('DIV'))).
          hide().addClassName('dropmarker').setStyle({position:'absolute'});
      document.getElementsByTagName("body").item(0).appendChild(Sortable._marker);
    }    
    var offsets = Position.cumulativeOffset(dropon);
    Sortable._marker.setStyle({left: offsets[0]+'px', top: offsets[1] + 'px'});
    
    if(position=='after')
      if(sortable.overlap == 'horizontal') 
        Sortable._marker.setStyle({left: (offsets[0]+dropon.clientWidth) + 'px'});
      else
        Sortable._marker.setStyle({top: (offsets[1]+dropon.clientHeight) + 'px'});
    
    Sortable._marker.show();
  },
  
  _tree: function(element, options, parent) {
    var children = Sortable.findElements(element, options) || [];
  
    for (var i = 0; i < children.length; ++i) {
      var match = children[i].id.match(options.format);

      if (!match) continue;
      
      var child = {
        id: encodeURIComponent(match ? match[1] : null),
        element: element,
        parent: parent,
        children: [],
        position: parent.children.length,
        container: $(children[i]).down(options.treeTag)
      }
      
      /* Get the element containing the children and recurse over it */
      if (child.container)
        this._tree(child.container, options, child)
      
      parent.children.push (child);
    }

    return parent; 
  },

  tree: function(element) {
    element = $(element);
    var sortableOptions = this.options(element);
    var options = Object.extend({
      tag: sortableOptions.tag,
      treeTag: sortableOptions.treeTag,
      only: sortableOptions.only,
      name: element.id,
      format: sortableOptions.format
    }, arguments[1] || {});
    
    var root = {
      id: null,
      parent: null,
      children: [],
      container: element,
      position: 0
    }
    
    return Sortable._tree(element, options, root);
  },

  /* Construct a [i] index for a particular node */
  _constructIndex: function(node) {
    var index = '';
    do {
      if (node.id) index = '[' + node.position + ']' + index;
    } while ((node = node.parent) != null);
    return index;
  },

  sequence: function(element) {
    element = $(element);
    var options = Object.extend(this.options(element), arguments[1] || {});
    
    return $(this.findElements(element, options) || []).map( function(item) {
      return item.id.match(options.format) ? item.id.match(options.format)[1] : '';
    });
  },

  setSequence: function(element, new_sequence) {
    element = $(element);
    var options = Object.extend(this.options(element), arguments[2] || {});
    
    var nodeMap = {};
    this.findElements(element, options).each( function(n) {
        if (n.id.match(options.format))
            nodeMap[n.id.match(options.format)[1]] = [n, n.parentNode];
        n.parentNode.removeChild(n);
    });
   
    new_sequence.each(function(ident) {
      var n = nodeMap[ident];
      if (n) {
        n[1].appendChild(n[0]);
        delete nodeMap[ident];
      }
    });
  },
  
  serialize: function(element) {
    element = $(element);
    var options = Object.extend(Sortable.options(element), arguments[1] || {});
    var name = encodeURIComponent(
      (arguments[1] && arguments[1].name) ? arguments[1].name : element.id);
    
    if (options.tree) {
      return Sortable.tree(element, arguments[1]).children.map( function (item) {
        return [name + Sortable._constructIndex(item) + "[id]=" + 
                encodeURIComponent(item.id)].concat(item.children.map(arguments.callee));
      }).flatten().join('&');
    } else {
      return Sortable.sequence(element, arguments[1]).map( function(item) {
        return name + "[]=" + encodeURIComponent(item);
      }).join('&');
    }
  }
}

// Returns true if child is contained within element
Element.isParent = function(child, element) {
  if (!child.parentNode || child == element) return false;
  if (child.parentNode == element) return true;
  return Element.isParent(child.parentNode, element);
}

Element.findChildren = function(element, only, recursive, tagName) {    
  if(!element.hasChildNodes()) return null;
  tagName = tagName.toUpperCase();
  if(only) only = [only].flatten();
  var elements = [];
  $A(element.childNodes).each( function(e) {
    if(e.tagName && e.tagName.toUpperCase()==tagName &&
      (!only || (Element.classNames(e).detect(function(v) { return only.include(v) }))))
        elements.push(e);
    if(recursive) {
      var grandchildren = Element.findChildren(e, only, recursive, tagName);
      if(grandchildren) elements.push(grandchildren);
    }
  });

  return (elements.length>0 ? elements.flatten() : []);
}

Element.offsetSize = function (element, type) {
  return element['offset' + ((type=='vertical' || type=='height') ? 'Height' : 'Width')];
}


// script.aculo.us slider.js v1.6.5, Wed Nov 08 14:17:49 CET 2006

// Copyright (c) 2005, 2006 Marty Haught, Thomas Fuchs 
//
// 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/

if(!Control) var Control = {};
Control.Slider = Class.create();

// options:
//  axis: 'vertical', or 'horizontal' (default)
//
// callbacks:
//  onChange(value)
//  onSlide(value)
Control.Slider.prototype = {
  initialize: function(handle, track, options) {
    var slider = this;
    
    if(handle instanceof Array) {
      this.handles = handle.collect( function(e) { return $(e) });
    } else {
      this.handles = [$(handle)];
    }
    
    this.track   = $(track);
    this.options = options || {};

    this.axis      = this.options.axis || 'horizontal';
    this.increment = this.options.increment || 1;
    this.step      = parseInt(this.options.step || '1');
    this.range     = this.options.range || $R(0,1);
    
    this.value     = 0; // assure backwards compat
    this.values    = this.handles.map( function() { return 0 });
    this.spans     = this.options.spans ? this.options.spans.map(function(s){ return $(s) }) : false;
    this.options.startSpan = $(this.options.startSpan || null);
    this.options.endSpan   = $(this.options.endSpan || null);

    this.restricted = this.options.restricted || false;

    this.maximum   = this.options.maximum || this.range.end;
    this.minimum   = this.options.minimum || this.range.start;

    // Will be used to align the handle onto the track, if necessary
    this.alignX = parseInt(this.options.alignX || '0');
    this.alignY = parseInt(this.options.alignY || '0');
    
    this.trackLength = this.maximumOffset() - this.minimumOffset();

    this.handleLength = this.isVertical() ? 
      (this.handles[0].offsetHeight != 0 ? 
        this.handles[0].offsetHeight : this.handles[0].style.height.replace(/px$/,"")) : 
      (this.handles[0].offsetWidth != 0 ? this.handles[0].offsetWidth : 
        this.handles[0].style.width.replace(/px$/,""));

    this.active   = false;
    this.dragging = false;
    this.disabled = false;

    if(this.options.disabled) this.setDisabled();

    // Allowed values array
    this.allowedValues = this.options.values ? this.options.values.sortBy(Prototype.K) : false;
    if(this.allowedValues) {
      this.minimum = this.allowedValues.min();
      this.maximum = this.allowedValues.max();
    }

    this.eventMouseDown = this.startDrag.bindAsEventListener(this);
    this.eventMouseUp   = this.endDrag.bindAsEventListener(this);
    this.eventMouseMove = this.update.bindAsEventListener(this);

    // Initialize handles in reverse (make sure first handle is active)
    this.handles.each( function(h,i) {
      i = slider.handles.length-1-i;
      slider.setValue(parseFloat(
        (slider.options.sliderValue instanceof Array ? 
          slider.options.sliderValue[i] : slider.options.sliderValue) || 
         slider.range.start), i);
      Element.makePositioned(h); // fix IE
      Event.observe(h, "mousedown", slider.eventMouseDown);
    });
    
    Event.observe(this.track, "mousedown", this.eventMouseDown);
    Event.observe(document, "mouseup", this.eventMouseUp);
    Event.observe(document, "mousemove", this.eventMouseMove);
    
    this.initialized = true;
  },
  dispose: function() {
    var slider = this;    
    Event.stopObserving(this.track, "mousedown", this.eventMouseDown);
    Event.stopObserving(document, "mouseup", this.eventMouseUp);
    Event.stopObserving(document, "mousemove", this.eventMouseMove);
    this.handles.each( function(h) {
      Event.stopObserving(h, "mousedown", slider.eventMouseDown);
    });
  },
  setDisabled: function(){
    this.disabled = true;
  },
  setEnabled: function(){
    this.disabled = false;
  },  
  getNearestValue: function(value){
    if(this.allowedValues){
      if(value >= this.allowedValues.max()) return(this.allowedValues.max());
      if(value <= this.allowedValues.min()) return(this.allowedValues.min());
      
      var offset = Math.abs(this.allowedValues[0] - value);
      var newValue = this.allowedValues[0];
      this.allowedValues.each( function(v) {
        var currentOffset = Math.abs(v - value);
        if(currentOffset <= offset){
          newValue = v;
          offset = currentOffset;
        } 
      });
      return newValue;
    }
    if(value > this.range.end) return this.range.end;
    if(value < this.range.start) return this.range.start;
    return value;
  },
  setValue: function(sliderValue, handleIdx){
    if(!this.active) {
      this.activeHandleIdx = handleIdx || 0;
      this.activeHandle    = this.handles[this.activeHandleIdx];
      this.updateStyles();
    }
    handleIdx = handleIdx || this.activeHandleIdx || 0;
    if(this.initialized && this.restricted) {
      if((handleIdx>0) && (sliderValue<this.values[handleIdx-1]))
        sliderValue = this.values[handleIdx-1];
      if((handleIdx < (this.handles.length-1)) && (sliderValue>this.values[handleIdx+1]))
        sliderValue = this.values[handleIdx+1];
    }
    sliderValue = this.getNearestValue(sliderValue);
    this.values[handleIdx] = sliderValue;
    this.value = this.values[0]; // assure backwards compat
    
    this.handles[handleIdx].style[this.isVertical() ? 'top' : 'left'] = 
      this.translateToPx(sliderValue);
    
    this.drawSpans();
    if(!this.dragging || !this.event) this.updateFinished();
  },
  setValueBy: function(delta, handleIdx) {
    this.setValue(this.values[handleIdx || this.activeHandleIdx || 0] + delta, 
      handleIdx || this.activeHandleIdx || 0);
  },
  translateToPx: function(value) {
    return Math.round(
      ((this.trackLength-this.handleLength)/(this.range.end-this.range.start)) * 
      (value - this.range.start)) + "px";
  },
  translateToValue: function(offset) {
    return ((offset/(this.trackLength-this.handleLength) * 
      (this.range.end-this.range.start)) + this.range.start);
  },
  getRange: function(range) {
    var v = this.values.sortBy(Prototype.K); 
    range = range || 0;
    return $R(v[range],v[range+1]);
  },
  minimumOffset: function(){
    return(this.isVertical() ? this.alignY : this.alignX);
  },
  maximumOffset: function(){
    return(this.isVertical() ? 
      (this.track.offsetHeight != 0 ? this.track.offsetHeight :
        this.track.style.height.replace(/px$/,"")) - this.alignY : 
      (this.track.offsetWidth != 0 ? this.track.offsetWidth : 
        this.track.style.width.replace(/px$/,"")) - this.alignY);
  },  
  isVertical:  function(){
    return (this.axis == 'vertical');
  },
  drawSpans: function() {
    var slider = this;
    if(this.spans)
      $R(0, this.spans.length-1).each(function(r) { slider.setSpan(slider.spans[r], slider.getRange(r)) });
    if(this.options.startSpan)
      this.setSpan(this.options.startSpan,
        $R(0, this.values.length>1 ? this.getRange(0).min() : this.value ));
    if(this.options.endSpan)
      this.setSpan(this.options.endSpan, 
        $R(this.values.length>1 ? this.getRange(this.spans.length-1).max() : this.value, this.maximum));
  },
  setSpan: function(span, range) {
    if(this.isVertical()) {
      span.style.top = this.translateToPx(range.start);
      span.style.height = this.translateToPx(range.end - range.start + this.range.start);
    } else {
      span.style.left = this.translateToPx(range.start);
      span.style.width = this.translateToPx(range.end - range.start + this.range.start);
    }
  },
  updateStyles: function() {
    this.handles.each( function(h){ Element.removeClassName(h, 'selected') });
    Element.addClassName(this.activeHandle, 'selected');
  },
  startDrag: function(event) {
    if(Event.isLeftClick(event)) {
      if(!this.disabled){
        this.active = true;
        
        var handle = Event.element(event);
        var pointer  = [Event.pointerX(event), Event.pointerY(event)];
        var track = handle;
        if(track==this.track) {
          var offsets  = Position.cumulativeOffset(this.track); 
          this.event = event;
          this.setValue(this.translateToValue( 
           (this.isVertical() ? pointer[1]-offsets[1] : pointer[0]-offsets[0])-(this.handleLength/2)
          ));
          var offsets  = Position.cumulativeOffset(this.activeHandle);
          this.offsetX = (pointer[0] - offsets[0]);
          this.offsetY = (pointer[1] - offsets[1]);
        } else {
          // find the handle (prevents issues with Safari)
          while((this.handles.indexOf(handle) == -1) && handle.parentNode) 
            handle = handle.parentNode;
            
          if(this.handles.indexOf(handle)!=-1) {
            this.activeHandle    = handle;
            this.activeHandleIdx = this.handles.indexOf(this.activeHandle);
            this.updateStyles();
            
            var offsets  = Position.cumulativeOffset(this.activeHandle);
            this.offsetX = (pointer[0] - offsets[0]);
            this.offsetY = (pointer[1] - offsets[1]);
          }
        }
      }
      Event.stop(event);
    }
  },
  update: function(event) {
   if(this.active) {
      if(!this.dragging) this.dragging = true;
      this.draw(event);
      // fix AppleWebKit rendering
      if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);
      Event.stop(event);
   }
  },
  draw: function(event) {
    var pointer = [Event.pointerX(event), Event.pointerY(event)];
    var offsets = Position.cumulativeOffset(this.track);
    pointer[0] -= this.offsetX + offsets[0];
    pointer[1] -= this.offsetY + offsets[1];
    this.event = event;
    this.setValue(this.translateToValue( this.isVertical() ? pointer[1] : pointer[0] ));
    if(this.initialized && this.options.onSlide)
      this.options.onSlide(this.values.length>1 ? this.values : this.value, this);
  },
  endDrag: function(event) {
    if(this.active && this.dragging) {
      this.finishDrag(event, true);
      Event.stop(event);
    }
    this.active = false;
    this.dragging = false;
  },  
  finishDrag: function(event, success) {
    this.active = false;
    this.dragging = false;
    this.updateFinished();
  },
  updateFinished: function() {
    if(this.initialized && this.options.onChange) 
      this.options.onChange(this.values.length>1 ? this.values : this.value, this);
    this.event = null;
  }
}

// lightWindow.js v1.2.1
//
// Copyright (c) 2007 Einstein Industries
// Author: Kevin P Miller | http://www.stickmanlabs.com
// 
// LightWindow is freely distributable under the terms of an MIT-style license.
//
// I don"t care what you think about the file size...
//   Be a pro: 
//	    http://www.thinkvitamin.com/features/webapps/serving-javascript-fast
//      http://rakaz.nl/item/make_your_pages_load_faster_by_combining_and_compressing_javascript_and_css_files
//

/*-----------------------------------------------------------------------------------------------*/

if(typeof Effect == "undefined")
  throw("lightWindow.js requires including script.aculo.us' effects.js library!");

var lightWindow = Class.create();	
lightWindow.prototype = {
	//
	//	Setup Variables
	//
	element : null,
	contentToFetch : null,
	boxOverFlow : "hidden",
	retroIE : null,
	windowType : null,
	animating : false,
	scrollX : null,
	scrollY : null,
	imageArray : [],
	preloadImage : null,
	activeGallery : null,
	activeImage : 0,
	galleryDirection : null,
	showDataToggle : false,
	galleryToggle : false,
	showTitleToggle : false,
	//
	//	Initialize the lightWindow.
	//
	initialize : function(options) {
		this.options = Object.extend({
			resizeSpeed : 9,
			cushion : 10,
			dimensions : {
				image : {height : 250, width : 250},
				page : {height : 250, width : 500},
				inline : {height : 250, width : 500},
				media : {height : 250, width : 250},
				external : {height : 250, width : 250},
				dataHeight : 40,
				titleHeight : 25
			},
			classNames : {	
				standard : "lWOn",
				action : "lWAction"
			},
			fileTypes : {
				page : ["asp", "aspx", "cgi", "htm", "html", "pl", "php4", "php3", "php", "php5", "phtml", "rhtml", "shtml", "txt", "vbs", "rb"],
				media : ["aif", "aiff", "asf", "avi", "divx", "m1v", "m2a", "m2v", "m3u", "mid", "midi", "mov", "moov", "movie", "mp2", "mp3", "mpa", "mpa", "mpe", "mpeg", "mpg", "mpg", "mpga", "pps", "qt", "rm", "ram", "swf", "viv", "vivo", "wav"],
				image : ["bmp", "gif", "jpg", "png", "tiff"]
			},
			mimeTypes : {
				avi : "video/avi",
				aif : "audio/aiff",
				aiff : "audio/aiff",
				gif : "image/gif",
				bmp : "image/bmp",
				jpeg : "image/jpeg",
				m1v : "video/mpeg",
				m2a : "audio/mpeg",
				m2v : "video/mpeg",
				m3u : "audio/x-mpequrl",
				mid : "audio/x-midi",
				midi : "audio/x-midi",
				mjpg : "video/x-motion-jpeg",
				moov : "video/quicktime",
				mov : "video/quicktime",
				movie : "video/x-sgi-movie",
				mp2 : "audio/mpeg",
				mp3 : "audio/mpeg3",
				mpa : "audio/mpeg",
				mpa : "video/mpeg",
				mpe : "video/mpeg",
				mpeg : "video/mpeg",
				mpg : "audio/mpeg",
				mpg : "video/mpeg",
				mpga : "audio/mpeg",
				pdf : "application/pdf",
				png : "image/png",
				pps : "application/mspowerpoint",
				qt : "video/quicktime",
				ram : "audio/x-pn-realaudio-plugin",
				rm : "application/vnd.rn-realmedia",
				swf	: "application/x-shockwave-flash",
				tiff : "image/tiff",
				viv : "video/vivo",
				vivo : "video/vivo",
				wav : "audio/wav"				
			},			
			loadingDialog : {
				message : "Loading",
				image :  "/images/ajax-loading.gif",
				options : '<a onclick="javascript: mylightWindow.deactivate();">Cancel</a>',
				delay : 3.0
			},
			authorLead : "by ",
			galleryTab : {
				name : "Galleries",
				height : 20,
				visible : true
			},
			overlay : {
				color : "#000000",
				opacity : 70,
				image : "/images/black-70.png"
			},
			formMethod : "post",
			hideFlash : true,
			showTitleBar : true
		}, options || {})
		this.duration = ((11-this.options.resizeSpeed)*0.15);
		this.setupLinks();
		this.addLightWindowMarkup(false);
		this.setupDimensions(true);
	},
	// 
	//  Set Links Up
	//
	setupLinks : function () {
		var links = $$("."+this.options.classNames.standard);
		links.each(function(link) {
			if (this.fileType(link.href) == "image") {
				if (gallery = this.getGalleryInfo(link.rel)) {
					if (!this.imageArray[gallery[0]]) this.imageArray[gallery[0]] = new Array();
					if (!this.imageArray[gallery[0]][gallery[1]]) this.imageArray[gallery[0]][gallery[1]] = new Array();
					this.imageArray[gallery[0]][gallery[1]].push(new Array(link.href, link.getAttribute("title"), link.getAttribute("caption"), link.getAttribute("author"), link.getAttribute("rel"), link.getAttribute("params")));
				}
			}
			var url = link.getAttribute("href");
			if (link.href.indexOf("?") > -1) url = url.substring(0, url.indexOf("?"));
			container = url.substring(url.indexOf("#")+1);
			if($(container)) $(container).style.display = "none";
			Event.observe(link, "click", this.activate.bindAsEventListener(this, link));
			link.onclick = function() {return false;};
		}.bind(this));	
	},
	//
	//  Initialize specific window
	//
	initializeWindow : function (id) {
		var link = $(id);
		if (this.fileType(link.href) == "image") {
			if (gallery = this.getGalleryInfo(link.rel)) {
				if (!this.imageArray[gallery[0]]) this.imageArray[gallery[0]] = new Array();
				if (!this.imageArray[gallery[0]][gallery[1]]) this.imageArray[gallery[0]][gallery[1]] = new Array();
				this.imageArray[gallery[0]][gallery[1]].push(new Array(link.href, link.getAttribute("title"), link.getAttribute("caption"), link.getAttribute("author"), link.getAttribute("rel"), link.getAttribute("params")));
			}
		}
		var url = link.getAttribute("href");
		if (link.href.indexOf("?") > -1) url = url.substring(0, url.indexOf("?"));
		container = url.substring(url.indexOf("#")+1);
		if($(container)) $(container).style.display = "none";
		Event.observe(link, "click", this.activate.bindAsEventListener(this, link));
		link.onclick = function() {return false;};
	},
	//
	//	Add the markup to the page.
	//
	addLightWindowMarkup : function(rebuild) {
	    if (!rebuild) {
			var overlay = document.createElement("div");
			overlay.setAttribute("id", "overlay");
			if (this.checkBrowser("firefox")) {
				overlay.style.backgroundImage = "url("+this.options.overlay.image+")";
			   	overlay.style.backgroundRepeat = "repeat";
			} else {
				overlay.style.backgroundColor = this.options.overlay.color;
			    overlay.style.MozOpacity = "."+this.options.overlay.opacity;
			    overlay.style.opacity = "."+this.options.overlay.opacity;
			    overlay.style.filter = "alpha(opacity="+this.options.overlay.opacity+")";
			}
			var lw = document.createElement("div");
			lw.setAttribute("id", "lightWindow");
		} else {
			var lw = $("lightWindow");
		}

		if (this.options.showTitleBar) lw = this.addTitleBarMarkup(lw);
				
		var lwc = document.createElement("div");
		lwc.setAttribute("id", "lightWindow-contents");
		
		var lwcc = document.createElement("div");
		lwcc.setAttribute("id", "lightWindow-contents-container");
		lwc.appendChild(lwcc);						
						
		var lwl = document.createElement("div");
		lwl.setAttribute("id", "lightWindow-loading");

		var lwi = document.createElement("img");
		lwi.setAttribute("src", this.options.loadingDialog.image);
		lwl.appendChild(lwi);

		var lwld = document.createElement("span");
		lwld.setAttribute("id", "lightWindow-loading-message");
		lwld.innerHTML += this.options.loadingDialog.message;
		lwl.appendChild(lwld);
		
		var lwlo = document.createElement("span");
		lwlo.setAttribute("id", "lightWindow-loading-options");
		lwlo.setAttribute("style", "display:none;");
		lwlo.innerHTML += this.options.loadingDialog.options;
		lwl.appendChild(lwlo);
		
		lwc.appendChild(lwl);
		
		lw.appendChild(lwc);
		
		if (!rebuild) {
			var body = document.getElementsByTagName("body")[0];
			body.appendChild(overlay);
			body.appendChild(lw);	
			Event.observe(overlay, "click", this.deactivate.bindAsEventListener(this), false);
			overlay.onclick = function() {return false;};
		}
		this.addDataWindowMarkup();
		this.actions("#lightWindow-loading-options");
	},
	//
	//	Add the Title Bar Markup
	//
	addTitleBarMarkup : function(lw) {
	
		var lwdt = document.createElement("div");
		lwdt.setAttribute("id", "lightWindow-title-bar");
		lwdt.style.visibility = "hidden";

		var lwdtt = document.createElement("div");
		lwdtt.setAttribute("id", "lightWindow-title-bar-title");
		lwdt.appendChild(lwdtt);
				
		var lwdtc = document.createElement("div");
		lwdtc.setAttribute("id", "lightWindow-title-bar-close");


		var lwdtca = document.createElement("a");
		lwdtca.setAttribute("id", "lightWindow-title-bar-close-link");
		lwdtca.innerHTML = "close";
		Event.observe(lwdtca, "click", this.deactivate.bindAsEventListener(this));
		lwdtca.onclick = function() {return false;};
		lwdtc.appendChild(lwdtca);
		lwdt.appendChild(lwdtc);
		
		lw.appendChild(lwdt);
		return lw;
		
	},
	//
	//	Add the Data Window Markup
	//
	addDataWindowMarkup : function() {
		var lw = $("lightWindow");
		
		var lwd = document.createElement("div");
		lwd.setAttribute("id", "lightWindow-data");	
		lwd.style.display = "none";

		// This container needs to be here to get the data slide to slide as a group
		var lwds = document.createElement("div");
		lwds.setAttribute("id", "lightWindow-data-slide");
		
		if (!this.options.showTitleBar) {
			var lwdt = document.createElement("div");
			lwdt.setAttribute("id", "lightWindow-data-title");	
			lwds.appendChild(lwdt);
		}
		
		var lwdc = document.createElement("div");
		lwdc.setAttribute("id", "lightWindow-data-caption");	
		lwds.appendChild(lwdc);
				
		var lwda = document.createElement("div");
		lwda.setAttribute("id", "lightWindow-data-author");	
		lwds.appendChild(lwda);
				
		var lwdi = document.createElement("div");
		lwdi.setAttribute("id", "lightWindow-data-image");	
		lwds.appendChild(lwdi);

		lwd.appendChild(lwds);
		lw.appendChild(lwd);
	},
	//
	//	Add Photo Window Markup
	//
	addPhotoWindowMarkup : function() {
		var lwc = $("lightWindow-contents");
		
		var lwpc = document.createElement("div");
		lwpc.setAttribute("id", "lightWindow-photo-container");
		lwpc.style.display = "none";
		
		if (images = parseInt(this.getParameter("lWShowImages"))) {
			for (var x = 0; x < images; x++) {
				lwp = document.createElement("img");
	    		lwp.setAttribute("id", "lightWindow-photo-"+x);
	    		lwpc.appendChild(lwp);
			}
		} else {
			lwp = document.createElement("img");
    		lwp.setAttribute("id", "lightWindow-photo-0");
    		lwpc.appendChild(lwp);
		}
		
		// You ask why I do this?  I ask why you insist on using a browser worse than IE? ...Safari!
		lwps = document.createElement("img");
		lwps.setAttribute("id", "lightWindow-photo-sizer");
		lwps.style.display = "none";
		lwps.style.height = "1px";	
		lwpc.appendChild(lwps);

    	lwc.appendChild(lwpc);
	},
	//
	//	Add Gallery Window Markup
	//
	addGalleryWindowMarkup : function() {
		var lwpc = $("lightWindow-photo-container");

		var lwpg = document.createElement("div");
		lwpg.setAttribute("id", "lightWindow-photo-galleries");
		lwpg.style.display = "none";
		if (!this.options.galleryTab.visible) lwpg.style.visibility = "hidden";
		
		var lwptc = document.createElement("div");
		lwptc.setAttribute("id", "lightWindow-photo-tab-container");
		
		var lwpgt = document.createElement("a");
		lwpgt.setAttribute("id", "lightWindow-photo-galleries-tab");
		lwpgt.className = "up";
		lwpgt.innerHTML = this.options.galleryTab.name;
		Event.observe(lwpgt, "click", this.getGallery.bindAsEventListener(this));
		lwpgt.onclick = function() {return false;};
		
		lwptc.appendChild(lwpgt);
		lwpg.appendChild(lwptc);
						
		var lwpgl = document.createElement("div");
		lwpgl.setAttribute("id", "lightWindow-photo-galleries-list");	
		lwpg.appendChild(lwpgl);

    	lwpc.appendChild(lwpg);
	},
	//
	//	Activate the lightWindow.
	//
	activate : function(e, link){
		link.blur();
		this.element = link;
		this.element.title = link.getAttribute("title");
		this.element.author = link.getAttribute("author");
		this.element.caption = link.getAttribute("caption");
		this.element.rel = link.getAttribute("rel");
		this.element.params = this.element.getAttribute("params");
		this.windowType = this.fileType(this.contentToFetch = link.href);
		if (this.element.caption || this.element.author) this.showDataToggle = true;
		if (this.options.showTitleBar && this.element.title) this.showTitleToggle = true;
		else if (!this.options.showTitleBar && this.element.title) this.showDataToggle = true;
		if (this.getGalleryInfo(this.element.rel)) this.galleryToggle = true;
		this.prepareIE(true);
		this.toggleTroubleElements("hidden", false);
		this.displayLightWindow(true);
		this.setupDimensions(true);
		this.monitorKeyboard(true);	
		this.loadInfo();	
	},
	//
	//	Turn off the window
	//
	deactivate : function(){
		var queue = Effect.Queues.get("lightWindowAnimation").each(function(e) {e.cancel();});
		queue = Effect.Queues.get("lightWindowAnimation-loading").each(function(e) {e.cancel();});
		if ($("lightWindow-iframe")) Element.remove($("lightWindow-iframe"));
		Element.remove($("lightWindow-contents"));
		if ($("lightWindow-data")) Element.remove($("lightWindow-data"));
		if ($("lightWindow-title-bar")) Element.remove($("lightWindow-title-bar"));
		this.displayLightWindow(false);	
		this.boxOverFlow = "hidden";
		this.prepareIE(false);
		this.setStatus(false);
		this.showDataToggle = this.galleryToggle = this.showTitleToggle = false;
		this.addLightWindowMarkup(true);
		this.setupDimensions(true);
		this.monitorKeyboard(false);
		this.toggleTroubleElements("visible", false);		
	},
	//
	//	Setup our actions
	//
	actions : function(prefix) {
		if (prefix) links = $$(prefix+" ."+this.options.classNames.action);
		else links = $$("."+this.options.classNames.action);
		links.each(function(link) {
			Event.observe(link, "click", this[link.rel].bindAsEventListener(this, link), false);
			link.onclick = function() {return false;};
		}.bind(this));
	},
	//
	//	Set the staus of our animation to keep things from getting clunky
	//
	setStatus : function(status) {
		this.animating = status;
		// We have to put this here to avoid a flicker in FF Mac
		if (this.showTitleToggle && !status && $("lightWindow-title-bar")) {
			$("lightWindow-title-bar").setStyle({ 
				visibility : "visible"
			});
		}
	},
	//
	//	Setup Dimensions of lightWindow.
	//
	setupDataDimensions : function() {
		if ($("lightWindow-contents") && $("lightWindow-data") && this.showDataToggle) {
			$("lightWindow-data").setStyle({
				height : this.options.dimensions.dataHeight+"px",
		  		width : (parseFloat($("lightWindow-contents").style.width)+this.options.cushion*2)+"px"
			});
			$("lightWindow-data-slide").setStyle({
				height : this.options.dimensions.dataHeight+"px",
		  		overflow : "hidden" // Because of IE
			});
		}	
		if (this.showTitleToggle && $("lightWindow-title-bar")) {
			$("lightWindow-title-bar").setStyle({
				height : this.options.dimensions.titleHeight+"px",
	  			width : (parseFloat($("lightWindow-contents").style.width)+this.options.cushion*2)+"px"
			});
		}
	},
	//
	//	Setup Dimensions of lightWindow.
	//
	setupDimensions : function(reset) {
		if (this.showDataToggle || (this.galleryToggle && this.options.galleryTab.visible)) var adjust = this.options.dimensions.dataHeight;
		else var adjust = 0;

		var originalHeight, originalWidth, titleHeight;
		switch (this.windowType) {
			case "page" :
				originalHeight = this.options.dimensions.page.height;
				originalWidth = this.options.dimensions.page.width;
				break;

			case "image" :
				originalHeight = this.options.dimensions.image.height;
				originalWidth = this.options.dimensions.image.width;
				break;
				
			case "media" :
				originalHeight = this.options.dimensions.media.height;
				originalWidth = this.options.dimensions.media.width;
				break;
			
			case "external" : 
				originalHeight = this.options.dimensions.external.height;
				originalWidth = this.options.dimensions.external.width;
				break;
				
			case "inline" :
				originalHeight = this.options.dimensions.inline.height;
				originalWidth = this.options.dimensions.inline.width;
				break;
				
			default :
				originalHeight = this.options.dimensions.page.height;
				originalWidth = this.options.dimensions.page.width;
				break;
				
		}
		if (this.showTitleToggle) titleHeight = this.options.dimensions.titleHeight; // We subtract one to smooth out the hiccup when the title bar is added
		else titleHeight = 0;
		
		if (reset) {
			if (parseFloat($("lightWindow-contents").style.height) != originalHeight) {
				$("lightWindow-contents").setStyle({
					top : titleHeight+"px",
				  	width : (originalWidth+this.options.cushion)+"px",
				  	height : (originalHeight+this.options.cushion)+"px"
				});
			} else {
				$("lightWindow-contents").setStyle({
					top : "0px",
				  	width : (originalWidth+this.options.cushion)+"px",
				  	height : (originalHeight+this.options.cushion)+"px"
				});
			}
			$("lightWindow").setStyle({
				padding : "0 0 0 0",
			  	width : "0px",
			  	height : "0px",		
				margin : (-(((originalHeight+this.options.cushion*3)/2)+(adjust/2)+(titleHeight/2)))+"px 0 0 "+(-((originalWidth+this.options.cushion*3)/2))+"px"
			});
		} else {
			$("lightWindow").setStyle({
				padding : parseFloat($("lightWindow-contents").style.height)+2*this.options.cushion+titleHeight+"px 0 0 0",
	  			width : "0px",
	  			height : "0px",
				margin : (-(((parseFloat($("lightWindow-contents").style.height)+this.options.cushion*2)/2)+(adjust/2)+(titleHeight/2)))+"px 0 0 "+(-((parseFloat($("lightWindow-contents").style.width)+this.options.cushion*2)/2))+"px"
			});
			if (parseFloat($("lightWindow-contents").style.height) != originalHeight) {
				$("lightWindow-contents").setStyle({
					top : titleHeight+"px",
					left : "0px"
				});
			}
		}
	}, 
	// 
	// Setup the Overlay (Special Thanks to quirksmode.com and huddletogether.com)
	//
	setupOverlay : function() {

		var xScroll, yScroll;

		if (window.innerHeight && window.scrollMaxY) {	
			xScroll = document.body.scrollWidth;
			yScroll = window.innerHeight + window.scrollMaxY;
		} else if (document.body.scrollHeight > document.body.offsetHeight){ 
			xScroll = document.body.scrollWidth;
			yScroll = document.body.scrollHeight;
		} else { 
			xScroll = document.body.offsetWidth;
			yScroll = document.body.offsetHeight;
		}

		var windowWidth, windowHeight;
		if (self.innerHeight) {	
			windowWidth = self.innerWidth;
			windowHeight = self.innerHeight;
		} else if (document.documentElement && document.documentElement.clientHeight) { 
			windowWidth = document.documentElement.clientWidth;
			windowHeight = document.documentElement.clientHeight;
		} else if (document.body) { 
			windowWidth = document.body.clientWidth;
			windowHeight = document.body.clientHeight;
		}	

		if(yScroll < windowHeight){
			pageHeight = windowHeight;
		} else { 
			pageHeight = yScroll;
		}

		if(xScroll < windowWidth){	
			pageWidth = windowWidth;
		} else {
			pageWidth = xScroll;
		}
		
		$("overlay").style.height = pageHeight;
		$("overlay").style.width = pageWidth;
	},  
	//
	//	Display the lightWindow.
	//
	displayLightWindow : function(display) {
		if (display) {
			$("overlay").style.display = $("lightWindow").style.display = $("lightWindow-contents").style.display = "block";	
		} else {
			$("overlay").style.display = $("lightWindow").style.display = "none"; 	
		}
	},  
	//
	//	Is this IE?
	//
	checkBrowser : function(type) {
		var detect = navigator.userAgent.toLowerCase();
		var version = parseInt(navigator.appVersion);
		var place = detect.indexOf(type)+1;
		return place;
	},
	//
	//	Prepare the window for IE.
	//
	prepareIE : function(setup) {
		if (this.checkBrowser("msie")) {
			var height, overflowX, overflowY;
			if (setup) { 
				this.getScroll();
				this.setScroll(0, 0);
				var height = "100%";
			} else {
				var height = "auto";
			}
			var body = document.getElementsByTagName("body")[0];
			var html = document.getElementsByTagName("html")[0];
			html.style.height = body.style.height = height;
			html.style.margin = body.style.margin = "0";
			this.setupOverlay();
			if (!setup) this.setScroll(this.scrollX, this.scrollY);				
		}
	},
	//
	//	Hide Selects from the page because of IE.
	//     We could use iframe shims instead here but why add all the extra markup for one browser when this is much easier and cleaner
	//
	toggleTroubleElements : function(visibility, content){
		if (content) var selects = $("lightWindow-contents").getElementsByTagName("select");
		else var selects = document.getElementsByTagName("select");
		for(var i = 0; i < selects.length; i++) {
			selects[i].style.visibility = visibility;
		}
		if (!content) {
			if (this.options.hideFlash){
				var objects = document.getElementsByTagName("object");
				for (i = 0; i != objects.length; i++) {
					objects[i].style.visibility = visibility;
				}
				var embeds = document.getElementsByTagName("embed");
				for (i = 0; i != embeds.length; i++) {
					embeds[i].style.visibility = visibility;
				}
			}
			var iframes = document.getElementsByTagName("iframe");
			for (i = 0; i != iframes.length; i++) {
				iframes[i].style.visibility = visibility;
			}
		}
	},
	//
	//	Get the scroll for the page.
	//
	getScroll : function(){
      	if(typeof(window.pageYOffset) == "number") {
        	this.scrollY = window.pageYOffset;
        	this.scrollX = window.pageXOffset;
      	} else if(document.body && (document.body.scrollLeft || document.body.scrollTop)) {
        	this.scrollY = document.body.scrollTop;
        	this.scrollX = document.body.scrollLeft;
      	} else if(document.documentElement && (document.documentElement.scrollLeft || document.documentElement.scrollTop)) {
        	this.scrollY = document.documentElement.scrollTop;
        	this.scrollX = document.documentElement.scrollLeft;
      	}
	},
	//
	//	Reset the scroll.
	//
	setScroll : function(x, y) {
		document.documentElement.scrollLeft = x; 
		document.documentElement.scrollTop = y; 
	},
	//
	//	Get the value from the params attribute string.
	//
	getParameter : function(parameter, parameterString) {
		if (!parameterString) {
			if (this.element.params) {
				var parameterString = this.element.params;
			} else {
				return;
			}
		}
		var parameterValue;
        var parameterPair = parameterString.split(",");
        var compareString = parameter+"=";
        var compareStringLength = compareString.length;
        for (var i = 0; i < parameterPair.length; i++) {
        	if (parameterPair[i].substr(0, compareStringLength) == compareString) {
            	var tmp = parameterPair[i].split("=");
                parameterValue = tmp[1];
                break;
            }
        }
		if (!parameterValue) {
			return false;
        } else {
        	return unescape(parameterValue);
    	}
	},
	//
	//	Get the domain from a string.
	//
	getDomain : function(url) {    
        var leadSlashes = url.indexOf("//");
        var domainStart = leadSlashes+2;
        var withoutResource = url.substring(domainStart, url.length);
        var nextSlash = withoutResource.indexOf("/");
        var domain = withoutResource.substring(0, nextSlash);
		if (domain.indexOf(":") > -1){
			var portColon = domain.indexOf(":");
			domain = domain.substring(0, portColon);
       	}
		return domain;
    },
	//
	//	Get the type of file.
	//
	fileType : function(url) {

		var image = new RegExp("[^\.]\.("+this.options.fileTypes.image.join('|')+")\s*$", "i");
		if (image.test(url)) return "image";
				
		if (url.indexOf("#") > -1 && (document.domain == this.getDomain(url))) return "inline";		
		if (url.indexOf("?") > -1) url = url.substring(0, url.indexOf("?"));

		var type = "unknown";
		var page = new RegExp("[^\.]\.("+this.options.fileTypes.page.join('|')+")\s*$", "i");
		var media = new RegExp("[^\.]\.("+this.options.fileTypes.media.join('|')+")\s*$", "i");
		
		if (document.domain != this.getDomain(url)) type = "external";
	  	if (media.test(url)) type = "media";
	
		if (type == "external" || type == "media") return type;
			
	  	if (page.test(url) || url.substr((url.length-1), url.length) == "/") type = "page";

		return type;
	},
	//
	//  Get file Extension
	//
	fileExtension : function(url) {
		if (url.indexOf("?") > -1) url = url.substring(0, url.indexOf("?"));
		var extenstion = "";
		for (var x = (url.length-1); x > -1; x--) {
			if (url.charAt(x) == ".") {
				return extenstion;
			}
			extenstion = url.charAt(x)+extenstion;
		}
	},
	//
	//	Monitor the keyboard while this lightWindow is up
	//
	monitorKeyboard : function(status) {
		if (status) document.onkeydown = this.eventKeypress.bind(this); 
		else document.onkeydown = "";
	},
	//
	//  Perform keyboard actions
	//
	eventKeypress : function(e) {

		if (e == null) var keycode = event.keyCode;
		else var keycode = e.which;
		
		switch (keycode) { 
			case 27: 
				this.deactivate(); 
				break;
			
			case 13:
				return;
				
			default:
				break;
		}
	
		// Gotta stop those quick fingers
		if (this.animating || !this.galleryToggle) return;

		switch (String.fromCharCode(keycode).toLowerCase()) {
			case "p":
				this.galleryDirection = -1;
				this.changeImage();
				break;
				
			case "n":
				this.galleryDirection = 1;
				this.changeImage();
				break;
				
			default:
				break;
		}
	},  
	//
	//	Make the Data Box for the Window
	//
	showData : function() {
		if (this.galleryToggle) $("lightWindow-photo-galleries").style.display = "block";
		this.setupDataDimensions();
		this.setupDimensions(false);		
		if (this.showDataToggle) {
			var showDatabox = new Effect.Parallel(
				[new Effect.SlideDown( "lightWindow-data", {sync: true, duration: this.duration+1.0, from: 0.0, to: 1.0}), 
			 	new Effect.Appear("lightWindow-data", {sync: true, duration: 1.0}) ], 
				{duration: 0.65, afterFinish: this.setStatus.bind(this, false), queue: {position: "end", scope: "lightWindowAnimation"} } 
			);
		} else {
			 this.setStatus(false);
		}
	},
	//
	//	Insert Data into Window
	//
	insertData : function() {
		if (this.element.title) {
			if (this.showTitleToggle) $("lightWindow-title-bar-title").innerHTML = this.element.title; 
			else $("lightWindow-data-title").innerHTML = this.element.title;
		}
		if (this.element.caption) $("lightWindow-data-caption").innerHTML = this.element.caption;
		if (this.element.author) $("lightWindow-data-author").innerHTML = this.options.authorLead+this.element.author;	
	},
	//
	//	Reset the scroll.
	//
	getGalleryInfo : function(rel) {
		if (rel.indexOf("[") > -1) {
			return new Array(escape(rel.substring(0, rel.indexOf("["))), escape(rel.substring(rel.indexOf("[")+1, rel.indexOf("]"))));
		} else {
			return false;
		}
	},
	// 
	//	Choose a gallery/category
	//
	getGallery : function() {
		var isBadBrowser = this.checkBrowser("msie 6");
		if (!$("lightWindow-photo-galleries").style.height || parseInt($("lightWindow-photo-galleries").style.height) == this.options.galleryTab.height) {
			if (isBadBrowser) {
				var gallerySize = 100;
			} else {
				var gallerySize = ((parseInt($("lightWindow-contents").style.height)*0.95)/this.options.galleryTab.height)*100;
			}
			
			$("lightWindow-photo-galleries-list").setStyle({
				height : (parseInt($("lightWindow-contents").style.height)*0.95)-this.options.galleryTab.height+"px"
			});

			// Get out Galleries from the imageArray
			$("lightWindow-photo-galleries-list").innerHTML = "";
			var output = "";
			for (i in this.imageArray) {
				if (typeof this.imageArray[i] == "object") {
					output += '<div class="lightWindow-photo-gallery-listing"><h1>'+unescape(i)+'</h1><ul>';
					for (j in this.imageArray[i]) {
						if (typeof this.imageArray[i][j] == "object") {
							if (this.imageArray[i][j][0][5]) showImages = ",lWShowImages="+this.getParameter("lWShowImages", this.imageArray[i][j][0][5]);
							else showImages = "";
							output += '<li><a href="#" params="lWGallery='+escape(i)+',lWCategory='+escape(j)+''+showImages+'" class="'+this.options.classNames.action+'" rel="reloadGallery" >'+unescape(j)+'</a></li>';
						}
					}
					output += '</ul></div>';
				}
			}
			new Insertion.Top("lightWindow-photo-galleries-list", output);
			this.actions(".lightWindow-photo-gallery-listing");

			// IE CSS support sucks and I cannot scale from the bottom....
			if (isBadBrowser) {
				$("lightWindow-photo-galleries").setStyle({
					height : (parseInt($("lightWindow-contents").style.height)*0.95)+"px",
					bottom : "0px"
				});				
				$("lightWindow-photo-galleries-tab").className = "down";
			} else {
				var showGalleries = new Effect.CushionScale("lightWindow-photo-galleries", gallerySize, {duration: this.duration, afterFinish: function(){$("lightWindow-photo-galleries-list").style.overflow = "auto"; $("lightWindow-photo-galleries-tab").className = "down";}, scaleX: false, scaleY: true, scaleContent: false, scaleFromCenter: false, queue: {position: "end", scope: "lightWindowAnimation"}});		
			}
		} else {
			if (isBadBrowser) {
				var bottom = -(parseInt($("lightWindow-contents").style.height)*0.95)+this.options.galleryTab.height;			
			} else {
				var bottom = 0;
			}
			
			$("lightWindow-photo-galleries").setStyle({
				height : this.options.galleryTab.height+"px",
				bottom : bottom+"px",
				top : ""
			});
			$("lightWindow-photo-galleries-list").setStyle({
				overflow : "hidden"
			});
			$("lightWindow-photo-galleries-tab").className = "up";
		}
	},
	//
	//	Set the gallery up.
	//
	setupGallery : function(gallery, start) 
	{
		var lwc = $("lightWindow-photo-container");

		if (!(images = parseInt(this.getParameter("lWShowImages")))) images = 1;		
		
		for (var x = 0; x < this.imageArray[gallery[0]][gallery[1]].length; x++) {
			if (this.imageArray[gallery[0]][gallery[1]][x][0] == this.contentToFetch) break;
		}

		this.activeImage = x;
		this.activeGallery = gallery;
		
		var lwn = document.createElement("div");
		lwn.setAttribute("id","lightWindow-navigation");
		lwc.appendChild(lwn);
				
		if (x != 0 && this.imageArray[gallery[0]][gallery[1]][x-images]) {
			var lwnp = document.createElement("a");
			lwnp.setAttribute("id","lightWindow-previous");
			lwnp.setAttribute("href","#");
			lwn.appendChild(lwnp);
			Event.observe(lwnp, "click", this.changeImage.bindAsEventListener(this, this.imageArray[gallery[0]][gallery[1]][x-images][0], this.imageArray[gallery[0]][gallery[1]][x-images][1], this.imageArray[gallery[0]][gallery[1]][x-images][2], this.imageArray[gallery[0]][gallery[1]][x-images][3], this.imageArray[gallery[0]][gallery[1]][x-images][4]));
			lwnp.onclick = function(){return false;};
		}
		if ((x+1) < this.imageArray[gallery[0]][gallery[1]].length && this.imageArray[gallery[0]][gallery[1]][x+images]) {
			var lwnn = document.createElement("a");
			lwnn.setAttribute("id","lightWindow-next");
			lwnn.setAttribute("href","#");
			lwn.appendChild(lwnn);
			Event.observe(lwnn, "click", this.changeImage.bindAsEventListener(this, this.imageArray[gallery[0]][gallery[1]][x+images][0], this.imageArray[gallery[0]][gallery[1]][x+images][1], this.imageArray[gallery[0]][gallery[1]][x+images][2], this.imageArray[gallery[0]][gallery[1]][x+images][3], this.imageArray[gallery[0]][gallery[1]][x+images][4]));
			lwnn.onclick = function(){return false;};
		}	
		if (images == 1) $("lightWindow-data-image").innerHTML = "Image "+(x+1)+" of "+this.imageArray[gallery[0]][gallery[1]].length;
		this.addGalleryWindowMarkup();
	},
	//
	//	Get the contents for the window
	//
	loadInfo : function() {	
		var showLoadingOptions = new Effect.Appear("lightWindow-loading-options", {delay: this.options.loadingDialog.delay, duration: this.duration, queue: {position: "front", scope: "lightWindowAnimation-loading"}});
		switch (this.windowType) {
			case "image" :
				this.preloadImage = new Array();
				if (!$("lightWindow-photo-container")) {
					this.addPhotoWindowMarkup();
					this.addDataWindowMarkup();
					this.addGalleryWindowMarkup();
				}
				var totalWidth = 0;
				var totalHeight = 0;
				var gallery = this.getGalleryInfo(this.element.rel);
				if (images = parseInt(this.getParameter("lWShowImages"))) {
					for (var z = 0; z < this.imageArray[gallery[0]][gallery[1]].length; z++) {
						if (this.imageArray[gallery[0]][gallery[1]][z][0] == this.contentToFetch) break;
					}
					$("lightWindow-photo-container").style.display = "none";
					this.loading = images-1;
					for (var x = 0; x < images; x++) {
						if (this.imageArray[gallery[0]][gallery[1]][x+z]) {
							this.preloadImage[x] = new Image();
							this.preloadImage[x].onload=function(){
								if ($("lightWindow-photo-container").style.display != "block") {
									for (var t = 0; t <= x; t++) {
										if (this.preloadImage[t] && (this.preloadImage[t].width != 0 && this.preloadImage[t].height != 0)) {
											totalWidth = totalWidth+this.preloadImage[t].width;
											totalHeight = this.preloadImage[t].height;
											this.preloadImage.splice(t, 1);
											this.loading--;	
										}
									}
									if (this.loading < 0) {
										$("lightWindow-photo-container").setStyle({
											display : "block"
										});
										$("lightWindow-photo-sizer").setStyle({
											width : totalWidth+"px",
											height : totalHeight+"px"
										});
										this.processInfo();
									}
								}
							}.bind(this, x);
							this.preloadImage[x].src = $("lightWindow-photo-"+x).src = this.imageArray[gallery[0]][gallery[1]][x+z][0];
						}
					}
					this.activeImage = this.activeImage+x-1;
					if (this.galleryToggle) this.setupGallery(this.getGalleryInfo(this.element.rel));
				} else {
					this.preloadImage[0] = new Image();
					this.preloadImage[0].onload=function(){
						totalWidth = this.preloadImage[0].width;
						totalHeight = this.preloadImage[0].height;
						$("lightWindow-photo-container").setStyle({
							display : "block"
						});
						$("lightWindow-photo-sizer").setStyle({
							width : totalWidth+"px",
							height : totalHeight+"px"
						});
						this.processInfo();
					}.bind(this);
					this.preloadImage[0].src = $("lightWindow-photo-0").src = this.contentToFetch;
					if (this.galleryToggle) this.setupGallery(this.getGalleryInfo(this.element.rel));
				}
				break;
			
			case "media" :	
				// We load the info in loadFinish so that the iframe will be properly sixe and set in our favorite browser... Safari-crap
				this.processInfo();
				break;

			case "external" :	
				var lwi = '<iframe id="lightWindow-iframe" name="lightWindow-iframe" height="100%" width="100%" frameborder="0" scrolling="auto"></iframe>';
				new Insertion.Top($("lightWindow-contents"), lwi);
				parent.$("lightWindow-iframe").style.visibility = "hidden";
				this.processInfo();
				break;
					
			case "page" :
				var newAJAX = new Ajax.Request(
        			this.contentToFetch,
        			{method: "post", parameters: "dede=deed", onComplete: this.processInfo.bind(this)}
				);
				break;
				
			case "inline" : 
				var content = this.contentToFetch;
				if (content.indexOf("?") > -1) {
					content = content.substring(0, content.indexOf("?"));
				}
				content = content.substring(content.indexOf("#")+1);
				new Insertion.Top($("lightWindow-contents-container"), $(content).innerHTML);
				this.toggleTroubleElements("hidden", true); 
				this.processInfo();
				break;
				
			default : 
				throw("Page Type could not be determined, please amend this lightWindow URL "+this.contentToFetch);
				break;
			}
	},
	//
	//	Finish the loading process and clean up.
	//
	loadFinish : function() {
		this.actions();	
		this.insertData(false);
		switch (this.windowType) {
			case "page" :
				var hideLoading = new Effect.Fade("lightWindow-loading", {duration: this.duration, afterFinish: this.windowAdjust.bind(this), queue: {position: "end", scope: "lightWindowAnimation"}});
				break;

			case "image" :
				var hideLoading = new Effect.Fade("lightWindow-loading", {duration: this.duration, afterFinish: this.windowAdjust.bind(this), queue: {position: "end", scope: "lightWindowAnimation"}});
				break;
				
			case "media" :	
				// We load the info in loadFinish so that the iframe will be properly sixe and set in our favorite browser... Safari-crap
				var lwi = '<iframe id="lightWindow-iframe" name="lightWindow-iframe" height="100%" width="100%" frameborder="0" scrolling="no" ></iframe>';
				new Insertion.Top($("lightWindow-contents"), lwi);
				iframeContent = '<html><head><style type="text/css">*, html, body{ margin: 0px; padding: 0px;}</style></head><body><embed type="'+this.options.mimeTypes[this.fileExtension(this.contentToFetch)]+'" src="'+this.contentToFetch+'" width="100%" height="100%" name="lightWindow-media" id="lightWindow-media" quality="high" wmode="opaque" /></body></html>';
				if (parent.$("lightWindow-iframe").contentWindow){
					parent.$("lightWindow-iframe").contentWindow.document.open();
					parent.$("lightWindow-iframe").contentWindow.document.write(iframeContent);
					parent.$("lightWindow-iframe").contentWindow.document.close();
				} else {
					parent.$("lightWindow-iframe").contentDocument.open();
					parent.$("lightWindow-iframe").contentDocument.write(iframeContent);
					parent.$("lightWindow-iframe").contentDocument.close();
				}
				var hideLoading = new Effect.Fade("lightWindow-loading", {duration: 0, afterFinish: this.windowAdjust.bind(this), queue: {position: "end", scope: "lightWindowAnimation"}});
				break;
			
			case "external" : 
				parent.$("lightWindow-iframe").src = this.contentToFetch;
				var hideLoading = new Effect.Fade("lightWindow-loading", {duration: this.duration, afterFinish: this.windowAdjust.bind(this), queue: {position: "end", scope: "lightWindowAnimation"}});
				break;
				
			case "inline" :
				var hideLoading = new Effect.Fade("lightWindow-loading", {duration: this.duration, afterFinish: this.windowAdjust.bind(this), queue: {position: "end", scope: "lightWindowAnimation"}});
				break;
				
			default :
				break;
		}
	},	
	// 
	//  Adjust the Window and add the data box if it needs it
	//
	windowAdjust : function() {
		if (this.windowType == "external" || this.windowType == "media") {
			// No I don't like this but it works with a small flicker, FF for the Mac is a little more buggy than I would have thought
			// Of Note this is really for the quicktime samples as far as I can tell....
			if (this.checkBrowser("firefox")) {
				if ($("overlay").style.height == "100%" || !$("overlay").style.height) $("overlay").style.height = "101%";
				else $("overlay").style.height = "100%";
			}
			parent.$("lightWindow-iframe").style.visibility = "visible";
		}
		$("lightWindow-contents").style.overflow = this.boxOverFlow;
		this.toggleTroubleElements("visible", true);
		if (this.showDataToggle || this.showTitleToggle) {
			this.showData();
		}
	},
	//
	//	Get the content into the window and show it off.
	//
	processInfo : function(response) {	
		if(this.checkBrowser("msie")) {
            var windowHeight = document.documentElement.clientHeight;
            var windowWidth = document.documentElement.clientWidth;   
        } else {
            var windowHeight = window.innerHeight;
            var windowWidth = window.innerWidth;
        }

		// What if the window size is ridiculously small? If so we need some overrides to make it fit and make it usable (even on set dimensions)
		if (this.showDataToggle) var dataWindow = this.options.dimensions.dataHeight;
		else var dataWindow = 0;
		// Set the title height for the bar
		if (this.options.showTitleBar) titleHeight = this.options.dimensions.titleHeight;
		else titleHeight = 0;
		var lWcWidth = parseInt($("lightWindow-contents").style.width);
		var lWcHeight = parseInt($("lightWindow-contents").style.height);
		var availableHeight = windowHeight-dataWindow-2*this.options.cushion-titleHeight;
		var availableWidth = windowWidth-2*this.options.cushion;
      	var boxWidth, boxScrollWidth, boxHeight, boxScrollHeight, scaleX, scaleY;	
		var totalHeight = 0;
		var totalWidth = 0;	
		switch (this.windowType) {
			case "image" :
				if (!(images = parseInt(this.getParameter("lWShowImages")))) images = 1;
				boxWidth = $("lightWindow-contents").offsetWidth;
				boxHeight = $("lightWindow-contents").offsetHeight;	
				if ($("lightWindow-photo-0").height > availableHeight) {
					var totalWidth = 0;
					for (var x = 0; x < images; x++) {
						$("lightWindow-photo-"+x).height = availableHeight;
						totalWidth = totalWidth+$("lightWindow-photo-"+x).width;
					}
					if (images > 1) totalWidth++; // This is needed for putting images side by side when we resize the iamge only
					boxScrollHeight = availableHeight;
					boxScrollWidth = totalWidth;
					$("lightWindow-photo-sizer").style.height = availableHeight+"px";
					$("lightWindow-photo-sizer").style.width = totalWidth+"px";
				} else {
					boxScrollHeight = parseInt($("lightWindow-photo-sizer").style.height);		
					boxScrollWidth = parseInt($("lightWindow-photo-sizer").style.width);
				}
				break;
				
			case "external" :				
		    	boxWidth = $("lightWindow-contents").offsetWidth;
				boxHeight = $("lightWindow-contents").offsetHeight;			
				break;
			
			case "media" :				
			    boxWidth = $("lightWindow-contents").offsetWidth;
				boxHeight = $("lightWindow-contents").offsetHeight;			
				break;
					
			case "page" :
				new Insertion.Top($("lightWindow-contents-container"), response.responseText);
				this.toggleTroubleElements("hidden", true); 
				boxWidth = $("lightWindow-contents").offsetWidth;
				boxScrollWidth = $("lightWindow-contents").scrollWidth;
				boxHeight = $("lightWindow-contents").offsetHeight;
				boxScrollHeight = $("lightWindow-contents").scrollHeight;
				break;
			
			case "inline" :
				boxWidth = $("lightWindow-contents").offsetWidth;
				boxScrollWidth = $("lightWindow-contents").scrollWidth;
				boxHeight = $("lightWindow-contents").offsetHeight;
				boxScrollHeight = $("lightWindow-contents").scrollHeight+3;
				break;
					
			default : 
				break;
				
		}

		// Were dimensions set?
		// This also resizes to fit the window, for things like flash!
		var ignorelWHeight = false;
      	if (lWWidth = this.getParameter("lWWidth")) {
			boxScrollWidth = parseFloat(lWWidth);
			if (boxScrollWidth > (windowWidth*.95)) {
				tmp = boxScrollWidth;
				boxScrollWidth = 0.90*windowWidth;
				lWHeight = this.getParameter("lWHeight"); // For this case I require a height to be set, why would you set width and not set height?
				boxScrollHeight = parseFloat(lWHeight);
				boxScrollHeight = boxScrollHeight * (boxScrollWidth/tmp)
				ignorelWHeight = true;
			}
		}

		if (lWHeight = this.getParameter("lWHeight")) {
			if (!ignorelWHeight) {
				boxScrollHeight = parseFloat(lWHeight);
				if (boxScrollHeight > (windowHeight*.8)) {
					boxScrollHeight = 0.8*windowHeight;
				}
			}
		}
		
		if (lWOverflow = this.getParameter("lWOverflow")) this.boxOverFlow = lWOverflow;

		if ((boxScrollHeight < (windowHeight*.8)) && this.windowType != "external" && this.windowType != "image") {
			scaleY = parseFloat((boxScrollHeight/boxHeight)*100);
		} else if (this.windowType == "external" && !lWHeight) {
			scaleY = parseFloat((windowHeight/(1.2*boxHeight))*100);
		} else if (this.windowType == "external" && lWHeight) {
			scaleY = parseFloat((boxScrollHeight/(boxHeight))*100);
		} else if (this.windowType == "image" || this.windowType == "media") {
			scaleY = parseFloat(((boxScrollHeight)/boxHeight)*100);
		} else {
			if (this.windowType != "media") this.boxOverFlow = "auto";
			$("lightWindow-contents-container").marginRight = "16px";
			scaleY = parseFloat((windowHeight/(1.2*boxHeight))*100);
		}
		if ((boxScrollWidth < (windowWidth*.8)) && this.windowType != "external" && this.windowType != "image" && this.windowType != "media") {
			scaleX = parseFloat(((boxScrollWidth)/boxWidth)*100);
		} else if (this.windowType == "external" && !lWWidth) {
			scaleX = parseFloat((windowWidth/(1.1*boxWidth))*100);
		} else if (this.windowType == "external" && lWWidth) {
			scaleX = parseFloat((boxScrollWidth/(boxWidth))*100);
		} else if (this.windowType == "image" || this.windowType == "media") {
			scaleX = parseFloat(((boxScrollWidth)/boxWidth)*100);
		} else {
			if (this.windowType != "media") this.boxOverFlow = "auto";
			$("lightWindow-contents-container").marginRight = "16px";
			scaleX = parseFloat((windowWidth/(1.1*boxWidth))*100);
		}
		
		this.setStatus(true);
		var doDelay = 0;
		if (scaleX != 100 && lWcWidth != boxScrollWidth) {
			if (scaleY == 100) var doX = new Effect.CushionScale("lightWindow-contents", scaleX, {duration: this.duration, scaleX: true, scaleY: false, scaleCushion: {top: this.options.cushion, left: this.options.cushion}, afterFinish: this.loadFinish.bind(this), scaleFromCenter: true, scaleContent: false, queue: {position: "front", scope: "lightWindowAnimation"}});	
			else var doX = new Effect.CushionScale("lightWindow-contents", scaleX, {duration: this.duration, scaleX: true, scaleY: false, scaleCushion: {top: this.options.cushion, left: this.options.cushion}, scaleContent: false, scaleFromCenter: true, queue: {position: "front", scope: "lightWindowAnimation"}});	
			doDelay = this.duration/2;
		}
		if (scaleY != 100 && lWcHeight != boxScrollHeight) {
			var doY = new Effect.CushionScale("lightWindow-contents", scaleY, {duration: this.duration, delay: doDelay, scaleX: false, scaleY: true, scaleCushion: {top: this.options.cushion, left: this.options.cushion}, afterFinish: this.loadFinish.bind(this), scaleContent: false, scaleFromCenter: true, queue: {position: "end", scope: "lightWindowAnimation"}});
		}
		if ((!doX && !doY) || (doX && scaleY != 100 && !doY)) this.loadFinish();	
	},	
	//
	//	Reload the window with another location
	//
	reloadWindow : function(element) {
		Element.remove($("lightWindow-contents"));
		if ($("lightWindow-data")) Element.remove($("lightWindow-data"));
		this.element = element;
		this.contentToFetch = this.element.href;
		this.addLightWindowMarkup(true);
		this.setupDimensions(true);
		this.displayLightWindow(true);
		this.loadInfo();
	},
	//
	//  Reload the Gallery
	//
	reloadGallery : function(e, link) {
		this.element.params = link.getAttribute("params");
		var gallery = this.getParameter("lWGallery", this.element.params);
		var category = this.getParameter("lWCategory", this.element.paramse);
		this.element.rel = this.imageArray[gallery][category][0][4];
		this.element.title = this.imageArray[gallery][category][0][1];
		this.element.caption = this.imageArray[gallery][category][0][2];
		this.element.author = this.imageArray[gallery][category][0][3];
		this.contentToFetch = this.imageArray[gallery][category][0][0];
		Element.remove($("lightWindow-photo-container"));
		if ($("lightWindow-data")) Element.remove($("lightWindow-data"));
		if ($("lightWindow-title-bar")) $("lightWindow-title-bar").style.display = "none";
		this.galleryToggle = true;
		this.activeGallery[0] = gallery
		this.activeGallery[1] = category;
		this.activeImage = 0;
		// Becuase of IE we have to use either Appear or setOpacity/show
		var showLoading = Effect.Appear("lightWindow-loading", {duration: 0, afterFinish: this.loadInfo.bind(this)});
	},
	//
	//	Change the Image
	//
	changeImage : function(e) {
		var queue = Effect.Queues.get("lightWindowAnimation").each(function(e) {e.cancel();});
	  	var data = $A(arguments);
	  	data.shift();
		if (data != "") {
			this.contentToFetch = data[0];
			this.element.title = data[1];
			this.element.caption = data[2];
			this.element.author = data[3];
			this.element.rel = data[4];
		} else {
			if (!(images = parseInt(this.getParameter("lWShowImages")))) images = 1;
			if ((this.galleryDirection < 0 && (this.activeImage-1*images) < 0) || (this.galleryDirection > 0 && (this.activeImage+1*images) >= this.imageArray[this.activeGallery[0]][this.activeGallery[1]].length)) return false;
			this.element.title = this.imageArray[this.activeGallery[0]][this.activeGallery[1]][this.activeImage+this.galleryDirection*images][1];
			this.element.caption = this.imageArray[this.activeGallery[0]][this.activeGallery[1]][this.activeImage+this.galleryDirection*images][2];
			this.element.author = this.imageArray[this.activeGallery[0]][this.activeGallery[1]][this.activeImage+this.galleryDirection*images][3];	
			this.element.params = this.imageArray[this.activeGallery[0]][this.activeGallery[1]][0][5];				
			this.element.rel = unescape(this.activeGallery[0]+'['+this.activeGallery[1]+']');			
			this.contentToFetch = this.imageArray[this.activeGallery[0]][this.activeGallery[1]][this.activeImage+this.galleryDirection*images][0];
			this.activeImage = this.activeImage+this.galleryDirection*images;	
		}
		// Preload the previous and next images
		if ((this.activeImage-1) >= 0) {
			var preloadNextImage = new Image();
			preloadNextImage.src = this.imageArray[this.activeGallery[0]][this.activeGallery[1]][this.activeImage-1][0];
		}
		if ((this.activeImage+1) < this.imageArray[this.activeGallery[0]][this.activeGallery[1]].length) {
			var preloadPrevImage = new Image();
			preloadPrevImage.src = this.imageArray[this.activeGallery[0]][this.activeGallery[1]][this.activeImage+1][0];
		}
		Element.remove($("lightWindow-photo-container"));
		if ($("lightWindow-data")) Element.remove($("lightWindow-data"));
		if ($("lightWindow-title-bar")) $("lightWindow-title-bar").style.visibility = "hidden";
		this.galleryToggle = true;
		$("lightWindow-loading-options").style.display = "none";
		// Becuase of IE we have to use either Appear or setOpacity/show
		var showLoading = Effect.Appear("lightWindow-loading", {duration: 0, afterFinish: this.loadInfo.bind(this)});
	},
	//
	//	Submit a form to another lightWindow
	//
	insertForm : function(e) {
		var element = Event.element(e).parentNode;
		var parameterString = Form.serialize(this.getParameter("lWForm", element.getAttribute("params")));
		Element.remove($("lightWindow-contents"));
		if ($("lightWindow-data")) Element.remove($("lightWindow-data"));
		this.element = element;
		this.contentToFetch = this.element.href;
		this.addLightWindowMarkup(true);
		this.setupDimensions(true);
		this.displayLightWindow(true);
		if (this.options.formMethod == "post") {
			var newAJAX = new Ajax.Request(
			    element.href,
			    {method: "post", postBody: parameterString, onComplete: this.processInfo.bind(this)}
			);
		} else if (this.options.formMethod == "get") {
			var newAJAX = new Ajax.Request(
			    element.href,
			    {method: "get", parameters: parameterString, onComplete: this.processInfo.bind(this)}
			);		
		}	
	}
}

/*-----------------------------------------------------------------------------------------------*/

Event.observe(window, "load", lightWindowInit, false);

//
//	Set up all of our links
//
var mylightWindow = null;
function lightWindowInit() {
	mylightWindow = new lightWindow();
}


/*-----------------------------------------------------------------------------------------------
	Problem:
		This effect does not take into account padding or a border on an element, especially an
		absolutely position element. 
	
	Added: 
		Options:
			scaleCushion: 0	// or {top, left} with provided values
			
			Example:
				scaleCushion: {top: 10, left: 10}
		
		Code:
			To setDimensions: function(height, width)
			
				Original:
		    		if(this.options.scaleY) d.top = this.originalTop-topd + 'px';
	        		if(this.options.scaleX) d.left = this.originalLeft-leftd + 'px';					
				
				New:
			    	if(this.options.scaleCushion == 'none') {
		        		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 = (this.originalTop-topd-this.options.scaleCushion.top-this.options.scaleCushion.bottom) + 'px';
			        	if(this.options.scaleX) d.left = (this.originalLeft-leftd-this.options.scaleCushion.right-this.options.scaleCushion.left) + 'px';		
					}
		
	Credit: Kevin P Miller http://www.stickmanlabs.com
-----------------------------------------------------------------------------------------------*/

Effect.CushionScale = Class.create();
Object.extend(Object.extend(Effect.CushionScale.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,
	  scaleCushion: "none"	   // 'none' or {} with provided values
    }, arguments[2] || {});
    this.start(options);
  },
  setup: function() {
    this.restoreAfterFinish = this.options.restoreAfterFinish || false;
    this.elementPositioning = this.element.getStyle("position");
    
    this.originalStyle = {};
    ["top","left","width","height","fontSize"].each( function(k) {
      this.originalStyle[k] = this.element.style[k];
    }.bind(this));
      
    this.originalTop  = this.element.offsetTop;
    this.originalLeft = this.element.offsetLeft;
    
    var fontSize = this.element.getStyle("font-size") || "100%";
    ["em","px","%","pt"].each( function(fontSizeType) {
      if(fontSize.indexOf(fontSizeType)>0) {
        this.fontSize     = parseFloat(fontSize);
        this.fontSizeType = fontSizeType;
      }
    }.bind(this));
    
    this.factor = (this.options.scaleTo - this.options.scaleFrom)/100;
    
    this.dims = null;
    if(this.options.scaleMode=="box")
      this.dims = [this.element.offsetHeight, this.element.offsetWidth];
    if(/^content/.test(this.options.scaleMode))
      this.dims = [this.element.scrollHeight, this.element.scrollWidth];
    if(!this.dims)
      this.dims = [this.options.scaleMode.originalHeight,
                   this.options.scaleMode.originalWidth];
  },
  update: function(position) {
    var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position);
    if(this.options.scaleContent && this.fontSize)
      this.element.setStyle({fontSize: this.fontSize * currentScale + this.fontSizeType });
    this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale);
  },
  finish: function(position) {
    if(this.restoreAfterFinish) this.element.setStyle(this.originalStyle);
  },
  setDimensions: function(height, width) {
    var d = {};
	if(this.options.scaleX) d.width = width + "px";
	if(this.options.scaleY) d.height = 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.scaleCushion == "none") {
        	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 = (this.originalTop-topd-this.options.scaleCushion.top) + "px";
        	if(this.options.scaleX) d.left = (this.originalLeft-leftd-this.options.scaleCushion.left) + "px";			
		}
      } else {
        if(this.options.scaleY) d.top = -topd + "px";
        if(this.options.scaleX) d.left = -leftd + "px";
      }
    }
    this.element.setStyle(d);
  }
});
