
//------------------------------------------------------------------------
// Name: Legato_Debug_Debugger
// Desc: Works with the PHP Legato_Debug_Debugger class to display debugging
//       information.
//------------------------------------------------------------------------
Legato_Debug_Debugger =
{
  
	debug_items:         Array(),  // The debug items.
	queries:             Array(),  // The queries array.
	database_resources:  Array(),  // The database resources array.
	resources:           Array(),  // The resources array.
	execution_time:      "",       // The execution time of the page.
	
	
	//----------------------------------------------------------------------
	// Name: addSystemSetting()
	// Desc: Adds a setting.
	//----------------------------------------------------------------------
	addSystemSetting: function( category, setting, value )
	{

		// Add the setting.
		Legato_Debug_Debugger.system_settings[category].push( { setting: setting,
		                                                    value:   value } );

	},
	

	//----------------------------------------------------------------------
	// Name: addItem()
	// Desc: Adds a debug item.
	//----------------------------------------------------------------------
	addItem: function( message, error_code, file, line, php_class, php_function, type )
	{

		// Add the debug item.
		Legato_Debug_Debugger.debug_items.push( { message:       message,
		                                      error_code:    error_code,
		                                      file:          file,
		                                      line:          line,
		                                      php_class:     php_class,
		                                      php_function:  php_function,
		                                      type:          type,
		                                      args:          Array() } );

	},


	//----------------------------------------------------------------------
	// Name: addFunctionArg()
	// Desc: Adds a function's argument.
	//----------------------------------------------------------------------
	addFunctionArg: function( id, arg )
	{

		// Get the debug item.
		var debug_item = Legato_Debug_Debugger.debug_items[id];

		// Add the function argument.
		debug_item.args.push( arg );

	},


	//----------------------------------------------------------------------
	// Name: addQuery()
	// Desc: Adds a query.
	//----------------------------------------------------------------------
	addQuery: function( query, file, line )
	{

		// Add the debug item.
		Legato_Debug_Debugger.queries.push( { query:  query,
																	    file:   file,
																	    line:   line } );

	},


	//----------------------------------------------------------------------
	// Name: addDB()
	// Desc: Adds a database resource.
	//----------------------------------------------------------------------
	addDB: function( host, name )
	{

		// Add the database resource.
		Legato_Debug_Debugger.database_resources.push( { host:  host,
																	               name:  name } );

	},


	//----------------------------------------------------------------------
	// Name: addResource()
	// Desc: Adds a resource.
	//----------------------------------------------------------------------
	addResource: function( class_name, id, data )
	{
		
		// Add the resource.
		Legato_Debug_Debugger.resources.push( { class_name: class_name, id: id, data: data } );

	},


	//----------------------------------------------------------------------
	// Name: showDebugInfo()
	// Desc: Pops up a window with the debug information.
	//----------------------------------------------------------------------
	showDebugInfo: function()
	{

		var window_html         = "";
		var debug_window        = null;
		var last_resource_class = "";

		// Start getting the debug HTML.
		window_html += "<html>";
		window_html += "<head>";

		window_html += "<title>Debug Information</title>";

		window_html += "<style>";
		window_html += "html { color: #000; background-color: #FFF; font-family: Verdana, Helvetica, sans-serif; font-size: 11px; }";
		window_html += "body { margin: 0; padding: 0; }";
		window_html += "h1, h2, h3, h4, h5, h6 { font-family: Trebuchet MS, verdana, sans-serif; margin: 0px; }";
		window_html += "h1 { font-size: 17px; color: #3870A9; border-bottom: 1px solid #CCC; padding-left: 10px; margin-top: 15px; }";
		window_html += "h2 { font-size: 14px; color: #3870A9; border-bottom: 1px solid #CCC; margin-top: 15px; padding: 0px 0px 2px 50px; }";
		window_html += ".item { background-color: #EEE; margin: 0px 10px 10px 10px; padding: 5px; }";
		window_html += "table, th, td, tr { font-family: Verdana, Helvetica, sans-serif; font-size: 11px; vertical-align: top; }";
		window_html += "table { width: 100%; }";
		window_html += "td { width: 46%; padding: 0% 2%; }";
		window_html += "</style>";

		window_html += "</head>";
		window_html += "<body>";

		////////////////////////////////////////
		// Execution Information
		window_html += "<h1>Execution Information</h1>";

		window_html += "<div class='item'>"
					 + "<strong>Page Execution Time: </strong> <br /> <em>" + Legato_Debug_Debugger.execution_time + " Seconds</em> <br /><br />"
					 + "<strong>Number of Debug Items: </strong> <em>" + Legato_Debug_Debugger.debug_items.length + "</em> <br />"
					 + "<strong>Number of Queries: </strong> <em>" + Legato_Debug_Debugger.queries.length + "</em> <br />"
					 + "<strong>Number of Resources: </strong> <em>" + Legato_Debug_Debugger.resources.length + "</em> <br />"
					 + "</div>";

		////////////////////////////////////////
		// Debug items.
		if ( Legato_Debug_Debugger.debug_items.length != 0 )
		{
			
			window_html += "<h1>Debug Information</h1>";
	
			// Loop through each debug item.
			formatted_debug_items = Legato_Debug_Debugger.formatDebugItems();
	
			for ( var i = 0; i < formatted_debug_items.length; i++ )
			{
	
				// Get the debug item.
				var debug_item = formatted_debug_items[i];
	
				window_html += "<h2>Item #" + (i + 1) + "</h2>"
							 + "<div class='item'>"
							 + debug_item
							 + "</div>";
	
			}  // Next debug item.
		
		}

		////////////////////////////////////////
		// Database queries.
		window_html += "<h1>Database Queries (" + Legato_Debug_Debugger.queries.length + ")</h1>";

		// Loop through each query.
		for ( var i = 0; i < Legato_Debug_Debugger.queries.length; i++ )
		{

			// Get the query.
			var query = Legato_Debug_Debugger.queries[i];

			// Show the query.
			window_html += "<h2>Query #" + (i + 1) + "</h2>"
						 + "<div class='item'>"
						 + '"' + query.query + '" <br />'
						 + "<strong>File:</strong> <em>" + query.file + "</em> <br />"
						 + "<strong>Line:</strong> <em>" + query.line + "</em> <br />"
						 + "</div>";

		}  // Next query.

		////////////////////////////////////////
		// Resource information.
		window_html += "<h1>Resource Information (" + Legato_Debug_Debugger.resources.length + ")</h1>";

		// Loop through each DB resource.
		for ( var i = 0; i < Legato_Debug_Debugger.database_resources.length; i++ )
		{

			// Get the DB resource.
			var resource = Legato_Debug_Debugger.database_resources[i];

			// Show the DB resource.
			window_html += "<h2>DB #" + (i + 1) + "</h2>"
						 + "<div class='item'>"
						 + "<strong>DB Host:</strong> <em>" + resource.host + "</em> <br />"
						 + "<strong>DB Name:</strong> <em>" + resource.name + "</em> <br />"
						 + "</div>";

		}  // Next DB resource.

		// Loop through each resource.
		for ( var i = 0; i < Legato_Debug_Debugger.resources.length; i++ )
		{

			// Get the resource.
			var resource = Legato_Debug_Debugger.resources[i];
			
			var resource_data = '';
			for ( n in resource.data )
				resource_data += "<strong>" + n + ":</strong> " + resource.data[n] + "<br />";

			// Show the resource.
			window_html += "<h2>" + resource.class_name + " (" + (resource.id) + ")</h2>"
						 + "<div class='item'>"
						 + "<table><tr>"
						 + "<td><h3>Resource Data</h3><br /><div>" + resource_data + "</div></td>"
						 + "<td><h3>Resource Info</h3><div></div></td>"
						 + "</tr></table>"
						 + "</div>";

		}  // Next resource.
		
		window += "</body>";
		window += "</html>";

		// Open a window for the output.
		debug_window = window.open( "", "DebugWindow", "menubar=yes,scrollbars=yes,status=yes,width=500,height=500" );

		// Show the output.
		debug_window.document.open();
		debug_window.document.write( window_html );
		debug_window.document.close();

	},


	//----------------------------------------------------------------------
	// Name: showDebugInfo()
	// Desc: Loops through each debug item and formats it ready for printing.
	//----------------------------------------------------------------------
	formatDebugItems: function()
	{

		var formatted_items = Array();

		// Loop through each debug item.
		for ( var i = 0; i < Legato_Debug_Debugger.debug_items.length; i++ )
		{

			var debug_item = Legato_Debug_Debugger.debug_items[i];

			formatted_items[i] = "";

			// Error code.
			if ( debug_item.error_code != "" )
				formatted_items[i] += "<strong>[ " + debug_item.error_code + " ]</strong> - ";

			// Message.
			if ( debug_item.message != "" )
				formatted_items[i] += '"<em>' + debug_item.message + '</em>" <br />';

			// File.
			if ( debug_item.file != "" )
				formatted_items[i] += "<strong>File:</strong> <em>" + debug_item.file + "</em> <br />";

			// Line.
			if ( debug_item.line != "" )
				formatted_items[i] += "<strong>Line:</strong> <em>" + debug_item.line + "</em> <br />";

			// Class.
			if ( debug_item.php_class != "" )
				formatted_items[i] += "<strong>Class:</strong> <em>" + debug_item.php_class + "</em> <br />";

			// Function.
			if ( debug_item.php_function != "" )
				formatted_items[i] += "<strong>Function:</strong> <em>" + debug_item.php_function + "</em> <br />";

			// Type.
			if ( debug_item.php_function != "" )
			{

				// Type of function?
				if ( debug_item.type == "->" )
				{
					formatted_items[i] += "<strong>Type:</strong> <em>Class Function</em> <br />";
				}
				else if ( debug_item.type == "::" )
				{
					formatted_items[i] += "<strong>Type:</strong> <em>Static Function</em> <br />";
				}
				else
				{
					formatted_items[i] += "<strong>Type:</strong> <em>Normal Function</em> <br />";
				}

			}  // End type.

			// Prototype.
			if ( debug_item.php_function != "" )
			{

				formatted_items[i] += "<strong>Prototype:</strong> <em>";

				// Any class?
				if ( debug_item.php_class != "" )
					formatted_items[i] += debug_item.php_class;

				// Any type?
				if ( debug_item.type != "" )
					formatted_items[i] += debug_item.type;

				// Put the function name.
				formatted_items[i] += debug_item.php_function + "( ";

				// Loop through the args.
				for ( var n = 0; n < debug_item.args.length; n++ )
				{

					formatted_items[i] += debug_item.args[n];

					if ( n != debug_item.args.length - 1 )
						formatted_items[i] += ", ";

				}  // Next arg.

				// End the function.
				formatted_items[i] += " )";
				formatted_items[i] += "</em> <br />";

			}  // End prototype.

			formatted_items[i] += "<br />";

		}  // Next debug item.

		// Return the formatted items.
		return formatted_items;

	}

};

//------------------------------------------------------------------------
// Package: Structures
// The various structures used by the system.
// 
// Topic: Dependencies
// - <DOM Library>
//------------------------------------------------------------------------

//------------------------------------------------------------------------
// Class: Legato_Structure_Color
// Handles a single color.
//------------------------------------------------------------------------

//------------------------------------------------------------------------
// Constructor: Legato_Structure_Color()
// Class constructor.
//
// Parameters:
//     RGB - A six character string of Red, Green and Blue values, eg: "FF2345".
//     
//     OR
//
//     R - Red value, 0 - 255.
//     G - Green value, 0 - 255.
//     B - Blue value, 0 - 255.
//------------------------------------------------------------------------
function Legato_Structure_Color()
{

	// What type of argument was passed in?
	if ( arguments.length == 1 && (typeof arguments[0] == "string" || arguments[0] instanceof String) )
	{

		this.R = parseInt( arguments[0].substring( 0, 2 ), 16 );
		this.G = parseInt( arguments[0].substring( 2, 4 ), 16 );
		this.B = parseInt( arguments[0].substring( 4, 6 ), 16 );

	}  // End if hex string.
	else if ( arguments.length == 3 )
	{

		this.R = arguments[0];
		this.G = arguments[1];
		this.B = arguments[2];

	}  // End if numbers passed in.
	else
	{

		this.R = null;
		this.G = null;
		this.B = null;

	}  // End if null passed in.

}


//------------------------------------------------------------------------
// Public Member Functions
//------------------------------------------------------------------------

//------------------------------------------------------------------------
// Function: toHexString()
// Returns the color as a string of hexidecimal values.
//------------------------------------------------------------------------
Legato_Structure_Color.prototype.toHexString = function()
{

	var R = (this.R < 16) ? "0" + this.R.toString( 16 ) : this.R.toString( 16 );
	var G = (this.G < 16) ? "0" + this.G.toString( 16 ) : this.G.toString( 16 );
	var B = (this.B < 16) ? "0" + this.B.toString( 16 ) : this.B.toString( 16 );

	return R + G + B;

}


//------------------------------------------------------------------------
// Class: Legato_Structure_Dimensions
// Handles a single set of dimensions.
//------------------------------------------------------------------------

//------------------------------------------------------------------------
// Constructor: Legato_Structure_Dimensions()
// Class constructor.
//
// Parameters:
//     width - The width to store.
//     height - The height to store.
//
//     OR
//
//     element - A DOM element, in which case it will store the dimensions
//               of that element at the time this structure was created.
//------------------------------------------------------------------------
function Legato_Structure_Dimensions()
{
	
	// What type of arguments passed in?
	if ( arguments.length == 2 )
	{

		// Store the passed in parameters.
		this.width   = arguments[0];
		this.height  = arguments[1];
		
	}  // End if a width and height.
	else if ( arguments.length == 1 )
	{
		
		var element = $( arguments[0] );

		// Get the element's dimensions.
		var dimensions = element.dimensions();
		this.width = dimensions[0];
		this.height = dimensions[1];
		
	}  // End if element passed in.

}


