
/* Global Javascript start here */
var RhapsodyUtility = {
 
	addLoadEvent: function(func){
	    var oldonload = window.onload;
	    if (typeof window.onload != 'function') {
	        window.onload = func;
	    } else {
	        window.onload = function() {
	            oldonload();
	            func();
	        }
	    }
	},
	
	addEvent: function( theElement, theEvent, theCallback ){
		if( theElement.addEventListener ){
			theElement.addEventListener( theEvent, theCallback, false );
		}
		else if( theElement.attachEvent ){
			theElement.attachEvent( "on" + theEvent, theCallback );
		} else return;
	},
	
	Ajax: {}
}

/* Global Javascript Ends here */


var RhapsodyDom = {
	bodyLoaded: false,
	init: function(){
		RhapsodyUtility.addLoadEvent(
			function(){ RhapsodyDom.bodyLoaded = true; }
		);
	}
}
RhapsodyDom.init();

function TabbedDisplay( holderId ){
	this.init( holderId );
}



/*****  Base Class for a Dialog Box Object  ******/
function DialogBox( argObj ){
	this.init( argObj );
}

DialogBox.prototype = {
	elementId: null,
	elementClassName: null,
	elementType: "DIV",
	spawnFrom: null,
	spawnFromOffset: [ 0, 0 ],
	spawnFromScrollingParent: null,
	topPos: "0px",
	leftPos: "0px",
	width: null,
	height: null,
	stylePosition: "absolute",
	srcUrl: null,
	htmlContent: null,
	zIndex: "1000",
	styleOverflow: "hidden",
	outerClickHandler: null,
	meddlesomeElements: ['query' ],
	
	_holdingElement: null,
	_maskElement: null,
	_shadowElement: null,
	
	_shadowOffset: 3,
	
	_loiteringTimeout: null,
		
	init: function( argObj ){
		if( argObj ){
			with( argObj ){
				if( typeof elementId != 'undefined' ) this.elementId = elementId;
				if( typeof elementClassName != 'undefined' ) this.elementClassName = elementClassName;
				if( typeof elementType != 'undefined' ) this.elementType = elementType;
				if( typeof spawnFrom != 'undefined' ) this.spawnFrom = ( typeof spawnFrom == 'string' )? document.getElementById( spawnFrom ): spawnFrom;
				if( typeof spawnFromOffset != 'undefined' ) this.spawnFromOffset = spawnFromOffset;
				if( typeof spawnFromScrollingParent != 'undefined' ) this.spawnFromScrollingParent = ( typeof spawnFromScrollingParent == 'string' )? document.getElementById( spawnFromScrollingParent ): spawnFromScrollingParent;
				if( typeof topPos != 'undefined' ) this.topPos = topPos;
				if( typeof leftPos != 'undefined' ) this.leftPos = leftPos;
				if( typeof width != 'undefined' ) this.width = width;
				if( typeof height != 'undefined' ) this.height = height;
				if( typeof srcUrl != 'undefined' ) this.srcUrl = srcUrl;			
				if( typeof htmlContent != 'undefined' ) this.htmlContent = htmlContent;			
			}
		}
		this._buildHoldingElement();
		var theThis = this;
		this.listenForOuterClicks = function( e ) {
			if( !theThis.outerClickHandler || ( typeof theThis.outerClickHandler == 'undefined' ) ) return; // Shouldn't happen, but what the heck...
			if( theThis._isMouseOutside( e ) ){
				if( theThis.loiteringTimeout ) clearTimeout( theThis.loiteringTimeout );
				theThis.outerClickHandler();
			}
		}
		this.listenForOuterLoitering = function() {
			if( !theThis.outerLoiteringHandler || ( typeof theThis.outerLoiteringHandler == 'undefined' ) ) return;
			var doTheCheckAndClose = function( e ){
				if( theThis._isMouseOutside( e ) ){
					theThis.outerLoiteringHandler();
					clearTimeout( theThis.loiteringTimeout );
				}
				else return;
			}
			theThis.loiteringTimeout = setTimeout( function(){
				RhapsodyUtility.addEvent( document, 'mousemove', doTheCheckAndClose );
			}, 4000 );
		}
	},
	
	_buildHoldingElement: function(){
	// TODO - see if we really are detecting whether the body exists
//if( document.body != null && ( typeof document.body != 'undefined' ) && RhapsodyDom.bodyLoaded ){
			this._holdingElement = document.createElement( this.elementType );
			document.getElementById("DialogManagerInitialHoldingElement").appendChild( this.getHoldingElement() );
			if( this.spawnFrom ){
				var positions =[ 0, 0 ];
				if( Position.cumulativeOffset ){
					positions = Position.cumulativeOffset( this.spawnFrom );
				} else { // had to move this locally from prototype.js b/c "Position" is randomly undefined
				var valueT = 0, valueL = 0;
				var element = this.spawnFrom;
					do{
						valueT += element.offsetTop  || 0;
						valueL += element.offsetLeft || 0;
						element = element.offsetParent;
					} while( element );
					positions = [ valueL, valueT ];
				}
				if( this.spawnFromScrollingParent ) positions = this._adjustSpawnFromForScrollingParent( positions );
				this.leftPos = ( positions[ 0 ] + this.spawnFromOffset[ 0 ] ) + 'px';
				this.topPos = ( positions[ 1 ] + this.spawnFromOffset[ 1 ] ) + 'px';
			}
			with( this.getHoldingElement() ){
				style.display = 'none';
				style.top = this.topPos;
				style.left = this.leftPos;
				if( this.width ) style.width = this.width;
				if( this.height ) style.height = this.height;
				style.position = this.stylePosition;
				style.zIndex = this.zIndex;
				style.overflow = this.styleOverflow;
				if( this.elementId ) setAttribute( "id", this.elementId) ;
				if( this.elementClassName ) className = this.elementClassName;
				this.loadContent();
			} 
//		} else this.destroy();
	},
	loadContent: function( lcObj ){
		if( lcObj ){
			if( lcObj.srcUrl )	this.srcUrl = lcObj.srcUrl;
			if( lcObj.htmlContent ) this.htmlContent = lcObj.htmlContent;
		}
		if( this.srcUrl ){
			RhapsodyUtility.Ajax.includeHtml( {
				ajaxUrl: this.srcUrl,
				target: this.getHoldingElement(),
				useLoadMessage: true,
				forceReload: true
			} );
		} else if( this.htmlContent ) this.getHoldingElement().innerHTML = this.htmlContent;
		
	},
	getHoldingElement: function(){
		return this._holdingElement;
	},
	hide: function(){
		this.getHoldingElement().style.display = 'none';
	},
	show: function( disableVisible ){
		this.getHoldingElement().style.display = 'block';
		if( !disableVisible ) this.setVisibility( 'visible' );
	},
	setVisibility: function( visibility ){
		this.getHoldingElement().style.visibility = visibility;
	},
	giveLayout: function(){
		with( this ){
			setVisibility( 'hidden' );
			show( true );
		}		
	},
	getLeft: function(){
		return parseInt( this.leftPos );
	},
	getTop: function(){
		return parseInt( this.topPos );
	},
	setLeft: function( l ){
		this.leftPos = l + "px";
		this.getHoldingElement().style.left = this.leftPos;
	},
	setTop: function( t ){
		this.topPos = t + "px";
		this.getHoldingElement().style.top = this.topPos;
	},
	setWidth: function( w ){
		this.width = ( typeof w == 'string' ) ? w : w + 'px';
		this.getHoldingElement().style.width = this.width;
	},
	setHeight: function( h ){
		this.height = ( typeof h == 'string' ) ? h : h + 'px';
		this.getHoldingElement().style.height = this.height;
	},
	setSize: function( w, h ){
		this.setWidth( w );
		this.setHeight( h );
	},
	centerInPage: function( hm, wm ){
		var hadShadow = false;
		var heightMultiplier = ( ( typeof hm != 'undefined' ) && hm != null )? hm: .75;
		var widthMultiplier = ( ( typeof wm != 'undefined' ) && wm != null )? wm: 1;
		this.giveLayout();
		if( this.getShadow() ){
			hadShadow = true;
			this.setShadow();
		}
		var offsetFromTop = Math.max( document.body.scrollTop, document.documentElement.scrollTop );
		if( window.pageYOffset ) offsetFromTop = Math.max( offsetFromTop, window.pageYOffset );
		var docWidth = document.documentElement.clientWidth;
		var docHeight = document.documentElement.clientHeight;
		if( ( navigator.appVersion.toLowerCase().indexOf( 'safari' ) != -1 ) ) docHeight = self.screen.availHeight * .75;
		var elementHeight = Element.getHeight( this.getHoldingElement() );
		var newLeft = Math.round( ( docWidth * widthMultiplier ) - parseInt( this.width ) ) / 2;
		var newTop = ( Math.round( ( docHeight * heightMultiplier ) - elementHeight ) / 2 ) + offsetFromTop;
		if( ( this.getLeft() != newLeft ) || ( this.getTop() != newTop ) ){
			if( newTop < offsetFromTop ) newTop = offsetFromTop;
			this.setLeft( newLeft );
			this.setTop( newTop );
		}
		this.show();
		if( hadShadow ) this.setShadow( true );
	},
	getMask: function(){
		return this._maskElement;
	},
	setMask: function( maskOn ){
		if( !maskOn || this.getMask() ){
			if( !maskOn ){
				this.getMask().style.display = 'none';
				if( document.getElementById("DialogManagerInitialHoldingElement") && this.getMask() ) document.getElementById("DialogManagerInitialHoldingElement").removeChild( this.getMask() );
			}
			return;
		}
		var maskOpacityPercent = 70;
		var maskElement = document.createElement( "DIV" );
		var maskHeight = Math.max( document.documentElement.clientHeight, document.body.clientHeight );
		var maskWidth = Math.max( document.documentElement.clientWidth, document.body.clientWidth );

		with( maskElement.style ){
			position = 'absolute';
			top = '0px';
			left = '0px';
			width = maskWidth + 'px';
			height = maskHeight + 'px';
			if( typeof opacity != 'undefined' ){
				opacity = maskOpacityPercent / 100;
			}
			if( typeof filter != 'undefined' ){
				filter = "alpha(opacity=" + maskOpacityPercent + ")";
			}
			zIndex = '500';
			backgroundColor = '#999';
		}
		document.getElementById("DialogManagerInitialHoldingElement").appendChild( maskElement );
		Event.observe( maskElement, 'mousedown', function(){ return false; }, true );
		this._maskElement = maskElement;
	},
	toggleMeddlesomeElements: function( showOnly ){
		var elementsToToggleIds = this.meddlesomeElements;
		for( var i=0; i < elementsToToggleIds.length; i++ ){
			var elementToToggle = $( elementsToToggleIds[ i ] );
			if( elementToToggle && ( typeof elementToToggle != 'undefined' ) ){
				if( elementToToggle.style.visibility == 'hidden' ) elementToToggle.style.visibility = 'visible';
				else if( !showOnly ) elementToToggle.style.visibility = 'hidden';
				else return;
			}
		}
	},
	getShadow: function(){
		return this._shadowElement;
	},
	setShadow: function( shadowOn ){
		if( this.getShadow() ){
			this.getShadow().style.display = 'none';
			document.getElementById("DialogManagerInitialHoldingElement").removeChild( this.getShadow() );
			this._shadowElement = null;
		}
		if( shadowOn ){
			var parentElementHeight = Element.getHeight( this.getHoldingElement() );
			var shadowOpacityPercent = 20;
			var shadowElement = document.createElement( "DIV" );
	
			with( shadowElement.style ){
				position = 'absolute';
				top = ( parseInt( this.topPos ) + this._shadowOffset ) + 'px';
				left = ( parseInt( this.leftPos ) + this._shadowOffset ) + 2 + 'px';
				width = this.width;
				height = parentElementHeight + 'px';
				if( typeof opacity != 'undefined' ){
					opacity = shadowOpacityPercent / 100;
				}
				if( typeof filter != 'undefined' ){
					filter = "alpha(opacity=" + shadowOpacityPercent + ")";
				}
				zIndex = '900';
				backgroundColor = 'black';
			}
			document.getElementById("DialogManagerInitialHoldingElement").appendChild( shadowElement );
			this._shadowElement = shadowElement;
		}
	},
	
	_adjustSpawnFromForScrollingParent: function( pArr ){
		var scrollingParentOffsetTop = this.spawnFromScrollingParent.scrollTop;
		var scrollingParentOffsetLeft = this.spawnFromScrollingParent.scrollLeft;
		var adjustedLeft = ( ( scrollingParentOffsetLeft > 0 ) && ( scrollingParentOffsetLeft ) && ( scrollingParentOffsetLeft != 'undefined' ) )? pArr[ 0 ] - scrollingParentOffsetLeft: pArr[ 0 ];
		var adjustedTop = ( ( scrollingParentOffsetTop > 0 ) && ( scrollingParentOffsetTop ) && ( scrollingParentOffsetTop != 'undefined' ) )? pArr[ 1 ] - scrollingParentOffsetTop: pArr[ 1 ];
		return [ adjustedLeft, adjustedTop ];
	},
	removeHoldingElement: function(){
		try {
			this.hide();
		} catch(e) {}
		if( document.getElementById("DialogManagerInitialHoldingElement") && this.getHoldingElement() ) document.getElementById("DialogManagerInitialHoldingElement").removeChild( this.getHoldingElement() );
	},
	_localWithin: function( clickX, clickY ){
		/* had to borrow from prototype.js b/c prototype.js Position object was
		randomly 'undefined', bug in prototype.js? */
			
		var element = this.getHoldingElement();
	    var offset, valueT = 0, valueL = 0;
			if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) {
				do {
					var elementToRecurse = element;
					valueT += elementToRecurse.offsetTop  || 0;
					valueL += elementToRecurse.offsetLeft || 0;
						if (elementToRecurse.offsetParent == document.body)
							if (Element.getStyle(elementToRecurse, 'position') == 'absolute') break;
						elementToRecurse = elementToRecurse.offsetParent;
					} while (elementToRecurse);
			} else {
				var elementToRecurse = element;
				do {
					valueT += elementToRecurse.offsetTop  || 0;
					valueL += elementToRecurse.offsetLeft || 0;
					elementToRecurse = elementToRecurse.offsetParent;
				} while (elementToRecurse);
			}
		offset = [ valueL, valueT ];
		return ( clickY >= offset[1] &&
			clickY <  offset[1] + element.offsetHeight &&
			clickX >= offset[0] &&
			clickX <  offset[0] + element.offsetWidth );
	},
	destroy: function() {
		this.removeHoldingElement();
		if( this.getMask() ) this.setMask( false );
		if( this.getShadow() ) this.setShadow( false );
		this.toggleMeddlesomeElements( true );
	}
}

