

/**
 * jQuery Cookie plugin
 *
 * Copyright (c) 2010 Klaus Hartl (stilbuero.de)
 * Dual licensed under the MIT and GPL licenses:
 * http://www.opensource.org/licenses/mit-license.php
 * http://www.gnu.org/licenses/gpl.html
 *
 */
jQuery.cookie = function (key, value, options) {

    // key and at least value given, set cookie...
    if (arguments.length > 1 && String(value) !== "[object Object]") {
        options = jQuery.extend({}, options);

        if (value === null || value === undefined) {
            options.expires = -1;
        }

        if (typeof options.expires === 'number') {
            var days = options.expires, t = options.expires = new Date();
            t.setDate(t.getDate() + days);
        }

        value = String(value);

        return (document.cookie = [
            encodeURIComponent(key), '=',
            options.raw ? value : encodeURIComponent(value),
            options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE
            options.path ? '; path=' + options.path : '',
            options.domain ? '; domain=' + options.domain : '',
            options.secure ? '; secure' : ''
        ].join(''));
    }

    // key and possibly options given, get cookie...
    options = value || {};
    var result, decode = options.raw ? function (s) { return s; } : decodeURIComponent;
    return (result = new RegExp('(?:^|; )' + encodeURIComponent(key) + '=([^;]*)').exec(document.cookie)) ? decode(result[1]) : null;
};




/*!
*  JqueryAsynchImageLoader (JAIL) : plugin for jQuery
*
* Developed by
* Sebastiano Armeli-Battana (@sebarmeli) - http://www.sebastianoarmelibattana.com
* Dual licensed under the MIT or GPL Version 3 licenses.
* @version 0.9.5
*/
/*!
*  JqueryAsynchImageLoader (JAIL) : plugin for jQuery
*
* Developed by
* Sebastiano Armeli-Battana (@sebarmeli) - http://www.sebastianoarmelibattana.com
* Dual licensed under the MIT or GPL Version 3 licenses.
*/
/*
	Copyright (c) 2011 Sebastiano Armeli-Battana (http://www.sebastianoarmelibattana.com)

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

/* JAIL helps loading images asynchronously and it can be used to make your page load faster.
* Selected images will be downloaded after the document is ready not blocking the page 
* to render other elements. Images can be loaded after an event is triggered (like clicking 
* on a link, mouseovering on some elements, scrolling up/down) or after some delay or simply the 
* visible images will be loaded.
*
* First of all, this plugin requires you to make some HTML changes. 
* E.g. 
*	<img class="lazy" src="/img/blank.gif" data-href="/img/image1.jpg" width="x" height="y"/>
*
* You can define a noscript block in order to respect the principles of progressive
* enhancemnt
* E.g.
*	<noscript>
*		<img class="lazy" src="/img/image1.jpg" width="x" height="y" />
*	</noscript>
*
* You can call the function in this way
* E.g.
*	$(function(){
*		$('img.lazy').asynchImageLoader();
*	});
* or
*	$(function(){
*		$('img.lazy').jail();
*	});
* You can also have different configurations:
*
* - timeout : number of msec after that the images will be loaded - Default: 10ms
* - effect : any jQuery effect that makes the images display (e.g. "fadeIn"). If you are loading a large number of images, it is best to NOT use this setting. Effect calls are very expensive - Default: NULL
* - speed :  string or number determining how long the animation will run  - Default: 400
* - selector : selector that you need to bind the trigger event - Default: NULL
* - event : event that triggers the image to load. You can choose "load", "load+scroll", "click", "mouseover", or "scroll". Default: "load+scroll"
* - offset : an offset of "500" would cause any images that are less than 500px below the bottom of the window or 500px above the top of the window to load. - Default: 0
* - callback : function that will be called after all the images are loaded - Default: ""
* - callbackAfterEachImage : function that will be called after an image is loaded - Default: ""
* - placeholder: location of an image (such a loader) you want to display while waiting for the images to be loaded - Default: ""
*
*
* Tested with jQuery 1.3.2+ on FF 2/3, Opera 10+, Safari 4+, Chrome on Mac and IE 6/7/8 on Win.
*
* Contributor : Derek Lindahl - dlindahl
*
* @link http://github.com/sebarmeli/JAIL
* @author Sebastiano Armeli-Battana
* @date 03/08/2011
* @version 0.9.5 
*
*/