//------------------------------------------------------------------------
// Class: Legato_Structure_Position
// Handles a single position. For positioning objects relative to its
// containing element.
//------------------------------------------------------------------------

//------------------------------------------------------------------------
// Constructor: Legato_Structure_Position()
// Class constructor.
//
// Parameters:
//     top - The value from the top of the containing element.
//     right - The value from the right of the containing element.
//     bottom - The value from the bottom of the containing element.
//     left - The value from the left of the containing element.
//------------------------------------------------------------------------
function Legato_Structure_Position( top, right, bottom, left )
{

	// Store the passed in parameters.
	this.top     = top;
	this.right   = right;
	this.bottom  = bottom;
	this.left    = left;

}


//------------------------------------------------------------------------
// Class: Legato_Structure_Point
// Handles a single point.
//------------------------------------------------------------------------

//------------------------------------------------------------------------
// Constructor: Legato_Structure_Point()
// Class constructor.
//
// Parameters:
//     X - The X value of the point.
//     Y - The Y value of the point.
//------------------------------------------------------------------------
function Legato_Structure_Point( X, Y )
{

	// Store the passed in parameters.
	this.X = X;
	this.Y = Y;

}


//------------------------------------------------------------------------
// Class: Legato_Structure_Region
// Handles a single region.
//------------------------------------------------------------------------

//------------------------------------------------------------------------
// Constructor: Legato_Structure_Region()
// Class constructor.
//
// Parameters:
//     min_point - The <Legato_Structure_Point> of the top left corner.
//     max_point - The <Legato_Structure_Point> of the bottom right corner.
//
//     OR
//
//     element - A DOM element, in which case the region will be the
//               containing region of the element.
//------------------------------------------------------------------------
function Legato_Structure_Region()
{

	// What was passed in?
	if ( arguments.length == 2 )
	{

		// Store the passed in parameters.
	  this.min_point  = arguments[0];
	  this.max_point  = arguments[1];

	}  // End if points passed in.
	else if ( arguments.length == 1 )
	{

		var element = $( arguments[0] );

		// Get the element's position for the region's min point.
		this.min_point = this.element.position();
		this.min_point = new Legato_Structure_Point( this.min_point[0], this.min_point[1] );

		// Get the max point for the region.
		var dimensions = element.dimensions();
		this.max_point = new Legato_Structure_Point( (this.min_point.X + dimensions[0]), (this.min_point.Y + dimensions[1]) );

	}  // End if HTML element passed in.

}


//------------------------------------------------------------------------
// Public Member Functions
//------------------------------------------------------------------------

//------------------------------------------------------------------------
// Function: intersectRegion()
// Used to test if two <Legato_Structure_Region> objects are intersecting
// each other.
//
// Parameters:
//     region - The <Legato_Structure_Region> that you'd like to test for
//              intersection against this object.
//     in_test - (Optional) If this is set to true, the region passed in
//               must be fully contained by this object.
//     epsilon - (Optional) This is the allowable mistake that can happen
//               between the tests, eg: if this is 1, then if the region
//               is 1 pixel away from intersecting, this function will
//               still return true.
//------------------------------------------------------------------------
Legato_Structure_Region.prototype.intersectRegion = function( region, in_test, epsilon )
{

	// Get the epsilon.
	epsilon = (epsilon) ? epsilon : 0;

	// Only do this if we are testing if it's completely contained.
	if ( in_test )
	{

	  var contained = true;

		// Is the region completely contained in this region?
		if ( region.min_point.X < (this.min_point.X + epsilon) || region.min_point.X > (this.max_point.X + epsilon) ) contained = false;
		else if ( region.min_point.Y < (this.min_point.Y + epsilon) || region.min_point.Y > (this.max_point.Y + epsilon) ) contained = false;
		else if ( region.max_point.X < (this.min_point.X + epsilon) || region.max_point.X > (this.max_point.X + epsilon) ) contained = false;
		else if ( region.max_point.Y < (this.min_point.Y + epsilon) || region.max_point.Y > (this.max_point.Y + epsilon) ) contained = false;

		// Return.
		return contained;

	}  // End if completely contained test.
	else
	{

		// Perform the intersection test.
		return ((this.min_point.X + epsilon) <= region.max_point.X) &&
						((this.min_point.Y + epsilon) <= region.max_point.Y) &&
						((this.max_point.X + epsilon) >= region.min_point.X) &&
						((this.max_point.Y + epsilon) >= region.min_point.Y);

	}  // End normal touching test.

}


//------------------------------------------------------------------------
// Function: containsPoint()
// Used to test if there is an <Legato_Structure_Point> object within the
// bounds of this region.
//
// Parameters:
//     point - The <Legato_Structure_Point> object.
//------------------------------------------------------------------------
Legato_Structure_Region.prototype.containsPoint = function( point )
{

	var contained = true;

	// Is the point completely contained in this region?
	if ( this.min_point.X > point.X || this.max_point.X < point.X ) contained = false;
	if ( this.min_point.Y > point.Y || this.max_point.Y < point.Y ) contained = false;

	// Return.
	return contained;

}