// This is used instead of document.body to "attach" dialog-box elements to (see 218455) 
document.write( '<div id="DialogManagerInitialHoldingElement" style="position: absolute; height: 0; width: 0; z-index: 10000; top: 0; left: 0;"><\/div>');



function possiblyRemoveAutoComplete() {
	if( navigator.userAgent.toLowerCase().indexOf("firefox")>=0 ) { return; }
	var theInput = document.getElementById("headerSearchQuery");
	if( theInput ) { theInput.autocomplete = "off"; }
	else { setTimeout("possiblyRemoveAutoComplete()",500); }
}
possiblyRemoveAutoComplete();


/*  Here are the script strip form 
 *  Prototype framework 
/*--------------------------------------------------------------------------*/


var PeriodicalExecuter = Class.create();
PeriodicalExecuter.prototype = {
  initialize: function(callback, frequency) {
    this.callback = callback;

    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);
    });
  },

  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;
    }
  },



  include: function(object) {
    var found = false;
    this.each(function(value) {
      if (value == object) {
        found = true;
        throw $break;
      }
    });
    return found;
  },



 
  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; i < iterable.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; i < this.length; i++)
      iterator(this[i]);
  },

  clear: function() {
    this.length = 0;
    return this;
  },


  reduce: function() {
    return this.length > 1 ? this : this[0];
  },

  inspect: function() {
    return '[' + this.map(Object.inspect).join(', ') + ']';
  }
});
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($H(this), function(mergedHash, pair) {
      mergedHash[pair.key] = pair.value;
      return mergedHash;
    });
  },

  toQueryString: function() {
    return this.map(function(pair) {
      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(responderToAdd) {
    if (!this.include(responderToAdd))
      this.responders.push(responderToAdd);
  },

  unregister: function(responderToRemove) {
    this.responders = this.responders.without(responderToRemove);
  },

  dispatch: function(callback, request, transport, json) {
    this.each(function(responder) {
      if (responder[callback] && 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',
      parameters:   ''
    }
    Object.extend(this.options, options || {});
  },

  responseIsSuccess: function() {
    return this.transport.status == undefined
        || this.transport.status == 0
        || (this.transport.status >= 200 && this.transport.status < 300);
  },

  responseIsFailure: function() {
    return !this.responseIsSuccess();
  }
}

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 parameters = this.options.parameters || '';
    if (parameters.length > 0) parameters += '&_=';

    /* Simulate other verbs over post */
    if (this.options.method != 'get' && this.options.method != 'post') {
      parameters += (parameters.length > 0 ? '&' : '') + '_method=' + this.options.method;
      this.options.method = 'post';
    }

    try {
      this.url = url;
      if (this.options.method == 'get' && parameters.length > 0)
        this.url += (this.url.match(/\?/) ? '&' : '?') + parameters;

      Ajax.Responders.dispatch('onCreate', this, this.transport);

      this.transport.open(this.options.method, this.url,
        this.options.asynchronous);

      if (this.options.asynchronous)
        setTimeout(function() { this.respondToReadyState(1) }.bind(this), 10);

      this.transport.onreadystatechange = this.onStateChange.bind(this);
      this.setRequestHeaders();

      var body = this.options.postBody ? this.options.postBody : parameters;
      this.transport.send(this.options.method == 'post' ? body : null);

      /* Force Firefox to handle ready state 4 for synchronous requests */
      if (!this.options.asynchronous && this.transport.overrideMimeType)
        this.onStateChange();

    } catch (e) {
      this.dispatchException(e);
    }
  },

  setRequestHeaders: function() {
    var requestHeaders =
      ['X-Requested-With', 'XMLHttpRequest',
       'X-Prototype-Version', Prototype.Version,
       'Accept', 'text/javascript, text/html, application/xml, text/xml, */*'];

    if (this.options.method == 'post') {
      requestHeaders.push('Content-type', this.options.contentType);

      /* Force "Connection: close" for Mozilla browsers to work around
       * a bug where XMLHttpReqeuest sends an incorrect Content-length
       * header. See Mozilla Bugzilla #246651.
       */
      if (this.transport.overrideMimeType)
        requestHeaders.push('Connection', 'close');
    }

    if (this.options.requestHeaders)
      requestHeaders.push.apply(requestHeaders, this.options.requestHeaders);

    for (var i = 0; i < requestHeaders.length; i += 2)
      this.transport.setRequestHeader(requestHeaders[i], requestHeaders[i+1]);
  },

  onStateChange: function() {
    var readyState = this.transport.readyState;
    if (readyState != 1)
      this.respondToReadyState(this.transport.readyState);
  },

  header: function(name) {
    try {
      return this.transport.getResponseHeader(name);
    } catch (e) {}
  },

  evalJSON: function() {
    try {
      return eval('(' + this.header('X-JSON') + ')');
    } catch (e) {}
  },

  evalResponse: function() {
    try {
      return eval(this.transport.responseText);
    } catch (e) {
      this.dispatchException(e);
    }
  },

  respondToReadyState: function(readyState) {
    var event = Ajax.Request.Events[readyState];
    var transport = this.transport, json = this.evalJSON();

    if (event == 'Complete') {
      try {
        (this.options['on' + this.transport.status]
         || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')]
         || Prototype.emptyFunction)(transport, json);
      } catch (e) {
        this.dispatchException(e);
      }

      if ((this.header('Content-type') || '').match(/^text\/javascript/i))
        this.evalResponse();
    }

    try {
      (this.options['on' + event] || Prototype.emptyFunction)(transport, json);
      Ajax.Responders.dispatch('on' + event, this, transport, json);
    } catch (e) {
      this.dispatchException(e);
    }

    /* Avoid memory leak in MSIE: clean up the oncomplete event handler */
    if (event == 'Complete')
      this.transport.onreadystatechange = Prototype.emptyFunction;
  },

  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.containers = {
      success: container.success ? $(container.success) : $(container),
      failure: 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, object) {
      this.updateContent();
      onComplete(transport, object);
    }).bind(this);

    this.request(url);
  },

  updateContent: function() {
    var receiver = this.responseIsSuccess() ?
      this.containers.success : this.containers.failure;
    var response = this.transport.responseText;

    if (!this.options.evalScripts)
      response = response.stripScripts();

    if (receiver) {
      if (this.options.insertion) {
        new this.options.insertion(receiver, response);
      } else {
        Element.update(receiver, response);
      }
    }

    if (this.responseIsSuccess()) {
      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 $() {
  var results = [], element;
  for (var i = 0; i < arguments.length; i++) {
    element = arguments[i];
    if (typeof element == 'string')
      element = document.getElementById(element);
    results.push(Element.extend(element));
  }
  return results.reduce();
}

document.getElementsByClassName = function(className, parentElement) {
  var children = ($(parentElement) || document.body).getElementsByTagName('*');
  return $A(children).inject([], function(elements, child) {
    if (child.className.match(new RegExp("(^|\\s)" + className + "(\\s|$)")))
      elements.push(Element.extend(child));
    return elements;
  });
}



/* 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) {
        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;
  },

  


  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();