/*globals window,jQuery,setTimeout,clearTimeout */
;(function($){
	var $window = $(window);

	$.fn.asynchImageLoader = $.fn.jail = function(options) {

		// Configuration
		options = $.extend({
			timeout : 10,
			effect : false,
			speed : 400,
			selector: null,
			offset : 1000,
			event : 'load+scroll',
			callback : jQuery.noop,
			callbackAfterEachImage : jQuery.noop,
			placeholder : false,
			container : window
		}, options);

		var images = this;
		
		$.jail.initialStack = this;

		// Store the selector into 'triggerEl' data for the images selected
		this.data('triggerEl', (options.selector) ? $(options.selector) : $window);
		
		// Use a placeholder in case it is specified
		if (options.placeholder !== false) {
			images.each(function(){
				$(this).attr("src", options.placeholder);
			});
		}

		// When the event is not specified the images will be loaded with a delay
		if(/^load/.test(options.event)) {
			$.asynchImageLoader.later.call(this, options);
		} else {
			$.asynchImageLoader.onEvent.call(this, options, images);
		}

		return this;
	};

	// Methods cointaing the logic
	$.asynchImageLoader = $.jail = {
	
		// Remove any elements that have been loaded from the jQuery stack.
		// This should speed up subsequent calls by not having to iterate over the loaded elements.
		_purgeStack : function(stack) {
			// number of images not loaded
			var i = 0;

			while(true) {
				if(i === stack.length) {
					break;
				} else {
					if(stack[i].getAttribute('data-href')) {
						i++;
					} else {
						stack.splice(i, 1);
					}
				}
			}
		},

		// Load the image - after the event is triggered on the image itself - no need
		// to check for visibility
		_loadOnEvent : function(e) {
			var $img = $(this),
			options = e.data.options,
			images = e.data.images;

			// Load images
			$.asynchImageLoader._loadImage(options, $img);

			// Image has been loaded so there is no need to listen anymore
			$img.unbind( options.event, $.asynchImageLoader._loadOnEvent );

			$.asynchImageLoader._purgeStack( images );
			
			if (!!options.callback) {
				$.asynchImageLoader._purgeStack( $.jail.initialStack );
				$.asynchImageLoader._launchCallback($.jail.initialStack, options);
			}
		},

		// Load the image - after the event is triggered by a DOM element different
		// from the images (options.selector value) or the event is "scroll" - 
		// visibility of the images is checked
		_bufferedEventListener : function(e) {
			var images = e.data.images,
			options = e.data.options,
			triggerEl = images.data('triggerEl');

			clearTimeout(images.data('poller'));
			images.data('poller', setTimeout(function() {
				images.each(function _imageLoader(){
					$.asynchImageLoader._loadImageIfVisible(options, this, triggerEl);
				});

				$.asynchImageLoader._purgeStack( images );
				
				if (!!options.callback) {
					$.asynchImageLoader._purgeStack( $.jail.initialStack );
					$.asynchImageLoader._launchCallback($.jail.initialStack, options);
				}
				
			}, options.timeout));
			
		},

		// Images loaded triggered by en event (event different from "load" or "load+scroll")
		onEvent : function(options, images) {
			images = images || this;

			if (options.event === 'scroll' || options.selector) {
				var triggerEl = images.data('triggerEl');

				if(images.length > 0) {

					// Bind the event to the selector specified in the config obj
					triggerEl.bind( options.event, { images:images, options:options }, $.asynchImageLoader._bufferedEventListener );
					
					if (options.event === 'scroll' || !options.selector) {
						$window.resize({ images:images, options:options }, $.asynchImageLoader._bufferedEventListener );
					}
					return;
				} else {
					if (!!triggerEl) {
						triggerEl.unbind( options.event, $.asynchImageLoader._bufferedEventListener );
					}
				}
			} else {
				// Bind the event to the images
				images.bind(options.event, { options:options, images:images }, $.asynchImageLoader._loadOnEvent);
			}
		},

		// Method called when event : "load" or "load+scroll" (default)
		later : function(options) {
			var images = this;

			// If the 'load' event is specified, immediately load all the visible images and remove them from the stack
			if (options.event === 'load') {
				images.each(function(){
					$.asynchImageLoader._loadImageIfVisible(options, this, images.data('triggerEl'));
				});
			}
			$.asynchImageLoader._purgeStack(images);
			
			$.asynchImageLoader._launchCallback(images, options);
			
			// After [timeout] has elapsed, load the remaining images if they are visible OR (if no event is specified)
			setTimeout(function() {

				if (options.event === 'load') {
					images.each(function(){
						$.asynchImageLoader._loadImage(options, $(this));
					});
				} else {
					// Method : "load+scroll"
					images.each(function(){
						$.asynchImageLoader._loadImageIfVisible(options, this, images.data('triggerEl'));
					});
				}

				$.asynchImageLoader._purgeStack( images );
				
				$.asynchImageLoader._launchCallback(images, options);

				if (options.event === 'load+scroll') {
					options.event = 'scroll';
					$.asynchImageLoader.onEvent( options, images );
				}
			}, options.timeout);
		},
		
		_launchCallback : function(images, options) {
			if (images.length === 0 && !$.jail.isCallback) {
					//Callback call
					options.callback.call(this, options);
					$.jail.isCallback = true;
			}
		},

		// Function that checks if the images have been loaded
		_loadImageIfVisible : function(options, image, triggerEl) {
			var $img = $(image),
			container = (/scroll/i.test(options.event)) ? triggerEl : $window;

			if ($.asynchImageLoader._isInTheScreen (container, $img, options.offset)) {
				$.asynchImageLoader._loadImage(options, $img);
			}
			
		},

		// Function that returns true if the image is visible inside the "window" (or specified container element)
		_isInTheScreen : function($ct, $img, optionOffset) {
			var is_ct_window  = $ct[0] === window,
				ct_offset  = (is_ct_window ? { top:0, left:0 } : $ct.offset()),
				ct_top     = ct_offset.top + ( is_ct_window ? $ct.scrollTop() : 0),
				ct_left    = ct_offset.left + ( is_ct_window ? $ct.scrollLeft() : 0),
				ct_right   = ct_left + $ct.width(),
				ct_bottom  = ct_top + $ct.height(),
				img_offset = $img.offset(),
				img_width = $img.width(),
				img_height = $img.height();
			
			return (ct_top - optionOffset) <= (img_offset.top + img_height) &&
				(ct_bottom + optionOffset) >= img_offset.top &&
					(ct_left - optionOffset)<= (img_offset.left + img_width) &&
						(ct_right + optionOffset) >= img_offset.left;
		},

		// Main function --> Load the images copying the "data-href" attribute into the "src" attribute
		_loadImage : function(options, $img) {

			$img.hide();
			$img.attr("src", $img.attr("data-href"));
			$img.removeAttr('data-href');

			// Images loaded with some effect if existing
			if(options.effect) {
				if (options.speed) {
					$img[options.effect](options.speed);
				} else {
					$img[options.effect]();
				}
			} else {
				$img.show();
			}
			
			// Callback after each image is loaded
			options.callbackAfterEachImage.call(this, $img, options);
		}
	};
}(jQuery));


/*
 * jQuery doTimeout: Like setTimeout, but better! - v1.0 - 3/3/2010
 * http://benalman.com/projects/jquery-dotimeout-plugin/
 * 
 * Copyright (c) 2010 "Cowboy" Ben Alman
 * Dual licensed under the MIT and GPL licenses.
 * http://benalman.com/about/license/
 */
(function($){var a={},c="doTimeout",d=Array.prototype.slice;$[c]=function(){return b.apply(window,[0].concat(d.call(arguments)))};$.fn[c]=function(){var f=d.call(arguments),e=b.apply(this,[c+f[0]].concat(f));return typeof f[0]==="number"||typeof f[1]==="number"?this:e};function b(l){var m=this,h,k={},g=l?$.fn:$,n=arguments,i=4,f=n[1],j=n[2],p=n[3];if(typeof f!=="string"){i--;f=l=0;j=n[1];p=n[2]}if(l){h=m.eq(0);h.data(l,k=h.data(l)||{})}else{if(f){k=a[f]||(a[f]={})}}k.id&&clearTimeout(k.id);delete k.id;function e(){if(l){h.removeData(l)}else{if(f){delete a[f]}}}function o(){k.id=setTimeout(function(){k.fn()},j)}if(p){k.fn=function(q){if(typeof p==="string"){p=g[p]}p.apply(m,d.call(n,i))===true&&!q?o():e()};o()}else{if(k.fn){j===undefined?e():k.fn(j===false);return true}else{e()}}}})(jQuery);



/**
 * jQuery.ScrollTo - Easy element scrolling using jQuery.
 * Copyright (c) 2007-2009 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com
 * Dual licensed under MIT and GPL.
 * Date: 5/25/2009
 * @author Ariel Flesler
 * @version 1.4.2
 *
 * http://flesler.blogspot.com/2007/10/jqueryscrollto.html
 */
;(function(d){var k=d.scrollTo=function(a,i,e){d(window).scrollTo(a,i,e)};k.defaults={axis:'xy',duration:parseFloat(d.fn.jquery)>=1.3?0:1};k.window=function(a){return d(window)._scrollable()};d.fn._scrollable=function(){return this.map(function(){var a=this,i=!a.nodeName||d.inArray(a.nodeName.toLowerCase(),['iframe','#document','html','body'])!=-1;if(!i)return a;var e=(a.contentWindow||a).document||a.ownerDocument||a;return d.browser.safari||e.compatMode=='BackCompat'?e.body:e.documentElement})};d.fn.scrollTo=function(n,j,b){if(typeof j=='object'){b=j;j=0}if(typeof b=='function')b={onAfter:b};if(n=='max')n=9e9;b=d.extend({},k.defaults,b);j=j||b.speed||b.duration;b.queue=b.queue&&b.axis.length>1;if(b.queue)j/=2;b.offset=p(b.offset);b.over=p(b.over);return this._scrollable().each(function(){var q=this,r=d(q),f=n,s,g={},u=r.is('html,body');switch(typeof f){case'number':case'string':if(/^([+-]=)?\d+(\.\d+)?(px|%)?$/.test(f)){f=p(f);break}f=d(f,this);case'object':if(f.is||f.style)s=(f=d(f)).offset()}d.each(b.axis.split(''),function(a,i){var e=i=='x'?'Left':'Top',h=e.toLowerCase(),c='scroll'+e,l=q[c],m=k.max(q,i);if(s){g[c]=s[h]+(u?0:l-r.offset()[h]);if(b.margin){g[c]-=parseInt(f.css('margin'+e))||0;g[c]-=parseInt(f.css('border'+e+'Width'))||0}g[c]+=b.offset[h]||0;if(b.over[h])g[c]+=f[i=='x'?'width':'height']()*b.over[h]}else{var o=f[h];g[c]=o.slice&&o.slice(-1)=='%'?parseFloat(o)/100*m:o}if(/^\d+$/.test(g[c]))g[c]=g[c]<=0?0:Math.min(g[c],m);if(!a&&b.queue){if(l!=g[c])t(b.onAfterFirst);delete g[c]}});t(b.onAfter);function t(a){r.animate(g,j,b.easing,a&&function(){a.call(this,n,b)})}}).end()};k.max=function(a,i){var e=i=='x'?'Width':'Height',h='scroll'+e;if(!d(a).is('html,body'))return a[h]-d(a)[e.toLowerCase()]();var c='client'+e,l=a.ownerDocument.documentElement,m=a.ownerDocument.body;return Math.max(l[h],m[h])-Math.min(l[c],m[c])};function p(a){return typeof a=='object'?a:{top:a,left:a}}})(jQuery);