// Developed by Robert Nyman/DOMAssistant team, code/licensing: http://code.google.com/p/domassistant/, documentation: http://www.domassistant.com/documentation, version 2.7.4
var DOMAssistant=function(){var G=function(){};var C=/*@cc_on!@*/false;var F=C&&parseFloat(navigator.appVersion)<6;var B={},K={},A=true;var J={accesskey:"accessKey","class":"className",colspan:"colSpan","for":"htmlFor",maxlength:"maxLength",readonly:"readOnly",rowspan:"rowSpan",tabindex:"tabIndex",valign:"vAlign",cellspacing:"cellSpacing",cellpadding:"cellPadding"};var I={rules:/\s*(,)\s*/g,selector:/^(\w+)?(#[\w\u00C0-\uFFFF\-\_]+|(\*))?((\.[\w\u00C0-\uFFFF\-_]+)*)?((\[\w+\s*(\^|\$|\*|\||~)?(=\s*([\w\u00C0-\uFFFF\s\-\_\.]+|"[^"]*"|'[^']*'))?\]+)*)?(((:\w+[\w\-]*)(\((odd|even|\-?\d*n?((\+|\-)\d+)?|[\w\u00C0-\uFFFF\-_\.]+|"[^"]*"|'[^']*'|((\w*\.[\w\u00C0-\uFFFF\-_]+)*)?|(\[#?\w+(\^|\$|\*|\||~)?=?[\w\u00C0-\uFFFF\s\-\_\.\'\"]+\]+)|(:\w+[\w\-]*))\))?)*)?(>|\+|~)?/,id:/^#([\w\u00C0-\uFFFF\-\_]+)$/,tag:/^(\w+)/,relation:/^(>|\+|~)$/,pseudo:/^:(\w[\w\-]*)(\((.+)\))?$/,pseudos:/:(\w[\w\-]*)(\(([^\)]+)\))?/g,attribs:/\[(\w+)\s*(\^|\$|\*|\||~)?=?\s*([\w\u00C0-\uFFFF\s\-_\.]+|"[^"]*"|'[^']*')?\]/g,classes:/\.([\w\u00C0-\uFFFF\-_]+)/g,quoted:/^["'](.*)["']$/,nth:/^((odd|even)|([1-9]\d*)|((([1-9]\d*)?)n([\+\-]\d+)?)|(\-(([1-9]\d*)?)n\+(\d+)))$/};var E=function(M,L){M.push.apply(M,[].slice.apply(L));return M};if(C){E=function(N,M){if(M.slice){return N.concat(M)}var L=0,O;while((O=M[L++])){N[N.length]=O}return N}}var D=function(O,N){if(O.indexOf){return O.indexOf(N)>=0}for(var M=0,L=O.length;M<L;M++){if(O[M]===N){return true}}return false};var H=function(N,L){var M=N.parentNode;return L===document||M===L||(M!==document&&H(M,L))};return{isIE:C,camel:J,allMethods:[],publicMethods:["cssSelect","elmsByClass","elmsByAttribute","elmsByTag"],initCore:function(){this.applyMethod.call(window,"$",this.$);this.applyMethod.call(window,"$$",this.$$);window.DOMAssistant=this;if(C){G=Array}G.prototype=[];G.prototype.each=function(N){for(var M=0,L=this.length;M<L;M++){N.call(this[M])}return this};G.prototype.first=function(){return(typeof this[0]!=="undefined")?DOMAssistant.addMethodsToElm(this[0]):null};G.prototype.end=function(){return this.previousSet};this.attach(this)},addMethods:function(L,M){if(typeof this.allMethods[L]==="undefined"){this.allMethods[L]=M;this.addHTMLArrayPrototype(L,M)}},addMethodsToElm:function(M){for(var L in this.allMethods){if(typeof this.allMethods[L]!=="undefined"){this.applyMethod.call(M,L,this.allMethods[L])}}return M},applyMethod:function(M,L){if(typeof this[M]!=="function"){this[M]=L}},attach:function(N){var L=N.publicMethods;if(typeof L==="undefined"){for(var P in N){if(P!=="init"&&typeof N[P]!=="undefined"){this.addMethods(P,N[P])}}}else{if(L.constructor===Array){for(var M=0,O;(O=L[M]);M++){this.addMethods(O,N[O])}}}if(typeof N.init==="function"){N.init()}},addHTMLArrayPrototype:function(L,M){G.prototype[L]=function(){var P=new G();P.previousSet=this;var Q;for(var O=0,N=this.length;O<N;O++){Q=M.apply(this[O],arguments);if(!!Q&&Q.constructor===Array){P=E(P,Q)}else{P.push(Q)}}return P}},clearHandlers:function(){var Q=this.all||this.getElementsByTagName("*");for(var P=0,R,L;(R=Q[P++]);){if((L=R.attributes)){for(var N=0,O=L.length,M;N<O;N++){M=L[N].nodeName.toLowerCase();if(typeof R[M]==="function"){R[M]=null}}}}},setCache:function(L){A=L},$:function(){var O=arguments[0];if(arguments.length===1&&(typeof O==="object"||(typeof O==="function"&&!!O.nodeName))){return DOMAssistant.$$(O)}var Q=new G();for(var M=0,L,P;(L=arguments[M]);M++){if(typeof L==="string"){L=L.replace(/^[^#]*(#)/,"$1");if(I.id.test(L)){if((P=DOMAssistant.$$(L.substr(1),false))){Q.push(P)}}else{var N=(document.all||document.getElementsByTagName("*")).length;Q=(!document.querySelectorAll&&A&&K.rule&&K.rule===L&&K.doc===N)?K.elms:E(Q,DOMAssistant.cssSelection.call(document,L));K={rule:L,elms:Q,doc:N}}}}return Q},$$:function(Q,N){var P=(typeof Q==="object"||(typeof Q==="function"&&!!Q.nodeName))?Q:document.getElementById(Q);var O=N||true;if(typeof Q==="string"&&P&&P.id!==Q){P=null;for(var L=0,M;(M=document.all[L]);L++){if(M.id===Q){P=M;break}}}if(P&&O){DOMAssistant.addMethodsToElm(P)}return P},getSequence:function(P){var Q,O=2,M=-1,L=-1,N=I.nth.exec(P.replace(/^0n\+/,"").replace(/^2n$/,"even").replace(/^2n+1$/,"odd"));if(!N){return null}if(N[2]){Q=(N[2]==="odd")?1:2;L=(Q===1)?1:0}else{if(N[3]){Q=parseInt(N[3],10);O=0;M=Q}else{if(N[4]){O=N[6]?parseInt(N[6],10):1;Q=N[7]?parseInt(N[7],10):0;while(Q<1){Q+=O}L=(Q>O)?(Q-O)%O:((Q===O)?0:Q)}else{if(N[8]){O=N[10]?parseInt(N[10],10):1;Q=M=parseInt(N[11],10);while(Q>O){Q-=O}L=(M>O)?(M-O)%O:((M===O)?0:M)}}}}return{start:Q,add:O,max:M,modVal:L}},cssByDOM:function(L){var AL=L.replace(I.rules,"$1").split(",");var AD=new G(),At=[],AI=[];var y,AU,X,T,d,Ax,N,Ak,Q,Z,M,Au,AO,O,AK;try{y=new RegExp("(?:\\[[^\\[]*\\]|\\(.*\\)|[^\\s\\+>~\\[\\(])+|[\\+>~]","g")}catch(Am){y=/[^\s]+/g}function AR(i){i=i||At;for(var e=0,a=i.length;e<a;e++){i[e].added=null}}function S(){for(var e=0,a=AU.length;e<a;e++){AU[e].childElms=null}}function Aq(k,a){for(var l=0,o;(o=k[l]);l++){var n=false;for(var e=0,m;(m=a[e]);e++){if(m===o){n=true;a.splice(e,1);break}}if(n){k.splice(l--,1)}}return k}function U(e,a){return C?e[J[a.toLowerCase()]||a]:e.getAttribute(a,2)}function g(a,e){a=a?a.replace(I.quoted,"$1").replace(/\./g,"\\."):null;switch(e){case"^":return"^"+a;case"$":return a+"$";case"*":return a;case"|":return"^"+a+"(\\-\\w+)*$";case"~":return"\\b"+a+"\\b";default:return a?"^"+a+"$":null}}function v(a,e){return F?((a==="*")?e.all:e.all.tags(a)):e.getElementsByTagName(a)}function AM(a,e){a=a||"*";e=e||document;return(e===document||e.lastModified)?B[a]||(B[a]=v(a,document)):v(a,e)}function Av(m,A5,j){AU=[];var k=A5.split("-"),r=[],AW=0,A4,AV;var l=(A4=/\-of\-type$/.test(A5))?"nodeName":"nodeType";function A6(A8){var A7=A4?A8.nodeName:1;while((A8=A8.previousSibling)&&A8[l]!==A7){}return A8}function q(A8){var A7=A4?A8.nodeName:1;while((A8=A8.nextSibling)&&A8[l]!==A7){}return A8}var o={first:function(A7){return !A6(A7)},last:function(A7){return !q(A7)},empty:function(A7){return !A7.childNodes.length},enabled:function(A7){return !Q.disabled&&Q.type!=="hidden"},disabled:function(A7){return Q.disabled},checked:function(A7){return Q.checked},contains:function(A7){return(Q.innerText||Q.textContent||"").indexOf(j.replace(I.quoted,"$1"))>-1},other:function(A7){return U(Q,A5)===j}};function i(A7){while((Q=m[AW++])){if(o[A7](Q)){r[r.length]=Q}}return r}var A1=k[0]||null;if(A1&&o[A1]){return i(A1)}switch(A1){case"only":var s;while((Q=m[AW++])){Z=Q.parentNode;if(Z!==s){if(!A6(Q)&&!q(Q)){r[r.length]=Q}s=Z}}break;case"nth":if(/^n$/.test(j)){r=m}else{var A3=(k[1]==="last")?["lastChild","previousSibling"]:["firstChild","nextSibling"];AK=DOMAssistant.getSequence.call(this,j);if(AK){while((Q=m[AW++])){Z=Q.parentNode;if(!Z.childElms){var A0=0,AX=Q.nodeName;AO=AK.start;O=Z[A3[0]];while(O&&(AK.max<0||AO<=AK.max)){var A2=O.nodeName;if((A4&&A2===AX)||(!A4&&O.nodeType===1)){if(++A0===AO){if(A2===AX){r[r.length]=O}AO+=AK.add}}O=O[A3[1]]}Z.childElms=true;AU[AU.length]=Z}}S()}}break;case"target":var e=document.location.hash.slice(1);if(e){while((Q=m[AW++])){if(U(Q,"name")===e||U(Q,"id")===e){r[r.length]=Q;break}}}break;case"not":if((AV=I.pseudo.exec(j))){r=Aq(m,Av(m,AV[1]?AV[1].toLowerCase():null,AV[3]||null))}else{for(var AY in I){if(I[AY].lastIndex){I[AY].lastIndex=0}}j=j.replace(I.id,"[id=$1]");var u=I.tag.exec(j);var n=I.classes.exec(j);var t=I.attribs.exec(j);var a=new RegExp(t?g(t[3],t[2]):"(^|\\s)"+(u?u[1]:n?n[1]:"")+"(\\s|$)","i");while((M=m[AW++])){Au=null;if(u&&!a.test(M.nodeName)){Au=M}else{if(n&&!a.test(M.className)){Au=M}else{if(t){var AZ=U(M,t[1]);if(!AZ||!a.test(AZ)){Au=M}}}}if(Au&&!Au.added){Au.added=true;r[r.length]=Au}}}break;default:return i("other")}return r}for(var Ao=0;(X=AL[Ao]);Ao++){if(Ao&&D(AL.slice(0,Ao),X)){continue}At=[this];T=X.match(y);for(var Al=0,V;(V=T[Al]);Al++){AI=[];if(Al>0&&I.relation.test(V)){if((d=I.relation.exec(V))){var Ar=null,AS=T[Al+1];if((Ax=I.tag.exec(AS))){Ax=Ax[1];N=new RegExp("(^|\\s)"+Ax+"(\\s|$)","i")}else{if(I.id.test(AS)){Ar=DOMAssistant.$(AS)||null}}for(var Aj=0,c;(c=At[Aj]);Aj++){switch(d[0]){case">":var AF=Ar||AM(Ax,c);for(var Ah=0,AA;(AA=AF[Ah]);Ah++){if(AA.parentNode===c){AI[AI.length]=AA}}break;case"+":while((c=c.nextSibling)&&c.nodeType!==1){}if(c){if((Ar&&Ar[0]===c)||(!Ar&&(!Ax||N.test(c.nodeName)))){AI[AI.length]=c}}break;case"~":while((c=c.nextSibling)&&!c.added){if((Ar&&Ar[0]===c)||(!Ar&&(!Ax||N.test(c.nodeName)))){c.added=true;AI[AI.length]=c}}break}}At=AI;AR();V=T[++Al];if(/^\w+$/.test(V)||I.id.test(V)){continue}At.skipTag=true}}var Aw=I.selector.exec(V);var AH={tag:(!Aw[1]||Aw[3]==="*")?"*":Aw[1],id:(Aw[3]!=="*")?Aw[2]:null,allClasses:Aw[4],allAttr:Aw[6],allPseudos:Aw[11]};if(AH.id){var f=0,Ap=document.getElementById(AH.id.replace(/#/,""));if(Ap){while(At[f]&&!H(Ap,At[f])){f++}AI=(f<At.length)?[Ap]:[]}At=AI}else{if(AH.tag&&!At.skipTag){if(Al===0&&!AI.length&&At.length===1){At=AI=E([],AM(AH.tag,At[0]))}else{for(var Ag=0,AP=At.length,AB,Ay;Ag<AP;Ag++){AB=AM(AH.tag,At[Ag]);for(var Ad=0;(Ay=AB[Ad]);Ad++){if(!Ay.added){Ay.added=true;AI[AI.length]=Ay}}}At=AI;AR()}}}if(!AI.length){break}At.skipTag=false;if(AH.allClasses){var Ac=0,Ae=[],Y=AH.allClasses.split(".").slice(1);while((Ak=At[Ac++])){var Ai=true,Az=Ak.className;if(Az&&Az.length){Az=Az.split(" ");for(var Aa=0,Ab=Y.length;Aa<Ab;Aa++){if(!D(Az,Y[Aa])){Ai=false;break}}if(Ai){Ae[Ae.length]=Ak}}}At=AI=Ae}if(AH.allAttr){var w=0,AE=[],Af=[],AJ=AH.allAttr.match(/\[[^\]]+\]/g);for(var z=0,P=AJ.length,x,AQ;z<P;z++){I.attribs.lastIndex=0;x=I.attribs.exec(AJ[z]);AQ=g(x[3],x[2]||null);AE[z]=[(AQ?new RegExp(AQ):null),x[1]]}while((Ak=AI[w++])){for(var p=0,AG=AE.length;p<AG;p++){var R=true,AC=AE[p][0],An=U(Ak,AE[p][1]);if(!AC&&An===true){continue}if((!AC&&(!An||typeof An!=="string"||!An.length))||(!!AC&&!AC.test(An))){R=false;break}}if(R){Af[Af.length]=Ak}}At=AI=Af}if(AH.allPseudos){var W=AH.allPseudos.match(I.pseudos);for(var h=0,As=W.length;h<As;h++){I.pseudos.lastIndex=0;var AT=I.pseudos.exec(W[h]);var b=AT[1]?AT[1].toLowerCase():null;var AN=AT[3]||null;AI=Av(AI,b,AN);AR(AI)}At=AI}}AD=E(AD,At)}return AD},cssByXpath:function(M){var N={xhtml:"http://www.w3.org/1999/xhtml"};var O=(document.documentElement.namespaceURI===N.xhtml)?"xhtml:":"";var L=function P(Q){return N[Q]||null};DOMAssistant.cssByXpath=function(l){if(/:checked/.test(l)){return DOMAssistant.cssByDOM.call(this,l)}var X=l.replace(I.rules,"$1").split(",");var W=new G();var p,r,f,U,V,Z;var q=new RegExp("(?:\\[[^\\[]*\\]|\\(.*\\)|[^\\s\\+>~\\[\\(])+|[\\+>~]","g");function h(i,t,k,j){j=j?j.replace(I.quoted,"$1"):j;switch(k){case"^":return"starts-with(@"+t+', "'+j+'")';case"$":return"substring(@"+t+", (string-length(@"+t+") - "+(j.length-1)+"), "+j.length+') = "'+j+'"';case"*":return'contains(concat(" ", @'+t+', " "), "'+j+'")';case"|":return"(@"+t+'="'+j+'" or starts-with(@'+t+', "'+j+'-"))';case"~":return'contains(concat(" ", @'+t+', " "), " '+j+' ")';default:return"@"+t+(j?'="'+j+'"':"")}}function T(i,t,k,j){return"["+h(i,t,k,j)+"]"}function n(y,x,k){y=/\-child$/.test(x)?"*":y;var t="",v=x.split("-"),u;switch(v[0]){case"nth":if(!/^n$/.test(k)){var j=((v[1]==="last")?"(count(following-sibling::":"(count(preceding-sibling::")+y+") + 1)";if((Z=DOMAssistant.getSequence.call(this,k))){t=(Z.start===Z.max)?j+" = "+Z.start:j+" mod "+Z.add+" = "+Z.modVal+((Z.start>1)?" and "+j+" >= "+Z.start:"")+((Z.max>0)?" and "+j+" <= "+Z.max:"")}}break;case"not":var w=(u=I.pseudo.exec(k))?n(y,u[1]?u[1].toLowerCase():null,u[3]||null):k.replace(I.id,"[id=$1]").replace(I.tag,"self::$1").replace(I.classes,'contains(concat(" ", @class, " "), " $1 ")').replace(I.attribs,h);t="not("+w+")";break;case"first":return"not(preceding-sibling::"+y+")";case"last":return"not(following-sibling::"+y+")";case"only":return"not(preceding-sibling::"+y+" or following-sibling::"+y+")";case"empty":return"count(child::*) = 0 and string-length(text()) = 0";case"contains":return'contains(., "'+k.replace(I.quoted,"$1")+'")';case"enabled":return'not(@disabled) and not(@type="hidden")';case"disabled":return"@disabled";case"target":var i=document.location.hash.slice(1);return'@name="'+i+'" or @id="'+i+'"';default:return"@"+x+'="'+k+'"'}return t}for(var m=0;(p=X[m]);m++){if(m&&D(X.slice(0,m),p)){continue}r=p.match(q);f=".";for(var g=0,o=r.length;g<o;g++){U=I.selector.exec(r[g]);V={tag:O+((!U[1]||U[3]==="*")?"*":U[1]),id:(U[3]!=="*")?U[2]:null,allClasses:U[4],allAttr:U[6],allPseudos:U[11],tagRelation:U[23]};if(V.tagRelation){var a={">":"/child::","+":"/following-sibling::*[1]/self::","~":"/following-sibling::"};f+=a[V.tagRelation]||""}else{f+=(g>0&&I.relation.test(r[g-1]))?V.tag:("/descendant::"+V.tag)}if(V.id){f+='[@id = "'+V.id.replace(/^#/,"")+'"]'}if(V.allClasses){f+=V.allClasses.replace(I.classes,'[contains(concat(" ", @class, " "), " $1 ")]')}if(V.allAttr){f+=V.allAttr.replace(I.attribs,T)}if(V.allPseudos){var Y=V.allPseudos.match(I.pseudos);for(var e=0,R=Y.length;e<R;e++){I.pseudos.lastIndex=0;var S=I.pseudos.exec(Y[e]);var s=S[1]?S[1].toLowerCase():null;var Q=S[3]||null;var b=n(V.tag,s,Q);if(b.length){f+="["+b+"]"}}}}var d=document.evaluate(f,this,L,0,null),c;while((c=d.iterateNext())){W.push(c)}}return W};return DOMAssistant.cssByXpath.call(this,M)},cssSelection:function(M){DOMAssistant.cssSelection=document.evaluate?DOMAssistant.cssByXpath:DOMAssistant.cssByDOM;if(document.querySelectorAll){var L=DOMAssistant.cssSelection;DOMAssistant.cssSelection=function(N){try{var P=new G();return E(P,this.querySelectorAll(N))}catch(O){return L.call(this,N)}}}return DOMAssistant.cssSelection.call(this,M)},cssSelect:function(L){return DOMAssistant.cssSelection.call(this,L)},elmsByClass:function(N,L){var M=(L||"")+"."+N;return DOMAssistant.cssSelection.call(this,M)},elmsByAttribute:function(M,N,L,P){var O=(L||"")+"["+M+((N&&N!=="*")?((P||"")+"="+N+"]"):"]");return DOMAssistant.cssSelection.call(this,O)},elmsByTag:function(L){return DOMAssistant.cssSelection.call(this,L)}}}();DOMAssistant.initCore();DOMAssistant.AJAX=function(){var globalXMLHttp=null;var readyState=0;var status=-1;var statusText="";var requestPool=[];var createAjaxObj=function(url,method,callback,addToContent){var params=null;if(/POST/i.test(method)){url=url.split("?");params=url[1];url=url[0]}return{url:url,method:method,callback:callback,params:params,headers:{},responseType:"text",addToContent:addToContent||false}};var inProgress=function(xhr){return(!!xhr&&xhr.readyState>=1&&xhr.readyState<=3)};return{publicMethods:["ajax","get","post","load"],initRequest:function(){var XMLHttp=null;if(!!window.XMLHttpRequest){XMLHttp=new XMLHttpRequest();DOMAssistant.AJAX.initRequest=function(){return requestPool.length?requestPool.pop():new XMLHttpRequest()}}else{if(!!window.ActiveXObject){var XMLHttpMS=["Msxml2.XMLHTTP.6.0","Msxml2.XMLHTTP.3.0","Msxml2.XMLHTTP","Microsoft.XMLHTTP"];for(var i=0;i<XMLHttpMS.length;i++){try{XMLHttp=new window.ActiveXObject(XMLHttpMS[i]);DOMAssistant.AJAX.initRequest=function(){return requestPool.length?requestPool.pop():new window.ActiveXObject(XMLHttpMS[i])};break}catch(e){XMLHttp=null}}}}return XMLHttp},ajax:function(ajaxObj){if(!ajaxObj.noParse&&ajaxObj.url&&/\?/.test(ajaxObj.url)&&ajaxObj.method&&/POST/i.test(ajaxObj.method)){var url=ajaxObj.url.split("?");ajaxObj.url=url[0];ajaxObj.params=url[1]+((url[1].length>0&&ajaxObj.params)?("&"+ajaxObj.params):"")}return DOMAssistant.AJAX.makeCall.call(this,ajaxObj)},get:function(url,callback,addToContent){var ajaxObj=createAjaxObj(url,"GET",callback,addToContent);return DOMAssistant.AJAX.makeCall.call(this,ajaxObj)},post:function(url,callback){var ajaxObj=createAjaxObj(url,"POST",callback);return DOMAssistant.AJAX.makeCall.call(this,ajaxObj)},load:function(url,addToContent){DOMAssistant.AJAX.get.call(this,url,DOMAssistant.AJAX.replaceWithAJAXContent,addToContent)},makeCall:function(ajaxObj){var XMLHttp=DOMAssistant.AJAX.initRequest();if(XMLHttp){globalXMLHttp=XMLHttp;(function(elm){var url=ajaxObj.url,method=ajaxObj.method||"GET",callback=ajaxObj.callback,params=ajaxObj.params,headers=ajaxObj.headers,responseType=ajaxObj.responseType||"text",addToContent=ajaxObj.addToContent,timeout=ajaxObj.timeout||null,ex=ajaxObj.exception,timeoutId=null;XMLHttp.open(method,url,true);XMLHttp.setRequestHeader("AJAX","true");XMLHttp.setRequestHeader("X-Requested-With","XMLHttpRequest");if(method==="POST"){var contentLength=params?params.length:0;XMLHttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");XMLHttp.setRequestHeader("Content-length",contentLength);if(XMLHttp.overrideMimeType){XMLHttp.setRequestHeader("Connection","close")}}if(responseType==="json"){XMLHttp.setRequestHeader("Accept","application/json, text/javascript, */*")}for(var i in headers){if(typeof i==="string"){XMLHttp.setRequestHeader(i,headers[i])}}if(typeof callback==="function"){XMLHttp.onreadystatechange=function(){try{if(XMLHttp.readyState===4){window.clearTimeout(timeoutId);status=XMLHttp.status;statusText=XMLHttp.statusText;readyState=4;if(!status||status!==200){throw new Error(statusText)}var response=/xml/i.test(responseType)?XMLHttp.responseXML:XMLHttp.responseText;if(/json/i.test(responseType)){response=(typeof JSON==="object"&&typeof JSON.parse==="function")?JSON.parse(response):eval("("+response+")")}globalXMLHttp=null;XMLHttp.onreadystatechange=function(){};requestPool.push(XMLHttp);callback.call(elm,response,addToContent)}}catch(e){globalXMLHttp=XMLHttp=null;if(typeof ex==="function"){ex.call(elm,e);ex=null}}}}XMLHttp.send(params);if(timeout){timeoutId=window.setTimeout(function(){if(inProgress(XMLHttp)){XMLHttp.abort();if(typeof ex==="function"){readyState=0;status=408;statusText="Request timeout";globalXMLHttp=XMLHttp=null;ex.call(elm,new Error(statusText));ex=null}}},timeout)}})(this)}return this},replaceWithAJAXContent:function(content,add){if(add){this.innerHTML+=content}else{DOMAssistant.clearHandlers.apply(this);this.innerHTML=content}},getReadyState:function(){return(globalXMLHttp&&typeof globalXMLHttp.readyState!=="undefined")?globalXMLHttp.readyState:readyState},getStatus:function(){return status},getStatusText:function(){return statusText}}}();DOMAssistant.attach(DOMAssistant.AJAX);DOMAssistant.CSS=function(){return{addClass:function(B){if(!DOMAssistant.CSS.hasClass.call(this,B)){var A=this.className;this.className=A+(A.length?" ":"")+B}return this},removeClass:function(A){return DOMAssistant.CSS.replaceClass.call(this,A)},replaceClass:function(B,C){var A=new RegExp(("(^|\\s)"+B+"(\\s|$)"),"i");this.className=this.className.replace(A,function(D,G,F){var E=C?(G+C+F):"";if(/^\s+.*\s+$/.test(D)){E=D.replace(/(\s+).+/,"$1")}return E}).replace(/^\s+|\s+$/g,"");return this},hasClass:function(A){return new RegExp(("(^|\\s)"+A+"(\\s|$)"),"i").test(this.className)},setStyle:function(C,D){if(this.filters&&(typeof C==="string"?/opacity/i.test(C):C.opacity)){this.style.filter="alpha(opacity="+(D||C.opacity||1)*100+")"}if(typeof this.style.cssText!=="undefined"){var A=this.style.cssText;if(typeof C==="object"){for(var B in C){if(typeof B==="string"){A+=";"+B+":"+C[B]}}}else{A+=";"+C+":"+D}this.style.cssText=A}return this},getStyle:function(A){var C="";A=A.toLowerCase();if(document.defaultView&&document.defaultView.getComputedStyle){C=document.defaultView.getComputedStyle(this,"").getPropertyValue(A)}else{if(this.currentStyle){if(this.filters&&/^opacity$/.test(A)){var B=this.filters["DXImageTransform.Microsoft.Alpha"]||this.filters.alpha||{};C=(B.opacity||100)/100}else{A=A.replace(/^float$/,"styleFloat").replace(/\-(\w)/g,function(D,E){return E.toUpperCase()});C=this.currentStyle[A]}if(C==="auto"&&/^(width|height)$/.test(A)&&this.currentStyle.display!=="none"){C=this["offset"+A.charAt(0).toUpperCase()+A.substr(1)]+"px"}}}return C}}}();DOMAssistant.attach(DOMAssistant.CSS);DOMAssistant.Content=function(){var A=DOMAssistant.$;return{init:function(){DOMAssistant.setCache(false)},prev:function(){var B=this;while((B=B.previousSibling)&&B.nodeType!==1){}return A(B)},next:function(){var B=this;while((B=B.nextSibling)&&B.nodeType!==1){}return A(B)},create:function(D,C,B,E){var F=A(document.createElement(D));if(C){F=F.setAttributes(C)}if(typeof E!=="undefined"){F.addContent(E)}if(B){DOMAssistant.Content.addContent.call(this,F)}return F},setAttributes:function(B){if(DOMAssistant.isIE){var C=function(G,E,F){var D=E.toLowerCase();switch(D){case"name":case"type":return document.createElement(G.outerHTML.replace(new RegExp(D+"=[a-zA-Z]+")," ").replace(">"," "+D+"="+F+">"));case"style":G.style.cssText=F;return G;default:G[DOMAssistant.camel[D]||E]=F;return G}};DOMAssistant.Content.setAttributes=function(D){var H=this;var G=this.parentNode;for(var F in D){if(typeof D[F]==="string"||typeof D[F]==="number"){var E=C(H,F,D[F]);if(G&&/(name|type)/i.test(F)){if(H.innerHTML){E.innerHTML=H.innerHTML}G.replaceChild(E,H)}H=E}}return A(H)}}else{DOMAssistant.Content.setAttributes=function(D){for(var E in D){if(/class/i.test(E)){this.className=D[E]}else{this.setAttribute(E,D[E])}}return this}}return DOMAssistant.Content.setAttributes.call(this,B)},addContent:function(C){var B=typeof C;if(B==="string"||B==="number"){this.innerHTML+=C}else{if(B==="object"||(B==="function"&&!!C.nodeName)){this.appendChild(C)}}return this},replaceContent:function(B){DOMAssistant.clearHandlers.apply(this);this.innerHTML="";return DOMAssistant.Content.addContent.call(this,B)},replace:function(G,B){var F=typeof G;if(F==="string"||F==="number"){var E=this.parentNode;var D=A(E).create("div",null,false,G);for(var C=D.childNodes.length-1;C>=0;C--){E.insertBefore(D.childNodes[C],this.nextSibling)}G=this.nextSibling;E.removeChild(this)}else{if(F==="object"||(F==="function"&&!!G.nodeName)){this.parentNode.replaceChild(G,this)}}return B?G:this},remove:function(){this.parentNode.removeChild(this);return null}}}();DOMAssistant.attach(DOMAssistant.Content);DOMAssistant.Events=function(){var A=1;return{publicMethods:["triggerEvent","addEvent","removeEvent","preventDefault","cancelBubble"],init:function(){window.addEvent=this.addEvent;window.removeEvent=this.removeEvent;DOMAssistant.preventDefault=this.preventDefault;DOMAssistant.cancelBubble=this.cancelBubble},triggerEvent:function(C,F){if(this.events&&this.events[C]){var E={type:C,target:F||this,currentTarget:this,bubbles:false,cancelable:false,preventDefault:function(){},stopPropagation:function(){},timeStamp:+new Date()};for(var D=0,B=this.events[C].length;D<B;D++){this.events[C][D].call(this,E)}}else{if(typeof this["on"+C]==="function"){this["on"+C].call(this,E)}}return this},addEvent:function(B,D){if(/^DOM/.test(B)){if(this.addEventListener){this.addEventListener(B,D,false)}}else{if(!this.uniqueHandlerId){this.uniqueHandlerId=A++}if(!(D.attachedElements&&D.attachedElements[B+this.uniqueHandlerId])){if(!this.events){this.events={}}if(!this.events[B]){this.events[B]=[];var C=this["on"+B];if(C){this.events[B].push(C)}}this.events[B].push(D);this["on"+B]=DOMAssistant.Events.handleEvent;if(typeof this.window==="object"){this.window["on"+B]=DOMAssistant.Events.handleEvent}if(!D.attachedElements){D.attachedElements={}}D.attachedElements[B+this.uniqueHandlerId]=true}}return this},handleEvent:function(B){var G=B||event;var H=G.target||G.srcElement||document;while(H.nodeType!==1&&H.parentNode){H=H.parentNode}G.eventTarget=H;var C=this.events[G.type].slice(0),F,E;if((F=C.length)){for(var D=0;D<F;D++){if(typeof C[D]==="function"){E=C[D].call(this,G)}}return E}},removeEvent:function(B,F){if(this.events&&this.events[B]){var C=this.events[B];for(var E,D=C.length-1;D>=0;D--){E=F||C[D];if(C[D]===E){delete C[D];C.splice(D,1);if(E.attachedElements){E.attachedElements[B+this.uniqueHandlerId]=null}}}}else{if(this["on"+B]&&!F){this["on"+B]=null}}return this},preventDefault:function(B){if(B&&B.preventDefault){DOMAssistant.Events.preventDefault=function(C){C.preventDefault()}}else{DOMAssistant.Events.preventDefault=function(C){event.returnValue=false}}return DOMAssistant.Events.preventDefault(B)},cancelBubble:function(B){if(B&&B.stopPropagation){DOMAssistant.Events.cancelBubble=function(C){C.stopPropagation()}}else{DOMAssistant.Events.cancelBubble=function(C){event.cancelBubble=true}}return DOMAssistant.Events.cancelBubble(B)}}}();DOMAssistant.attach(DOMAssistant.Events);DOMAssistant.DOMLoad=function(){var DOMLoaded=false;var DOMLoadTimer=null;var functionsToCall=[];var addedStrings={};var errorHandling=null;var execFunctions=function(){for(var i=0,il=functionsToCall.length;i<il;i++){try{functionsToCall[i]()}catch(e){if(errorHandling&&typeof errorHandling==="function"){errorHandling(e)}}}functionsToCall=[]};var DOMHasLoaded=function(){if(DOMLoaded){return}DOMLoaded=true;execFunctions()};
/*@cc_on @if(@_win32||@_win64)if(document.getElementById){document.write("<script id=\"ieScriptLoad\" defer src=\"//:\"><\/script>");document.getElementById("ieScriptLoad").onreadystatechange=function(){if(this.readyState==="complete"){DOMHasLoaded()}}}@end@*/
if(document.addEventListener){document.addEventListener("DOMContentLoaded",DOMHasLoaded,false)}if(/KHTML|WebKit|iCab/i.test(navigator.userAgent)){DOMLoadTimer=setInterval(function(){if(/loaded|complete/i.test(document.readyState)){DOMHasLoaded();clearInterval(DOMLoadTimer)}},10)}window.onload=DOMHasLoaded;return{DOMReady:function(){for(var i=0,il=arguments.length,funcRef;i<il;i++){funcRef=arguments[i];if(!funcRef.DOMReady&&!addedStrings[funcRef]){if(typeof funcRef==="string"){addedStrings[funcRef]=true;funcRef=new Function(funcRef)}funcRef.DOMReady=true;functionsToCall.push(funcRef)}}if(DOMLoaded){execFunctions()}},setErrorHandling:function(funcRef){errorHandling=funcRef}}}();DOMAssistant.DOMReady=DOMAssistant.DOMLoad.DOMReady;


/*
	Class: Legato_DOM_Library
	Provides a plugin to DOMAssistant to allow extra features for working with the DOM.
*/
Legato_DOM_Library = {};

Legato_DOM_Library.DOMAssistantPlugIn = function ()
{

	return {

		/*
			Function: dimensions()
			Sets/gets the dimension's of the element.
			If no dimensions passed in, will return the element's dimensions.

			Syntax:
				*Getting Dimensions*

				array dimensions()

				*Setting Dimensions*

				object dimensions( int width, int height )

			Parameters:
				*Setting Dimensions*

				int width - The new width you'd like the element to have. Pass in null if you would like the width to stay the same.
				int height - The new height you'd like the element to have. Pass in null if you would like the height to stay the same.

			Returns:
				*Getting Dimensions*

				Returns an array of the dimensions, with the first item being the width and the second item being the height.

				*Setting Dimensions*

				Returns the element the dimensions were set on.

			Examples:
			(begin code)
				var dimensions = $$( 'container' ).dimensions();
				alert( dimensions[0] )  // Show the width of the container.
			(end)

			(begin code)
				// Set the height of the container to 300 pixels.
				$$( 'container' ).dimensions( null, 300 );
			(end)
		*/
		dimensions: function()
		{

			if ( this.window == window )
			{

				var width = window.innerWidth || (window.document.documentElement.clientWidth || window.document.body.clientWidth);
		        var height = window.innerHeight || (window.document.documentElement.clientHeight || window.document.body.clientHeight);

		        return [ width, height ];

			}
			else if ( arguments.length == 0 )
			{

				return [ this.offsetWidth, this.offsetHeight ];

			}
			else
			{

				if ( arguments[0] !== null ) this.setStyle( 'width', arguments[0] + 'px' );
				if ( arguments[1] !== null ) this.setStyle( 'height', arguments[1] + 'px' );
				return this;

			}

		},


		/*
			Function: position()
			Sets/gets the position of an element.
			If no position passed in, will return the current position of the element.

			Syntax:
				*Getting Position*

				array position()

				*Setting Position*

				object position( int X, int Y )

			Parameters:
				*Setting Position*

				int X - The new X value that you'd like the element to have. Pass in null if you would like the X position to stay the same.
				int Y - The new Y value that you'd like the element to have. Pass in null if you would like the Y position to stay the same.

			Returns:
				*Getting Position*

				Returns an array of the position, with the first item being the X value and the second item being the Y value.

				*Setting Position*

				Returns the element the position was set on.

			Notes:
				This function works off of the page grid and not the containing element. So, setting an X value of 50 would put the element
				50 pixels from the top of the page.

			Examples:
			(begin code)
				// Show the position of the container element.
				var pos = $$( 'container' ).position();
				alert( pos[0] + ' | ' + pos[1] );

				// Set the Y position to 50 pixels.
				$$( 'container' ).position( null, 50 );
			(end)
		*/
		position: function()
		{

			if ( arguments.length == 0 )
			{

				var offsetLeft = offsetTop = 0;
				var elem = this;

				if ( elem.offsetParent )
				{
					do
					{
						offsetLeft += elem.offsetLeft;
						offsetTop += elem.offsetTop;
					}
					while ( elem = elem.offsetParent );
				}

				return [ offsetLeft, offsetTop ];

			}
			else
			{

				// Get the positioning of this element.
				var positioning = this.getStyle( 'position' );

				// If it's statically positioned, we change it to relative positioning.
				// If it's absolute, we leave it.
                if ( positioning == 'static' )
				{
					positioning = 'relative';
                    this.setStyle( 'position', 'relative' );
                }

                // Try to get the offset value.
                var offset =
				[
                    parseInt( this.getStyle( 'left' ), 10 ),
                    parseInt( this.getStyle( 'top' ), 10 )
                ];

            	// If auto was returned, retrieve the correct offset.
                if ( isNaN( offset[0] ) )
                    offset[0] = (positioning == 'relative') ? 0 : this.offsetLeft;

                // If auto was returned, retrieve the correct offset.
                if ( isNaN( offset[1] ) )
                    offset[1] = (positioning == 'relative') ? 0 : this.offsetTop;

                // Get the page XY position of the element.
                var posXY = this.position();

                // If a new X or Y value was passed in, set it.
                if ( arguments[0] !== null ) this.setStyle( 'left', arguments[0] - posXY[0] + offset[0] + 'px' );
                if ( arguments[1] !== null ) this.setStyle( 'top', arguments[1] - posXY[1] + offset[1] + 'px' );

                return this;

			}

		},


		/*
			Function: opacity()
			Sets/gets the opacity of an element.
			If no opacity passed in, will return the current opacity of the element.

			Syntax:
				*Getting Opacity*

				float opacity()

				*Setting Opacity*

				object opacity( float opacity )

			Parameters:
				*Setting Opacity*

				float opacity - The new opacity you'd like the element to have. This parameter should be a value between 0 and 1.

			Returns:
				*Getting Opacity*

				Returns the current opacity of the element as a value between 0 and 1.

				*Setting Opacity*

				Returns the element the opacity was set on.

			Examples:
			(begin code)
				// Show the opacity of the container element.
				alert( $$( 'container' ).opacity() );

				// Set the opacity of the container element to 50%.
				$$( 'container' ).opacity( 0.5 );
			(end)
		*/
		opacity: function()
		{

			if ( arguments.length == 0 )
			{

				// For all browsers besides IE.
				if ( !document.all )
					return this.getStyle( 'opacity' );

				// Below is for just IE.
				var value = 100;

                try { value = this.filters['DXImageTransform.Microsoft.Alpha'].opacity; }
				catch( e )
				{
                    try { value = this.filters( 'alpha' ).opacity; }
					catch( e ){}
                }

                return value / 100;

			}
			else
			{

				this.setStyle( 'opacity', arguments[0] );
				this.style.filter = 'alpha(opacity=' + arguments[0] * 100 + ')';  // For Internet Explorer.

				return this;

			}

		},


		/*
			Function: scrollOffset()
			Sets/gets the scroll offset of an element.
			If no offset passed in, will return the current offset of the element.

			Syntax:
				*Getting Offset*

				array scrollOffset()

				*Setting Offset*

				object scrollOffset( int X, int Y )

			Parameters:
				*Setting Offset*

				int X - The new X value that you'd like the element's scroll offset to be. Pass in null if you would like the X offset to stay the same.
				int Y - The new Y value that you'd like the element's scroll offset to be. Pass in null if you would like the Y offset to stay the same.

			Returns:
				*Getting Offset*

				Returns an array of the scroll offset, with the first item being the X offset and the second item being the Y offset.

				*Setting Offset*

				Returns the element the scroll offset was set on.

			Examples:
			(begin code)
				// Show the Y offset of the container element.
				alert( $$( 'container' ).position() );

				// Set the X offset to 75 pixels.
				$$( 'container' ).scrollOffset( 75, null );
			(end)
		*/
		scrollOffset: function()
		{

			if ( this.window == window || this == document.body )
			{

				var X = Y = 0;

				if( typeof( window.pageXOffset ) == 'number' )
				{
					X = window.pageXOffset;
					Y = window.pageYOffset;
				}  // Netscape.
				else if( document.body && ( document.body.scrollLeft || document.body.scrollTop ) )
				{
					X = document.body.scrollLeft;
					Y = document.body.scrollTop;
				}  // Standards compliant.
				else if( document.documentElement && ( document.documentElement.scrollLeft || document.documentElement.scrollTop ) )
				{
					X = document.documentElement.scrollLeft;
					Y = document.documentElement.scrollTop;
				}  // IE 6 standards mode.

				return [ X, Y ];

			}
			else if ( arguments.length == 0 )
			{

				return [ this.scrollLeft, this.scrollTop ];

			}
			else
			{

				if ( arguments[0] !== null ) this.scrollLeft = arguments[0];
				if ( arguments[1] !== null ) this.scrollTop = arguments[1];
				return this;

			}

		}

	};

}();

DOMAssistant.attach( Legato_DOM_Library.DOMAssistantPlugIn );
//------------------------------------------------------------------------
// Package: Animation
// For animating elements in the DOM in various ways.
//
// Topic: Dependencies
// - <Events Handler>
// - <Structures>
// - <DOM Library>
//------------------------------------------------------------------------

//------------------------------------------------------------------------
// Class: Legato_Animation_Controller
// Stores the animations parameters.
//------------------------------------------------------------------------

//------------------------------------------------------------------------
// Constructor: Legato_Animation_Controller()
// Class constructor. You don't need to instantiate this as it is used by
// the system.
//------------------------------------------------------------------------
function Legato_Animation_Controller()
{

	// Store the default values.
	this.move              = { to:    new Legato_Structure_Point(),
	                           by:    new Legato_Structure_Point(),
							   ease:  Legato_Animation.EASE_NONE };

	this.width             = { to:    null,
	                           by:    null,
							   ease:  Legato_Animation.EASE_NONE };

	this.height            = { to:    null,
	                           by:    null,
							   ease:  Legato_Animation.EASE_NONE };

	this.opacity           = { to:    null,
	                           by:    null,
							   ease:  Legato_Animation.EASE_NONE };

	this.background_color  = { to:    new Legato_Structure_Color(),
	                           by:    new Legato_Structure_Color() };

	this.border_color      = { to:    new Legato_Structure_Color(),
	                           by:    new Legato_Structure_Color() };

	this.text_color        = { to:    new Legato_Structure_Color(),
	                           by:    new Legato_Structure_Color() };

	this.delay             = 0;

}


//------------------------------------------------------------------------
// Class: Legato_Animation
// Holds a single animation for an element and the necessary methods to
// handle it.
//------------------------------------------------------------------------

//------------------------------------------------------------------------
// Class Constants
//------------------------------------------------------------------------
Legato_Animation.EASE_NONE          = 0;
Legato_Animation.EASE_IN            = 1;
Legato_Animation.EASE_OUT           = 2;
Legato_Animation.EASE_BOTH          = 3;
Legato_Animation.STRONG_EASE_IN     = 4;
Legato_Animation.STRONG_EASE_OUT    = 5;
Legato_Animation.STRONG_EASE_BOTH   = 6;
Legato_Animation.BACK_EASE_IN       = 7;
Legato_Animation.BACK_EASE_OUT      = 8;
Legato_Animation.BACK_EASE_BOTH     = 9;
Legato_Animation.BOUNCE_EASE_IN     = 10;
Legato_Animation.BOUNCE_EASE_OUT    = 11;
Legato_Animation.BOUNCE_EASE_BOTH   = 12;
Legato_Animation.ELASTIC_EASE_IN    = 13;
Legato_Animation.ELASTIC_EASE_OUT   = 14;
Legato_Animation.ELASTIC_EASE_BOTH  = 15;


//------------------------------------------------------------------------
// Public Member Functions
//------------------------------------------------------------------------

//------------------------------------------------------------------------
// Constructor: Legato_Animation()
// Class constructor.
//
// Parameters:
//     element - The DOM element that you'd like to animate.
//     run_time - The length that you'd like the animation to run.
//------------------------------------------------------------------------
function Legato_Animation( element, run_time )
{

	// Store the values.
	this.element               = $( element );
	this.element_properties    = Object();
	this.run_time              = run_time;
	this.controller            = new Legato_Animation_Controller();

	this.onStart               = null;
	this.onInterval            = null;
	this.onAdvance             = null;
	this.onEventFrame          = null;
	this.onStop                = null;
	this.onFinish              = null;

	// These values are used by the Legato_Animation system internally.
	this.status                = false;
	this.event_frames          = new Array();

	this.start_time            = null;
	this.current_time          = null;

	this.begin_width           = null;
	this.begin_height          = null;
	this.begin_pos             = null;
	this.begin_back_color      = null;
	this.begin_border_color    = null;
	this.begin_text_color      = null;
	this.begin_opacity         = null;

	this.offset_width          = null;
	this.offset_height         = null;
	this.offset_pos            = new Legato_Structure_Point();
	this.offset_back_color     = new Legato_Structure_Color();
	this.offset_border_color   = new Legato_Structure_Color();
	this.offset_text_color     = new Legato_Structure_Color();
	this.offset_opacity        = null;

	this.desired_width         = null;
	this.desired_height        = null;
	this.desired_pos           = new Legato_Structure_Point();
	this.desired_back_color    = null;
	this.desired_border_color  = null;
	this.desired_text_color    = null;
	this.desired_opacity       = null;

}


//------------------------------------------------------------------------
// Function: addEventFrame()
// Adds an event frame to the animation.
//
// Parameters:
//      time_offset - The offset from the beginning of the animation that
//                    you'd like this event to be fired.
//      event_func - The function that you'd like to execute.
//------------------------------------------------------------------------
Legato_Animation.prototype.addEventFrame = function( time_offset, event_func )
{

  // Add the new event frame to the animation.
	this.event_frames.push( { time_offset: time_offset, event_func: event_func, triggered: false } );

}


//------------------------------------------------------------------------
// Function: start()
// Sets the animation to start playing.
//------------------------------------------------------------------------
Legato_Animation.prototype.start = function()
{

	// Don't start if in the middle of playing.
	if ( this.status ) return;

	// Set the necessary values.
	this.status      = true;
	this.start_time  = new Date();

	// Width.
	if ( this.controller.width.to != null || this.controller.width.by != null )
	{

		// Get the element's width.
		this.begin_width = this.element.dimensions()[0];

		// Get the desired width and offset width.
		this.desired_width  = (this.controller.width.to != null) ? (this.controller.width.to) : (this.begin_width + this.controller.width.by);
		this.offset_width   = this.desired_width - this.begin_width;

	}

	// Height.
	if ( this.controller.height.to != null || this.controller.height.by != null )
	{

		// Get the element's height.
		this.begin_height = this.element.dimensions()[1];

		// Get the desired height and offset height.
		this.desired_height  = (this.controller.height.to != null) ? (this.controller.height.to) : (this.begin_height + this.controller.height.by);
		this.offset_height   = this.desired_height - this.begin_height;

	}

	// Position.
	if ( this.controller.move.to.X != null || this.controller.move.to.Y != null || this.controller.move.by.X != null || this.controller.move.by.Y != null )
	{

		// Get the element's position.
		this.begin_pos = this.element.position();
		this.begin_pos = new Legato_Structure_Point( this.begin_pos[0], this.begin_pos[1] );

		// Get the desired X position and X offset position.
		if ( this.controller.move.to.X != null || this.controller.move.by.X != null )
		{

			this.desired_pos.X  = (this.controller.move.to.X != null) ? (this.controller.move.to.X) : (this.begin_pos.X + this.controller.move.by.X);
			this.offset_pos.X   = this.desired_pos.X - this.begin_pos.X;

		}

		// Get the desired Y position and Y offset position.
		if ( this.controller.move.to.Y != null || this.controller.move.by.Y != null )
		{

			this.desired_pos.Y  = (this.controller.move.to.Y != null) ? (this.controller.move.to.Y) : (this.begin_pos.Y + this.controller.move.by.Y);
			this.offset_pos.Y   = this.desired_pos.Y - this.begin_pos.Y;

		}

	}

	// Opacity.
	if ( this.controller.opacity.to != null || this.controller.opacity.by != null )
	{
		
		// Get the element's opacity.
		this.begin_opacity = this.element.opacity();
		
		// Get the desired opacity and offset opacity.
		this.desired_opacity  = (this.controller.opacity.to != null) ? (this.controller.opacity.to) : (this.begin_opacity + this.controller.opacity.by);
		this.offset_opacity   = this.desired_opacity - this.begin_opacity;
		
	}

	// Background Color.
	if ( this.controller.background_color.to.R != null || 
	     this.controller.background_color.to.G != null || 
		 this.controller.background_color.to.B != null || 
	     this.controller.background_color.by.R != null ||
		 this.controller.background_color.by.G != null ||
		 this.controller.background_color.by.B != null )
	{
		
		// Get the element's background color.
		this.begin_back_color   = new Legato_Structure_Color( this.element.getStyle( 'background-color' ).substring( 1 ) );
		this.desired_back_color = new Legato_Structure_Color( this.begin_back_color.toHexString() );

		// Get the desired red value and offset value.
		if ( this.controller.background_color.to.R != null || this.controller.background_color.by.R != null )
		{

			this.desired_back_color.R  = (this.controller.background_color.to.R != null) ? (this.controller.background_color.to.R) : (this.begin_back_color.R + this.controller.background_color.by.R);
			this.offset_back_color.R   = this.desired_back_color.R - this.begin_back_color.R;

		}

		// Get the desired green value and offset value.
		if ( this.controller.background_color.to.G != null || this.controller.background_color.by.G != null )
		{

			this.desired_back_color.G  = (this.controller.background_color.to.G != null) ? (this.controller.background_color.to.G) : (this.begin_back_color.G + this.controller.background_color.by.G);
			this.offset_back_color.G   = this.desired_back_color.G - this.begin_back_color.G;

		}

		// Get the desired blue value and offset value.
		if ( this.controller.background_color.to.B != null || this.controller.background_color.by.B != null )
		{

			this.desired_back_color.B  = (this.controller.background_color.to.B != null) ? (this.controller.background_color.to.B) : (this.begin_back_color.B + this.controller.background_color.by.B);
			this.offset_back_color.B   = this.desired_back_color.B - this.begin_back_color.B;

		}

	}

	// Border Color.
	if ( this.controller.border_color.to.R != null || 
	     this.controller.border_color.to.G != null || 
		 this.controller.border_color.to.B != null || 
	     this.controller.border_color.by.R != null ||
		 this.controller.border_color.by.G != null ||
		 this.controller.border_color.by.B != null )
	{
		
		// Get the element's border color.
		this.begin_border_color   = new Legato_Structure_Color( this.element.getStyle( 'border-color' ).substring( 1 ) );
		this.desired_border_color = new Legato_Structure_Color( this.begin_border_color.toHexString() );

		// Get the desired red value and offset value.
		if ( this.controller.border_color.to.R != null || this.controller.border_color.by.R != null )
		{

			this.desired_border_color.R  = (this.controller.border_color.to.R != null) ? (this.controller.border_color.to.R) : (this.begin_border_color.R + this.controller.border_color.by.R);
			this.offset_border_color.R   = this.desired_border_color.R - this.begin_border_color.R;

		}

		// Get the desired green value and offset value.
		if ( this.controller.border_color.to.G != null || this.controller.border_color.by.G != null )
		{

			this.desired_border_color.G  = (this.controller.border_color.to.G != null) ? (this.controller.border_color.to.G) : (this.begin_border_color.G + this.controller.border_color.by.G);
			this.offset_border_color.G   = this.desired_border_color.G - this.begin_border_color.G;

		}

		// Get the desired blue value and offset value.
		if ( this.controller.border_color.to.B != null || this.controller.border_color.by.B != null )
		{

			this.desired_border_color.B  = (this.controller.border_color.to.B != null) ? (this.controller.border_color.to.B) : (this.begin_border_color.B + this.controller.border_color.by.B);
			this.offset_border_color.B   = this.desired_border_color.B - this.begin_border_color.B;

		}

	}

	// Text Color.
	if ( this.controller.text_color.to.R != null || 
	     this.controller.text_color.to.G != null || 
		 this.controller.text_color.to.B != null || 
	     this.controller.text_color.by.R != null ||
		 this.controller.text_color.by.G != null ||
		 this.controller.text_color.by.B != null )
	{

		// Get the element's text color.
		this.begin_text_color   = new Legato_Structure_Color( this.element.getStyle( 'color' ).substring( 1 ) );
		this.desired_text_color = new Legato_Structure_Color( this.begin_text_color.toHexString() );
		
		// Get the desired red value and offset value.
		if ( this.controller.text_color.to.R != null || this.controller.text_color.by.R != null )
		{

			this.desired_text_color.R  = (this.controller.text_color.to.R != null) ? (this.controller.text_color.to.R) : (this.begin_text_color.R + this.controller.text_color.by.R);
			this.offset_text_color.R   = this.desired_text_color.R - this.begin_text_color.R;

		}

		// Get the desired green value and offset value.
		if ( this.controller.text_color.to.G != null || this.controller.text_color.by.G != null )
		{

			this.desired_text_color.G  = (this.controller.text_color.to.G != null) ? (this.controller.text_color.to.G) : (this.begin_text_color.G + this.controller.text_color.by.G);
			this.offset_text_color.G   = this.desired_text_color.G - this.begin_text_color.G;

		}

		// Get the desired blue value and offset value.
		if ( this.controller.text_color.to.B != null || this.controller.text_color.by.B != null )
		{

			this.desired_text_color.B  = (this.controller.text_color.to.B != null) ? (this.controller.text_color.to.B) : (this.begin_text_color.B + this.controller.text_color.by.B);
			this.offset_text_color.B   = this.desired_text_color.B - this.begin_text_color.B;

		}

	}

	// Call the onStart function if there is any.
	if ( this.onStart != null )
	  this.onStart( this );

	// Call the incrementAnimation function. It will start the animation.
	Legato_Animation_Manager.addAnimation( this );

}


//------------------------------------------------------------------------
// (Exclude)
// Function: advanceWidth()
// Advances the width.
//------------------------------------------------------------------------
Legato_Animation.prototype.advanceWidth = function()
{

	// Get the new width.
	var new_width = Legato_Animation.tweenValue( this.controller.width.ease, (this.current_time - this.controller.delay), this.run_time, this.begin_width, this.offset_width );

	// Bounds.
	new_width = Math.max( new_width, 0 );

	// Set the new width on the element.
	this.element.dimensions( Math.ceil( new_width ), null );

}


//------------------------------------------------------------------------
// (Exclude)
// Function: advanceHeight()
// Advances the height.
//------------------------------------------------------------------------
Legato_Animation.prototype.advanceHeight = function()
{

	// Get the new height.
	var new_height = Legato_Animation.tweenValue( this.controller.height.ease, (this.current_time - this.controller.delay), this.run_time, this.begin_height, this.offset_height );
	
	// Bounds.
	new_height = Math.max( new_height, 0 );
	
	// Set the new height on the element.
	this.element.dimensions( null, Math.ceil( new_height ) );

}


//------------------------------------------------------------------------
// (Exclude)
// Function: advancePosition()
// Advances the position.
//------------------------------------------------------------------------
Legato_Animation.prototype.advancePosition = function()
{

	// Updating X position?
	if ( this.offset_pos.X != null )
	{

		// Get the new X position.
		var new_X_pos = Legato_Animation.tweenValue( this.controller.move.ease, (this.current_time - this.controller.delay), this.run_time, this.begin_pos.X, this.offset_pos.X );
		
		// Bounds.
		new_X_pos = Math.max( new_X_pos, 0 );

		// Set the new X position on the element.
		this.element.position( Math.ceil( new_X_pos ), null );

	}  // End if updating X position.

	// Updating Y position?
	if ( this.offset_pos.Y != null )
	{

		// Get the new Y position.
		var new_Y_pos = Legato_Animation.tweenValue( this.controller.move.ease, (this.current_time - this.controller.delay), this.run_time, this.begin_pos.Y, this.offset_pos.Y );
		
		// Bounds.
		new_Y_pos = Math.max( new_Y_pos, 0 );

		// Set the new Y position on the element.
		this.element.position( null, Math.ceil( new_Y_pos ) );

	}  // End if updating Y position.

}


//------------------------------------------------------------------------
// (Exclude)
// Function: advanceOpacity()
// Advances the opacity.
//------------------------------------------------------------------------
Legato_Animation.prototype.advanceOpacity = function()
{

	// Get the new opacity.
	var new_opacity = (Legato_Animation.tweenValue( this.controller.opacity.ease, (this.current_time - this.controller.delay), this.run_time, (this.begin_opacity * 100), (this.offset_opacity * 100) ) / 100);
	
	// Bounds.
	new_opacity = Math.min( Math.max( new_opacity, 0 ), 1 );
	
	// Set the new opacity on the element.
	this.element.opacity( new_opacity );

}


//------------------------------------------------------------------------
// (Exclude)
// Function: advanceBackgroundColor()
// Advances the background color.
//------------------------------------------------------------------------
Legato_Animation.prototype.advanceBackgroundColor = function()
{

	// Set the new back color as the beginning color.
	var new_back_color = new Legato_Structure_Color( this.begin_back_color.toHexString() );

	// Updating red value?
	if ( this.offset_back_color.R != null )
	{

		// Get the new background color.
		new_back_color.R = Math.ceil( Legato_Animation.tweenValue( Legato_Animation.EASE_NONE, (this.current_time - this.controller.delay), this.run_time, this.begin_back_color.R, this.offset_back_color.R ) );
	
	}  // End if updating red value.

	// Updating green value?
	if ( this.offset_back_color.G != null )
	{

		// Get the new background color.
		new_back_color.G = Math.ceil( Legato_Animation.tweenValue( Legato_Animation.EASE_NONE, (this.current_time - this.controller.delay), this.run_time, this.begin_back_color.G, this.offset_back_color.G ) );

	}  // End if updating red value.

	// Updating blue value?
	if ( this.offset_back_color.B != null )
	{

		// Get the new background color.
		new_back_color.B = Math.ceil( Legato_Animation.tweenValue( Legato_Animation.EASE_NONE, (this.current_time - this.controller.delay), this.run_time, this.begin_back_color.B, this.offset_back_color.B ) );

	}  // End if updating red value.
	
	// Bounds.
	new_back_color.R = Math.min( Math.max( new_back_color.R, 0 ), 255 );
	new_back_color.G = Math.min( Math.max( new_back_color.G, 0 ), 255 );
	new_back_color.B = Math.min( Math.max( new_back_color.B, 0 ), 255 );
	
	// Set the new background color on the element.
	this.element.setStyle( 'background-color', '#' + new_back_color.toHexString() );

}


//------------------------------------------------------------------------
// (Exclude)
// Function: advanceBorderColor()
// Advances the border color.
//------------------------------------------------------------------------
Legato_Animation.prototype.advanceBorderColor = function()
{

	// Set the new border color as the beginning color.
	var new_border_color = new Legato_Structure_Color( this.begin_border_color.toHexString() );

	// Updating red value?
	if ( this.offset_border_color.R != null )
	{

		// Get the new border color.
		new_border_color.R = Math.ceil( Legato_Animation.tweenValue( Legato_Animation.EASE_NONE, (this.current_time - this.controller.delay), this.run_time, this.begin_border_color.R, this.offset_border_color.R ) );

	}  // End if updating red value.

	// Updating green value?
	if ( this.offset_back_color.G != null )
	{

		// Get the new border color.
		new_border_color.G = Math.ceil( Legato_Animation.tweenValue( Legato_Animation.EASE_NONE, (this.current_time - this.controller.delay), this.run_time, this.begin_border_color.G, this.offset_border_color.G ) );

	}  // End if updating red value.

	// Updating blue value?
	if ( this.offset_border_color.B != null )
	{

		// Get the new border color.
		new_border_color.B = Math.ceil( Legato_Animation.tweenValue( Legato_Animation.EASE_NONE, (this.current_time - this.controller.delay), this.run_time, this.begin_border_color.B, this.offset_border_color.B ) );

	}  // End if updating red value.
	
	// Bounds.
	new_border_color.R = Math.min( Math.max( new_border_color.R, 0 ), 255 );
	new_border_color.G = Math.min( Math.max( new_border_color.G, 0 ), 255 );
	new_border_color.B = Math.min( Math.max( new_border_color.B, 0 ), 255 );

	// Set the new border color on the element.
	this.element.setStyle( 'border-color', '#' + new_border_color.toHexString() );
	
}


//------------------------------------------------------------------------
// (Exclude)
// Function: advanceTextColor()
// Advances the text color.
//------------------------------------------------------------------------
Legato_Animation.prototype.advanceTextColor = function()
{
	
	// Set the new text color as the beginning color.
	var new_text_color = new Legato_Structure_Color( this.begin_text_color.toHexString() );

	// Updating red value?
	if ( this.offset_text_color.R != null )
	{
		
		// Get the new text color.
		new_text_color.R = Math.ceil( Legato_Animation.tweenValue( Legato_Animation.EASE_NONE, (this.current_time - this.controller.delay), this.run_time, this.begin_text_color.R, this.offset_text_color.R ) );

	}  // End if updating red value.

	// Updating green value?
	if ( this.offset_text_color.G != null )
	{

		// Get the new text color.
		new_text_color.G = Math.ceil( Legato_Animation.tweenValue( Legato_Animation.EASE_NONE, (this.current_time - this.controller.delay), this.run_time, this.begin_text_color.G, this.offset_text_color.G ) );

	}  // End if updating red value.

	// Updating blue value?
	if ( this.offset_text_color.B != null )
	{

		// Get the new text color.
		new_text_color.B = Math.ceil( Legato_Animation.tweenValue( Legato_Animation.EASE_NONE, (this.current_time - this.controller.delay), this.run_time, this.begin_text_color.B, this.offset_text_color.B ) );

	}  // End if updating red value.
	
	// Bounds.
	new_text_color.R = Math.min( Math.max( new_text_color.R, 0 ), 255 );
	new_text_color.G = Math.min( Math.max( new_text_color.G, 0 ), 255 );
	new_text_color.B = Math.min( Math.max( new_text_color.B, 0 ), 255 );

	// Set the new text color on the element.
	this.element.setStyle( 'color', '#' + new_text_color.toHexString() );

}


//------------------------------------------------------------------------
// (Exclude)
// Function: advanceFrame()
// Carries out the next frame of the animation.
//------------------------------------------------------------------------
Legato_Animation.prototype.advanceFrame = function()
{

	// If the animation is stopped, return false.
	if ( !this.status )
	  return false;

	// Update the current time.
	this.current_time = new Date() - this.start_time;

	// Only start incrementing if we have passed the delay time.
	if ( this.current_time > this.controller.delay )
	{
		
		// Animating width?
		if ( this.desired_width != null )
			this.advanceWidth();

		// Animating height?
		if ( this.desired_height != null )
			this.advanceHeight();

		// Animating position?
		if ( this.desired_pos.X != null || this.desired_pos.Y != null )
			this.advancePosition();

		// Animating opacity?
		if ( this.desired_opacity != null )
			this.advanceOpacity();

		// Animating background color?
		if ( this.desired_back_color != null )
			this.advanceBackgroundColor();

		// Animating border color?
		if ( this.desired_border_color != null )
			this.advanceBorderColor();

		// Animating text color?
		if ( this.desired_text_color != null )
			this.advanceTextColor();
			
		// Loop through each event frame.
		var event_triggered = false;
		for ( var i = 0; i < this.event_frames.length; i++ )
		{

			// If it is time (or passed time) to trigger the event, do so.
			if ( !this.event_frames[i].triggered && this.current_time >= this.controller.delay + this.event_frames[i].time_offset )
			{

			  this.event_frames[i].event_func( this );
				this.event_frames[i].triggered = true;
				event_triggered = true;

			}

		}  // Next event frame.

		// If an event was triggered and there's an onEventFrame function, call it.
		if ( event_triggered && this.onEventFrame )
		  this.onEventFrame( this );

		// Call the onAdvance function if there is any.
		if ( this.onAdvance )
			this.onAdvance( this );

	}  // End if delay is over.

	// Call the onAdvance function if there is any.
	if ( this.onInterval )
		this.onInterval( this );

	// Should we continue processing?
	if ( this.current_time < this.run_time + this.controller.delay )
		return true;
	else
		return false;

}


//------------------------------------------------------------------------
// Function: stop()
// Stops the animation where it currently is. Does not finish it.
//------------------------------------------------------------------------
Legato_Animation.prototype.stop = function()
{

	// Set the animation's status to not playing.
	this.status = false;

	// Call the onStop function if there is any.
	if ( this.onStop )
	  this.onStop( this );

}


//------------------------------------------------------------------------
// (Exclude)
// Function: finish()
// Does the required clean up of the animation.
//------------------------------------------------------------------------
Legato_Animation.prototype.finish = function()
{

	// Set the animation's status to not playing.
	this.status = false;
	
	// Get rid of any animation errors. Set the desired values on the elements.
	if ( this.desired_width        ) this.element.dimensions( this.desired_width, null );
	if ( this.desired_height       ) this.element.dimensions( null, this.desired_height );

	if ( this.desired_pos.X        ) this.element.position( this.desired_pos.X, null );
	if ( this.desired_pos.Y        ) this.element.position( null, this.desired_pos.Y );

	if ( this.desired_opacity      ) this.element.opacity( this.desired_opacity );

	if ( this.desired_back_color   ) this.element.setStyle( 'background-color', '#' + this.desired_back_color.toHexString() );

	if ( this.desired_border_color ) this.element.setStyle( 'border-color', '#' + this.desired_border_color.toHexString() );

	if ( this.desired_text_color   ) this.element.setStyle( 'color', '#' + this.desired_text_color.toHexString() );

	// Call the onFinish function if there is any.
	if ( this.onFinish )
	  this.onFinish( this );

}


//------------------------------------------------------------------------
// Public Static Member Functions
//------------------------------------------------------------------------

//------------------------------------------------------------------------
// (Exclude)
// Function: tweenValue()
// Tweens the value.
//------------------------------------------------------------------------
Legato_Animation.tweenValue = function( ease_type, current_time, duration, begin_val, change_val )
{
	
	// What easing equation?
	switch( ease_type )
	{
		
	// EASE NONE
	case Legato_Animation.EASE_NONE:	
		return change_val * (current_time / duration) + begin_val;
		
	// EASE IN
	case Legato_Animation.EASE_IN:
		return change_val * (current_time /= duration) * current_time + begin_val;
		
	// EASE OUT
	case Legato_Animation.EASE_OUT:
		return -change_val * (current_time /= duration) * (current_time - 2) + begin_val;
		
	// EASE BOTH
	case Legato_Animation.EASE_BOTH:
		
		if ( (current_time /= duration / 2) < 1 ) 
			return change_val / 2 * current_time * current_time + begin_val;

		return -change_val / 2 * ((--current_time) * (current_time - 2) - 1) + begin_val;
		
	// STRONG EASE IN
	case Legato_Animation.STRONG_EASE_IN:
		return change_val * (current_time /= duration) * current_time * current_time * current_time + begin_val;
	
	// STRONG EASE OUT	
	case Legato_Animation.STRONG_EASE_OUT:
		return -change_val * ((current_time = current_time / duration - 1) * current_time * current_time * current_time - 1) + begin_val;
		
	// STRONG EASE BOTH
	case Legato_Animation.STRONG_EASE_BOTH:
	
		if ( (current_time /= duration / 2) < 1 ) 
			return change_val / 2 * current_time * current_time * current_time * current_time + begin_val;

		return -change_val / 2 * ((current_time -= 2) * current_time * current_time * current_time - 2) + begin_val;
		
	// BACK EASE IN
	case Legato_Animation.BACK_EASE_IN:
		return change_val * (current_time /= duration) * current_time * (2.70158 * current_time - 1.70158) + begin_val;
		
	// BACK EASE OUT
	case Legato_Animation.BACK_EASE_OUT:
		return change_val * ((current_time = current_time / duration - 1) * current_time * (2.70158 * current_time + 1.70158) + 1) + begin_val;
		
	// BACK EASE BOTH
	case Legato_Animation.BACK_EASE_BOTH:
		
		if ( (current_time /= duration / 2) < 1 ) 
			return change_val / 2 * (current_time * current_time * (3.5949095 * current_time - 2.5949095)) + begin_val;

		return change_val / 2 * ((current_time -= 2) * current_time * (3.5949095 * current_time + 2.5949095) + 2) + begin_val;
		
	// BOUNCE EASE IN
	case Legato_Animation.BOUNCE_EASE_IN:
		
		current_time = duration - current_time;

		if ( (current_time /= duration) < (1 / 2.75) )
			return change_val - (change_val * (7.5625 * current_time * current_time)) + begin_val;
		else if ( current_time < (2 / 2.75 ) )
			return change_val - (change_val * (7.5625 * (current_time -= (1.5 / 2.75)) * current_time + 0.75)) + begin_val;
		else if ( current_time < (2.5 / 2.75) )
			return change_val - (change_val * (7.5625 * (current_time -= (2.25 / 2.75)) * current_time + 0.9375)) + begin_val;
		else
			return change_val - (change_val * (7.5625 * (current_time -= (2.625 / 2.75)) * current_time + 0.984375)) + begin_val;
		
	// BOUNCE EASE OUT	
	case Legato_Animation.BOUNCE_EASE_OUT:
	
		if ( (current_time /= duration) < (1 / 2.75) )
		  return change_val * (7.5625 * current_time * current_time) + begin_val;
		else if ( current_time < (2 / 2.75 ) )
		  return change_val * (7.5625 * (current_time -= (1.5 / 2.75)) * current_time + 0.75) + begin_val;
		else if ( current_time < (2.5 / 2.75) )
		  return change_val * (7.5625 * (current_time -= (2.25 / 2.75)) * current_time + 0.9375) + begin_val;
		else
		  return change_val * (7.5625 * (current_time -= (2.625 / 2.75)) * current_time + 0.984375) + begin_val;
		  
	// BOUNCE EASE BOTH
	case Legato_Animation.BOUNCE_EASE_BOTH:
	
		if ( current_time < duration / 2 )
		{

			current_time = duration - (current_time * 2);

			if ( (current_time /= duration) < (1 / 2.75) )
				return (change_val - (change_val * (7.5625 * current_time * current_time))) * 0.5 + begin_val;
			else if ( current_time < (2 / 2.75 ) )
				return (change_val - (change_val * (7.5625 * (current_time -= (1.5 / 2.75)) * current_time + 0.75))) * 0.5 + begin_val;
			else if ( current_time < (2.5 / 2.75) )
				return (change_val - (change_val * (7.5625 * (current_time -= (2.25 / 2.75)) * current_time + 0.9375))) * 0.5 + begin_val;
			else
				return (change_val - (change_val * (7.5625 * (current_time -= (2.625 / 2.75)) * current_time + 0.984375))) * 0.5 + begin_val;

		}

		current_time = current_time * 2 - duration;

		if ( (current_time /= duration) < (1 / 2.75) )
		  return change_val * (7.5625 * current_time * current_time) * 0.5 + change_val * 0.5 + begin_val;
		else if ( current_time < (2 / 2.75 ) )
		  return change_val * (7.5625 * (current_time -= (1.5 / 2.75)) * current_time + 0.75) * 0.5 + change_val * 0.5 + begin_val;
		else if ( current_time < (2.5 / 2.75) )
		  return change_val * (7.5625 * (current_time -= (2.25 / 2.75)) * current_time + 0.9375) * 0.5 + change_val * 0.5 + begin_val;
		else
		  return change_val * (7.5625 * (current_time -= (2.625 / 2.75)) * current_time + 0.984375) * 0.5 + change_val * 0.5 + begin_val;
		  
	// ELASTIC EASE IN
	case Legato_Animation.ELASTIC_EASE_IN:
	
		if ( current_time == 0 ) 
			return begin_val;
			
		if ( (current_time /= duration) == 1 ) 
			return begin_val + change_val;

		var p = duration * 0.3;
		var a = change_val;
		var s = p / 4;

		return -(a * Math.pow( 2, 10 * (current_time -= 1) ) * Math.sin( (current_time * duration - s) * (2 * Math.PI) / p )) + begin_val;
		
	// ELASTIC EASE OUT
	case Legato_Animation.ELASTIC_EASE_OUT:
		
		if ( current_time == 0 ) 
			return begin_val;
			
		if ( (current_time /= duration) == 1 ) 
			return begin_val + change_val;

		var p = duration * 0.3;
		var a = change_val;
		var s = p / 4;

		return a * Math.pow( 2, -10 * current_time ) * Math.sin( (current_time * duration - s) * (2 * Math.PI) / p ) + change_val + begin_val;
		
	// ELASTIC EASE BOTH
	case Legato_Animation.ELASTIC_EASE_BOTH:
	
		if ( current_time == 0 ) 
			return begin_val;
			
		if ( (current_time /= duration / 2) == 2 ) 
			return begin_val + change_val;

		var p = duration * (0.3 * 1.5);
		var a = change_val;
		var s = p / 4;

		if ( current_time < 1 ) return -0.5 * (a * Math.pow( 2, 10 * (current_time -= 1) ) * Math.sin( (current_time * duration - s) * (2 * Math.PI) / p )) + begin_val;

		return a * Math.pow( 2, -10 * (current_time -= 1) ) * Math.sin( (current_time * duration - s) * (2 * Math.PI) / p ) * 0.5 + change_val + begin_val;
		
	}

}


//------------------------------------------------------------------------
// Class: Legato_Animation_Sequence
// Stores a sequence of <Legato_Animation> objects.
//------------------------------------------------------------------------

//------------------------------------------------------------------------
// Static Variables
//------------------------------------------------------------------------
Legato_Animation_Sequence.sequences = new Array();


//------------------------------------------------------------------------
// Public Member Functions
//------------------------------------------------------------------------

//------------------------------------------------------------------------
// Constructor: Legato_Animation_Sequence()
// Class constructor.
//
// Parameters:
//     options - An optional object of options for the Animation Sequence.
//------------------------------------------------------------------------
function Legato_Animation_Sequence( options )
{

	// Store the default values.
	this.animations               = new Array();
	this.current_animation_index  = 0;
	this.sequence_index           = Legato_Animation_Sequence.sequences.length;
	this.status                   = false;
	this.options                  = options;
	
	// Callbacks.
	this.onStart               = null;
	this.onAdvance             = null;
	this.onLoop                = null;
	this.onFinish              = null;

	// Store this animation sequence in the global sequences array.
	Legato_Animation_Sequence.sequences[this.sequence_index] = this;

}


//------------------------------------------------------------------------
// Function: addAnimation()
// Adds an <Legato_Animation> object to the animation sequence.
//
// Parameters:
//     animation - An <Legato_Animation> object that you would like to set up
//                 to play in the animation. Will add it at the end of the
//                 sequence.
//------------------------------------------------------------------------
Legato_Animation_Sequence.prototype.addAnimation = function( animation )
{

	// Store the animation in the sequence.
	this.animations.push( animation );

	// Add the onFinish and onStop functions.
	Legato_Events_Handler.addEvent( animation, "onFinish", Legato_Animation_Sequence.nextAnimation );
	Legato_Events_Handler.addEvent( animation, "onStop", Legato_Animation_Sequence.nextAnimation );

	// Store the sequence index in the animation.
	animation.sequence_index = this.sequence_index;

}


//------------------------------------------------------------------------
// Function: start()
// Sets the Animation Sequence to start playing.
//------------------------------------------------------------------------
Legato_Animation_Sequence.prototype.start = function()
{

	// Only start if there is at least one animation in the sequence
	// and we are not already playing.
	if ( this.animations.length == 0 || this.status ) return;

	// Set as playing.
	this.status = true;
	
	// On start callback.
	if ( this.onStart != null && this.onStart( this ) == false )
		return;

	// Start the first animation in the sequence.
	this.animations[0].start();

}


//------------------------------------------------------------------------
// (Exclude)
// Function: reset()
// Cleans up the animation sequence.
//------------------------------------------------------------------------
Legato_Animation_Sequence.prototype.reset = function()
{

	// Reset the values.
	this.status                   = false;
	this.current_animation_index  = 0;

}


//------------------------------------------------------------------------
// Public Static Member Functions
//------------------------------------------------------------------------

//------------------------------------------------------------------------
// (Exclude)
// Function: nextAnimation()
// Plays the next animation in the sequence. This is set as the previous
// animation's onFinish function so that a chain forms.
//------------------------------------------------------------------------
Legato_Animation_Sequence.nextAnimation = function( animation )
{

	// Get the animation sequence.
	var animation_sequence = Legato_Animation_Sequence.sequences[animation.sequence_index];

	// If the animation sequence is stopped, return false.
	if ( !animation_sequence.status )
	  return false;

	// Increment the current animation index.
	animation_sequence.current_animation_index++;

	// Play the next animation if there is one.
	if ( animation_sequence.animations[animation_sequence.current_animation_index] != null )
	{
		
		// On advance callback.
		if ( animation_sequence.onAdvance != null && animation_sequence.onAdvance( animation_sequence ) == false )
			return;

		// Start the next animation.
		animation_sequence.animations[animation_sequence.current_animation_index].start();

	}  // End if next animation.
	else
	{
		
		// Should we loop?
		if ( animation_sequence.options && animation_sequence.options.loop == true )
		{
			
			// On loop callback.
			if ( animation_sequence.onLoop != null && animation_sequence.onLoop( animation_sequence ) == false )
				return;
				
			// Loop.
			animation_sequence.reset();
			animation_sequence.start();
			
		}  // End if looping.
		else
		{

			// Finish the animation sequence.
			animation_sequence.reset();
			
			// On finish callback.
			if ( animation_sequence.onFinish != null )
				animation_sequence.onFinish( animation_sequence );
			
		}

	}  // End if no more animations.

}


//------------------------------------------------------------------------
// (Exclude)
// Class: Legato_Animation_Manager
// Manages each animation. All the animations are incremented through the
// manager.
//------------------------------------------------------------------------
Legato_Animation_Manager =
{

	//----------------------------------------------------------------------
	// Public Variables
	//----------------------------------------------------------------------
	increment_speed:     20,           // The speed at which the animation manager will increment each animation.
	playing_animations:  new Array(),  // An array of all the currently playing animations.
	interval_handle:     null,         // The handle that the setInterval() function returns.


	//----------------------------------------------------------------------
	// Public Member Functions
	//----------------------------------------------------------------------
	//----------------------------------------------------------------------
	// (Exclude)
	// Function: addAnimation()
	// This function is used to add an animation to the animation manager
	// for playing.
	//----------------------------------------------------------------------
	addAnimation: function( animation )
	{

		// Loop through each animation being played.
		for ( var i = 0; i < this.playing_animations.length; i++ )
		{

			// Get the animation.
			var playing_animation = this.playing_animations[i];

			// Is the animation we're adding animate the
			// same element than this animation's element?
			if ( animation.element == playing_animation.element )
			{

				// Remove the animation from the playing animations array.
				this.playing_animations.splice( i, 1 );

				// Stop the currently playing animation so that we can play this one.
				playing_animation.stop();

			}  // End if managing the same element.

		}  // Next playing animation.

		// Add the animation to the playing animations array.
		this.playing_animations.push( animation );

		// If we don't have any animations playing,
		// we have to set up the timeout.
		if ( this.interval_handle == null )
		{

			// Set to advanced all animations.
			this.interval_handle = setInterval( Legato_Animation_Manager.advanceAnimations, this.increment_speed, null );

		}  // End if no animations currently playing.

	},


	//------------------------------------------------------------------------
	// (Exclude)
	// Function: advanceAnimations()
	// Advances each animation being played.
	//------------------------------------------------------------------------
	advanceAnimations: function()
	{

		// Loop through each animation being played.
		for ( var i = 0; i < Legato_Animation_Manager.playing_animations.length; i++ )
		{

			// Get the animation from the array.
			var animation = Legato_Animation_Manager.playing_animations[i];

			// Advance the animation.
			var continue_playing = animation.advanceFrame();

			// Is the animation done playing?
			if ( !continue_playing )
			{
				
				// Remove the animation from the playing animations array.
				Legato_Animation_Manager.playing_animations.splice( i, 1 );
				
				// Finish up the animation.
				animation.finish();
				
				// If we don't have any more animations to play, stop
				// JavaScript from calling this function again.
				if ( Legato_Animation_Manager.playing_animations.length == 0 )
				{
					clearInterval( Legato_Animation_Manager.interval_handle );
					Legato_Animation_Manager.interval_handle = null;
				}

			}  // End if stop playing this animation.

		}  // Next playing animation.

	}

}



//------------------------------------------------------------------------
// Name: Slideshow
// Desc: Manages the setting up and animation of the slides.
//------------------------------------------------------------------------
Slideshow =
{

	//----------------------------------------------------------------------
	// Public Variables
	//----------------------------------------------------------------------
	slides: new Array(),
	current_index: 0,
	delay: 3000,
	offset: 0,


	//----------------------------------------------------------------------
	// Public Member Functions
	//----------------------------------------------------------------------
	//------------------------------------------------------------------------
	// Name: initialize()
	// Desc: Initializes the Slideshow. Adds all the slides to the DOM and
	//       sets them up for animation.
	//------------------------------------------------------------------------
	initialize: function( section, num, offset )
	{

		Slideshow.offset = offset;

		// Let's loop through all the slides.
		for ( var i = 1; i <= num; i++ )
		{

			var index = i - 1;

			// Create a div for this slide.
			Slideshow.slides[index] = $$( 'right_col' ).create( 'div', {}, true, '<img src="' + SITE_URL + '/img/slides/' + section + i + '.jpg" />' );
			Slideshow.slides[index] = $( Slideshow.slides[index].elmsByTag( 'img' )[0] );
			var slide = Slideshow.slides[index];

			slide.opacity( 0 );
			slide.position( null, 0 );

		}

		// Set up the first slide.
		Slideshow.setupSlide( 0 );

	},


	//------------------------------------------------------------------------
	// Name: setupSlide()
	// Desc: Sets up the particular slide at the particular stage that it
	//       should be in.
	//------------------------------------------------------------------------
	setupSlide: function( slide_id )
	{

		// Get the variables we need.
		var slide = Slideshow.slides[slide_id];
		var right_colY = $$( 'right_col' ).position()[1];

		// Set the new Y value.
		slide.position( null, right_colY - 60 + Slideshow.offset );

		// Now let's set this slide up for animation.
		Slideshow.setupAnimation( slide_id );

	},


	//------------------------------------------------------------------------
	// Name: setupAnimation()
	// Desc: This sets up the slide's animation depending upon which stage
	//       it's at.
	//------------------------------------------------------------------------
	setupAnimation: function( slide_id )
	{

		var slide = Slideshow.slides[slide_id];

		// Create the animation sequence object.
		var anim_sequence = new Legato_Animation_Sequence();

		// Add the slide in animation.
		var anim = new Legato_Animation( slide, 1000 );

		anim.controller.move.by.Y = 160;
		anim.controller.move.ease = Legato_Animation.STRONG_EASE_OUT;
		anim.controller.opacity.to = 1;

		anim_sequence.addAnimation( anim );

		// Only add the slide out animation if this isn't the last slide.
		if ( slide_id != Slideshow.slides.length - 1 )
		{

			// Add the slide out animation.
			var anim = new Legato_Animation( slide, 800 );

			anim.controller.opacity.to = 0;
			anim.controller.delay = Slideshow.delay;

			anim_sequence.addAnimation( anim );

			// We do this so that the next slide will be called to roll in when this
			// slide's animation sequence finishes.
			anim_sequence.onFinish = function(){ Slideshow.nextSlide( slide_id ); };

		}  // End if not last slide.

		// Start the sequence.
		anim_sequence.start();

	},


	//------------------------------------------------------------------------
	// Name: nextSlide()
	// Desc: Calls the next slide in the slideshow.
	//------------------------------------------------------------------------
	nextSlide: function( slide_id )
	{

		// Get the next slide's ID.
		var next_slide = Slideshow.current_index + 1;

		// If this is the last slide in the slideshow, start over again.
		if ( next_slide == Slideshow.slides.length )
			next_slide = 0;

		// Set the current index to the next slide's ID.
		Slideshow.current_index = next_slide;

		// Now set up the slide to slide in.
		Slideshow.setupSlide( next_slide );

	}

}
var Enlarger =
{

	showImage: function( elem )
	{

		// Create the HTML.
		var enlarged_html = '<div id="projects-close">X CLOSE</div><div id="projects-loading"><img src="' + SITE_URL + '/img/loading-1.gif" alt="Loading">Loading...</div>';

		// Create the enlarged image element.
		var enlarged_elem = $$( document.body ).create( 'div', { id: 'projects-enlarged' }, true, enlarged_html );
		enlarged_elem.position( ($( document.body ).dimensions()[0] - 300) * 0.5, $( document.body ).scrollOffset()[1] + 20 );

		// Create the background element.
		var back_elem = $( document.body ).create( 'div', { id: 'projects-background' }, true );
		back_elem.dimensions( $( document.body ).dimensions()[0], Math.max( $( document.body ).dimensions()[1], $( window ).dimensions()[1] ) );
		back_elem.setStyle( 'opacity', 0.7 );
		back_elem.position( 0, 0 );

		$$( 'projects-close' ).onclick = function(){ Enlarger.hideImage(); return false; };

		// Start loading the enlarged image.
		var img = new Image();

		img.onload = Enlarger.imageLoaded;

		img.id = 'projects-enlarged-img';
		img.alt = 'Enlarged Image';
		img.src = elem.href;

	},

	imageLoaded: function()
	{

		$$( 'projects-loading' ).replace( this );

		var img = $$( 'projects-enlarged-img' );
		img.setStyle( 'visibility', 'hidden' );

		var popup = $$( 'projects-enlarged' );
		var popup_dimensions = popup.dimensions();

		var anim = new Legato_Animation( popup, 700 );
		anim.controller.move.by = { X: -(img.width * 0.5 - popup_dimensions[0] * 0.5) };
		anim.controller.move.ease = Legato_Animation.STRONG_EASE_OUT;
		anim.controller.width.to = img.width;
		anim.controller.width.ease = Legato_Animation.STRONG_EASE_OUT;
		anim.start();

		anim.onFinish = function()
		{

			var anim = new Legato_Animation( popup, 700 );
			anim.controller.height.to = (img.height + 30);
			anim.controller.height.ease = Legato_Animation.STRONG_EASE_OUT;
			anim.start();

			anim.onFinish = function()
			{

				img.setStyle( 'visibility', 'visible' );
				img.setStyle( 'opacity', 0 );

				var anim = new Legato_Animation( img, 500 );
				anim.controller.opacity.to = 1;
				anim.start();

			}

		}

	},

	hideImage: function()
	{

		// Remove the background and enlarged image elements.
		$$( 'projects-background' ).remove();
		$$( 'projects-enlarged' ).remove();

	}

};