/**
 * writeCapture.js v1.0.5
 *
 * @author noah <noah.sloan@gmail.com>
 * 
 */
(function($,global) {
	var doc = global.document;
	function doEvil(code) {
		var div = doc.createElement('div');
		doc.body.insertBefore(div,null);
		$.replaceWith(div,'<script type="text/javascript">'+code+'</script>');
	}
	// ensure we have our support functions
	$ = $ || (function(jQuery) {
		/**
		 * @name writeCaptureSupport
		 *
		 * The support functions writeCapture needs.
		 */		
		return {
			/**
			 * Takes an options parameter that must support the following:
			 * {
			 * 	url: url,
			 * 	type: 'GET', // all requests are GET
			 * 	dataType: "script", // it this is set to script, script tag injection is expected, otherwise, treat as plain text
			 * 	async: true/false, // local scripts are loaded synchronously by default
			 * 	success: callback(text,status), // must not pass a truthy 3rd parameter
			 * 	error: callback(xhr,status,error) // must pass truthy 3rd parameter to indicate error
			 * }
			 */
			ajax: jQuery.ajax,
			/**
			 * @param {String Element} selector an Element or selector
			 * @return {Element} the first element matching selector
			 */
			$: function(s) { return jQuery(s)[0]; },
			/**
			 * @param {String jQuery Element} selector the element to replace.
			 * writeCapture only needs the first matched element to be replaced.
			 * @param {String} content the content to replace 
			 * the matched element with. script tags must be evaluated/loaded 
			 * and executed if present.
			 */
			replaceWith: function(selector,content) {
				// jQuery 1.4? has a bug in replaceWith so we can't use it directly
				var el = jQuery(selector)[0];
				var next = el.nextSibling, parent = el.parentNode;

				jQuery(el).remove();

				if ( next ) {
					jQuery(next).before( content );
				} else {
					jQuery(parent).append( content );
				}
			},

			onLoad: function(fn) {
				jQuery(fn);
			},
			
			copyAttrs: function(src,dest) {
				var el = jQuery(dest), attrs = src.attributes;
				for (var i = 0, len = attrs.length; i < len; i++) {
					if(attrs[i] && attrs[i].value) {
						try {
							el.attr(attrs[i].name,attrs[i].value);
						} catch(e) { }
					}
				}
			}
		};
	})(global.jQuery);

	$.copyAttrs = $.copyAttrs || function() {};
	$.onLoad = $.onLoad || function() {
		throw "error: autoAsync cannot be used without jQuery " +
			"or defining writeCaptureSupport.onLoad";
	};

	// utilities
	function each(array,fn) {
		for(var i =0, len = array.length; i < len; i++) { 
			if( fn(array[i]) === false) return; 
		}
	}	
	function isFunction(o) {
		return Object.prototype.toString.call(o) === "[object Function]";
	}
	function isString(o) {
		return Object.prototype.toString.call(o) === "[object String]";
	}	
	function slice(array,start,end) {
		return Array.prototype.slice.call(array,start || 0,end || array && array.length);		
	}
	function any(array,fn) {
		var result = false;
		each(array,check);
		function check(it) {
			return !(result = fn(it));
		}
		return result;
	}
	
	function SubQ(parent) {
		this._queue = [];
		this._children = [];
		this._parent = parent;
		if(parent) parent._addChild(this);
	}
	
	SubQ.prototype = {
		_addChild: function(q) {
			this._children.push(q);
		},
		push: function (task) {
			this._queue.push(task);
			this._bubble('_doRun');
		},
		pause: function() {
			this._bubble('_doPause');
		},
		resume: function() {
			this._bubble('_doResume');
		},
		_bubble: function(name) {
			var root = this;
			while(!root[name]) {
				root = root._parent;
			}
			return root[name]();
		},
		_next: function() {
			if(any(this._children,runNext)) return true;
			function runNext(c) {
				return c._next();
			}
			var task = this._queue.shift();
			if(task) {
				task();
			}
			return !!task;
		}
	};
	
	/**
	 * Provides a task queue for ensuring that scripts are run in order.
	 *
	 * The only public methods are push, pause and resume.
	 */
	function Q(parent) {
		if(parent) {
			return new SubQ(parent);
		}
		SubQ.call(this);
		this.paused = 0;
	}
	
	Q.prototype = (function() {
		function f() {}
		f.prototype = SubQ.prototype;
		return new f();
	})();
	
	Q.prototype._doRun = function() {
		if(!this.running) {
			this.running = true;
			try {
				// just in case there is a bug, always resume 
				// if paused is less than 1
				while(this.paused < 1 && this._next()){}
			} finally {
				this.running = false;
			}
		}
	};
	Q.prototype._doPause= function() {
		this.paused++;
	};
	Q.prototype._doResume = function() {
		this.paused--;
		this._doRun();
	};
	
	// TODO unit tests...
	function MockDocument() { }
	MockDocument.prototype = {
		_html: '',
		open: function( ) { 
			this._opened = true;
			if(this._delegate) {
				this._delegate.open();
			}
		},
		write: function(s) { 
			if(this._closed) return; 
			this._written = true;
			if(this._delegate) {
				this._delegate.write(s);
			} else {
				this._html += s;
			}
		}, 
		writeln: function(s) { 
			this.write(s + '\n');
		}, 
		close: function( ) { 
			this._closed = true;
			if(this._delegate) {
				this._delegate.close();
			}
		}, 
		copyTo: function(d) { 
			this._delegate = d;
			d.foobar = true;
			if(this._opened) {
				d.open();
			}
			if(this._written) {
				d.write(this._html); 
			}
			if(this._closed) {
				d.close();
			}
		}
	};
	
	// test for IE 6/7 issue (issue 6) that prevents us from using call
	var canCall = (function() {
		var f = { f: doc.getElementById };
		try {
			f.f.call(doc,'abc');
			return true;
		} catch(e) {
			return false;
		}
	})();
	
	function unProxy(elements) {
		each(elements,function(it) {
			var real = doc.getElementById(it.id);
			if(!real) {
				logError('<proxyGetElementById - finish>',
					'no element in writen markup with id ' + it.id);
				return;
			}

			each(it.el.childNodes,function(it) {
				real.appendChild(it);
			});

			if(real.contentWindow) {
				// TODO why is the setTimeout necessary?
				global.setTimeout(function() {
					it.el.contentWindow.document.
						copyTo(real.contentWindow.document);
				},1);
			}
			$.copyAttrs(it.el,real);
		});
	}
	
	function getOption(name,options) {
		if(options && options[name] === false) {
			return false;
		}
		return options && options[name] || self[name];
	}
	
	function capture(context,options) {
		var tempEls = [],
			proxy = getOption('proxyGetElementById',options),
			forceLast = getOption('forceLastScriptTag',options),
			writeOnGet = getOption('writeOnGetElementById',options),
			immediate = getOption('immediateWrites', options),
			state = {
				write: doc.write,
				writeln: doc.writeln,
				finish: function() {},
				out: ''
			};
		context.state = state;
		doc.write = immediate ? immediateWrite : replacementWrite;
		doc.writeln = immediate ? immediateWriteln : replacementWriteln;
		if(proxy || writeOnGet) {
			state.getEl = doc.getElementById;
			doc.getElementById = getEl;
			if(writeOnGet) {
				findEl = writeThenGet;
			} else {
				findEl = makeTemp;
				state.finish = function() {
					unProxy(tempEls);
				};
			}
		}
		if(forceLast) {
			state.getByTag = doc.getElementsByTagName;
			doc.getElementsByTagName = function(name) {
				var result = slice(canCall ? state.getByTag.call(doc,name) :
					state.getByTag(name));				
				if(name === 'script') {
					result.push( $.$(context.target) );
				}
				return result;
			};
			var f = state.finish;
			state.finish = function() {
				f();
				doc.getElementsByTagName = state.getByTag;
			};
		}
		function replacementWrite(s) {
			state.out +=  s;
		}
		function replacementWriteln(s) {
			state.out +=  s + '\n';
		}
		function immediateWrite(s) {
			var target = $.$(context.target);
			var div = doc.createElement('div');
			target.parentNode.insertBefore(div,target);
			$.replaceWith(div,sanitize(s));
		}
		function immediateWriteln(s) {
			var target = $.$(context.target);
			var div = doc.createElement('div');
			target.parentNode.insertBefore(div,target);
			$.replaceWith(div,sanitize(s) + '\n');
		}
		function makeTemp(id) {
			var t = doc.createElement('div');
			tempEls.push({id:id,el:t});
			// mock contentWindow in case it's supposed to be an iframe
			t.contentWindow = { document: new MockDocument() };
			return t;
		}
		function writeThenGet(id) {
			var target = $.$(context.target);
			var div = doc.createElement('div');
			target.parentNode.insertBefore(div,target);
			$.replaceWith(div,state.out);
			state.out = '';
			return canCall ? state.getEl.call(doc,id) : 
				state.getEl(id);
		}
		function getEl(id) {
			var result = canCall ? state.getEl.call(doc,id) : 
				state.getEl(id);
			return result || findEl(id);
		}
		return state;
	}
	function uncapture(state) {
		doc.write = state.write;
		doc.writeln = state.writeln;
		if(state.getEl) {
			doc.getElementById = state.getEl;
		}
		return state.out;
	}
	
	function clean(code) {
		// IE will execute inline scripts with <!-- (uncommented) on the first
		// line, but will not eval() them happily
		return code && code.replace(/^\s*<!(\[CDATA\[|--)/,'').replace(/(\]\]|--)>\s*$/,'');
	}
	
	function ignore() {}
	function doLog(code,error) {
		console.error("Error",error,"executing code:",code);
	}
	
	var logError = isFunction(global.console && console.error) ? 
			doLog : ignore;
	
	function captureWrite(code,context,options) {
		var state = capture(context,options);
		try {
			doEvil(clean(code));
		} catch(e) {
			logError(code,e);
		} finally {
			uncapture(state);
		}
		return state;
	}
	
	// copied from jQuery
	function isXDomain(src) {
		var parts = /^(\w+:)?\/\/([^\/?#]+)/.exec(src);
		return parts && ( parts[1] && parts[1] != location.protocol || parts[2] != location.host );
	}
	
	function attrPattern(name) {
		return new RegExp('[\\s\\r\\n]'+name+'[\\s\\r\\n]*=[\\s\\r\\n]*(?:(["\'])([\\s\\S]*?)\\1|([^\\s>]+))','i');
	}
	
	function matchAttr(name) {
		var regex = attrPattern(name);
		return function(tag) {
			var match = regex.exec(tag) || [];
			return match[2] || match[3];
		};
	}

	var SCRIPT_TAGS = /(<script[^>]*>)([\s\S]*?)<\/script>/ig, 
		SCRIPT_2 = /<script[^>]*\/>/ig,
		SRC_REGEX = attrPattern('src'),
		SRC_ATTR = matchAttr('src'),
		TYPE_ATTR = matchAttr('type'),
		LANG_ATTR = matchAttr('language'),
		GLOBAL = "__document_write_ajax_callbacks__",
		DIV_PREFIX = "__document_write_ajax_div-",
		TEMPLATE = "window['"+GLOBAL+"']['%d']();",
		callbacks = global[GLOBAL] = {},
		TEMPLATE_TAG = '<script type="text/javascript">' + TEMPLATE + '</script>',
		global_id = 0;
	function nextId() {
		return (++global_id).toString();
	}
	
	function normalizeOptions(options,callback) {
		var done;
		if(isFunction(options)) {
			done = options;
			options = null;
		}
		options = options || {};
		done = done || options && options.done;
		options.done = callback ? function() {
			callback(done);
		} : done;
		return options;
	}
	
	// The global Q synchronizes all sanitize operations. 
	// The only time this synchronization is really necessary is when two or 
	// more consecutive sanitize operations make async requests. e.g.,
	// sanitize call A requests foo, then sanitize B is called and bar is 
	// requested. document.write was replaced by B, so if A returns first, the 
	// content will be captured by B, then when B returns, document.write will
	// be the original document.write, probably messing up the page. At the 
	// very least, A will get nothing and B will get the wrong content.
	var GLOBAL_Q = new Q();
	
	var debug = [];
	var logDebug = window._debugWriteCapture ? function() {} :
		function (type,src,data) {
		    debug.push({type:type,src:src,data:data});
		};

	var logString = window._debugWriteCapture ? function() {} :
		function () {
			debug.push(arguments);
		};

	function newCallback(fn) {
		var id = nextId();
		callbacks[id] = function() {
			fn();
			delete callbacks[id];
		};
		return id;
	}
	
	function newCallbackTag(fn) {			
		return TEMPLATE_TAG.replace(/%d/,newCallback(fn));
	}	

	/**
	 * Sanitize the given HTML so that the scripts will execute with a modified
	 * document.write that will capture the output and append it in the 
	 * appropriate location.  
	 * 
	 * @param {String} html
	 * @param {Object Function} [options]
	 * @param {Function} [options.done] Called when all the scripts in the 
	 * sanitized HTML have run.
	 * @param {boolean} [options.asyncAll] If true, scripts loaded from the
	 * same domain will be loaded asynchronously. This can improve UI 
	 * responsiveness, but will delay completion of the scripts and may
	 * cause problems with some scripts, so it defaults to false.
	 */
	function sanitize(html,options,parentQ,parentContext) {
		// each HTML fragment has it's own queue
		var queue = parentQ && new Q(parentQ) || GLOBAL_Q;
		options = normalizeOptions(options);
		var done = getOption('done',options);
		var doneHtml = '';
		
		var fixUrls = getOption('fixUrls',options);
		if(!isFunction(fixUrls)) {
			fixUrls = function(src) { return src; };
		}
		
		// if a done callback is passed, append a script to call it
		if(isFunction(done)) {
			// no need to proxy the call to done, so we can append this to the 
			// filtered HTML
			doneHtml = newCallbackTag(function() {
				queue.push(done);
			});
		}
		// for each tag, generate a function to load and eval the code and queue
		// themselves
		return html.replace(SCRIPT_TAGS,proxyTag).replace(SCRIPT_2,proxyBodyless) + doneHtml;
		function proxyBodyless(tag) {
			// hack in a bodyless tag...
			return proxyTag(tag,tag.substring(0,tag.length-2)+'>','');
		}
		function proxyTag(element,openTag,code) {
			var src = SRC_ATTR(openTag),
				type = TYPE_ATTR(openTag) || '',
				lang = LANG_ATTR(openTag) || '',
				isJs = (!type && !lang) || // no type or lang assumes JS
					type.toLowerCase().indexOf('javascript') !== -1 || 
					lang.toLowerCase().indexOf('javascript') !== -1;
			
			logDebug('replace',src,element);
			
			if(!isJs) {
			    return element;
			}
			
			var id = newCallback(queueScript), divId = DIV_PREFIX + id,
				run, context = { target: '#' + divId, parent: parentContext };
			
			function queueScript() {
				queue.push(run);
			}
			
			if(src) {
				// fix for the inline script that writes a script tag with encoded 
				// ampersands hack (more comon than you'd think)
				src = fixUrls(src);
								
				openTag = openTag.replace(SRC_REGEX,'');
				if(isXDomain(src)) {
					// will load async via script tag injection (eval()'d on
					// it's own)
					run = loadXDomain;
				} else {
					// can be loaded then eval()d
					if(getOption('asyncAll',options)) {
						run = loadAsync();
					} else {
						run = loadSync;
					}
				}
			} else {
				// just eval code and be done
				run = runInline;
				                  
			}
			function runInline() {
				captureHtml(code);
			}
			function loadSync() {
				$.ajax({
					url: src,
					type: 'GET',
					dataType: 'text',
					async: false,
					success: function(html) {
						captureHtml(html);
					}	
				});
			}
			function logAjaxError(xhr,status,error) {
				logError("<XHR for "+src+">",error);
				queue.resume();
			}
			function setupResume() {
				return newCallbackTag(function() {
					queue.resume();
				});
			}
			function loadAsync() {
				var ready, scriptText;
				function captureAndResume(script,status) {
					if(!ready) {
						// loaded before queue run, cache text
						scriptText = script;
						return;
					}
					try {
						captureHtml(script, setupResume());
					} catch(e) {
						logError(script,e);
					}
				}
				// start loading the text
				$.ajax({
					url: src,
					type: 'GET',
					dataType: 'text',
					async: true,
					success: captureAndResume,
					error: logAjaxError
				});				
				return function() {
					ready = true;
					if(scriptText) {
						// already loaded, so don't pause the queue and don't resume!
						captureHtml(scriptText);
					} else {
						queue.pause();	
					}
				};
			}
			function loadXDomain(cb) {
				var state = capture(context,options);
				queue.pause(); // pause the queue while the script loads
				logDebug('pause',src);
				
				doXDomainLoad(context.target,src,captureAndResume);		

				function captureAndResume(xhr,st,error) {
					logDebug('out', src, state.out);
					html(uncapture(state), 
						newCallbackTag(state.finish) + setupResume());
					logDebug('resume',src);
				}
			}
			function captureHtml(script, cb) {
				var state = captureWrite(script,context,options);
				cb = newCallbackTag(state.finish) + (cb || '');
				html(state.out,cb);
			}
			function safeOpts(options) {
				var copy = {};
				for(var i in options) {
					if(options.hasOwnProperty(i)) {
						copy[i] = options[i];
					}
				}
				delete copy.done;
				return copy;
			}
			function html(markup,cb) {
			 	$.replaceWith(context.target,sanitize(markup,safeOpts(options),queue,context) + (cb || ''));
			} 
			return '<div style="display: none" id="'+divId+'"></div>' + openTag +
				TEMPLATE.replace(/%d/,id) + '</script>';
		}
	}
    
    function doXDomainLoad(target,url,success) {
    	// TODO what about scripts that fail to load? bad url, etc.?
		var script = document.createElement("script");
		script.src = url;

		target = $.$(target);

		var done = false, parent = target.parentNode;

		// Attach handlers for all browsers
		script.onload = script.onreadystatechange = function(){
			if ( !done && (!this.readyState ||
					this.readyState == "loaded" || this.readyState == "complete") ) {
				done = true;
				success();

				// Handle memory leak in IE
				script.onload = script.onreadystatechange = null;
				parent.removeChild( script );
			}
		};		
		
		parent.insertBefore(script,target);        
    }	
	
	/**
	 * Sanitizes all the given fragments and calls action with the HTML.
	 * The next fragment is not started until the previous fragment
	 * has executed completely.
	 * 
	 * @param {Array} fragments array of objects like this:
	 * {
	 *   html: '<p>My html with a <script...',
	 *   action: function(safeHtml,frag) { doSomethingToInject(safeHtml); },
	 *   options: {} // optional, see #sanitize
	 * }
	 * Where frag is the object.
	 * 
	 * @param {Function} [done] Optional. Called when all fragments are done.
	 */
	function sanitizeSerial(fragments,done) {
		// create a queue for these fragments and make it the parent of each 
		// sanitize call
		var queue = GLOBAL_Q;
		each(fragments, function (f) {
			queue.push(run);
			function run() {
				f.action(sanitize(f.html,f.options,queue),f);
			}
		});
		if(done) {
			queue.push(done);		
		}
	}
	
	function findLastChild(el) {
		var n = el;
		while(n && n.nodeType === 1) {
			el = n;
			n = n.lastChild;
			// last child may not be an element
			while(n && n.nodeType !== 1) {
				n = n.previousSibling;
			}
		}
		return el;
	}
		
	/**
	  * Experimental - automatically captures document.write calls and 
	  * defers them untill after page load.
	  * @param {Function} [done] optional callback for when all the 
	  * captured content has been loaded.
	  */
	function autoCapture(done) {
		var write = doc.write, 
			writeln = doc.writeln,
			currentScript,
			autoQ = [];
		doc.writeln = function(s) {
			doc.write(s+'\n');
		};
		var state;
		doc.write = function(s) {
			var scriptEl = findLastChild(doc.body);
			if(scriptEl !== currentScript) {
				currentScript = scriptEl;
				autoQ.push(state = {
					el: scriptEl,
					out: []
				});					
			}
			state.out.push(s);
		};
		$.onLoad(function() {			
			// for each script, append a div immediately after it, 
			// then replace the div with the sanitized output
			var el, div, out, safe, doneFn;
			done = normalizeOptions(done);
			doneFn = done.done;
			done.done = function() {
				doc.write = write;
				doc.writeln = writeln;
				if(doneFn) doneFn();				
			};
			for(var i = 0, len = autoQ.length; i < len; i++ ) {
				el = autoQ[i].el;
				div = doc.createElement('div');
				el.parentNode.insertBefore( div, el.nextSibling );
				out = autoQ[i].out.join('');
				// only the last snippet gets passed the callback
				safe = len - i === 1 ? sanitize(out,done) : sanitize(out);
				$.replaceWith(div,safe);
			}
		});
	}
	
	function extsrc(cb) {
		var scripts = document.getElementsByTagName('script'),
			s,o, html, q, ext, async, doneCount = 0,
			done = cb ? newCallbackTag(function() {
				if(++doneCount >= exts.length) {
					cb();
				}
			}) : '',
			exts = [];
			
		for(var i = 0, len = scripts.length; i < len; i++) {
			s = scripts[i];
			ext = s.getAttribute('extsrc');
			async = s.getAttribute('asyncsrc');
			if(ext || async) {
				exts.push({ext:ext,async:async,s:s});
			}
		}

		for(i = 0, len = exts.length; i < len; i++) {
			o = exts[i];
			if(o.ext) {
				html = '<script type="text/javascript" src="'+o.ext+'"> </script>';
				$.replaceWith(o.s,sanitize(html) + done);				
			} else if(o.async) {
				html = '<script type="text/javascript" src="'+o.async+'"> </script>';
				$.replaceWith(o.s,sanitize(html,{asyncAll:true}, new Q()) + done);
			}
		}
	}
	
	var name = 'writeCapture';
	var self = global[name] = {
		_original: global[name],
		support: $,
		/**
		 */
		fixUrls: function(src) {
		    return src.replace(/&amp;/g,'&');
		},
		noConflict: function() {
			global[name] = this._original;
			return this;
		},
		debug: debug,
		/**
		 * Enables a fun little hack that replaces document.getElementById and
		 * creates temporary elements for the calling code to use.
		 */
		proxyGetElementById: false,
		// this is only for testing, please don't use these
		_forTest: {
			Q: Q,
			GLOBAL_Q: GLOBAL_Q,
			$: $,
			matchAttr: matchAttr,
			slice: slice,
			capture: capture,
			uncapture: uncapture,
			captureWrite: captureWrite
		},
		replaceWith: function(selector,content,options) {
			$.replaceWith(selector,sanitize(content,options));
		},
		html: function(selector,content,options) {
			var el = $.$(selector);
			el.innerHTML ='<span/>';
			$.replaceWith(el.firstChild,sanitize(content,options));
		},	
		load: function(selector,url,options) {
			$.ajax({
				url: url,
				dataType: 'text',
				type: "GET",
				success: function(content) {
					self.html(selector,content,options);
				}
			});
		},
		extsrc: extsrc,
		autoAsync: autoCapture,
		sanitize: sanitize,
		sanitizeSerial: sanitizeSerial
	};
	
})(this.writeCaptureSupport,this);

/**
 * jquery.writeCapture.js 
 * 
 * Note that this file only provides the jQuery plugin functionality, you still
 * need writeCapture.js. The compressed version will contain both as as single
 * file.
 *
 * @author noah <noah.sloan@gmail.com>
 * 
 */
(function($,wc,noop) {
	// methods that take HTML content (according to API)
	var methods = {
		html: html
	};
	// TODO wrap domManip instead?
	$.each(['append', 'prepend', 'after', 'before', 'wrap', 'wrapAll', 'replaceWith',
		'wrapInner'],function() { methods[this] = makeMethod(this); });
	
	function isString(s) {
		return Object.prototype.toString.call(s) == "[object String]";
	}
	
	function executeMethod(method,content,options,cb) {
		if(arguments.length == 0) return proxyMethods.call(this);
		
		var m = methods[method];
		if(method == 'load') {
			return load.call(this,content,options,cb);
		}
		if(!m) error(method);
		return doEach.call(this,content,options,m);
	}
	
	$.fn.writeCapture = executeMethod;
	
	var PROXIED = '__writeCaptureJsProxied-fghebd__';
	// inherit from the jQuery instance, proxying the HTML injection methods
	// so that the HTML is sanitized
	function proxyMethods() {
		if(this[PROXIED]) return this;
		
		var jq = this;
		function F() {
			var _this = this, sanitizing = false;
			this[PROXIED] = true;
			$.each(methods,function(method) {
				var _super = jq[method];
				if(!_super) return;
				_this[method] = function(content,options,cb) {
					// if it's unsanitized HTML, proxy it
					if(!sanitizing && isString(content)) {
						try {
							sanitizing = true;
							return executeMethod.call(_this,method,content,
								options,cb);
						} finally {
							sanitizing = false;
						}
					} 
					return _super.apply(_this,arguments); // else delegate
				};
			});
			// wrap pushStack so that the new jQuery instance is also wrapped
			this.pushStack = function() {
				return proxyMethods.call(jq.pushStack.apply(_this,arguments));
			};
			this.endCapture = function() { return jq; };
		}
		F.prototype = jq;
		return new F();
	}
	
	function doEach(content,options,action) {
		var done, self = this;
		if(options && options.done) {
			done = options.done;
			delete options.done;
		} else if($.isFunction(options)) {
			done = options;
			options = null;
		}
		wc.sanitizeSerial($.map(this,function(el) {
			return {
				html: content,
				options: options,
				action: function(text) {
					action.call(el,text);
				}
			};
		}),done && function() { done.call(self); } || done);
		return this;
	}
	
	
	function html(safe) {
		$(this).html(safe);
	}
	
	function makeMethod(method) {
		return function(safe) {
			$(this)[method](safe);
		};
	}
	
	function load(url,options,callback) {
		var self = this,  selector, off = url.indexOf(' ');
		if ( off >= 0 ) {
			selector = url.slice(off, url.length);
			url = url.slice(0, off);
		}
		if($.isFunction(callback)) {
			options = options || {};
			options.done = callback;
		}
		return $.ajax({
			url: url,
			type:  options && options.type || "GET",
			dataType: "html",
			data: options && options.params,
			complete: loadCallback(self,options,selector)
		});
	}
	
	function loadCallback(self,options,selector) {
		return function(res,status) {
			if ( status == "success" || status == "notmodified" ) {
				var text = getText(res.responseText,selector);
				doEach.call(self,text,options,html);
			}
		};
	}
	
	var PLACEHOLDER = /jquery-writeCapture-script-placeholder-(\d+)-wc/g;
	function getText(text,selector) {
		if(!selector || !text) return text;
		
		var id = 0, scripts = {};			
		return $('<div/>').append(
			text.replace(/<script(.|\s)*?\/script>/g, function(s) {
				scripts[id] = s;
				return "jquery-writeCapture-script-placeholder-"+(id++)+'-wc';
			})
		).find(selector).html().replace(PLACEHOLDER,function(all,id) {
			return scripts[id];
		});
	}
	
	function error(method) {
		throw "invalid method parameter "+method;
	}
	
	// expose core
	$.writeCapture = wc;
})(jQuery,writeCapture.noConflict());





/* =========================================================
// jquery.innerFade.js

// Date: 2010-07-23
// Author: Wes Baker
// Mail: wes@wesbaker.com	
// Web: http://www.wesbaker.com
// ========================================================= */

(function($) {
	var default_options = {
		'animationType':			'fade',
		'animate': 					true,
		'first_slide': 				0,
		'easing':					'linear',
		'speed':					'normal',
		'type':						'sequence',
		'timeout':					2000,
		'startDelay': 				0,
		'loop': 					true,
		'containerHeight':			'auto',
		'runningClass':				'innerFade',
		'children':					null,
		'cancelLink':				null, 
		'pauseLink':				null,
		'prevLink':					null,
		'nextLink':					null,
		'indexContainer': 			null,
		'currentItemContainer': 	null,
		'totalItemsContainer': 		null,
		'callback_index_update': 	null
	};
	
	$.fn.innerFade = function(options) {
		return this.each(function() {
			$fade_object = new Object();
			// Assign the container
			$fade_object.container = this;
			// Combine default and set settings or use default
			// Pay attention kids, there's an important lesson here. When using $.extend, the first parameter will
			// be CHANGED to the combination of all the parameters. In my situation, I just wanted to combine two 
			// objects, but not affect them in any way hence the empty object.
			$fade_object.settings = $.extend({}, default_options, options);
			// If children option is set use that as elements, otherwise use the called jQuery object
			$fade_object.elements = ($fade_object.settings.children === null) ? $($fade_object.container).children() : $($fade_object.container).children($fade_object.settings.children);
			// Setup the count
			$fade_object.count = 0;
			// Save data to container for use later
			$($fade_object.container).data('object', $fade_object);
			
			// Start the loop
			if ($fade_object.elements.length > 1) {
				// Establish the Next and Previous Handlers
				$.bindControls($fade_object);

				// Establish Cancel Handler
				if ($fade_object.settings.cancelLink) { $.bindCancel($fade_object); };

				// Set outer container as relative, and use the height that's set and add the running class
				$($fade_object.container).css({'position': 'relative'}).addClass($fade_object.settings.runningClass);
				if ($fade_object.settings.containerHeight == 'auto') {
					height = $($fade_object.elements).filter(':first').height();
					$($fade_object.container).css({'height': height + 'px'});
				} else {
					$($fade_object.container).css({'height': $fade_object.settings.containerHeight});
				};

				// Build the Index if one is specified
				if ($fade_object.settings.indexContainer) {				
					$.innerFadeIndex($fade_object);
				};

				$($fade_object.elements).filter(':gt(0)').hide(0);
				// Set the z-index from highest to lowest (20, 19, 18...) and set their position as absolute
				for (var i = 0; i < $fade_object.elements.length; i++) {
					$($fade_object.elements[i]).css('z-index', String($fade_object.elements.length-i)).css('position', 'absolute');
				}

				var toShow = '';
				var toHide = '';

				if ($fade_object.settings.type == "random") {
					toHide = Math.floor(Math.random() * $fade_object.elements.length);
					do { 
						toShow = Math.floor(Math.random() * $fade_object.elements.length);
					} while (toHide == toShow );				
					$($fade_object.elements[toHide]).show();
				} else if ( $fade_object.settings.type == 'random_start' ) {
					$fade_object.settings.type = 'sequence';
					toHide = Math.floor ( Math.random () * ( $fade_object.elements.length ) );
					toShow = (toHide + 1) % $fade_object.elements.length;
				} else {
					// Otherwise and if its sequence
					toShow = $fade_object.settings.first_slide;
					toHide = ($fade_object.settings.first_slide == 0) ? $fade_object.elements.length - 1 : $fade_object.settings.first_slide - 1;
				}

				if ($fade_object.settings.animate) {
					$.fadeTimeout($fade_object, toShow, toHide, true);
				} else {
					$($fade_object.elements[toShow]).show();
					$($fade_object.elements[toHide]).hide();
					$.updateIndexes($fade_object, toShow);
				};
				$.updateIndexes($fade_object, toShow);

				if ($fade_object.settings.type == 'random') {
					$($fade_object.elements[toHide]).show();
				} else {
					$($fade_object.elements[toShow]).show();
				};

				// Set item count containers
				if ($fade_object.settings.currentItemContainer) { $.currentItem($fade_object, toShow); };
				if ($fade_object.settings.totalItemsContainer) { $.totalItems($fade_object); };

				// Establish the Pause Handler
				if ($fade_object.settings.pauseLink) {
					$.bind_pause($fade_object);
				};
			}
		});
	};
	
	/**
	 * Public function to change to a specific slide. This is expecting a zero-index slide number.
	 * @param {Number} slide_number Zero-indexed slide number
	 */
	$.fn.innerFadeTo = function(slide_number) {
		return this.each(function(index) {
			var $fade_object = $(this).data('object');
			
			var $currentVisibleItem = $($fade_object.elements).filter(':visible');
			var currentItemIndex = $($fade_object.elements).index($currentVisibleItem);
			$.stopSlideshow($fade_object);
			if (slide_number != currentItemIndex) {
				$.fadeToItem($fade_object, slide_number, currentItemIndex);
			};
		});
	};

	/**
	 * Fades the slideshow to the item selected from the previous item
	 * @param {Object} $fade_object The object that contains the settings, elements and container for this slideshow
	 * @param {Number} toShow The position in the elements array of the item to be shown
	 * @param {Number} toHide The position in the elements array of the item to be hidden
	 */
	$.fadeToItem = function($fade_object, toShow, toHide) {		
		// Update the next and previous controls
		var buildControls = function() {
			if ($fade_object.settings.nextLink || $fade_object.settings.prevLink) { $.bindControls($fade_object); }
		};
		
		if ($fade_object.settings.animationType == 'slide') {
			$($fade_object.elements[toHide]).slideUp($fade_object.settings.speed);
			$($fade_object.elements[toShow]).slideDown($fade_object.settings.speed, function() {buildControls();});
		} else if ($fade_object.settings.animationType == 'slideOver') {
			var itemWidth = $($fade_object.elements[0]).width(),
				to_hide_css = {},
				to_show_css = {},
				to_hide_animation = {},
				to_show_animation = {};
				
			$($fade_object.container).css({'overflow': 'hidden'});
			
			// Both CSS Declarations use the same initial CSS
			to_hide_css = {
				'position': 'absolute',
				'top': '0px'
			};
			
			to_show_css = $.extend({}, to_hide_css);
			
			// If going forward, we want the item (to be shown) to animate from the right to left
			// If going backwards, we want the item (to be shown) to animate from the left to the right
			if (toShow > toHide) { // Forwards
				console.log('Forwards!');
				to_hide_css.left = "0px";
				to_hide_css.right = "auto";

				to_show_css.left = 'auto';
				to_show_css.right = '-' + itemWidth + 'px';

				to_hide_animation.left = '-' + itemWidth + 'px';

				to_show_animation.right = '0px';
				
				console.log(to_hide_css);
			} else { // Backwards
				console.log("Backwards!");
				to_hide_css.left = "auto";
				to_hide_css.right = "0px";

				to_show_css.left = '-' + itemWidth + 'px';
				to_show_css.right = 'auto';

				to_hide_animation.right = '-' + itemWidth + 'px';

				to_show_animation.left = '0px';
			};
			
			$($fade_object.elements[toHide]).css(to_hide_css);
			$($fade_object.elements[toShow]).css(to_show_css).show();

			$($fade_object.elements[toHide]).animate(to_hide_animation, $fade_object.settings.speed, $fade_object.settings.easing, function() {
				$(this).hide();
			});
			
			$($fade_object.elements[toShow]).animate(to_show_animation ,$fade_object.settings.speed, $fade_object.settings.easing, function() {
				buildControls();
			});
		} else {
			$($fade_object.elements[toHide]).fadeOut($fade_object.settings.speed);
			$($fade_object.elements[toShow]).fadeIn($fade_object.settings.speed, function() {
				buildControls();
			});
		}
		// Update the toShow item
		if ($fade_object.settings.currentItemContainer) {
			$.currentItem($fade_object, toShow);
		};
		
		// Update indexes with active classes
		if ($fade_object.settings.indexContainer || $fade_object.settings.callback_index_update) {
			$.updateIndexes($fade_object, toShow);
		};
	};

	/**
	 * Fades to the item of your choosing and establishes the timeout for the next item to fade to
	 * @param {Object} $fade_object The object that contains the settings, elements and container for this slideshow
	 * @param {Number} toShow The position in the elements array of the item to be shown
	 * @param {Number} toHide The position in the elements array of the item to be hidden
	 * @param {Boolean} firstRun If this is the first run of innerfade, pass true, otherwise pass false
	 */
	$.fadeTimeout = function($fade_object, toShow, toHide, firstRun) {
		// If its not the first run, then fade
		if (firstRun != true) {
			$.fadeToItem($fade_object, toShow, toHide);
		};
		
		// Increment the count of slides shown
		$fade_object.count++;
		
		// Check if loop is false, if it is check to see how many slides have been shown.
		// In the case that you're at the last slide, stop the slideshow and return.
		if ($fade_object.settings.loop == false && $fade_object.count >= $fade_object.elements.length) {
			$.stopSlideshow($fade_object);
			return;
		};

		// Get ready for next fade
		if ($fade_object.settings.type == "random") {
			toHide = toShow;
			while (toShow == toHide) { toShow = Math.floor(Math.random() * $fade_object.elements.length); }
		} else {
			toHide = (toHide > toShow) ? 0 : toShow;
			toShow = (toShow + 1 >= $fade_object.elements.length) ? 0 : toShow + 1;
		}
		
		// Set the time out; if its first run and a start delay exists, use the start delay
		var timeout = (firstRun && $fade_object.settings.startDelay) ? $fade_object.settings.startDelay : $fade_object.settings.timeout;
		$($fade_object.container).data('current_timeout', setTimeout((function() { $.fadeTimeout($fade_object, toShow, toHide, false); }), timeout));
	};

	/* Allows the unbind function to be called from javascript */
	$.fn.innerFadeUnbind = function() {
		return this.each(function(index) {
			var $fade_object = $(this).data('object');
			$.stopSlideshow($fade_object);
		});
	};
	
	/**
	 * Stops the slideshow
	 * @param {Object} $fade_object The object that contains the settings, elements and container for this slideshow
	 */
	$.stopSlideshow = function($fade_object) {
		clearTimeout($($fade_object.container).data('current_timeout'));
		$($fade_object.container).data('current_timeout', null);
	};
	
	/**
	 * Establishes the Next and Previous link behavior
	 * @param {Object} $fade_object The object that contains the settings, elements and container for this slideshow
	 */
	$.bindControls = function($fade_object) {
		$($fade_object.settings.nextLink).unbind().one('click', function(event) {
			event.preventDefault();
			$.stopSlideshow($fade_object);
			
			var $currentElement = $($fade_object.elements).filter(':visible');
			var currentElementIndex = $($fade_object.elements).index($currentElement);

			var $nextElement = ($currentElement.next().length > 0) ? $currentElement.next() : $($fade_object.elements).filter(':first');
			var nextElementIndex = $($fade_object.elements).index($nextElement);
			
			$.fadeToItem($fade_object, nextElementIndex, currentElementIndex);
		});
			
		$($fade_object.settings.prevLink).unbind().one('click', function(event) {
			event.preventDefault();
			$.stopSlideshow($fade_object);
			
			var $currentElement = $($fade_object.elements).filter(':visible');
			var currentElementIndex = $($fade_object.elements).index($currentElement);

			var $previousElement = ($currentElement.prev().length > 0) ? $currentElement.prev() : $($fade_object.elements).filter(':last');
			var previousElementIndex = $($fade_object.elements).index($previousElement);
			
			$.fadeToItem($fade_object, previousElementIndex, currentElementIndex);
		});
	};
	
	/**
	 * Establishes the Pause Button
	 * @param {Object} $fade_object The object that contains the settings, elements and container for this slideshow
	 */
	$.bind_pause = function($fade_object) {		
		$($fade_object.settings.pauseLink).unbind().click(function(event) {
			event.preventDefault(); 
			if ($($fade_object.container).data('current_timeout') != null) {
				$.stopSlideshow($fade_object);
			} else {
				// Restart the slideshow				
				var tag = $($fade_object.container).children(':first').attr('tagName').toLowerCase();
				var nextItem = '';
				var previousItem = '';
				
				if ($fade_object.settings.type == "random") {
					previousItem = Math.floor(Math.random() * $fade_object.elements.length);
					do { 
						nextItem = Math.floor(Math.random() * $fade_object.elements.length);
					} while (previousItem == nextItem);
				} else if ($fade_object.settings.type == "random_start") {
					previousItem = Math.floor(Math.random() * $fade_object.elements.length);
					nextItem = (previousItem + 1) % $fade_object.elements.length;
				} else {
					previousItem = $(tag, $($fade_object.container)).index($(tag+':visible', $($fade_object.container)));
					nextItem = ((previousItem + 1) == $fade_object.elements.length) ? 0 : previousItem + 1;
				}
				
				$.fadeTimeout($fade_object, nextItem, previousItem, false);
			}
		});
	};
		
	/**
	 * Establishes the Cancel Button
	 * @param {Object} $fade_object The object that contains the settings, elements and container for this slideshow
	 */
	$.bindCancel = function($fade_object) {
		$($fade_object.settings.cancelLink).unbind().click(function(event) {
			event.preventDefault();
			$.stopSlideshow($fade_object);
		});
	};

	/**
	 * Updates the indexes and adds an active class to the visible item
	 * @param {Object} $fade_object The object that contains the settings, elements and container for this slideshow
	 * @param {Number} toShow The position in the elements array of the item to be shown
	 */
	$.updateIndexes = function($fade_object, toShow) {
		$($fade_object.settings.indexContainer).children().removeClass('active');
		$('> :eq(' + toShow + ')', $($fade_object.settings.indexContainer)).addClass('active');
		
		// Check for the callback index update
		if (typeof($fade_object.settings.callback_index_update) == "function") {
			$fade_object.settings.callback_index_update.call(this, toShow);
		};
	};
	
	/**
	 * Creates handlers for the links created by the $.handleIndexes and $.generateIndexes functions
	 * @param {Object} $fade_object The object that contains the settings, elements and container for this slideshow
	 * @param {Number} count The item to be setting the link on
	 * @param {jQuery Object} link The selector or jQuery object of the link
	 */
	$.createIndexHandler = function($fade_object, count, link) {
		$(link).click(function(event) {
			event.preventDefault();
			var $currentVisibleItem = $($fade_object.elements).filter(':visible');
			var currentItemIndex = $($fade_object.elements).index($currentVisibleItem);
			$.stopSlideshow($fade_object);
			if ($currentVisibleItem.size() <= 1 && count != currentItemIndex) {
				$.fadeToItem($fade_object, count, currentItemIndex);
			};
		});
	};
	
	/**
	 * Creates one link for each item in the slideshow, to show that item immediately
	 * @param {Object} $fade_object The object that contains the settings, elements and container for this slideshow
	 */
	$.createIndexes = function($fade_object) {
		var $indexContainer = $($fade_object.settings.indexContainer);
		
		for (var i=0; i < $fade_object.elements.length; i++) {
			var	$link = $('<li><a href="#">' + (i + 1) + '</a></li>');
			$.createIndexHandler($fade_object, i, $link);
			$indexContainer.append($link);
		};
	};
	
	/**
	 * Establishes links between the slide elements and index items in the indexContainer
	 * @param {Object} $fade_object The object that contains the settings, elements and container for this slideshow
	 */
	$.linkIndexes = function($fade_object) {
		var $indexContainer = $($fade_object.settings.indexContainer);
		var $indexContainerChildren = $('> :visible', $indexContainer);
		
		if ($indexContainerChildren.size() == $fade_object.elements.length) {
			var count = $fade_object.elements.length;
			for (var i=0; i < count; i++) {
				$('a', $indexContainer).click(function(event) {event.preventDefault();});
				$.createIndexHandler($fade_object, i, $indexContainerChildren[i]);
			};
		} else {
			alert("There is a different number of items in the menu and slides. There needs to be the same number in both.\nThere are " + $indexContainerChildren.size() + " in the indexContainer.\nThere are " + $fade_object.elements.length + " in the slides container.");
		};		
	};
	
	/**
	 * Determines if the index container is empty or not. If its empty then it generates links, if its not empty 
	 * it links one to one
	 * @param {Object} $fade_object The object that contains the settings, elements and container for this slideshow
	 */
	$.innerFadeIndex = function($fade_object) {
		var $indexContainer = $($fade_object.settings.indexContainer);
		if ($(':visible', $indexContainer).size() <= 0) {
			$.createIndexes($fade_object);
		} else {
			$.linkIndexes($fade_object);
		};
	};
	
	/**
	 * Changes the text of the current item selector to the index of the current item
	 * @param {Object} $fade_object The object that contains the settings, elements and container for this slideshow
	 * @param {Number} current Index of the current slide
	 */
	$.currentItem = function($fade_object, current) {
		var $container = $($fade_object.settings.currentItemContainer);
		$container.text(current + 1);
	};
	
	/**
	 * Changes the text of the total item selector to the total number of items
	 * @param {Object} $fade_object The object that contains the settings, elements and container for this slideshow
	 */
	$.totalItems = function($fade_object) {
		var $container = $($fade_object.settings.totalItemsContainer);
		$container.text($fade_object.elements.length);
	};
})(jQuery);

