var offline = false;/* prevent execution of jQuery if included more than once */
if(typeof window.jQuery == "undefined") {
/*
 * jQuery 1.1.2 - New Wave Javascript
 *
 * Copyright (c) 2007 John Resig (jquery.com)
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 * $Date: 2007-02-28 12:03:00 -0500 (Wed, 28 Feb 2007) $
 * $Rev: 1465 $
 */

// Global undefined variable
window.undefined = window.undefined;
var jQuery = function(a,c) {
	// If the context is global, return a new object
	if ( window == this )
		return new jQuery(a,c);

	// Make sure that a selection was provided
	a = a || document;
	
	// HANDLE: $(function)
	// Shortcut for document ready
	if ( jQuery.isFunction(a) )
		return new jQuery(document)[ jQuery.fn.ready ? "ready" : "load" ]( a );
	
	// Handle HTML strings
	if ( typeof a  == "string" ) {
		// HANDLE: $(html) -> $(array)
		var m = /^[^<]*(<(.|\s)+>)[^>]*$/.exec(a);
		if ( m )
			a = jQuery.clean( [ m[1] ] );
		
		// HANDLE: $(expr)
		else
			return new jQuery( c ).find( a );
	}
	
	return this.setArray(
		// HANDLE: $(array)
		a.constructor == Array && a ||

		// HANDLE: $(arraylike)
		// Watch for when an array-like object is passed as the selector
		(a.jquery || a.length && a != window && !a.nodeType && a[0] != undefined && a[0].nodeType) && jQuery.makeArray( a ) ||

		// HANDLE: $(*)
		[ a ] );
};

// Map over the $ in case of overwrite
if ( typeof $ != "undefined" )
	jQuery._$ = $;
	
// Map the jQuery namespace to the '$' one
var $ = jQuery;

jQuery.fn = jQuery.prototype = {
	jquery: "1.1.2",

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

	get: function( num ) {
		return num == undefined ?

			// Return a 'clean' array
			jQuery.makeArray( this ) :

			// Return just the object
			this[num];
	},
	pushStack: function( a ) {
		var ret = jQuery(a);
		ret.prevObject = this;
		return ret;
	},
	setArray: function( a ) {
		this.length = 0;
		[].push.apply( this, a );
		return this;
	},
	each: function( fn, args ) {
		return jQuery.each( this, fn, args );
	},
	index: function( obj ) {
		var pos = -1;
		this.each(function(i){
			if ( this == obj ) pos = i;
		});
		return pos;
	},

	attr: function( key, value, type ) {
		var obj = key;
		
		// Look for the case where we're accessing a style value
		if ( key.constructor == String )
			if ( value == undefined )
				return this.length && jQuery[ type || "attr" ]( this[0], key ) || undefined;
			else {
				obj = {};
				obj[ key ] = value;
			}
		
		// Check to see if we're setting style values
		return this.each(function(index){
			// Set all the styles
			for ( var prop in obj )
				jQuery.attr(
					type ? this.style : this,
					prop, jQuery.prop(this, obj[prop], type, index, prop)
				);
		});
	},

	css: function( key, value ) {
		return this.attr( key, value, "curCSS" );
	},

	text: function(e) {
		if ( typeof e == "string" )
			return this.empty().append( document.createTextNode( e ) );

		var t = "";
		jQuery.each( e || this, function(){
			jQuery.each( this.childNodes, function(){
				if ( this.nodeType != 8 )
					t += this.nodeType != 1 ?
						this.nodeValue : jQuery.fn.text([ this ]);
			});
		});
		return t;
	},

	wrap: function() {
		// The elements to wrap the target around
		var a = jQuery.clean(arguments);

		// Wrap each of the matched elements individually
		return this.each(function(){
			// Clone the structure that we're using to wrap
			var b = a[0].cloneNode(true);

			// Insert it before the element to be wrapped
			this.parentNode.insertBefore( b, this );

			// Find the deepest point in the wrap structure
			while ( b.firstChild )
				b = b.firstChild;

			// Move the matched element to within the wrap structure
			b.appendChild( this );
		});
	},
	append: function() {
		return this.domManip(arguments, true, 1, function(a){
			this.appendChild( a );
		});
	},
	prepend: function() {
		return this.domManip(arguments, true, -1, function(a){
			this.insertBefore( a, this.firstChild );
		});
	},
	before: function() {
		return this.domManip(arguments, false, 1, function(a){
			this.parentNode.insertBefore( a, this );
		});
	},
	after: function() {
		return this.domManip(arguments, false, -1, function(a){
			this.parentNode.insertBefore( a, this.nextSibling );
		});
	},
	end: function() {
		return this.prevObject || jQuery([]);
	},
	find: function(t) {
		return this.pushStack( jQuery.map( this, function(a){
			return jQuery.find(t,a);
		}), t );
	},
	clone: function(deep) {
		return this.pushStack( jQuery.map( this, function(a){
			var a = a.cloneNode( deep != undefined ? deep : true );
			a.$events = null; // drop $events expando to avoid firing incorrect events
			return a;
		}) );
	},

	filter: function(t) {
		return this.pushStack(
			jQuery.isFunction( t ) &&
			jQuery.grep(this, function(el, index){
				return t.apply(el, [index])
			}) ||

			jQuery.multiFilter(t,this) );
	},

	not: function(t) {
		return this.pushStack(
			t.constructor == String &&
			jQuery.multiFilter(t, this, true) ||

			jQuery.grep(this, function(a) {
				return ( t.constructor == Array || t.jquery )
					? jQuery.inArray( a, t ) < 0
					: a != t;
			})
		);
	},

	add: function(t) {
		return this.pushStack( jQuery.merge(
			this.get(),
			t.constructor == String ?
				jQuery(t).get() :
				t.length != undefined && (!t.nodeName || t.nodeName == "FORM") ?
					t : [t] )
		);
	},
	is: function(expr) {
		return expr ? jQuery.filter(expr,this).r.length > 0 : false;
	},

	val: function( val ) {
		return val == undefined ?
			( this.length ? this[0].value : null ) :
			this.attr( "value", val );
	},

	html: function( val ) {
		return val == undefined ?
			( this.length ? this[0].innerHTML : null ) :
			this.empty().append( val );
	},
	domManip: function(args, table, dir, fn){
		var clone = this.length > 1; 
		var a = jQuery.clean(args);
		if ( dir < 0 )
			a.reverse();

		return this.each(function(){
			var obj = this;

			if ( table && jQuery.nodeName(this, "table") && jQuery.nodeName(a[0], "tr") )
				obj = this.getElementsByTagName("tbody")[0] || this.appendChild(document.createElement("tbody"));

			jQuery.each( a, function(){
				fn.apply( obj, [ clone ? this.cloneNode(true) : this ] );
			});

		});
	}
};

jQuery.extend = jQuery.fn.extend = function() {
	// copy reference to target object
	var target = arguments[0],
		a = 1;

	// extend jQuery itself if only one argument is passed
	if ( arguments.length == 1 ) {
		target = this;
		a = 0;
	}
	var prop;
	while (prop = arguments[a++])
		// Extend the base object
		for ( var i in prop ) target[i] = prop[i];

	// Return the modified object
	return target;
};

jQuery.extend({
	noConflict: function() {
		if ( jQuery._$ )
			$ = jQuery._$;
		return jQuery;
	},

	// This may seem like some crazy code, but trust me when I say that this
	// is the only cross-browser way to do this. --John
	isFunction: function( fn ) {
		return !!fn && typeof fn != "string" && !fn.nodeName && 
			typeof fn[0] == "undefined" && /function/i.test( fn + "" );
	},
	
	// check if an element is in a XML document
	isXMLDoc: function(elem) {
		return elem.tagName && elem.ownerDocument && !elem.ownerDocument.body;
	},

	nodeName: function( elem, name ) {
		return elem.nodeName && elem.nodeName.toUpperCase() == name.toUpperCase();
	},
	// args is for internal usage only
	each: function( obj, fn, args ) {
		if ( obj.length == undefined )
			for ( var i in obj )
				fn.apply( obj[i], args || [i, obj[i]] );
		else
			for ( var i = 0, ol = obj.length; i < ol; i++ )
				if ( fn.apply( obj[i], args || [i, obj[i]] ) === false ) break;
		return obj;
	},
	
	prop: function(elem, value, type, index, prop){
			// Handle executable functions
			if ( jQuery.isFunction( value ) )
				value = value.call( elem, [index] );
				
			// exclude the following css properties to add px
			var exclude = /z-?index|font-?weight|opacity|zoom|line-?height/i;

			// Handle passing in a number to a CSS property
			return value && value.constructor == Number && type == "curCSS" && !exclude.test(prop) ?
				value + "px" :
				value;
	},

	className: {
		// internal only, use addClass("class")
		add: function( elem, c ){
			jQuery.each( c.split(/\s+/), function(i, cur){
				if ( !jQuery.className.has( elem.className, cur ) )
					elem.className += ( elem.className ? " " : "" ) + cur;
			});
		},

		// internal only, use removeClass("class")
		remove: function( elem, c ){
			elem.className = c ?
				jQuery.grep( elem.className.split(/\s+/), function(cur){
					return !jQuery.className.has( c, cur );	
				}).join(" ") : "";
		},

		// internal only, use is(".class")
		has: function( t, c ) {
			t = t.className || t;
			// escape regex characters
			c = c.replace(/([\.\\\+\*\?\[\^\]\$\(\)\{\}\=\!\<\>\|\:])/g, "\\$1");
			return t && new RegExp("(^|\\s)" + c + "(\\s|$)").test( t );
		}
	},
	swap: function(e,o,f) {
		for ( var i in o ) {
			e.style["old"+i] = e.style[i];
			e.style[i] = o[i];
		}
		f.apply( e, [] );
		for ( var i in o )
			e.style[i] = e.style["old"+i];
	},

	css: function(e,p) {
		if ( p == "height" || p == "width" ) {
			var old = {}, oHeight, oWidth, d = ["Top","Bottom","Right","Left"];

			jQuery.each( d, function(){
				old["padding" + this] = 0;
				old["border" + this + "Width"] = 0;
			});

			jQuery.swap( e, old, function() {
				if (jQuery.css(e,"display") != "none") {
					oHeight = e.offsetHeight;
					oWidth = e.offsetWidth;
				} else {
					e = jQuery(e.cloneNode(true))
						.find(":radio").removeAttr("checked").end()
						.css({
							visibility: "hidden", position: "absolute", display: "block", right: "0", left: "0"
						}).appendTo(e.parentNode)[0];

					var parPos = jQuery.css(e.parentNode,"position");
					if ( parPos == "" || parPos == "static" )
						e.parentNode.style.position = "relative";

					oHeight = e.clientHeight;
					oWidth = e.clientWidth;

					if ( parPos == "" || parPos == "static" )
						e.parentNode.style.position = "static";

					e.parentNode.removeChild(e);
				}
			});

			return p == "height" ? oHeight : oWidth;
		}

		return jQuery.curCSS( e, p );
	},

	curCSS: function(elem, prop, force) {
		var ret;
		
		if (prop == "opacity" && jQuery.browser.msie)
			return jQuery.attr(elem.style, "opacity");
			
		if (prop == "float" || prop == "cssFloat")
		    prop = jQuery.browser.msie ? "styleFloat" : "cssFloat";

		if (!force && elem.style[prop])
			ret = elem.style[prop];

		else if (document.defaultView && document.defaultView.getComputedStyle) {

			if (prop == "cssFloat" || prop == "styleFloat")
				prop = "float";

			prop = prop.replace(/([A-Z])/g,"-$1").toLowerCase();
			var cur = document.defaultView.getComputedStyle(elem, null);

			if ( cur )
				ret = cur.getPropertyValue(prop);
			else if ( prop == "display" )
				ret = "none";
			else
				jQuery.swap(elem, { display: "block" }, function() {
				    var c = document.defaultView.getComputedStyle(this, "");
				    ret = c && c.getPropertyValue(prop) || "";
				});

		} else if (elem.currentStyle) {

			var newProp = prop.replace(/\-(\w)/g,function(m,c){return c.toUpperCase();});
			ret = elem.currentStyle[prop] || elem.currentStyle[newProp];
			
		}

		return ret;
	},
	
	clean: function(a) {
		var r = [];

		jQuery.each( a, function(i,arg){
			if ( !arg ) return;

			if ( arg.constructor == Number )
				arg = arg.toString();
			
			 // Convert html string into DOM nodes
			if ( typeof arg == "string" ) {
				// Trim whitespace, otherwise indexOf won't work as expected
				var s = jQuery.trim(arg), div = document.createElement("div"), tb = [];

				var wrap =
					 // option or optgroup
					!s.indexOf("<opt") &&
					[1, "<select>", "</select>"] ||
					
					(!s.indexOf("<thead") || !s.indexOf("<tbody") || !s.indexOf("<tfoot")) &&
					[1, "<table>", "</table>"] ||
					
					!s.indexOf("<tr") &&
					[2, "<table><tbody>", "</tbody></table>"] ||
					
				 	// <thead> matched above
					(!s.indexOf("<td") || !s.indexOf("<th")) &&
					[3, "<table><tbody><tr>", "</tr></tbody></table>"] ||
					
					[0,"",""];

				// Go to html and back, then peel off extra wrappers
				div.innerHTML = wrap[1] + s + wrap[2];
				
				// Move to the right depth
				while ( wrap[0]-- )
					div = div.firstChild;
				
				// Remove IE's autoinserted <tbody> from table fragments
				if ( jQuery.browser.msie ) {
					
					// String was a <table>, *may* have spurious <tbody>
					if ( !s.indexOf("<table") && s.indexOf("<tbody") < 0 ) 
						tb = div.firstChild && div.firstChild.childNodes;
						
					// String was a bare <thead> or <tfoot>
					else if ( wrap[1] == "<table>" && s.indexOf("<tbody") < 0 )
						tb = div.childNodes;

					for ( var n = tb.length-1; n >= 0 ; --n )
						if ( jQuery.nodeName(tb[n], "tbody") && !tb[n].childNodes.length )
							tb[n].parentNode.removeChild(tb[n]);
					
				}
				
				arg = [];
				for (var i=0, l=div.childNodes.length; i<l; i++)
					arg.push(div.childNodes[i]);
			}

			if ( arg.length === 0 && !jQuery.nodeName(arg, "form") )
				return;
			
			if ( arg[0] == undefined || jQuery.nodeName(arg, "form") )
				r.push( arg );
			else
				r = jQuery.merge( r, arg );

		});

		return r;
	},
	
	attr: function(elem, name, value){
		var fix = jQuery.isXMLDoc(elem) ? {} : {
			"for": "htmlFor",
			"class": "className",
			"float": jQuery.browser.msie ? "styleFloat" : "cssFloat",
			cssFloat: jQuery.browser.msie ? "styleFloat" : "cssFloat",
			innerHTML: "innerHTML",
			className: "className",
			value: "value",
			disabled: "disabled",
			checked: "checked",
			readonly: "readOnly",
			selected: "selected"
		};
		
		// IE actually uses filters for opacity ... elem is actually elem.style
		if ( name == "opacity" && jQuery.browser.msie && value != undefined ) {
			// IE has trouble with opacity if it does not have layout
			// Force it by setting the zoom level
			elem.zoom = 1; 
			// Set the alpha filter to set the opacity
			return elem.filter = (elem.filter ? elem.filter.replace(/alpha\([^\)]*\)/gi,"") : "") +
					( value == 1 ? "" : "alpha(opacity=" + value * 100 + ")" );
		} else if ( name == "opacity" && jQuery.browser.msie )
			return elem.filter ? 
				parseFloat( elem.filter.match(/alpha\(opacity=(.*)\)/)[1] ) / 100 : 1;
		
		// Mozilla doesn't play well with opacity 1
		if ( name == "opacity" && jQuery.browser.mozilla && value == 1 )
			value = 0.9999;
			

		// Certain attributes only work when accessed via the old DOM 0 way
		if ( fix[name] ) {
			if ( value != undefined ) elem[fix[name]] = value;
			return elem[fix[name]];

		} else if ( value == undefined && jQuery.browser.msie && jQuery.nodeName(elem, "form") && (name == "action" || name == "method") )
			return elem.getAttributeNode(name).nodeValue;

		// IE elem.getAttribute passes even for style
		else if ( elem.tagName ) {
			if ( value != undefined ) elem.setAttribute( name, value );
			if ( jQuery.browser.msie && /href|src/.test(name) && !jQuery.isXMLDoc(elem) ) 
				return elem.getAttribute( name, 2 );
			return elem.getAttribute( name );

		// elem is actually elem.style ... set the style
		} else {
			name = name.replace(/-([a-z])/ig,function(z,b){return b.toUpperCase();});
			if ( value != undefined ) elem[name] = value;
			return elem[name];
		}
	},
	trim: function(t){
		return t.replace(/^\s+|\s+$/g, "");
	},

	makeArray: function( a ) {
		var r = [];

		if ( a.constructor != Array )
			for ( var i = 0, al = a.length; i < al; i++ )
				r.push( a[i] );
		else
			r = a.slice( 0 );

		return r;
	},

	inArray: function( b, a ) {
		for ( var i = 0, al = a.length; i < al; i++ )
			if ( a[i] == b )
				return i;
		return -1;
	},
	merge: function(first, second) {
		var r = [].slice.call( first, 0 );

		// Now check for duplicates between the two arrays
		// and only add the unique items
		for ( var i = 0, sl = second.length; i < sl; i++ )
			// Check for duplicates
			if ( jQuery.inArray( second[i], r ) == -1 )
				// The item is unique, add it
				first.push( second[i] );

		return first;
	},
	grep: function(elems, fn, inv) {
		// If a string is passed in for the function, make a function
		// for it (a handy shortcut)
		if ( typeof fn == "string" )
			fn = new Function("a","i","return " + fn);

		var result = [];

		// Go through the array, only saving the items
		// that pass the validator function
		for ( var i = 0, el = elems.length; i < el; i++ )
			if ( !inv && fn(elems[i],i) || inv && !fn(elems[i],i) )
				result.push( elems[i] );

		return result;
	},
	map: function(elems, fn) {
		// If a string is passed in for the function, make a function
		// for it (a handy shortcut)
		if ( typeof fn == "string" )
			fn = new Function("a","return " + fn);

		var result = [], r = [];

		// Go through the array, translating each of the items to their
		// new value (or values).
		for ( var i = 0, el = elems.length; i < el; i++ ) {
			var val = fn(elems[i],i);

			if ( val !== null && val != undefined ) {
				if ( val.constructor != Array ) val = [val];
				result = result.concat( val );
			}
		}

		var r = result.length ? [ result[0] ] : [];

		check: for ( var i = 1, rl = result.length; i < rl; i++ ) {
			for ( var j = 0; j < i; j++ )
				if ( result[i] == r[j] )
					continue check;

			r.push( result[i] );
		}

		return r;
	}
});
 
/*
 * Whether the W3C compliant box model is being used.
 *
 * @property
 * @name $.boxModel
 * @type Boolean
 * @cat JavaScript
 */
new function() {
	var b = navigator.userAgent.toLowerCase();

	// Figure out what browser is being used
	jQuery.browser = {
		safari: /webkit/.test(b),
		opera: /opera/.test(b),
		msie: /msie/.test(b) && !/opera/.test(b),
		mozilla: /mozilla/.test(b) && !/(compatible|webkit)/.test(b)
	};

	// Check to see if the W3C box model is being used
	jQuery.boxModel = !jQuery.browser.msie || document.compatMode == "CSS1Compat";
};

jQuery.each({
	parent: "a.parentNode",
	parents: "jQuery.parents(a)",
	next: "jQuery.nth(a,2,'nextSibling')",
	prev: "jQuery.nth(a,2,'previousSibling')",
	siblings: "jQuery.sibling(a.parentNode.firstChild,a)",
	children: "jQuery.sibling(a.firstChild)"
}, function(i,n){
	jQuery.fn[ i ] = function(a) {
		var ret = jQuery.map(this,n);
		if ( a && typeof a == "string" )
			ret = jQuery.multiFilter(a,ret);
		return this.pushStack( ret );
	};
});

jQuery.each({
	appendTo: "append",
	prependTo: "prepend",
	insertBefore: "before",
	insertAfter: "after"
}, function(i,n){
	jQuery.fn[ i ] = function(){
		var a = arguments;
		return this.each(function(){
			for ( var j = 0, al = a.length; j < al; j++ )
				jQuery(a[j])[n]( this );
		});
	};
});

jQuery.each( {
	removeAttr: function( key ) {
		jQuery.attr( this, key, "" );
		this.removeAttribute( key );
	},
	addClass: function(c){
		jQuery.className.add(this,c);
	},
	removeClass: function(c){
		jQuery.className.remove(this,c);
	},
	toggleClass: function( c ){
		jQuery.className[ jQuery.className.has(this,c) ? "remove" : "add" ](this, c);
	},
	remove: function(a){
		if ( !a || jQuery.filter( a, [this] ).r.length )
			this.parentNode.removeChild( this );
	},
	empty: function() {
		while ( this.firstChild )
			this.removeChild( this.firstChild );
	}
}, function(i,n){
	jQuery.fn[ i ] = function() {
		return this.each( n, arguments );
	};
});

jQuery.each( [ "eq", "lt", "gt", "contains" ], function(i,n){
	jQuery.fn[ n ] = function(num,fn) {
		return this.filter( ":" + n + "(" + num + ")", fn );
	};
});

jQuery.each( [ "height", "width" ], function(i,n){
	jQuery.fn[ n ] = function(h) {
		return h == undefined ?
			( this.length ? jQuery.css( this[0], n ) : null ) :
			this.css( n, h.constructor == String ? h : h + "px" );
	};
});
jQuery.extend({
	expr: {
		"": "m[2]=='*'||jQuery.nodeName(a,m[2])",
		"#": "a.getAttribute('id')==m[2]",
		":": {
			// Position Checks
			lt: "i<m[3]-0",
			gt: "i>m[3]-0",
			nth: "m[3]-0==i",
			eq: "m[3]-0==i",
			first: "i==0",
			last: "i==r.length-1",
			even: "i%2==0",
			odd: "i%2",

			// Child Checks
			"nth-child": "jQuery.nth(a.parentNode.firstChild,m[3],'nextSibling',a)==a",
			"first-child": "jQuery.nth(a.parentNode.firstChild,1,'nextSibling')==a",
			"last-child": "jQuery.nth(a.parentNode.lastChild,1,'previousSibling')==a",
			"only-child": "jQuery.sibling(a.parentNode.firstChild).length==1",

			// Parent Checks
			parent: "a.firstChild",
			empty: "!a.firstChild",

			// Text Check
			contains: "jQuery.fn.text.apply([a]).indexOf(m[3])>=0",

			// Visibility
			visible: 'a.type!="hidden"&&jQuery.css(a,"display")!="none"&&jQuery.css(a,"visibility")!="hidden"',
			hidden: 'a.type=="hidden"||jQuery.css(a,"display")=="none"||jQuery.css(a,"visibility")=="hidden"',

			// Form attributes
			enabled: "!a.disabled",
			disabled: "a.disabled",
			checked: "a.checked",
			selected: "a.selected||jQuery.attr(a,'selected')",

			// Form elements
			text: "a.type=='text'",
			radio: "a.type=='radio'",
			checkbox: "a.type=='checkbox'",
			file: "a.type=='file'",
			password: "a.type=='password'",
			submit: "a.type=='submit'",
			image: "a.type=='image'",
			reset: "a.type=='reset'",
			button: 'a.type=="button"||jQuery.nodeName(a,"button")',
			input: "/input|select|textarea|button/i.test(a.nodeName)"
		},
		".": "jQuery.className.has(a,m[2])",
		"@": {
			"=": "z==m[4]",
			"!=": "z!=m[4]",
			"^=": "z&&!z.indexOf(m[4])",
			"$=": "z&&z.substr(z.length - m[4].length,m[4].length)==m[4]",
			"*=": "z&&z.indexOf(m[4])>=0",
			"": "z",
			_resort: function(m){
				return ["", m[1], m[3], m[2], m[5]];
			},
			_prefix: "z=a[m[3]];if(!z||/href|src/.test(m[3]))z=jQuery.attr(a,m[3]);"
		},
		"[": "jQuery.find(m[2],a).length"
	},
	
	// The regular expressions that power the parsing engine
	parse: [
		// Match: [@value='test'], [@foo]
		/^\[ *(@)([a-z0-9_-]*) *([!*$^=]*) *('?"?)(.*?)\4 *\]/i,

		// Match: [div], [div p]
		/^(\[)\s*(.*?(\[.*?\])?[^[]*?)\s*\]/,

		// Match: :contains('foo')
		/^(:)([a-z0-9_-]*)\("?'?(.*?(\(.*?\))?[^(]*?)"?'?\)/i,

		// Match: :even, :last-chlid
		/^([:.#]*)([a-z0-9_*-]*)/i
	],

	token: [
		/^(\/?\.\.)/, "a.parentNode",
		/^(>|\/)/, "jQuery.sibling(a.firstChild)",
		/^(\+)/, "jQuery.nth(a,2,'nextSibling')",
		/^(~)/, function(a){
			var s = jQuery.sibling(a.parentNode.firstChild);
			return s.slice(jQuery.inArray(a,s) + 1);
		}
	],

	multiFilter: function( expr, elems, not ) {
		var old, cur = [];

		while ( expr && expr != old ) {
			old = expr;
			var f = jQuery.filter( expr, elems, not );
			expr = f.t.replace(/^\s*,\s*/, "" );
			cur = not ? elems = f.r : jQuery.merge( cur, f.r );
		}

		return cur;
	},
	find: function( t, context ) {
		// Quickly handle non-string expressions
		if ( typeof t != "string" )
			return [ t ];

		// Make sure that the context is a DOM Element
		if ( context && !context.nodeType )
			context = null;

		// Set the correct context (if none is provided)
		context = context || document;

		// Handle the common XPath // expression
		if ( !t.indexOf("//") ) {
			context = context.documentElement;
			t = t.substr(2,t.length);

		// And the / root expression
		} else if ( !t.indexOf("/") ) {
			context = context.documentElement;
			t = t.substr(1,t.length);
			if ( t.indexOf("/") >= 1 )
				t = t.substr(t.indexOf("/"),t.length);
		}

		// Initialize the search
		var ret = [context], done = [], last = null;

		// Continue while a selector expression exists, and while
		// we're no longer looping upon ourselves
		while ( t && last != t ) {
			var r = [];
			last = t;

			t = jQuery.trim(t).replace( /^\/\//i, "" );

			var foundToken = false;

			// An attempt at speeding up child selectors that
			// point to a specific element tag
			var re = /^[\/>]\s*([a-z0-9*-]+)/i;
			var m = re.exec(t);

			if ( m ) {
				// Perform our own iteration and filter
				jQuery.each( ret, function(){
					for ( var c = this.firstChild; c; c = c.nextSibling )
						if ( c.nodeType == 1 && ( jQuery.nodeName(c, m[1]) || m[1] == "*" ) )
							r.push( c );
				});

				ret = r;
				t = t.replace( re, "" );
				if ( t.indexOf(" ") == 0 ) continue;
				foundToken = true;
			} else {
				// Look for pre-defined expression tokens
				for ( var i = 0; i < jQuery.token.length; i += 2 ) {
					// Attempt to match each, individual, token in
					// the specified order
					var re = jQuery.token[i];
					var m = re.exec(t);

					// If the token match was found
					if ( m ) {
						// Map it against the token's handler
						r = ret = jQuery.map( ret, jQuery.isFunction( jQuery.token[i+1] ) ?
							jQuery.token[i+1] :
							function(a){ return eval(jQuery.token[i+1]); });

						// And remove the token
						t = jQuery.trim( t.replace( re, "" ) );
						foundToken = true;
						break;
					}
				}
			}

			// See if there's still an expression, and that we haven't already
			// matched a token
			if ( t && !foundToken ) {
				// Handle multiple expressions
				if ( !t.indexOf(",") ) {
					// Clean the result set
					if ( ret[0] == context ) ret.shift();

					// Merge the result sets
					jQuery.merge( done, ret );

					// Reset the context
					r = ret = [context];

					// Touch up the selector string
					t = " " + t.substr(1,t.length);

				} else {
					// Optomize for the case nodeName#idName
					var re2 = /^([a-z0-9_-]+)(#)([a-z0-9\\*_-]*)/i;
					var m = re2.exec(t);
					
					// Re-organize the results, so that they're consistent
					if ( m ) {
					   m = [ 0, m[2], m[3], m[1] ];

					} else {
						// Otherwise, do a traditional filter check for
						// ID, class, and element selectors
						re2 = /^([#.]?)([a-z0-9\\*_-]*)/i;
						m = re2.exec(t);
					}

					// Try to do a global search by ID, where we can
					if ( m[1] == "#" && ret[ret.length-1].getElementById ) {
						// Optimization for HTML document case
						var oid = ret[ret.length-1].getElementById(m[2]);
						
						// Do a quick check for the existence of the actual ID attribute
						// to avoid selecting by the name attribute in IE
						if ( jQuery.browser.msie && oid && oid.id != m[2] )
							oid = jQuery('[@id="'+m[2]+'"]', ret[ret.length-1])[0];

						// Do a quick check for node name (where applicable) so
						// that div#foo searches will be really fast
						ret = r = oid && (!m[3] || jQuery.nodeName(oid, m[3])) ? [oid] : [];

					} else {
						// Pre-compile a regular expression to handle class searches
						if ( m[1] == "." )
							var rec = new RegExp("(^|\\s)" + m[2] + "(\\s|$)");

						// We need to find all descendant elements, it is more
						// efficient to use getAll() when we are already further down
						// the tree - we try to recognize that here
						jQuery.each( ret, function(){
							// Grab the tag name being searched for
							var tag = m[1] != "" || m[0] == "" ? "*" : m[2];

							// Handle IE7 being really dumb about <object>s
							if ( jQuery.nodeName(this, "object") && tag == "*" )
								tag = "param";

							jQuery.merge( r,
								m[1] != "" && ret.length != 1 ?
									jQuery.getAll( this, [], m[1], m[2], rec ) :
									this.getElementsByTagName( tag )
							);
						});

						// It's faster to filter by class and be done with it
						if ( m[1] == "." && ret.length == 1 )
							r = jQuery.grep( r, function(e) {
								return rec.test(e.className);
							});

						// Same with ID filtering
						if ( m[1] == "#" && ret.length == 1 ) {
							// Remember, then wipe out, the result set
							var tmp = r;
							r = [];

							// Then try to find the element with the ID
							jQuery.each( tmp, function(){
								if ( this.getAttribute("id") == m[2] ) {
									r = [ this ];
									return false;
								}
							});
						}

						ret = r;
					}

					t = t.replace( re2, "" );
				}

			}

			// If a selector string still exists
			if ( t ) {
				// Attempt to filter it
				var val = jQuery.filter(t,r);
				ret = r = val.r;
				t = jQuery.trim(val.t);
			}
		}

		// Remove the root context
		if ( ret && ret[0] == context ) ret.shift();

		// And combine the results
		jQuery.merge( done, ret );

		return done;
	},

	filter: function(t,r,not) {
		// Look for common filter expressions
		while ( t && /^[a-z[({<*:.#]/i.test(t) ) {

			var p = jQuery.parse, m;

			jQuery.each( p, function(i,re){
		
				// Look for, and replace, string-like sequences
				// and finally build a regexp out of it
				m = re.exec( t );

				if ( m ) {
					// Remove what we just matched
					t = t.substring( m[0].length );

					// Re-organize the first match
					if ( jQuery.expr[ m[1] ]._resort )
						m = jQuery.expr[ m[1] ]._resort( m );

					return false;
				}
			});

			// :not() is a special case that can be optimized by
			// keeping it out of the expression list
			if ( m[1] == ":" && m[2] == "not" )
				r = jQuery.filter(m[3], r, true).r;

			// Handle classes as a special case (this will help to
			// improve the speed, as the regexp will only be compiled once)
			else if ( m[1] == "." ) {

				var re = new RegExp("(^|\\s)" + m[2] + "(\\s|$)");
				r = jQuery.grep( r, function(e){
					return re.test(e.className || "");
				}, not);

			// Otherwise, find the expression to execute
			} else {
				var f = jQuery.expr[m[1]];
				if ( typeof f != "string" )
					f = jQuery.expr[m[1]][m[2]];

				// Build a custom macro to enclose it
				eval("f = function(a,i){" +
					( jQuery.expr[ m[1] ]._prefix || "" ) +
					"return " + f + "}");

				// Execute it against the current filter
				r = jQuery.grep( r, f, not );
			}
		}

		// Return an array of filtered elements (r)
		// and the modified expression string (t)
		return { r: r, t: t };
	},
	
	getAll: function( o, r, token, name, re ) {
		for ( var s = o.firstChild; s; s = s.nextSibling )
			if ( s.nodeType == 1 ) {
				var add = true;

				if ( token == "." )
					add = s.className && re.test(s.className);
				else if ( token == "#" )
					add = s.getAttribute("id") == name;
	
				if ( add )
					r.push( s );

				if ( token == "#" && r.length ) break;

				if ( s.firstChild )
					jQuery.getAll( s, r, token, name, re );
			}

		return r;
	},
	parents: function( elem ){
		var matched = [];
		var cur = elem.parentNode;
		while ( cur && cur != document ) {
			matched.push( cur );
			cur = cur.parentNode;
		}
		return matched;
	},
	nth: function(cur,result,dir,elem){
		result = result || 1;
		var num = 0;
		for ( ; cur; cur = cur[dir] ) {
			if ( cur.nodeType == 1 ) num++;
			if ( num == result || result == "even" && num % 2 == 0 && num > 1 && cur == elem ||
				result == "odd" && num % 2 == 1 && cur == elem ) return cur;
		}
	},
	sibling: function( n, elem ) {
		var r = [];

		for ( ; n; n = n.nextSibling ) {
			if ( n.nodeType == 1 && (!elem || n != elem) )
				r.push( n );
		}

		return r;
	}
});
/*
 * A number of helper functions used for managing events.
 * Many of the ideas behind this code orignated from 
 * Dean Edwards' addEvent library.
 */
jQuery.event = {

	// Bind an event to an element
	// Original by Dean Edwards
	add: function(element, type, handler, data) {
		// For whatever reason, IE has trouble passing the window object
		// around, causing it to be cloned in the process
		if ( jQuery.browser.msie && element.setInterval != undefined )
			element = window;

		// if data is passed, bind to handler
		if( data ) 
			handler.data = data;

		// Make sure that the function being executed has a unique ID
		if ( !handler.guid )
			handler.guid = this.guid++;

		// Init the element's event structure
		if (!element.$events)
			element.$events = {};

		// Get the current list of functions bound to this event
		var handlers = element.$events[type];

		// If it hasn't been initialized yet
		if (!handlers) {
			// Init the event handler queue
			handlers = element.$events[type] = {};

			// Remember an existing handler, if it's already there
			if (element["on" + type])
				handlers[0] = element["on" + type];
		}

		// Add the function to the element's handler list
		handlers[handler.guid] = handler;

		// And bind the global event handler to the element
		element["on" + type] = this.handle;

		// Remember the function in a global list (for triggering)
		if (!this.global[type])
			this.global[type] = [];
		this.global[type].push( element );
	},

	guid: 1,
	global: {},

	// Detach an event or set of events from an element
	remove: function(element, type, handler) {
		if (element.$events) {
			var i,j,k;
			if ( type && type.type ) { // type is actually an event object here
				handler = type.handler;
				type    = type.type;
			}
			
			if (type && element.$events[type])
				// remove the given handler for the given type
				if ( handler )
					delete element.$events[type][handler.guid];
					
				// remove all handlers for the given type
				else
					for ( i in element.$events[type] )
						delete element.$events[type][i];
						
			// remove all handlers		
			else
				for ( j in element.$events )
					this.remove( element, j );
			
			// remove event handler if no more handlers exist
			for ( k in element.$events[type] )
				if (k) {
					k = true;
					break;
				}
			if (!k) element["on" + type] = null;
		}
	},

	trigger: function(type, data, element) {
		// Clone the incoming data, if any
		data = jQuery.makeArray(data || []);

		// Handle a global trigger
		if ( !element )
			jQuery.each( this.global[type] || [], function(){
				jQuery.event.trigger( type, data, this );
			});

		// Handle triggering a single element
		else {
			var handler = element["on" + type ], val,
				fn = jQuery.isFunction( element[ type ] );

			if ( handler ) {
				// Pass along a fake event
				data.unshift( this.fix({ type: type, target: element }) );
	
				// Trigger the event
				if ( (val = handler.apply( element, data )) !== false )
					this.triggered = true;
			}

			if ( fn && val !== false )
				element[ type ]();

			this.triggered = false;
		}
	},

	handle: function(event) {
		// Handle the second event of a trigger and when
		// an event is called after a page has unloaded
		if ( typeof jQuery == "undefined" || jQuery.event.triggered ) return;

		// Empty object is for triggered events with no data
		event = jQuery.event.fix( event || window.event || {} ); 

		// returned undefined or false
		var returnValue;

		var c = this.$events[event.type];

		var args = [].slice.call( arguments, 1 );
		args.unshift( event );

		for ( var j in c ) {
			// Pass in a reference to the handler function itself
			// So that we can later remove it
			args[0].handler = c[j];
			args[0].data = c[j].data;

			if ( c[j].apply( this, args ) === false ) {
				event.preventDefault();
				event.stopPropagation();
				returnValue = false;
			}
		}

		// Clean up added properties in IE to prevent memory leak
		if (jQuery.browser.msie) event.target = event.preventDefault = event.stopPropagation = event.handler = event.data = null;

		return returnValue;
	},

	fix: function(event) {
		// Fix target property, if necessary
		if ( !event.target && event.srcElement )
			event.target = event.srcElement;

		// Calculate pageX/Y if missing and clientX/Y available
		if ( event.pageX == undefined && event.clientX != undefined ) {
			var e = document.documentElement, b = document.body;
			event.pageX = event.clientX + (e.scrollLeft || b.scrollLeft);
			event.pageY = event.clientY + (e.scrollTop || b.scrollTop);
		}
				
		// check if target is a textnode (safari)
		if (jQuery.browser.safari && event.target.nodeType == 3) {
			// store a copy of the original event object 
			// and clone because target is read only
			var originalEvent = event;
			event = jQuery.extend({}, originalEvent);
			
			// get parentnode from textnode
			event.target = originalEvent.target.parentNode;
			
			// add preventDefault and stopPropagation since 
			// they will not work on the clone
			event.preventDefault = function() {
				return originalEvent.preventDefault();
			};
			event.stopPropagation = function() {
				return originalEvent.stopPropagation();
			};
		}
		
		// fix preventDefault and stopPropagation
		if (!event.preventDefault)
			event.preventDefault = function() {
				this.returnValue = false;
			};
			
		if (!event.stopPropagation)
			event.stopPropagation = function() {
				this.cancelBubble = true;
			};
			
		return event;
	}
};

jQuery.fn.extend({
	bind: function( type, data, fn ) {
		return this.each(function(){
			jQuery.event.add( this, type, fn || data, data );
		});
	},
	one: function( type, data, fn ) {
		return this.each(function(){
			jQuery.event.add( this, type, function(event) {
				jQuery(this).unbind(event);
				return (fn || data).apply( this, arguments);
			}, data);
		});
	},
	unbind: function( type, fn ) {
		return this.each(function(){
			jQuery.event.remove( this, type, fn );
		});
	},
	trigger: function( type, data ) {
		return this.each(function(){
			jQuery.event.trigger( type, data, this );
		});
	},
	toggle: function() {
		// Save reference to arguments for access in closure
		var a = arguments;

		return this.click(function(e) {
			// Figure out which function to execute
			this.lastToggle = this.lastToggle == 0 ? 1 : 0;
			
			// Make sure that clicks stop
			e.preventDefault();
			
			// and execute the function
			return a[this.lastToggle].apply( this, [e] ) || false;
		});
	},
	hover: function(f,g) {
		
		// A private function for handling mouse 'hovering'
		function handleHover(e) {
			// Check if mouse(over|out) are still within the same parent element
			var p = (e.type == "mouseover" ? e.fromElement : e.toElement) || e.relatedTarget;
	
			// Traverse up the tree
			while ( p && p != this ) try { p = p.parentNode } catch(e) { p = this; };
			
			// If we actually just moused on to a sub-element, ignore it
			if ( p == this ) return false;
			
			// Execute the right function
			return (e.type == "mouseover" ? f : g).apply(this, [e]);
		}
		
		// Bind the function to the two event listeners
		return this.mouseover(handleHover).mouseout(handleHover);
	},
	ready: function(f) {
		// If the DOM is already ready
		if ( jQuery.isReady )
			// Execute the function immediately
			f.apply( document, [jQuery] );
			
		// Otherwise, remember the function for later
		else {
			// Add the function to the wait list
			jQuery.readyList.push( function() { return f.apply(this, [jQuery]) } );
		}
	
		return this;
	}
});

jQuery.extend({
	/*
	 * All the code that makes DOM Ready work nicely.
	 */
	isReady: false,
	readyList: [],
	
	// Handle when the DOM is ready
	ready: function() {
		// Make sure that the DOM is not already loaded
		if ( !jQuery.isReady ) {
			// Remember that the DOM is ready
			jQuery.isReady = true;
			
			// If there are functions bound, to execute
			if ( jQuery.readyList ) {
				// Execute all of them
				jQuery.each( jQuery.readyList, function(){
					this.apply( document );
				});
				
				// Reset the list of functions
				jQuery.readyList = null;
			}
			// Remove event lisenter to avoid memory leak
			if ( jQuery.browser.mozilla || jQuery.browser.opera )
				document.removeEventListener( "DOMContentLoaded", jQuery.ready, false );
		}
	}
});

new function(){

	jQuery.each( ("blur,focus,load,resize,scroll,unload,click,dblclick," +
		"mousedown,mouseup,mousemove,mouseover,mouseout,change,select," + 
		"submit,keydown,keypress,keyup,error").split(","), function(i,o){
		
		// Handle event binding
		jQuery.fn[o] = function(f){
			return f ? this.bind(o, f) : this.trigger(o);
		};
			
	});
	
	// If Mozilla is used
	if ( jQuery.browser.mozilla || jQuery.browser.opera )
		// Use the handy event callback
		document.addEventListener( "DOMContentLoaded", jQuery.ready, false );
	
	// If IE is used, use the excellent hack by Matthias Miller
	// http://www.outofhanwell.com/blog/index.php?title=the_window_onload_problem_revisited
	else if ( jQuery.browser.msie ) {
	
		// Only works if you document.write() it
		document.write("<scr" + "ipt id=__ie_init defer=true " + 
			"src=//:><\/script>");
	
		// Use the defer script hack
		var script = document.getElementById("__ie_init");
		
		// script does not exist if jQuery is loaded dynamically
		if ( script ) 
			script.onreadystatechange = function() {
				if ( this.readyState != "complete" ) return;
				this.parentNode.removeChild( this );
				jQuery.ready();
			};
	
		// Clear from memory
		script = null;
	
	// If Safari  is used
	} else if ( jQuery.browser.safari )
		// Continually check to see if the document.readyState is valid
		jQuery.safariTimer = setInterval(function(){
			// loaded and complete are both valid states
			if ( document.readyState == "loaded" || 
				document.readyState == "complete" ) {
	
				// If either one are found, remove the timer
				clearInterval( jQuery.safariTimer );
				jQuery.safariTimer = null;
	
				// and execute any waiting functions
				jQuery.ready();
			}
		}, 10); 

	// A fallback to window.onload, that will always work
	jQuery.event.add( window, "load", jQuery.ready );
	
};

// Clean up after IE to avoid memory leaks
if (jQuery.browser.msie)
	jQuery(window).one("unload", function() {
		var global = jQuery.event.global;
		for ( var type in global ) {
			var els = global[type], i = els.length;
			if ( i && type != 'unload' )
				do
					jQuery.event.remove(els[i-1], type);
				while (--i);
		}
	});
jQuery.fn.extend({
	loadIfModified: function( url, params, callback ) {
		this.load( url, params, callback, 1 );
	},
	load: function( url, params, callback, ifModified ) {
		if ( jQuery.isFunction( url ) )
			return this.bind("load", url);

		callback = callback || function(){};

		// Default to a GET request
		var type = "GET";

		// If the second parameter was provided
		if ( params )
			// If it's a function
			if ( jQuery.isFunction( params ) ) {
				// We assume that it's the callback
				callback = params;
				params = null;

			// Otherwise, build a param string
			} else {
				params = jQuery.param( params );
				type = "POST";
			}

		var self = this;

		// Request the remote document
		jQuery.ajax({
			url: url,
			type: type,
			data: params,
			ifModified: ifModified,
			complete: function(res, status){
				if ( status == "success" || !ifModified && status == "notmodified" )
					// Inject the HTML into all the matched elements
					self.attr("innerHTML", res.responseText)
					  // Execute all the scripts inside of the newly-injected HTML
					  .evalScripts()
					  // Execute callback
					  .each( callback, [res.responseText, status, res] );
				else
					callback.apply( self, [res.responseText, status, res] );
			}
		});
		return this;
	},
	serialize: function() {
		return jQuery.param( this );
	},
	evalScripts: function() {
		return this.find("script").each(function(){
			if ( this.src )
				jQuery.getScript( this.src );
			else
				jQuery.globalEval( this.text || this.textContent || this.innerHTML || "" );
		}).end();
	}

});

// If IE is used, create a wrapper for the XMLHttpRequest object
if ( !window.XMLHttpRequest )
	XMLHttpRequest = function(){
		return new ActiveXObject("Microsoft.XMLHTTP");
	};

// Attach a bunch of functions for handling common AJAX events

jQuery.each( "ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","), function(i,o){
	jQuery.fn[o] = function(f){
		return this.bind(o, f);
	};
});

jQuery.extend({
	get: function( url, data, callback, type, ifModified ) {
		// shift arguments if data argument was ommited
		if ( jQuery.isFunction( data ) ) {
			callback = data;
			data = null;
		}
		
		return jQuery.ajax({
			url: url,
			data: data,
			success: callback,
			dataType: type,
			ifModified: ifModified
		});
	},
	getIfModified: function( url, data, callback, type ) {
		return jQuery.get(url, data, callback, type, 1);
	},
	getScript: function( url, callback ) {
		return jQuery.get(url, null, callback, "script");
	},
	getJSON: function( url, data, callback ) {
		return jQuery.get(url, data, callback, "json");
	},
	post: function( url, data, callback, type ) {
		if ( jQuery.isFunction( data ) ) {
			callback = data;
			data = {};
		}

		return jQuery.ajax({
			type: "POST",
			url: url,
			data: data,
			success: callback,
			dataType: type
		});
	},

	// timeout (ms)
	//timeout: 0,
	ajaxTimeout: function( timeout ) {
		jQuery.ajaxSettings.timeout = timeout;
	},
	ajaxSetup: function( settings ) {
		jQuery.extend( jQuery.ajaxSettings, settings );
	},

	ajaxSettings: {
		global: true,
		type: "GET",
		timeout: 0,
		contentType: "application/x-www-form-urlencoded",
		processData: true,
		async: true,
		data: null
	},
	
	// Last-Modified header cache for next request
	lastModified: {},
	ajax: function( s ) {
		// TODO introduce global settings, allowing the client to modify them for all requests, not only timeout
		s = jQuery.extend({}, jQuery.ajaxSettings, s);

		// if data available
		if ( s.data ) {
			// convert data if not already a string
			if (s.processData && typeof s.data != "string")
    			s.data = jQuery.param(s.data);
			// append data to url for get requests
			if( s.type.toLowerCase() == "get" ) {
				// "?" + data or "&" + data (in case there are already params)
				s.url += ((s.url.indexOf("?") > -1) ? "&" : "?") + s.data;
				// IE likes to send both get and post data, prevent this
				s.data = null;
			}
		}

		// Watch for a new set of requests
		if ( s.global && ! jQuery.active++ )
			jQuery.event.trigger( "ajaxStart" );

		var requestDone = false;

		// Create the request object
		var xml = new XMLHttpRequest();

		// Open the socket
		xml.open(s.type, s.url, s.async);

		// Set the correct header, if data is being sent
		if ( s.data )
			xml.setRequestHeader("Content-Type", s.contentType);

		// Set the If-Modified-Since header, if ifModified mode.
		if ( s.ifModified )
			xml.setRequestHeader("If-Modified-Since",
				jQuery.lastModified[s.url] || "Thu, 01 Jan 1970 00:00:00 GMT" );

		// Set header so the called script knows that it's an XMLHttpRequest
		xml.setRequestHeader("X-Requested-With", "XMLHttpRequest");

		// Make sure the browser sends the right content length
		if ( xml.overrideMimeType )
			xml.setRequestHeader("Connection", "close");
			
		// Allow custom headers/mimetypes
		if( s.beforeSend )
			s.beforeSend(xml);
			
		if ( s.global )
		    jQuery.event.trigger("ajaxSend", [xml, s]);

		// Wait for a response to come back
		var onreadystatechange = function(isTimeout){
			// The transfer is complete and the data is available, or the request timed out
			if ( xml && (xml.readyState == 4 || isTimeout == "timeout") ) {
				requestDone = true;
				
				// clear poll interval
				if (ival) {
					clearInterval(ival);
					ival = null;
				}
				
				var status;
				try {
					status = jQuery.httpSuccess( xml ) && isTimeout != "timeout" ?
						s.ifModified && jQuery.httpNotModified( xml, s.url ) ? "notmodified" : "success" : "error";
					// Make sure that the request was successful or notmodified
					if ( status != "error" ) {
						// Cache Last-Modified header, if ifModified mode.
						var modRes;
						try {
							modRes = xml.getResponseHeader("Last-Modified");
						} catch(e) {} // swallow exception thrown by FF if header is not available
	
						if ( s.ifModified && modRes )
							jQuery.lastModified[s.url] = modRes;
	
						// process the data (runs the xml through httpData regardless of callback)
						var data = jQuery.httpData( xml, s.dataType );
	
						// If a local callback was specified, fire it and pass it the data
						if ( s.success )
							s.success( data, status );
	
						// Fire the global callback
						if( s.global )
							jQuery.event.trigger( "ajaxSuccess", [xml, s] );
					} else
						jQuery.handleError(s, xml, status);
				} catch(e) {
					status = "error";
					jQuery.handleError(s, xml, status, e);
				}

				// The request was completed
				if( s.global )
					jQuery.event.trigger( "ajaxComplete", [xml, s] );

				// Handle the global AJAX counter
				if ( s.global && ! --jQuery.active )
					jQuery.event.trigger( "ajaxStop" );

				// Process result
				if ( s.complete )
					s.complete(xml, status);

				// Stop memory leaks
				if(s.async)
					xml = null;
			}
		};
		
		// don't attach the handler to the request, just poll it instead
		var ival = setInterval(onreadystatechange, 13); 

		// Timeout checker
		if ( s.timeout > 0 )
			setTimeout(function(){
				// Check to see if the request is still happening
				if ( xml ) {
					// Cancel the request
					xml.abort();

					if( !requestDone )
						onreadystatechange( "timeout" );
				}
			}, s.timeout);
			
		// Send the data
		try {
			xml.send(s.data);
		} catch(e) {
			jQuery.handleError(s, xml, null, e);
		}
		
		// firefox 1.5 doesn't fire statechange for sync requests
		if ( !s.async )
			onreadystatechange();
		
		// return XMLHttpRequest to allow aborting the request etc.
		return xml;
	},

	handleError: function( s, xml, status, e ) {
		// If a local callback was specified, fire it
		if ( s.error ) s.error( xml, status, e );

		// Fire the global callback
		if ( s.global )
			jQuery.event.trigger( "ajaxError", [xml, s, e] );
	},

	// Counter for holding the number of active queries
	active: 0,

	// Determines if an XMLHttpRequest was successful or not
	httpSuccess: function( r ) {
		try {
			return !r.status && location.protocol == "file:" ||
				( r.status >= 200 && r.status < 300 ) || r.status == 304 ||
				jQuery.browser.safari && r.status == undefined;
		} catch(e){}
		return false;
	},

	// Determines if an XMLHttpRequest returns NotModified
	httpNotModified: function( xml, url ) {
		try {
			var xmlRes = xml.getResponseHeader("Last-Modified");

			// Firefox always returns 200. check Last-Modified date
			return xml.status == 304 || xmlRes == jQuery.lastModified[url] ||
				jQuery.browser.safari && xml.status == undefined;
		} catch(e){}
		return false;
	},

	/* Get the data out of an XMLHttpRequest.
	 * Return parsed XML if content-type header is "xml" and type is "xml" or omitted,
	 * otherwise return plain text.
	 * (String) data - The type of data that you're expecting back,
	 * (e.g. "xml", "html", "script")
	 */
	httpData: function( r, type ) {
		var ct = r.getResponseHeader("content-type");
		var data = !type && ct && ct.indexOf("xml") >= 0;
		data = type == "xml" || data ? r.responseXML : r.responseText;

		// If the type is "script", eval it in global context
		if ( type == "script" )
			jQuery.globalEval( data );

		// Get the JavaScript object, if JSON is used.
		if ( type == "json" )
			eval( "data = " + data );

		// evaluate scripts within html
		if ( type == "html" )
			jQuery("<div>").html(data).evalScripts();

		return data;
	},

	// Serialize an array of form elements or a set of
	// key/values into a query string
	param: function( a ) {
		var s = [];

		// If an array was passed in, assume that it is an array
		// of form elements
		if ( a.constructor == Array || a.jquery )
			// Serialize the form elements
			jQuery.each( a, function(){
				s.push( encodeURIComponent(this.name) + "=" + encodeURIComponent( this.value ) );
			});

		// Otherwise, assume that it's an object of key/value pairs
		else
			// Serialize the key/values
			for ( var j in a )
				// If the value is an array then the key names need to be repeated
				if ( a[j] && a[j].constructor == Array )
					jQuery.each( a[j], function(){
						s.push( encodeURIComponent(j) + "=" + encodeURIComponent( this ) );
					});
				else
					s.push( encodeURIComponent(j) + "=" + encodeURIComponent( a[j] ) );

		// Return the resulting serialization
		return s.join("&");
	},
	
	// evalulates a script in global context
	// not reliable for safari
	globalEval: function( data ) {
		if ( window.execScript )
			window.execScript( data );
		else if ( jQuery.browser.safari )
			// safari doesn't provide a synchronous global eval
			window.setTimeout( data, 0 );
		else
			eval.call( window, data );
	}

});
jQuery.fn.extend({

	show: function(speed,callback){
		var hidden = this.filter(":hidden");
		speed ?
			hidden.animate({
				height: "show", width: "show", opacity: "show"
			}, speed, callback) :
			
			hidden.each(function(){
				this.style.display = this.oldblock ? this.oldblock : "";
				if ( jQuery.css(this,"display") == "none" )
					this.style.display = "block";
			});
		return this;
	},

	hide: function(speed,callback){
		var visible = this.filter(":visible");
		speed ?
			visible.animate({
				height: "hide", width: "hide", opacity: "hide"
			}, speed, callback) :
			
			visible.each(function(){
				this.oldblock = this.oldblock || jQuery.css(this,"display");
				if ( this.oldblock == "none" )
					this.oldblock = "block";
				this.style.display = "none";
			});
		return this;
	},

	// Save the old toggle function
	_toggle: jQuery.fn.toggle,
	toggle: function( fn, fn2 ){
		var args = arguments;
		return jQuery.isFunction(fn) && jQuery.isFunction(fn2) ?
			this._toggle( fn, fn2 ) :
			this.each(function(){
				jQuery(this)[ jQuery(this).is(":hidden") ? "show" : "hide" ]
					.apply( jQuery(this), args );
			});
	},
	slideDown: function(speed,callback){
		return this.animate({height: "show"}, speed, callback);
	},
	slideUp: function(speed,callback){
		return this.animate({height: "hide"}, speed, callback);
	},
	slideToggle: function(speed, callback){
		return this.each(function(){
			var state = jQuery(this).is(":hidden") ? "show" : "hide";
			jQuery(this).animate({height: state}, speed, callback);
		});
	},
	fadeIn: function(speed, callback){
		return this.animate({opacity: "show"}, speed, callback);
	},
	fadeOut: function(speed, callback){
		return this.animate({opacity: "hide"}, speed, callback);
	},
	fadeTo: function(speed,to,callback){
		return this.animate({opacity: to}, speed, callback);
	},
	animate: function( prop, speed, easing, callback ) {
		return this.queue(function(){
		
			this.curAnim = jQuery.extend({}, prop);
			var opt = jQuery.speed(speed, easing, callback);
			
			for ( var p in prop ) {
				var e = new jQuery.fx( this, opt, p );
				if ( prop[p].constructor == Number )
					e.custom( e.cur(), prop[p] );
				else
					e[ prop[p] ]( prop );
			}
			
		});
	},
	queue: function(type,fn){
		if ( !fn ) {
			fn = type;
			type = "fx";
		}
	
		return this.each(function(){
			if ( !this.queue )
				this.queue = {};
	
			if ( !this.queue[type] )
				this.queue[type] = [];
	
			this.queue[type].push( fn );
		
			if ( this.queue[type].length == 1 )
				fn.apply(this);
		});
	}

});

jQuery.extend({
	
	speed: function(speed, easing, fn) {
		var opt = speed && speed.constructor == Object ? speed : {
			complete: fn || !fn && easing || 
				jQuery.isFunction( speed ) && speed,
			duration: speed,
			easing: fn && easing || easing && easing.constructor != Function && easing
		};

		opt.duration = (opt.duration && opt.duration.constructor == Number ? 
			opt.duration : 
			{ slow: 600, fast: 200 }[opt.duration]) || 400;
	
		// Queueing
		opt.old = opt.complete;
		opt.complete = function(){
			jQuery.dequeue(this, "fx");
			if ( jQuery.isFunction( opt.old ) )
				opt.old.apply( this );
		};
	
		return opt;
	},
	
	easing: {},
	
	queue: {},
	
	dequeue: function(elem,type){
		type = type || "fx";
	
		if ( elem.queue && elem.queue[type] ) {
			// Remove self
			elem.queue[type].shift();
	
			// Get next function
			var f = elem.queue[type][0];
		
			if ( f ) f.apply( elem );
		}
	},

	/*
	 * I originally wrote fx() as a clone of moo.fx and in the process
	 * of making it small in size the code became illegible to sane
	 * people. You've been warned.
	 */
	
	fx: function( elem, options, prop ){

		var z = this;

		// The styles
		var y = elem.style;
		
		// Store display property
		var oldDisplay = jQuery.css(elem, "display");

		// Make sure that nothing sneaks out
		y.overflow = "hidden";

		// Simple function for setting a style value
		z.a = function(){
			if ( options.step )
				options.step.apply( elem, [ z.now ] );

			if ( prop == "opacity" )
				jQuery.attr(y, "opacity", z.now); // Let attr handle opacity
			else if ( parseInt(z.now) ) // My hate for IE will never die
				y[prop] = parseInt(z.now) + "px";
			
			y.display = "block"; // Set display property to block for animation
		};

		// Figure out the maximum number to run to
		z.max = function(){
			return parseFloat( jQuery.css(elem,prop) );
		};

		// Get the current size
		z.cur = function(){
			var r = parseFloat( jQuery.curCSS(elem, prop) );
			return r && r > -10000 ? r : z.max();
		};

		// Start an animation from one number to another
		z.custom = function(from,to){
			z.startTime = (new Date()).getTime();
			z.now = from;
			z.a();

			z.timer = setInterval(function(){
				z.step(from, to);
			}, 13);
		};

		// Simple 'show' function
		z.show = function(){
			if ( !elem.orig ) elem.orig = {};

			// Remember where we started, so that we can go back to it later
			elem.orig[prop] = this.cur();

			options.show = true;

			// Begin the animation
			z.custom(0, elem.orig[prop]);

			// Stupid IE, look what you made me do
			if ( prop != "opacity" )
				y[prop] = "1px";
		};

		// Simple 'hide' function
		z.hide = function(){
			if ( !elem.orig ) elem.orig = {};

			// Remember where we started, so that we can go back to it later
			elem.orig[prop] = this.cur();

			options.hide = true;

			// Begin the animation
			z.custom(elem.orig[prop], 0);
		};
		
		//Simple 'toggle' function
		z.toggle = function() {
			if ( !elem.orig ) elem.orig = {};

			// Remember where we started, so that we can go back to it later
			elem.orig[prop] = this.cur();

			if(oldDisplay == "none")  {
				options.show = true;
				
				// Stupid IE, look what you made me do
				if ( prop != "opacity" )
					y[prop] = "1px";

				// Begin the animation
				z.custom(0, elem.orig[prop]);	
			} else {
				options.hide = true;

				// Begin the animation
				z.custom(elem.orig[prop], 0);
			}		
		};

		// Each step of an animation
		z.step = function(firstNum, lastNum){
			var t = (new Date()).getTime();

			if (t > options.duration + z.startTime) {
				// Stop the timer
				clearInterval(z.timer);
				z.timer = null;

				z.now = lastNum;
				z.a();

				if (elem.curAnim) elem.curAnim[ prop ] = true;

				var done = true;
				for ( var i in elem.curAnim )
					if ( elem.curAnim[i] !== true )
						done = false;

				if ( done ) {
					// Reset the overflow
					y.overflow = "";
					
					// Reset the display
					y.display = oldDisplay;
					if (jQuery.css(elem, "display") == "none")
						y.display = "block";

					// Hide the element if the "hide" operation was done
					if ( options.hide ) 
						y.display = "none";

					// Reset the properties, if the item has been hidden or shown
					if ( options.hide || options.show )
						for ( var p in elem.curAnim )
							if (p == "opacity")
								jQuery.attr(y, p, elem.orig[p]);
							else
								y[p] = "";
				}

				// If a callback was provided, execute it
				if ( done && jQuery.isFunction( options.complete ) )
					// Execute the complete function
					options.complete.apply( elem );
			} else {
				var n = t - this.startTime;
				// Figure out where in the animation we are and set the number
				var p = n / options.duration;
				
				// If the easing function exists, then use it 
				z.now = options.easing && jQuery.easing[options.easing] ?
					jQuery.easing[options.easing](p, n,  firstNum, (lastNum-firstNum), options.duration) :
					// else use default linear easing
					((-Math.cos(p*Math.PI)/2) + 0.5) * (lastNum-firstNum) + firstNum;

				// Perform the next step of the animation
				z.a();
			}
		};
	
	}
});
}
/*
 * jQuery Media Plugin for converting elements into rich media content.
 *
 * Examples and documentation at: http://malsup.com/jquery/media/
 * Copyright (c) 2007 M. Alsup
 * Dual licensed under the MIT and GPL licenses:
 * http://www.opensource.org/licenses/mit-license.php
 * http://www.gnu.org/licenses/gpl.html
 *
 * @author: M. Alsup
 * @version: 0.70 (7/05/2007)
 * @requires jQuery v1.1.2 or later
 *
 * Supported Media Players:
 *    - Flash
 *    - Quicktime
 *    - Real Player
 *    - Silverlight
 *    - Windows Media Player
 *    - iframe
 *
 * Supported Media Formats:
 *   Any types supported by the above players, such as:
 *     Video: asf, avi, flv, mov, mpg, mpeg, mp4, qt, smil, swf, wmv, 3g2, 3gp
 *     Audio: aif, aac, au, gsm, mid, midi, mov, mp3, m4a, snd, rm, wav, wma
 *     Other: bmp, html, pdf, psd, qif, qtif, qti, tif, tiff, xaml
 *
 * Thanks to Mark Hicken and Brent Pedersen for helping me debug this on the Mac!
 */
(function($) {

/**
 * Chainable method for converting elements into rich media.
 *
 * @name media
 * @param Object options Options object
 * @param Function callback fn invoked for each matched element before conversion
 * @param Function callback fn invoked for each matched element after conversion
 * @cat Plugins/media
 */
$.fn.media = function(options, f1, f2) {
    return this.each(function() {
        if (typeof options == 'function') {
            f2 = f1;
            f1 = options;
            options = {};
        }
        var o = getSettings(this, options);
        // pre-conversion callback, passes original element and fully populated options
        if (typeof f1 == 'function') f1(this, o);
        
        var r = getTypesRegExp();
        var m = r.exec(o.src) || [''];
        o.type ? m[0] = o.type : m.shift();
        for (var i=0; i < m.length; i++) {
            fn = m[i].toLowerCase();
            if (isDigit(fn[0])) fn = 'fn' + fn; // fns can't begin with numbers
            if (!$.fn.media[fn]) 
                continue;  // unrecognized media type
            // normalize autoplay settings
            var player = $.fn.media[fn+'_player'];
            if (!o.params) o.params = {};
            if (player) {
                var num = player.autoplayAttr == 'autostart';
                o.params[player.autoplayAttr || 'autoplay'] = num ? (o.autoplay ? 1 : 0) : o.autoplay ? true : false;
            }
            var $div = $.fn.media[fn](this, o);

            $div.css('backgroundColor', o.bgColor).width(o.width);
            
            // post-conversion callback, passes original element, new div element and fully populated options
            if (typeof f2 == 'function') f2(this, $div[0], o, player.name);
            break;
        }
    });
};

/**
 * Chainable method for preparing elements to display rich media with
 * a page overlay.
 *
 * @name mediabox
 * @param Object options Options object
 * @param Object css values for the media div
 * @cat Plugins/media
 */
$.fn.mediabox = function(options, css) {
    return this.click(function() {
        if (typeof $.blockUI == 'undefined' || typeof $.blockUI.version == 'undefined' || $.blockUI.version < 1.26) {
            if (typeof $.fn.mediabox.warning != 'undefined') return this; // one warning is enough
            $.fn.mediabox.warning = 1;
            alert('The mediabox method requires blockUI v1.26 or later.');
            return false;
        }
        var o, p, div=0, $e = $(this).clone();
        $e.appendTo('body').hide().css({margin: 0});
        options = $.extend({}, options, { autoplay: 1 }); // force autoplay in box mode
        $e.media(options, function(){}, function(origEl, newEl, opts, player) {
            div = newEl;
            o = opts;
            p = player;
        });
        if (!div) return false;
        // don't pull element from the dom on Safari
        var $div = $.browser.safari ? $(div).hide() : $(div).remove();

        if (o.loadingImage)
            $div.css({
                backgroundImage:    'url('+o.loadingImage+')',
                backgroundPosition: 'center center',
                backgroundRepeat:   'no-repeat'
            });
        if (o.boxTitle)
            $div.prepend('<div style="margin:0;padding:0">' + o.boxTitle + '</div>');
        
        if (css) $div.css(css);

        $div.displayBox( { width: o.width, height: o.height }, function(el) {
            // quirkiness; sometimes media doesn't stop when removed from the DOM (especially in IE)
            $('object,embed', el).each(function() {
                try { this.Stop();   } catch(e) {}  // quicktime
                try { this.DoStop(); } catch(e) {}  // real
                try { this.controls.stop(); } catch(e) {} // windows media player
            });
        }, p == 'flash'); // <-- mac/ff workaround
        return false;
    });
};

  
/**
 * Non-chainable method for adding or changing file format / player mapping
 * @name mapFormat
 * @param String format File format extension (ie: mov, wav, mp3)
 * @param String player Player name to use for the format (one of: flash, quicktime, realplayer, winmedia, silverlight or iframe
 */
$.fn.media.mapFormat = function(format, player) {
    if (!format || !player || !$.fn.media.defaults.players[player]) return; // invalid
    format = format.toLowerCase();
    if (isDigit(format[0])) format = 'fn' + format;
    $.fn.media[format] = $.fn.media[player];
};


// global defautls; override as needed
$.fn.media.defaults = {
    width:         400,
    height:        400,
    preferMeta:    1,         // true if markup metadata takes precedence over options object
    autoplay:      0,         // normalized cross-player setting
    bgColor:       '#ffffff', // background color
    params:        {},        // added to object element as param elements; added to embed element as attrs
    attrs:         {},        // added to object and embed elements as attrs
    flashvars:     {},        // added to flash content as flashvars param/attr
    flashVersion:  '7',       // required flash version
    
    // MediaBox options
    boxTitle:      null,      // MediaBox titlebar
    loadingImage:  null,      // MediaBox loading indicator
    
    // default flash video and mp3 player (@see: http://jeroenwijering.com/?item=Flash_Media_Player)
    flvPlayer:     'mediaplayer.swf',
    mp3Player:     'mediaplayer.swf',
    
    // @see http://msdn2.microsoft.com/en-us/library/bb412401.aspx
    silverlight: {
        inplaceInstallPrompt: 'true', // display in-place install prompt?
        isWindowless:         'true', // windowless mode (false for wrapping markup)
        framerate:            '24',   // maximum framerate
        version:              '0.9',  // Silverlight version
        onError:              null,   // onError callback
        onLoad:               null,   // onLoad callback
        initParams:           null,   // object init params
        userContext:          null    // callback arg passed to the load callback
    }
};

// Media Players; think twice before overriding
$.fn.media.defaults.players = {
    flash: {
        name:         'flash',
        types:        'flv,mp3,swf',
        oAttrs:   {
            classid:  'clsid:d27cdb6e-ae6d-11cf-96b8-444553540000',
            type:     'application/x-oleobject',
            codebase: 'http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=' + $.fn.media.defaults.flashVersion
        },
        eAttrs: {
            type:         'application/x-shockwave-flash',
            pluginspage:  'http://www.adobe.com/go/getflashplayer'
        }        
    },
    quicktime: {
        name:         'quicktime',
        types:        'aif,aiff,aac,au,bmp,gsm,mov,mid,midi,mpg,mpeg,mp4,m4a,psd,qt,qtif,qif,qti,snd,tif,tiff,wav,3g2,3gp',
        oAttrs:   {
            classid:  'clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B',
            codebase: 'http://www.apple.com/qtactivex/qtplugin.cab'
        },
        eAttrs: {
            pluginspage:  'http://www.apple.com/quicktime/download/'
        }
    },
    realplayer: {
        name:         'real',
        types:        'ra,ram,rm,rpm,rv,smi,smil',
        autoplayAttr: 'autostart',
        oAttrs:   {
            classid:  'clsid:CFCDAA03-8BE4-11cf-B84B-0020AFBBCCFA'
        },
        eAttrs: {
            type:         'audio/x-pn-realaudio-plugin',
            pluginspage:  'http://www.real.com/player/'
        }
    },
    winmedia: {
        name:         'winmedia',
        types:        'asf,avi,wma,wmv',
        autoplayAttr: 'autostart',
        oUrl:         'url',
        oAttrs:   {
            classid:  'clsid:6BF52A52-394A-11d3-B153-00C04F79FAA6',
            type:     'application/x-oleobject'
        },
        eAttrs: {
            type:         'application/x-mplayer2',
            pluginspage:  'http://www.microsoft.com/Windows/MediaPlayer/'
        }        
    },
    // special cases
    iframe: {
        name:  'iframe',
        types: 'html,pdf'
    },
    silverlight: {
        name:  'silverlight',
        types: 'xaml'
    }
};

//
//  everything below here is private
//


var counter = 1;

for (var player in $.fn.media.defaults.players) {
    var types = $.fn.media.defaults.players[player].types;
    $.each(types.split(','), function(i,o) {
        if (isDigit(o[0])) o = 'fn' + o;
        $.fn.media[o] = $.fn.media[player] = getGenerator(player);
        $.fn.media[o+'_player'] = $.fn.media.defaults.players[player];
    });
};

function getTypesRegExp() {
    var types = '';
    for (var player in $.fn.media.defaults.players) {
        if (types.length) types += ',';
        types += $.fn.media.defaults.players[player].types;
    };
    return new RegExp('\\.(' + types.replace(/,/g,'|') + ')\\b');
};

function getGenerator(player) {
    return function(el, options) {
        return generate(el, options, player);
    };
};

function isDigit(c) {
    return '0123456789'.indexOf(c) > -1;
};

// flatten all possible options: global defaults, meta, option obj
function getSettings(el, options) {
    options = options || {};
    var $el = $(el);
    
    var cls = el.className || '';
    var meta = $.meta ? $el.data() : {};
    var w = meta.width  || parseInt(((cls.match(/w:(\d+)/)||[])[1]||0));
    var h = meta.height || parseInt(((cls.match(/h:(\d+)/)||[])[1]||0));
    if (w) meta.width  = w;
    if (h) meta.height = h;
    if (cls) meta.cls = cls;

    var a = $.fn.media.defaults;
    var b = $.meta && $.fn.media.defaults.preferMeta ? options : meta;
    var c = b == options ? meta : options;

    var p = { params: { bgColor: options.bgColor || $.fn.media.defaults.bgColor } };
    var opts = $.extend({}, a, b, c);
    $.each(['attrs','params','flashvars','silverlight'], function(i,o) {
        opts[o] = $.extend({}, p[o] || {}, a[o] || {}, b[o] || {}, c[o] || {});
    });

    if (typeof opts.caption == 'undefined') opts.caption = $el.text();

    // make sure we have a source!
    opts.src = opts.src || $el.attr('href') || $el.attr('src') || 'unknown';
    return opts;
};

//
//  Flash Player
//

// generate flash using SWFObject if possible
$.fn.media.swf = function(el, opts) {
    if (typeof SWFObject == 'undefined') {
        // roll our own
        if (opts.flashvars) {
            var a = [];
            for (var f in opts.flashvars)
                a.push(f + '=' + opts.flashvars[f]);
            if (!opts.params) opts.params = {};
            opts.params.flashvars = a.join('&');
        }
        return generate(el, opts, 'flash');
    }

    var id = el.id ? (' id="'+el.id+'"') : '';
    var cls = opts.cls ? (' class="' + opts.cls + '"') : '';
    var $div = $('<div' + id + cls + '>');
    $(el).after($div).remove();

    var so = new SWFObject(opts.src, 'movie_player_' + counter++, opts.width, opts.height, opts.flashVersion, opts.bgColor);
    for (var p in opts.params)
        if (p != 'bgColor') so.addParam(p, opts.params[p]);
    for (var f in opts.flashvars)
        so.addVariable(f, opts.flashvars[f]);
    so.write($div[0]);

    if (opts.caption) $('<div>').appendTo($div).html(opts.caption);
    return $div;
};

// map flv and mp3 files to the swf player by default
$.fn.media.flv = $.fn.media.mp3 = function(el, opts) {
    var src = opts.src;
    var player = /\.mp3\b/i.test(src) ? $.fn.media.defaults.mp3Player : $.fn.media.defaults.flvPlayer;
    opts.src = player;
    opts.src = opts.src + '?file=' + src;
    opts.flashvars = $.extend({}, { file: src }, opts.flashvars );
    return $.fn.media.swf(el, opts);
};

//
//  Silverlight
//
$.fn.media.xaml = function(el, opts) {
    if (!window.Sys || !window.Sys.Silverlight) {
        if ($.fn.media.xaml.warning) return;
        $.fn.media.xaml.warning = 1;
        alert('You must include the Silverlight.js script.');
        return;
    }

    var props = {
        width: opts.width,
        height: opts.height,
        background: opts.bgColor,
        inplaceInstallPrompt: opts.silverlight.inplaceInstallPrompt,
        isWindowless: opts.silverlight.isWindowless,
        framerate: opts.silverlight.framerate,
        version: opts.silverlight.version
    };
    var events = {
        onError: opts.silverlight.onError,
        onLoad: opts.silverlight.onLoad
    };

    var id1 = el.id ? (' id="'+el.id+'"') : '';
    var id2 = opts.id || 'AG' + counter++;
    // convert element to div
    var cls = opts.cls ? (' class="' + opts.cls + '"') : '';
    var $div = $('<div' + id1 + cls + '>');
    $(el).after($div).remove();
    
    Sys.Silverlight.createObjectEx({
        source: opts.src,
        initParams: opts.silverlight.initParams,
        userContext: opts.silverlight.userContext,
        id: id2,
        parentElement: $div[0],
        properties: props,
        events: events
    });

    if (opts.caption) $('<div>').appendTo($div).html(opts.caption);
    return $div;
};

//
// generate object/embed markup
//
function generate(el, opts, player) {
    var $el = $(el);
    var o = $.fn.media.defaults.players[player];
    
    if (player == 'iframe') {
        var o = $('<iframe' + ' width="' + opts.width + '" height="' + opts.height + '" >');
        o.attr('src', opts.src);
        o.css('backgroundColor', o.bgColor);
    }
    else if ($.browser.msie) {
        var a = ['<object width="' + opts.width + '" height="' + opts.height + '" '];
        for (var key in opts.attrs)
            a.push(key + '="'+opts.attrs[key]+'" ');
        for (var key in o.oAttrs || {})
            a.push(key + '="'+o.oAttrs[key]+'" ');
        a.push('></ob'+'ject'+'>');
        var p = ['<param name="' + (o.oUrl || 'src') +'" value="' + opts.src + '">'];
        for (var key in opts.params)
            p.push('<param name="'+ key +'" value="' + opts.params[key] + '">');
        var o = document.createElement(a.join(''));
        for (var i=0; i < p.length; i++)
            o.appendChild(document.createElement(p[i]));
    }
    else {
        var a = ['<embed width="' + opts.width + '" height="' + opts.height + '" style="display:inline"'];
        if (opts.src) a.push(' src="' + opts.src + '" ');
        for (var key in opts.attrs)
            a.push(key + '="'+opts.attrs[key]+'" ');
        for (var key in o.eAttrs || {})
            a.push(key + '="'+o.eAttrs[key]+'" ');
        for (var key in opts.params)
            a.push(key + '="'+opts.params[key]+'" ');
        a.push('></em'+'bed'+'>');
    }
    // convert element to div
    var id = el.id ? (' id="'+el.id+'"') : '';
    var cls = opts.cls ? (' class="' + opts.cls + '"') : '';
    var $div = $('<div' + id + cls + '>');
    $el.after($div).remove();
    ($.browser.msie || player == 'iframe') ? $div.append(o) : $div.html(a.join(''));
    if (opts.caption) $('<div>').appendTo($div).html(opts.caption);
    return $div;
};


})(jQuery);
/*
 * jQuery history plugin
 *
 * Copyright (c) 2006 Taku Sano (Mikage Sawatari)
 * Licensed under the MIT License:
 *   http://www.opensource.org/licenses/mit-license.php
 *
 * Modified by Lincoln Cooper to add Safari support and only call the callback once during initialization
 * for msie when no initial hash supplied.
 */


jQuery.extend({
	historyCurrentHash: undefined,
	
	historyCallback: undefined,
	
	historyInit: function(callback){
		jQuery.historyCallback = callback;
		var current_hash = location.hash;
		
		jQuery.historyCurrentHash = current_hash;
		if(jQuery.browser.msie) {
			// To stop the callback firing twice during initilization if no hash present
			if (jQuery.historyCurrentHash == '') {
			jQuery.historyCurrentHash = '#';
		}
		
			// add hidden iframe for IE
			$("body").prepend('<iframe id="jQuery_history" style="display: none;"></iframe>');
			var ihistory = $("#jQuery_history")[0];
			var iframe = ihistory.contentWindow.document;
			iframe.open();
			iframe.close();
			iframe.location.hash = current_hash;
		}
		else if ($.browser.safari) {
			// etablish back/forward stacks
			jQuery.historyBackStack = [];
			jQuery.historyBackStack.length = history.length;
			jQuery.historyForwardStack = [];
			
			jQuery.isFirst = true;
		}
		jQuery.historyCallback(current_hash.replace(/^#/, ''));
		setInterval(jQuery.historyCheck, 100);
	},
	
	historyAddHistory: function(hash) {
		// This makes the looping function do something
		jQuery.historyBackStack.push(hash);
		
		jQuery.historyForwardStack.length = 0; // clear forwardStack (true click occured)
		this.isFirst = true;
	},
	
	historyCheck: function(){
		if(jQuery.browser.msie) {
			// On IE, check for location.hash of iframe
			var ihistory = $("#jQuery_history")[0];
			var iframe = ihistory.contentDocument || ihistory.contentWindow.document;
			var current_hash = iframe.location.hash;
			if(current_hash != jQuery.historyCurrentHash) {
			
				location.hash = current_hash;
				jQuery.historyCurrentHash = current_hash;
				jQuery.historyCallback(current_hash.replace(/^#/, ''));
				
			}
		} else if ($.browser.safari) {
			if (!jQuery.dontCheck) {
				var historyDelta = history.length - jQuery.historyBackStack.length;
				
				if (historyDelta) { // back or forward button has been pushed
					jQuery.isFirst = false;
					if (historyDelta < 0) { // back button has been pushed
						// move items to forward stack
						for (var i = 0; i < Math.abs(historyDelta); i++) jQuery.historyForwardStack.unshift(jQuery.historyBackStack.pop());
					} else { // forward button has been pushed
						// move items to back stack
						for (var i = 0; i < historyDelta; i++) jQuery.historyBackStack.push(jQuery.historyForwardStack.shift());
					}
					var cachedHash = jQuery.historyBackStack[jQuery.historyBackStack.length - 1];
					if (cachedHash != undefined) {
						jQuery.historyCurrentHash = location.hash;
						jQuery.historyCallback(cachedHash);
					}
				} else if (jQuery.historyBackStack[jQuery.historyBackStack.length - 1] == undefined && !jQuery.isFirst) {
					// back button has been pushed to beginning and URL already pointed to hash (e.g. a bookmark)
					// document.URL doesn't change in Safari
					if (document.URL.indexOf('#') >= 0) {
						jQuery.historyCallback(document.URL.split('#')[1]);
					} else {
						var current_hash = location.hash;
						jQuery.historyCallback('');
					}
					jQuery.isFirst = true;
				}
			}
		} else {
			// otherwise, check for location.hash
			var current_hash = location.hash;
			if(current_hash != jQuery.historyCurrentHash) {
				jQuery.historyCurrentHash = current_hash;
				jQuery.historyCallback(current_hash.replace(/^#/, ''));
			}
		}
	},
	historyLoad: function(hash){
		var newhash;
		
		if (jQuery.browser.safari) {
			newhash = hash;
		}
		else {
			newhash = '#' + hash;
			location.hash = newhash;
		}
		jQuery.historyCurrentHash = newhash;
		
		if(jQuery.browser.msie) {
			var ihistory = $("#jQuery_history")[0];
			var iframe = ihistory.contentWindow.document;
			iframe.open();
			iframe.close();
			iframe.location.hash = newhash;
			jQuery.historyCallback(hash);
		}
		else if (jQuery.browser.safari) {
			jQuery.dontCheck = true;
			// Manually keep track of the history values for Safari
			this.historyAddHistory(hash);
			
			// Wait a while before allowing checking so that Safari has time to update the "history" object
			// correctly (otherwise the check loop would detect a false change in hash).
			var fn = function() {jQuery.dontCheck = false;};
			window.setTimeout(fn, 200);
			jQuery.historyCallback(hash);
			// N.B. "location.hash=" must be the last line of code for Safari as execution stops afterwards.
			//      By explicitly using the "location.hash" command (instead of using a variable set to "location.hash") the
			//      URL in the browser and the "history" object are both updated correctly.
			location.hash = newhash;
		}
		else {
		  jQuery.historyCallback(hash);
		}
	}
});


/*
 * Interface elements for jQuery - http://interface.eyecon.ro
 *
 * Copyright (c) 2006 Stefan Petre
 * Dual licensed under the MIT (MIT-LICENSE.txt) 
 * and GPL (GPL-LICENSE.txt) licenses.
 */
 eval(function(p,a,c,k,e,d){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--){d[e(c)]=k[c]||e(c)}k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c])}}return p}('6.W={2t:D(e){u x=0;u y=0;u 34=B;u X=e.S;8(6(e).M(\'U\')==\'10\'){33=X.21;4G=X.1f;X.21=\'2B\';X.U=\'1Z\';X.1f=\'2z\';34=P}u G=e;4o(G){x+=G.5e+(G.35&&!6.1P.3W?L(G.35.5F)||0:0);y+=G.5c+(G.35&&!6.1P.3W?L(G.35.5y)||0:0);G=G.5H}G=e;4o(G&&G.5I&&G.5I.4U()!=\'1m\'){x-=G.2T||0;y-=G.2E||0;G=G.20}8(34){X.U=\'10\';X.1f=4G;X.21=33}H{x:x,y:y}},7Y:D(G){u x=0,y=0;4o(G){x+=G.5e||0;y+=G.5c||0;G=G.5H}H{x:x,y:y}},2n:D(e){u w=6.M(e,\'2J\');u h=6.M(e,\'2I\');u 1p=0;u 1j=0;u X=e.S;8(6(e).M(\'U\')!=\'10\'){1p=e.5m;1j=e.59}N{33=X.21;4G=X.1f;X.21=\'2B\';X.U=\'1Z\';X.1f=\'2z\';1p=e.5m;1j=e.59;X.U=\'10\';X.1f=4G;X.21=33}H{w:w,h:h,1p:1p,1j:1j}},4D:D(G){H{1p:G.5m||0,1j:G.59||0}},6A:D(e){u h,w,36;8(e){w=e.3I;h=e.3K}N{36=T.1O;w=2w.5t||4r.5t||(36&&36.3I)||T.1m.3I;h=2w.4O||4r.4O||(36&&36.3K)||T.1m.3K}H{w:w,h:h}},65:D(e){u t,l,w,h,3k,3e;8(e&&e.4y.4U()!=\'1m\'){t=e.2E;l=e.2T;w=e.5B;h=e.5z;3k=0;3e=0}N{8(T.1O&&T.1O.2E){t=T.1O.2E;l=T.1O.2T;w=T.1O.5B;h=T.1O.5z}N 8(T.1m){t=T.1m.2E;l=T.1m.2T;w=T.1m.5B;h=T.1m.5z}3k=4r.5t||T.1O.3I||T.1m.3I||0;3e=4r.4O||T.1O.3K||T.1m.3K||0}H{t:t,l:l,w:w,h:h,3k:3k,3e:3e}},4W:D(e,2Q){u G=6(e);u t=G.M(\'25\')||\'\';u r=G.M(\'28\')||\'\';u b=G.M(\'24\')||\'\';u l=G.M(\'2b\')||\'\';8(2Q)H{t:L(t)||0,r:L(r)||0,b:L(b)||0,l:L(l)};N H{t:t,r:r,b:b,l:l}},7X:D(e,2Q){u G=6(e);u t=G.M(\'69\')||\'\';u r=G.M(\'6a\')||\'\';u b=G.M(\'5Z\')||\'\';u l=G.M(\'60\')||\'\';8(2Q)H{t:L(t)||0,r:L(r)||0,b:L(b)||0,l:L(l)};N H{t:t,r:r,b:b,l:l}},4a:D(e,2Q){u G=6(e);u t=G.M(\'5y\')||\'\';u r=G.M(\'5P\')||\'\';u b=G.M(\'5Q\')||\'\';u l=G.M(\'5F\')||\'\';8(2Q)H{t:L(t)||0,r:L(r)||0,b:L(b)||0,l:L(l)||0};N H{t:t,r:r,b:b,l:l}},5f:D(3L){u x=3L.7V||(3L.7W+(T.1O.2T||T.1m.2T))||0;u y=3L.81||(3L.86+(T.1O.2E||T.1m.2E))||0;H{x:x,y:y}},4T:D(1T,52){52(1T);1T=1T.3O;4o(1T){6.W.4T(1T,52);1T=1T.84}},83:D(1T){6.W.4T(1T,D(G){1d(u 1n 1z G){8(3Q G[1n]===\'D\'){G[1n]=V}}})},82:D(G,1c){u 26=$.W.65();u 53=$.W.2n(G);8(!1c||1c==\'3q\')$(G).M({19:26.t+((1v.4u(26.h,26.3e)-26.t-53.1j)/2)+\'1b\'});8(!1c||1c==\'3m\')$(G).M({1a:26.l+((1v.4u(26.w,26.3k)-26.l-53.1p)/2)+\'1b\'})},7U:D(G,63){u 66=$(\'5O[@4v*="4q"]\',G||T),4q;66.1s(D(){4q=A.4v;A.4v=63;A.S.5h="7T:7L.7K.7J(4v=\'"+4q+"\')"})}};[].6c||(4K.7H.6c=D(v,n){n=(n==V)?0:n;u m=A.1i;1d(u i=n;i<m;i++)8(A[i]==v)H i;H-1});6.6b=D(e){8(/^7M$|^7N$|^7S$|^7R$|^7Q$|^7O$|^7P$|^87$|^88$|^1m$|^8r$|^8q$|^8p$|^8n$|^8o$|^8s$|^8t$/i.3j(e.4y))H B;N H P};6.J.8x=D(e,2m){u c=e.3O;u 1x=c.S;1x.1f=2m.1f;1x.25=2m.1u.t;1x.2b=2m.1u.l;1x.24=2m.1u.b;1x.28=2m.1u.r;1x.19=2m.19+\'1b\';1x.1a=2m.1a+\'1b\';e.20.5L(c,e);e.20.8w(e)};6.J.8v=D(e){8(!6.6b(e))H B;u t=6(e);u X=e.S;u 34=B;u 1g={};1g.1f=t.M(\'1f\');8(t.M(\'U\')==\'10\'){33=t.M(\'21\');X.21=\'2B\';X.U=\'\';34=P}1g.5x=6.W.2n(e);1g.1u=6.W.4W(e);u 5d=e.35?e.35.5K:t.M(\'7G\');1g.19=L(t.M(\'19\'))||0;1g.1a=L(t.M(\'1a\'))||0;u 5N=\'8l\'+L(1v.6Y()*5a);u 2H=T.8d(/^5O$|^8b$|^89$|^8a$|^4E$|^8e$|^5p$|^8f$|^8k$|^8j$|^8i$|^8g$|^8h$|^8y$/i.3j(e.4y)?\'3T\':e.4y);6.1n(2H,\'1e\',5N);2H.4x=\'7f\';u 1y=2H.S;u 19=0;u 1a=0;8(1g.1f==\'3y\'||1g.1f==\'2z\'){19=1g.19;1a=1g.1a}1y.U=\'10\';1y.19=19+\'1b\';1y.1a=1a+\'1b\';1y.1f=1g.1f!=\'3y\'&&1g.1f!=\'2z\'?\'3y\':1g.1f;1y.3P=\'2B\';1y.2I=1g.5x.1j+\'1b\';1y.2J=1g.5x.1p+\'1b\';1y.25=1g.1u.t;1y.28=1g.1u.r;1y.24=1g.1u.b;1y.2b=1g.1u.l;8(6.1P.2S){1y.5K=5d}N{1y.7h=5d}e.20.5L(2H,e);X.25=\'1t\';X.28=\'1t\';X.24=\'1t\';X.2b=\'1t\';X.1f=\'2z\';X.6L=\'10\';X.19=\'1t\';X.1a=\'1t\';8(34){X.U=\'10\';X.21=33}2H.7a(e);1y.U=\'1Z\';H{1g:1g,7z:6(2H)}};6.J.3u={7x:[0,Z,Z],7A:[5X,Z,Z],7B:[5M,5M,7D],7u:[0,0,0],7n:[0,0,Z],7k:[5U,42,42],7o:[0,Z,Z],7p:[0,0,2W],7s:[0,2W,2W],7r:[58,58,58],7w:[0,5i,0],7q:[7t,7l,5R],7m:[2W,0,2W],7v:[85,5R,47],7E:[Z,5Y,0],7j:[7y,50,7b],7d:[2W,0,0],8m:[8N,9I,9H],8z:[9F,0,4C],9J:[Z,0,Z],9K:[Z,9O,0],9N:[0,2y,0],9M:[75,0,9L],9E:[5X,5W,5Y],9D:[9w,9v,5W],9Q:[5T,Z,Z],9s:[5V,9t,5V],9y:[4C,4C,4C],9C:[Z,9B,9A],9z:[Z,Z,5T],9P:[0,Z,0],9W:[Z,0,Z],a2:[2y,0,0],a1:[0,0,2y],a4:[2y,2y,0],a3:[Z,5U,0],a6:[Z,3Z,9Z],9T:[2y,0,2y],9S:[Z,0,0],9V:[3Z,3Z,3Z],9X:[Z,Z,Z],9Y:[Z,Z,0]};6.J.2D=D(1V,5S){8(6.J.3u[1V])H{r:6.J.3u[1V][0],g:6.J.3u[1V][1],b:6.J.3u[1V][2]};N 8(1l=/^2U\\(\\s*([0-9]{1,3})\\s*,\\s*([0-9]{1,3})\\s*,\\s*([0-9]{1,3})\\s*\\)$/.4e(1V))H{r:L(1l[1]),g:L(1l[2]),b:L(1l[3])};N 8(1l=/2U\\(\\s*([0-9]+(?:\\.[0-9]+)?)\\%\\s*,\\s*([0-9]+(?:\\.[0-9]+)?)\\%\\s*,\\s*([0-9]+(?:\\.[0-9]+)?)\\%\\s*\\)$/.4e(1V))H{r:1A(1l[1])*2.55,g:1A(1l[2])*2.55,b:1A(1l[3])*2.55};N 8(1l=/^#([a-2Y-2X-9])([a-2Y-2X-9])([a-2Y-2X-9])$/.4e(1V))H{r:L("2V"+1l[1]+1l[1]),g:L("2V"+1l[2]+1l[2]),b:L("2V"+1l[3]+1l[3])};N 8(1l=/^#([a-2Y-2X-9]{2})([a-2Y-2X-9]{2})([a-2Y-2X-9]{2})$/.4e(1V))H{r:L("2V"+1l[1]),g:L("2V"+1l[2]),b:L("2V"+1l[3])};N H 5S==P?B:{r:Z,g:Z,b:Z}};6.J.62={5Q:1,5F:1,5P:1,5y:1,4b:1,a0:1,2I:1,1a:1,9u:1,9q:1,24:1,2b:1,28:1,25:1,8S:1,8R:1,8Q:1,8O:1,18:1,8P:1,8T:1,5Z:1,60:1,6a:1,69:1,44:1,8V:1,19:1,2J:1,1Y:1};6.J.64={9r:1,8M:1,8E:1,8D:1,8C:1,1V:1,8B:1};6.J.3G=[\'8F\',\'8G\',\'8L\',\'8K\'];6.J.4Q={\'54\':[\'3s\',\'6f\'],\'3V\':[\'3s\',\'56\'],\'49\':[\'49\',\'\'],\'4d\':[\'4d\',\'\']};6.4F.1K({6m:D(2s,3f,1r,46){H A.3S(D(){u 45=6.3f(3f,1r,46);u e=2u 6.5J(A,45,2s)})},4N:D(3f,46){H A.3S(D(){u 45=6.3f(3f,46);u e=2u 6.4N(A,45)})},8H:D(1U){H A.1s(D(){8(A.2k)6.4J(A,1U)})},8I:D(1U){H A.1s(D(){8(A.2k)6.4J(A,1U);8(A.3S&&A.3S[\'J\'])A.3S.J=[]})}});6.1K({4N:D(Y,16){u z=A,68;z.1U=D(){8(6.6V(16.3X))16.3X.1J(Y)};z.3N=6S(D(){z.1U()},16.1W);Y.2k=z},1r:{67:D(p,n,6d,6e,1W){H((-1v.8Z(p*1v.90)/2)+0.5)*6e+6d}},5J:D(Y,16,2s){u z=A,68;u y=Y.S;u 6X=6.M(Y,"3P");u 38=6.M(Y,"U");u 11={};z.41=(2u 74()).6T();16.1r=16.1r&&6.1r[16.1r]?16.1r:\'67\';z.43=D(17,1H){8(6.J.62[17]){8(1H==\'4c\'||1H==\'3A\'||1H==\'61\'){8(!Y.2L)Y.2L={};u r=1A(6.2A(Y,17));Y.2L[17]=r&&r>-5a?r:(1A(6.M(Y,17))||0);1H=1H==\'61\'?(38==\'10\'?\'4c\':\'3A\'):1H;16[1H]=P;11[17]=1H==\'4c\'?[0,Y.2L[17]]:[Y.2L[17],0];8(17!=\'18\')y[17]=11[17][0]+(17!=\'1Y\'&&17!=\'5v\'?\'1b\':\'\');N 6.1n(y,"18",11[17][0])}N{11[17]=[1A(6.2A(Y,17)),1A(1H)||0]}}N 8(6.J.64[17])11[17]=[6.J.2D(6.2A(Y,17)),6.J.2D(1H)];N 8(/^49$|4d$|3s$|3V$|54$/i.3j(17)){u m=1H.2P(/\\s+/g,\' \').2P(/2U\\s*\\(\\s*/g,\'2U(\').2P(/\\s*,\\s*/g,\',\').2P(/\\s*\\)/g,\')\').9g(/([^\\s]+)/g);9k(17){3B\'49\':3B\'4d\':3B\'54\':3B\'3V\':m[3]=m[3]||m[1]||m[0];m[2]=m[2]||m[0];m[1]=m[1]||m[0];1d(u i=0;i<6.J.3G.1i;i++){u 2p=6.J.4Q[17][0]+6.J.3G[i]+6.J.4Q[17][1];11[2p]=17==\'3V\'?[6.J.2D(6.2A(Y,2p)),6.J.2D(m[i])]:[1A(6.2A(Y,2p)),1A(m[i])]}4Z;3B\'3s\':1d(u i=0;i<m.1i;i++){u 5C=1A(m[i]);u 3Y=!9o(5C)?\'6f\':(!/9n|10|2B|9m|9e|9d|95|94|93|91|92/i.3j(m[i])?\'56\':B);8(3Y){1d(u j=0;j<6.J.3G.1i;j++){2p=\'3s\'+6.J.3G[j]+3Y;11[2p]=3Y==\'56\'?[6.J.2D(6.2A(Y,2p)),6.J.2D(m[i])]:[1A(6.2A(Y,2p)),5C]}}N{y[\'9b\']=m[i]}}4Z}}N{y[17]=1H}H B};1d(p 1z 2s){8(p==\'S\'){u 2e=6.4V(2s[p]);1d(39 1z 2e){A.43(39,2e[39])}}N 8(p==\'4x\'){8(T.48)1d(u i=0;i<T.48.1i;i++){u 37=T.48[i].37||T.48[i].9a||V;8(37){1d(u j=0;j<37.1i;j++){8(37[j].98==\'.\'+2s[p]){u 3n=2u 99(\'\\.\'+2s[p]+\' {\');u 2q=37[j].S.9G;u 2e=6.4V(2q.2P(3n,\'\').2P(/}/g,\'\'));1d(39 1z 2e){A.43(39,2e[39])}}}}}}N{A.43(p,2s[p])}}y.U=38==\'10\'?\'1Z\':38;y.3P=\'2B\';z.1U=D(){u t=(2u 74()).6T();8(t>16.1W+z.41){6Q(z.3N);z.3N=V;1d(p 1z 11){8(p=="18")6.1n(y,"18",11[p][1]);N 8(3Q 11[p][1]==\'5p\')y[p]=\'2U(\'+11[p][1].r+\',\'+11[p][1].g+\',\'+11[p][1].b+\')\';N y[p]=11[p][1]+(p!=\'1Y\'&&p!=\'5v\'?\'1b\':\'\')}8(16.3A||16.4c)1d(u p 1z Y.2L)8(p=="18")6.1n(y,p,Y.2L[p]);N y[p]="";y.U=16.3A?\'10\':(38!=\'10\'?38:\'1Z\');y.3P=6X;Y.2k=V;8(6.6V(16.3X))16.3X.1J(Y)}N{u n=t-A.41;u 3R=n/16.1W;1d(p 1z 11){8(3Q 11[p][1]==\'5p\'){y[p]=\'2U(\'+L(6.1r[16.1r](3R,n,11[p][0].r,(11[p][1].r-11[p][0].r),16.1W))+\',\'+L(6.1r[16.1r](3R,n,11[p][0].g,(11[p][1].g-11[p][0].g),16.1W))+\',\'+L(6.1r[16.1r](3R,n,11[p][0].b,(11[p][1].b-11[p][0].b),16.1W))+\')\'}N{u 5w=6.1r[16.1r](3R,n,11[p][0],(11[p][1]-11[p][0]),16.1W);8(p=="18")6.1n(y,"18",5w);N y[p]=5w+(p!=\'1Y\'&&p!=\'5v\'?\'1b\':\'\')}}}};z.3N=6S(D(){z.1U()},13);Y.2k=z},4J:D(Y,1U){8(1U)Y.2k.41-=9c;N{2w.6Q(Y.2k.3N);Y.2k=V;6.97(Y,"J")}}});6.4V=D(2q){u 2e={};8(3Q 2q==\'96\'){2q=2q.4U().78(\';\');1d(u i=0;i<2q.1i;i++){3n=2q[i].78(\':\');8(3n.1i==2){2e[6.6g(3n[0].2P(/\\-(\\w)/g,D(m,c){H c.9p()}))]=6.6g(3n[1])}}}H 2e};6.I={3d:[],2f:{},O:B,3g:V,70:D(){8(6.C.k==V){H}u 1M,1u,c,1x;6.I.O.Q(0).4x=6.C.k.7.2M;1M=6.I.O.Q(0).S;1M.U=\'1Z\';6.I.O.R=6.1K(6.W.2t(6.I.O.Q(0)),6.W.2n(6.I.O.Q(0)));1M.2J=6.C.k.7.R.1p+\'1b\';1M.2I=6.C.k.7.R.1j+\'1b\';1u=6.W.4W(6.C.k);1M.25=1u.t;1M.28=1u.r;1M.24=1u.b;1M.2b=1u.l;8(6.C.k.7.1G==P){c=6.C.k.6B(P);1x=c.S;1x.25=\'1t\';1x.28=\'1t\';1x.24=\'1t\';1x.2b=\'1t\';1x.U=\'1Z\';6.I.O.5k().2o(c)}6(6.C.k).6M(6.I.O.Q(0));6.C.k.S.U=\'10\'},6h:D(e){8(!e.7.1F&&6.K.2g.5D){8(e.7.1I)e.7.1I.1J(k);6(e).M(\'1f\',e.7.5E||e.7.2Z);6(e).4I();6(6.K.2g).6k(e)}6.I.O.3J(e.7.2M).9l(\'&6v;\');6.I.3g=V;u 1M=6.I.O.Q(0).S;1M.U=\'10\';6.I.O.6M(e);8(e.7.J>0){6(e).9f(e.7.J)}6(\'1m\').2o(6.I.O.Q(0));u 3E=[];u 3C=B;1d(u i=0;i<6.I.3d.1i;i++){u F=6.K.1w[6.I.3d[i]].Q(0);u 1e=6.1n(F,\'1e\');u 3x=6.I.3U(1e);8(F.E.4p!=3x.3H){F.E.4p=3x.3H;8(3C==B&&F.E.1B){3C=F.E.1B}3x.1e=1e;3E[3E.1i]=3x}}6.I.3d=[];8(3C!=B&&3E.1i>0){3C(3E)}},4A:D(e,o){8(!6.C.k)H;u 2j=B;u i=0;8(e.E.G.6t()>0){1d(i=e.E.G.6t();i>0;i--){8(e.E.G.Q(i-1)!=6.C.k){8(!e.2h.4L){8((e.E.G.Q(i-1).2F.y+e.E.G.Q(i-1).2F.1j/2)>6.C.k.7.1R){2j=e.E.G.Q(i-1)}N{4Z}}N{8((e.E.G.Q(i-1).2F.x+e.E.G.Q(i-1).2F.1p/2)>6.C.k.7.2c&&(e.E.G.Q(i-1).2F.y+e.E.G.Q(i-1).2F.1j/2)>6.C.k.7.1R){2j=e.E.G.Q(i-1)}}}}}8(2j&&6.I.3g!=2j){6.I.3g=2j;6(2j).9h(6.I.O.Q(0))}N 8(!2j&&(6.I.3g!=V||6.I.O.Q(0).20!=e)){6.I.3g=V;6(e).2o(6.I.O.Q(0))}6.I.O.Q(0).S.U=\'1Z\'},4S:D(e){8(6.C.k==V){H}e.E.G.1s(D(){A.2F=6.1K(6.W.4D(A),6.W.2t(A))})},3U:D(s){u i;u h=\'\';u o={};8(s){8(6.I.2f[s]){o[s]=[];6(\'#\'+s+\' .\'+6.I.2f[s]).1s(D(){8(h.1i>0){h+=\'&\'}h+=s+\'[]=\'+6.1n(A,\'1e\');o[s][o[s].1i]=6.1n(A,\'1e\')})}N{1d(a 1z s){8(6.I.2f[s[a]]){o[s[a]]=[];6(\'#\'+s[a]+\' .\'+6.I.2f[s[a]]).1s(D(){8(h.1i>0){h+=\'&\'}h+=s[a]+\'[]=\'+6.1n(A,\'1e\');o[s[a]][o[s[a]].1i]=6.1n(A,\'1e\')})}}}}N{1d(i 1z 6.I.2f){o[i]=[];6(\'#\'+i+\' .\'+6.I.2f[i]).1s(D(){8(h.1i>0){h+=\'&\'}h+=i+\'[]=\'+6.1n(A,\'1e\');o[i][o[i].1i]=6.1n(A,\'1e\')})}}H{3H:h,o:o}},6l:D(e){8(!e.9i){H}H A.1s(D(){8(!A.2h||!6(e).4R(\'.\'+A.2h.1N))6(e).3D(A.2h.1N);6(e).4P(A.2h.7)})},32:D(){H A.1s(D(){6(\'.\'+A.2h.1N).4I();6(A).6O();A.2h=V;A.6o=V})},31:D(o){8(o.1N&&6.W&&6.C&&6.K){8(!6.I.O){6(\'1m\',T).2o(\'<3T 1e="6N">&6v;</3T>\');6.I.O=6(\'#6N\');6.I.O.Q(0).S.U=\'10\'}A.6R({1N:o.1N,4B:o.4B?o.4B:B,4h:o.4h?o.4h:B,2r:o.2r?o.2r:B,3a:o.3a||o.77,2R:o.2R||o.6P,5D:P,1B:o.1B||o.9j,J:o.J?o.J:B,1G:o.1G?P:B,2C:o.2C?o.2C:\'5u\'});H A.1s(D(){u 7={2v:o.2v?P:B,6j:6i,18:o.18?1A(o.18):B,2M:o.2r?o.2r:B,J:o.J?o.J:B,1F:P,1G:o.1G?P:B,2l:o.2l?o.2l:V,15:o.15?o.15:V,1X:o.1X&&o.1X.1D==29?o.1X:B,1Q:o.1Q&&o.1Q.1D==29?o.1Q:B,1I:o.1I&&o.1I.1D==29?o.1I:B,1c:/3q|3m/.3j(o.1c)?o.1c:B,2G:o.2G?L(o.2G)||0:B,1k:o.1k?o.1k:B};6(\'.\'+o.1N,A).4P(7);A.6o=P;A.2h={1N:o.1N,2v:o.2v?P:B,6j:6i,18:o.18?1A(o.18):B,2M:o.2r?o.2r:B,J:o.J?o.J:B,1F:P,1G:o.1G?P:B,2l:o.2l?o.2l:V,15:o.15?o.15:V,4L:o.4L?P:B,7:7}})}}};6.4F.1K({8J:6.I.31,6k:6.I.6l,8A:6.I.32});6.8W=6.I.3U;6.C={O:V,k:V,32:D(){H A.1s(D(){8(A.4l){A.7.1S.5j(\'73\',6.C.51);A.7=V;A.4l=B;8(6.1P.2S){A.5A="8X"}N{A.S.8Y=\'\';A.S.6z=\'\';A.S.6F=\'\'}}})},51:D(e){8(6.C.k!=V){6.C.40(e);H B}u q=A.4H;6(T).4Y(\'6E\',6.C.5g).4Y(\'6K\',6.C.40);q.7.1o=6.W.5f(e);q.7.1L=q.7.1o;q.7.4i=B;q.7.8U=A!=A.4H;6.C.k=q;8(q.7.2x&&A!=A.4H){5q=6.W.2t(q.20);57=6.W.2n(q);5s={x:L(6.M(q,\'1a\'))||0,y:L(6.M(q,\'19\'))||0};12=q.7.1L.x-5q.x-57.1p/2-5s.x;14=q.7.1L.y-5q.y-57.1j/2-5s.y;6.5b.a5(q,[12,14])}H 6.9R||B},6w:D(e){u q=6.C.k;q.7.4i=P;u 4j=q.S;q.7.3l=6.M(q,\'U\');q.7.2Z=6.M(q,\'1f\');8(!q.7.5E)q.7.5E=q.7.2Z;q.7.1h={x:L(6.M(q,\'1a\'))||0,y:L(6.M(q,\'19\'))||0};q.7.4n=0;q.7.4s=0;8(6.1P.2S){u 5G=6.W.4a(q,P);q.7.4n=5G.l||0;q.7.4s=5G.t||0}q.7.R=6.1K(6.W.2t(q),6.W.2n(q));8(q.7.2Z!=\'3y\'&&q.7.2Z!=\'2z\'){4j.1f=\'3y\'}6.C.O.5k();u 23=q.6B(P);6(23).M({U:\'1Z\',1a:\'1t\',19:\'1t\'});23.S.25=\'0\';23.S.28=\'0\';23.S.24=\'0\';23.S.2b=\'0\';6.C.O.2o(23);u 1E=6.C.O.Q(0).S;8(q.7.5o){1E.2J=\'6D\';1E.2I=\'6D\'}N{1E.2I=q.7.R.1j+\'1b\';1E.2J=q.7.R.1p+\'1b\'}1E.U=\'1Z\';1E.25=\'1t\';1E.28=\'1t\';1E.24=\'1t\';1E.2b=\'1t\';6.1K(q.7.R,6.W.2n(23));8(q.7.1k){8(q.7.1k.1a){q.7.1h.x+=q.7.1o.x-q.7.R.x-q.7.1k.1a;q.7.R.x=q.7.1o.x-q.7.1k.1a}8(q.7.1k.19){q.7.1h.y+=q.7.1o.y-q.7.R.y-q.7.1k.19;q.7.R.y=q.7.1o.y-q.7.1k.19}8(q.7.1k.44){q.7.1h.x+=q.7.1o.x-q.7.R.x-q.7.R.1j+q.7.1k.44;q.7.R.x=q.7.1o.x-q.7.R.1p+q.7.1k.44}8(q.7.1k.4b){q.7.1h.y+=q.7.1o.y-q.7.R.y-q.7.R.1j+q.7.1k.4b;q.7.R.y=q.7.1o.y-q.7.R.1j+q.7.1k.4b}}q.7.2c=q.7.1h.x;q.7.1R=q.7.1h.y;8(q.7.3M||q.7.15==\'4z\'){3t=6.W.4a(q.20,P);q.7.R.x=q.5e+(6.1P.2S?0:6.1P.3W?-3t.l:3t.l);q.7.R.y=q.5c+(6.1P.2S?0:6.1P.3W?-3t.t:3t.t);6(q.20).2o(6.C.O.Q(0))}8(q.7.15){6.C.6C(q);q.7.27.15=6.C.6r}8(q.7.2x){6.5b.9U(q)}1E.1a=q.7.R.x-q.7.4n+\'1b\';1E.19=q.7.R.y-q.7.4s+\'1b\';1E.2J=q.7.R.1p+\'1b\';1E.2I=q.7.R.1j+\'1b\';6.C.k.7.4k=B;8(q.7.3h){q.7.27.2i=6.C.6p}8(q.7.1Y!=B){6.C.O.M(\'1Y\',q.7.1Y)}8(q.7.18){6.C.O.M(\'18\',q.7.18);8(2w.4f){6.C.O.M(\'5h\',\'6y(18=\'+q.7.18*5i+\')\')}}8(q.7.3c){6.C.O.3D(q.7.3c);6.C.O.Q(0).3O.S.U=\'10\'}8(q.7.1X)q.7.1X.1J(q,[23,q.7.1h.x,q.7.1h.y]);8(6.K&&6.K.3r>0){6.K.71(q)}8(q.7.1G==B){4j.U=\'10\'}H B},6C:D(q){8(q.7.15.1D==6G){8(q.7.15==\'4z\'){q.7.1q=6.1K({x:0,y:0},6.W.2n(q.20));u 3z=6.W.4a(q.20,P);q.7.1q.w=q.7.1q.1p-3z.l-3z.r;q.7.1q.h=q.7.1q.1j-3z.t-3z.b}N 8(q.7.15==\'T\'){u 5l=6.W.6A();q.7.1q={x:0,y:0,w:5l.w,h:5l.h}}}N 8(q.7.15.1D==4K){q.7.1q={x:L(q.7.15[0])||0,y:L(q.7.15[1])||0,w:L(q.7.15[2])||0,h:L(q.7.15[3])||0}}q.7.1q.12=q.7.1q.x-q.7.R.x;q.7.1q.14=q.7.1q.y-q.7.R.y},4w:D(k){8(k.7.3M||k.7.15==\'4z\'){6(\'1m\',T).2o(6.C.O.Q(0))}6.C.O.5k().3A().M(\'18\',1);8(2w.4f){6.C.O.M(\'5h\',\'6y(18=5i)\')}},40:D(e){6(T).5j(\'6E\',6.C.5g).5j(\'6K\',6.C.40);8(6.C.k==V){H}u k=6.C.k;6.C.k=V;8(k.7.4i==B){H B}8(k.7.1F==P){6(k).M(\'1f\',k.7.2Z)}u 4j=k.S;8(k.2x){6.C.O.M(\'6I\',\'6J\')}8(k.7.3c){6.C.O.3J(k.7.3c)}8(k.7.2v==B){8(k.7.J>0){8(!k.7.1c||k.7.1c==\'3m\'){u x=2u 6.J(k,{1W:k.7.J},\'1a\');x.6H(k.7.1h.x,k.7.3v)}8(!k.7.1c||k.7.1c==\'3q\'){u y=2u 6.J(k,{1W:k.7.J},\'19\');y.6H(k.7.1h.y,k.7.3F)}}N{8(!k.7.1c||k.7.1c==\'3m\')k.S.1a=k.7.3v+\'1b\';8(!k.7.1c||k.7.1c==\'3q\')k.S.19=k.7.3F+\'1b\'}6.C.4w(k);8(k.7.1G==B){6(k).M(\'U\',k.7.3l)}}N 8(k.7.J>0){k.7.4k=P;u 30=B;8(6.K&&6.I&&k.7.1F){30=6.W.2t(6.I.O.Q(0))}6.C.O.6m({1a:30?30.x:k.7.R.x,19:30?30.y:k.7.R.y},k.7.J,D(){k.7.4k=B;8(k.7.1G==B){k.S.U=k.7.3l}6.C.4w(k)})}N{6.C.4w(k);8(k.7.1G==B){6(k).M(\'U\',k.7.3l)}}8(6.K&&6.K.3r>0){6.K.6Z(k)}8(6.I&&k.7.1F){6.I.6h(k)}8(k.7.1B&&(k.7.3v!=k.7.1h.x||k.7.3F!=k.7.1h.y)){k.7.1B.1J(k,k.7.9x||[0,0,k.7.3v,k.7.3F])}8(k.7.1I)k.7.1I.1J(k);H B},6p:D(x,y,12,14){8(12!=0)12=L((12+(A.7.3h*12/1v.6q(12))/2)/A.7.3h)*A.7.3h;8(14!=0)14=L((14+(A.7.3w*14/1v.6q(14))/2)/A.7.3w)*A.7.3w;H{12:12,14:14,x:0,y:0}},6r:D(x,y,12,14){12=1v.72(1v.4u(12,A.7.1q.12),A.7.1q.w+A.7.1q.12-A.7.R.1p);14=1v.72(1v.4u(14,A.7.1q.14),A.7.1q.h+A.7.1q.14-A.7.R.1j);H{12:12,14:14,x:0,y:0}},5g:D(e){8(6.C.k==V||6.C.k.7.4k==P){H}u k=6.C.k;k.7.1L=6.W.5f(e);8(k.7.4i==B){6n=1v.7C(1v.6s(k.7.1o.x-k.7.1L.x,2)+1v.6s(k.7.1o.y-k.7.1L.y,2));8(6n<k.7.2G){H}N{6.C.6w(e)}}u 12=k.7.1L.x-k.7.1o.x;u 14=k.7.1L.y-k.7.1o.y;1d(u i 1z k.7.27){u 2K=k.7.27[i].1J(k,[k.7.1h.x+12,k.7.1h.y+14,12,14]);8(2K&&2K.1D==7F){12=i!=\'3b\'?2K.12:(2K.x-k.7.1h.x);14=i!=\'3b\'?2K.14:(2K.y-k.7.1h.y)}}k.7.2c=k.7.R.x+12-k.7.4n;k.7.1R=k.7.R.y+14-k.7.4s;8(k.7.2x&&(k.7.3i||k.7.1B)){6.5b.3i(k,k.7.2c,k.7.1R)}8(k.7.1Q)k.7.1Q.1J(k,[k.7.1h.x+12,k.7.1h.y+14]);8(!k.7.1c||k.7.1c==\'3m\'){k.7.3v=k.7.1h.x+12;6.C.O.Q(0).S.1a=k.7.2c+\'1b\'}8(!k.7.1c||k.7.1c==\'3q\'){k.7.3F=k.7.1h.y+14;6.C.O.Q(0).S.19=k.7.1R+\'1b\'}8(6.K&&6.K.3r>0){6.K.4A(k)}H B},31:D(o){8(!6.C.O){6(\'1m\',T).2o(\'<3T 1e="6x"></3T>\');6.C.O=6(\'#6x\');u G=6.C.O.Q(0);u 2a=G.S;2a.1f=\'2z\';2a.U=\'10\';2a.6I=\'6J\';2a.6L=\'10\';2a.3P=\'2B\';8(2w.4f){G.5A="6u"}N{2a.7i=\'10\';2a.6F=\'10\';2a.6z=\'10\'}}8(!o){o={}}H A.1s(D(){8(A.4l||!6.W)H;8(2w.4f){A.7g=D(){H B};A.7c=D(){H B}}u G=A;u 1S=o.2l?6(A).7e(o.2l):6(A);8(6.1P.2S){1S.1s(D(){A.5A="6u"})}N{1S.M(\'-8c-3b-4E\',\'10\');1S.M(\'3b-4E\',\'10\');1S.M(\'-8u-3b-4E\',\'10\')}A.7={1S:1S,2v:o.2v?P:B,1G:o.1G?P:B,1F:o.1F?o.1F:B,2x:o.2x?o.2x:B,3M:o.3M?o.3M:B,1Y:o.1Y?L(o.1Y)||0:B,18:o.18?1A(o.18):B,J:L(o.J)||V,2M:o.2M?o.2M:B,27:{},1o:{},1X:o.1X&&o.1X.1D==29?o.1X:B,1I:o.1I&&o.1I.1D==29?o.1I:B,1B:o.1B&&o.1B.1D==29?o.1B:B,1c:/3q|3m/.3j(o.1c)?o.1c:B,2G:o.2G?L(o.2G)||0:0,1k:o.1k?o.1k:B,5o:o.5o?P:B,3c:o.3c||B};8(o.27&&o.27.1D==29)A.7.27.3b=o.27;8(o.1Q&&o.1Q.1D==29)A.7.1Q=o.1Q;8(o.15&&((o.15.1D==6G&&(o.15==\'4z\'||o.15==\'T\'))||(o.15.1D==4K&&o.15.1i==4))){A.7.15=o.15}8(o.4M){A.7.4M=o.4M}8(o.2i){8(3Q o.2i==\'7I\'){A.7.3h=L(o.2i)||1;A.7.3w=L(o.2i)||1}N 8(o.2i.1i==2){A.7.3h=L(o.2i[0])||1;A.7.3w=L(o.2i[1])||1}}8(o.3i&&o.3i.1D==29){A.7.3i=o.3i}A.4l=P;1S.1s(D(){A.4H=G});1S.4Y(\'73\',6.C.51)})}};6.4F.1K({4I:6.C.32,4P:6.C.31});6.K={6U:D(2d,22,3p,3o){H 2d<=6.C.k.7.2c&&(2d+3p)>=(6.C.k.7.2c+6.C.k.7.R.w)&&22<=6.C.k.7.1R&&(22+3o)>=(6.C.k.7.1R+6.C.k.7.R.h)?P:B},5u:D(2d,22,3p,3o){H!(2d>(6.C.k.7.2c+6.C.k.7.R.w)||(2d+3p)<6.C.k.7.2c||22>(6.C.k.7.1R+6.C.k.7.R.h)||(22+3o)<6.C.k.7.1R)?P:B},1o:D(2d,22,3p,3o){H 2d<6.C.k.7.1L.x&&(2d+3p)>6.C.k.7.1L.x&&22<6.C.k.7.1L.y&&(22+3o)>6.C.k.7.1L.y?P:B},2g:B,1C:{},3r:0,1w:{},71:D(q){8(6.C.k==V){H}u i;6.K.1C={};u 4X=B;1d(i 1z 6.K.1w){8(6.K.1w[i]!=V){u F=6.K.1w[i].Q(0);8(6(6.C.k).4R(\'.\'+F.E.a)){8(F.E.m==B){F.E.p=6.1K(6.W.2t(F),6.W.4D(F));F.E.m=P}8(F.E.2N){6.K.1w[i].3D(F.E.2N)}6.K.1C[i]=6.K.1w[i];8(6.I&&F.E.s&&6.C.k.7.1F){F.E.G=6(\'.\'+F.E.a,F);q.S.U=\'10\';6.I.4S(F);F.E.4p=6.I.3U(6.1n(F,\'1e\')).3H;q.S.U=q.7.3l;4X=P}8(F.E.4t){F.E.4t.1J(6.K.1w[i].Q(0),[6.C.k])}}}}8(4X){6.I.70()}},79:D(){6.K.1C={};1d(i 1z 6.K.1w){8(6.K.1w[i]!=V){u F=6.K.1w[i].Q(0);8(6(6.C.k).4R(\'.\'+F.E.a)){F.E.p=6.1K(6.W.2t(F),6.W.4D(F));8(F.E.2N){6.K.1w[i].3D(F.E.2N)}6.K.1C[i]=6.K.1w[i];8(6.I&&F.E.s&&6.C.k.7.1F){F.E.G=6(\'.\'+F.E.a,F);q.S.U=\'10\';6.I.4S(F);q.S.U=q.7.3l}}}}},4A:D(e){8(6.C.k==V){H}6.K.2g=B;u i;u 5r=B;u 76=0;1d(i 1z 6.K.1C){u F=6.K.1C[i].Q(0);8(6.K.2g==B&&6.K[F.E.t](F.E.p.x,F.E.p.y,F.E.p.1p,F.E.p.1j)){8(F.E.2O&&F.E.h==B){6.K.1C[i].3D(F.E.2O)}8(F.E.h==B&&F.E.3a){5r=P}F.E.h=P;6.K.2g=F;8(6.I&&F.E.s&&6.C.k.7.1F){6.I.O.Q(0).4x=F.E.6W;6.I.4A(F)}76++}N 8(F.E.h==P){8(F.E.2R){F.E.2R.1J(F,[e,6.C.O.Q(0).3O,F.E.J])}8(F.E.2O){6.K.1C[i].3J(F.E.2O)}F.E.h=B}}8(6.I&&!6.K.2g&&6.C.k.1F){6.I.O.Q(0).S.U=\'10\'}8(5r){6.K.2g.E.3a.1J(6.K.2g,[e,6.C.O.Q(0).3O])}},6Z:D(e){u i;1d(i 1z 6.K.1C){u F=6.K.1C[i].Q(0);8(F.E.2N){6.K.1C[i].3J(F.E.2N)}8(F.E.2O){6.K.1C[i].3J(F.E.2O)}8(F.E.s){6.I.3d[6.I.3d.1i]=i}8(F.E.4g&&F.E.h==P){F.E.h=B;F.E.4g.1J(F,[e,F.E.J])}F.E.m=B;F.E.h=B}6.K.1C={}},32:D(){H A.1s(D(){8(A.4m){8(A.E.s){1e=6.1n(A,\'1e\');6.I.2f[1e]=V;6(\'.\'+A.E.a,A).4I()}6.K.1w[\'d\'+A.5n]=V;A.4m=B;A.f=V}})},31:D(o){H A.1s(D(){8(A.4m==P||!o.1N||!6.W||!6.C){H}A.E={a:o.1N,2N:o.4B||B,2O:o.4h||B,6W:o.2r||B,4g:o.80||o.4g||B,3a:o.3a||o.77||B,2R:o.2R||o.6P||B,4t:o.4t||B,t:o.2C&&(o.2C==\'6U\'||o.2C==\'5u\')?o.2C:\'1o\',J:o.J?o.J:B,m:B,h:B};8(o.5D==P&&6.I){1e=6.1n(A,\'1e\');6.I.2f[1e]=A.E.a;A.E.s=P;8(o.1B){A.E.1B=o.1B;A.E.4p=6.I.3U(1e).3H}}A.4m=P;A.5n=L(1v.6Y()*5a);6.K.1w[\'d\'+A.5n]=6(A);6.K.3r++})}};6.4F.1K({6O:6.K.32,6R:6.K.31});6.7Z=6.K.79;',62,627,'||||||jQuery|dragCfg|if||||||||||||dragged||||||elm||||var||||||this|false|iDrag|function|dropCfg|iEL|el|return|iSort|fx|iDrop|parseInt|css|else|helper|true|get|oC|style|document|display|null|iUtil|es|elem|255|none|props|dx||dy|containment|options|tp|opacity|top|left|px|axis|for|id|position|oldStyle|oR|length|hb|cursorAt|result|body|attr|pointer|wb|cont|easing|each|0px|margins|Math|zones|cs|wrs|in|parseFloat|onChange|highlighted|constructor|dhs|so|ghosting|vp|onStop|apply|extend|currentPointer|shs|accept|documentElement|browser|onDrag|ny|dhe|nodeEl|step|color|duration|onStart|zIndex|block|parentNode|visibility|zoney|clonedEl|marginBottom|marginTop|clientScroll|onDragModifier|marginRight|Function|els|marginLeft|nx|zonex|newStyles|collected|overzone|sortCfg|grid|cur|animationHandler|handle|old|getSize|append|nmp|styles|helperclass|prop|getPosition|new|revert|window|si|128|absolute|curCSS|hidden|tolerance|parseColor|scrollTop|pos|snapDistance|wr|height|width|newCoords|orig|hpc|ac|hc|replace|toInteger|onOut|msie|scrollLeft|rgb|0x|139|F0|fA|oP|dh|build|destroy|oldVisibility|restoreStyle|currentStyle|de|cssRules|oldDisplay|np|onHover|user|frameClass|changed|ih|speed|inFrontOf|gx|onSlide|test|iw|oD|horizontally|rule|zoneh|zonew|vertically|count|border|parentBorders|namedColors|nRx|gy|ser|relative|contBorders|hide|case|fnc|addClass|ts|nRy|cssSides|hash|clientWidth|removeClass|clientHeight|event|insideParent|timer|firstChild|overflow|typeof|pr|queue|div|serialize|borderColor|opera|complete|sideEnd|192|dragstop|startTime||getValues|right|opt|callback||styleSheets|margin|getBorder|bottom|show|padding|exec|ActiveXObject|onDrop|hoverclass|init|dEs|prot|isDraggable|isDroppable|diffX|while|os|png|self|diffY|onActivate|max|src|hidehelper|className|nodeName|parent|checkhover|activeclass|211|getSizeLite|select|fn|oldPosition|dragElem|DraggableDestroy|stopAnim|Array|floats|fractions|pause|innerHeight|Draggable|cssSidesEnd|is|measure|traverseDOM|toLowerCase|parseStyle|getMargins|oneIsSortable|bind|break||draginit|func|windowSize|borderWidth||Color|sliderSize|169|offsetHeight|10000|iSlider|offsetTop|oldFloat|offsetLeft|getPointer|dragmove|filter|100|unbind|empty|clnt|offsetWidth|idsa|autoSize|object|parentPos|applyOnHover|sliderPos|innerWidth|intersect|fontWeight|pValue|sizes|borderTopWidth|scrollHeight|unselectable|scrollWidth|floatVal|sortable|initialPosition|borderLeftWidth|oldBorder|offsetParent|tagName|fxe|styleFloat|insertBefore|245|wid|img|borderRightWidth|borderBottomWidth|107|notColor|224|165|144|230|240|140|paddingBottom|paddingLeft|toggle|cssProps|emptyGIF|colorCssProps|getScroll|images|linear|values|paddingTop|paddingRight|fxCheckTag|indexOf|firstNum|delta|Width|trim|check|3000|zindex|SortableAddItem|addItem|animate|distance|isSortable|snapToGrid|abs|fitToContainer|pow|size|on|nbsp|dragstart|dragHelper|alpha|KhtmlUserSelect|getClient|cloneNode|getContainment|auto|mousemove|userSelect|String|custom|cursor|move|mouseup|listStyle|after|sortHelper|DroppableDestroy|onout|clearInterval|Droppable|setInterval|getTime|fit|isFunction|shc|oldOverflow|random|checkdrop|start|highlight|min|mousedown|Date||hlt|onhover|split|remeasure|appendChild|204|ondragstart|darkred|find|fxWrapper|onselectstart|cssFloat|mozUserSelect|darkorchid|brown|183|darkmagenta|blue|cyan|darkblue|darkkhaki|darkgrey|darkcyan|189|black|darkolivegreen|darkgreen|aqua|153|wrapper|azure|beige|sqrt|220|darkorange|Object|float|prototype|number|AlphaImageLoader|Microsoft|DXImageTransform|tr|td|tfoot|col|thead|caption|tbody|progid|fixPNG|pageX|clientX|getPadding|getPositionLite|recallDroppables|ondrop|pageY|centerEl|purgeEvents|nextSibling||clientY|colgroup|th|input|hr|br|moz|createElement|textarea|iframe|ul|dl|table|form|button|w_|darksalmon|frameset|option|frame|script|header|optgroup|meta|khtml|buildWrapper|removeChild|destroyWrapper|ol|darkviolet|SortableDestroy|outlineColor|borderTopColor|borderRightColor|borderLeftColor|Top|Right|stop|stopAll|Sortable|Left|Bottom|borderBottomColor|233|minWidth|outlineOffset|minHeight|maxWidth|maxHeight|outlineWidth|fromHandler|textIndent|SortSerialize|off|MozUserSelect|cos|PI|inset|outset|ridge|groove|double|string|dequeue|selectorText|RegExp|rules|borderStyle|100000000|solid|dashed|fadeIn|match|before|childNodes|onchange|switch|html|dotted|transparent|isNaN|toUpperCase|lineHeight|backgroundColor|lightgreen|238|letterSpacing|216|173|lastSi|lightgrey|lightyellow|193|182|lightpink|lightblue|khaki|148|cssText|122|150|fuchsia|gold|130|indigo|green|215|lime|lightcyan|selectKeyHelper|red|purple|modifyContainer|silver|magenta|white|yellow|203|fontSize|navy|maroon|orange|olive|dragmoveBy|pink'.split('|'),0,{}))
/*
 * jQuery form plugin
 * @requires jQuery v1.0.3
 *
 * Dual licensed under the MIT and GPL licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 *
 * Revision: $Id$
 * Version: .97
 */

/**
 * ajaxSubmit() provides a mechanism for submitting an HTML form using AJAX.
 *
 * ajaxSubmit accepts a single argument which can be either a success callback function
 * or an options Object.  If a function is provided it will be invoked upon successful
 * completion of the submit and will be passed the response from the server.
 * If an options Object is provided, the following attributes are supported:
 *
 *  target:   Identifies the element(s) in the page to be updated with the server response.
 *            This value may be specified as a jQuery selection string, a jQuery object,
 *            or a DOM element.
 *            default value: null
 *
 *  url:      URL to which the form data will be submitted.
 *            default value: value of form's 'action' attribute
 *
 *  type:     The method in which the form data should be submitted, 'GET' or 'POST'.
 *            default value: value of form's 'method' attribute (or 'GET' if none found)
 *
 *  beforeSubmit:  Callback method to be invoked before the form is submitted.
 *            default value: null
 *
 *  success:  Callback method to be invoked after the form has been successfully submitted
 *            and the response has been returned from the server
 *            default value: null
 *
 *  dataType: Expected dataType of the response.  One of: null, 'xml', 'script', or 'json'
 *            default value: null
 *
 *  semantic: Boolean flag indicating whether data must be submitted in semantic order (slower).
 *            default value: false
 *
 *  resetForm: Boolean flag indicating whether the form should be reset if the submit is successful
 *
 *  clearForm: Boolean flag indicating whether the form should be cleared if the submit is successful
 *
 *
 * The 'beforeSubmit' callback can be provided as a hook for running pre-submit logic or for
 * validating the form data.  If the 'beforeSubmit' callback returns false then the form will
 * not be submitted. The 'beforeSubmit' callback is invoked with three arguments: the form data
 * in array format, the jQuery object, and the options object passed into ajaxSubmit.
 * The form data array takes the following form:
 *
 *     [ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ]
 *
 * If a 'success' callback method is provided it is invoked after the response has been returned
 * from the server.  It is passed the responseText or responseXML value (depending on dataType).
 * See jQuery.ajax for further details.
 *
 *
 * The dataType option provides a means for specifying how the server response should be handled.
 * This maps directly to the jQuery.httpData method.  The following values are supported:
 *
 *      'xml':    if dataType == 'xml' the server response is treated as XML and the 'after'
 *                   callback method, if specified, will be passed the responseXML value
 *      'json':   if dataType == 'json' the server response will be evaluted and passed to
 *                   the 'after' callback, if specified
 *      'script': if dataType == 'script' the server response is evaluated in the global context
 *
 *
 * Note that it does not make sense to use both the 'target' and 'dataType' options.  If both
 * are provided the target will be ignored.
 *
 * The semantic argument can be used to force form serialization in semantic order.
 * This is normally true anyway, unless the form contains input elements of type='image'.
 * If your form must be submitted with name/value pairs in semantic order and your form
 * contains an input of type='image" then pass true for this arg, otherwise pass false
 * (or nothing) to avoid the overhead for this logic.
 *
 *
 * When used on its own, ajaxSubmit() is typically bound to a form's submit event like this:
 *
 * $("#form-id").submit(function() {
 *     $(this).ajaxSubmit(options);
 *     return false; // cancel conventional submit
 * });
 *
 * When using ajaxForm(), however, this is done for you.
 *
 * @example
 * $('#myForm').ajaxSubmit(function(data) {
 *     alert('Form submit succeeded! Server returned: ' + data);
 * });
 * @desc Submit form and alert server response
 *
 *
 * @example
 * var options = {
 *     target: '#myTargetDiv'
 * };
 * $('#myForm').ajaxSubmit(options);
 * @desc Submit form and update page element with server response
 *
 *
 * @example
 * var options = {
 *     success: function(responseText) {
 *         alert(responseText);
 *     }
 * };
 * $('#myForm').ajaxSubmit(options);
 * @desc Submit form and alert the server response
 *
 *
 * @example
 * var options = {
 *     beforeSubmit: function(formArray, jqForm) {
 *         if (formArray.length == 0) {
 *             alert('Please enter data.');
 *             return false;
 *         }
 *     }
 * };
 * $('#myForm').ajaxSubmit(options);
 * @desc Pre-submit validation which aborts the submit operation if form data is empty
 *
 *
 * @example
 * var options = {
 *     url: myJsonUrl.php,
 *     dataType: 'json',
 *     success: function(data) {
 *        // 'data' is an object representing the the evaluated json data
 *     }
 * };
 * $('#myForm').ajaxSubmit(options);
 * @desc json data returned and evaluated
 *
 *
 * @example
 * var options = {
 *     url: myXmlUrl.php,
 *     dataType: 'xml',
 *     success: function(responseXML) {
 *        // responseXML is XML document object
 *        var data = $('myElement', responseXML).text();
 *     }
 * };
 * $('#myForm').ajaxSubmit(options);
 * @desc XML data returned from server
 *
 *
 * @example
 * var options = {
 *     resetForm: true
 * };
 * $('#myForm').ajaxSubmit(options);
 * @desc submit form and reset it if successful
 *
 * @example
 * $('#myForm).submit(function() {
 *    $(this).ajaxSubmit();
 *    return false;
 * });
 * @desc Bind form's submit event to use ajaxSubmit
 *
 *
 * @name ajaxSubmit
 * @type jQuery
 * @param options  object literal containing options which control the form submission process
 * @cat Plugins/Form
 * @return jQuery
 * @see formToArray
 * @see ajaxForm
 * @see $.ajax
 * @author jQuery Community
 */
jQuery.fn.ajaxSubmit = function(options) {
    if (typeof options == 'function')
        options = { success: options };

    options = jQuery.extend({
        url:  this.attr('action') || window.location,
        type: this.attr('method') || 'GET'
    }, options || {});

    var a = this.formToArray(options.semantic);

    // give pre-submit callback an opportunity to abort the submit
    if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) return this;

    // fire vetoable 'validate' event
    var veto = {};
    jQuery.event.trigger('form.submit.validate', [a, this, options, veto]);
    if (veto.veto)
        return this;

    var q = jQuery.param(a);//.replace(/%20/g,'+');

    if (options.type.toUpperCase() == 'GET') {
        options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q;
        options.data = null;  // data is null for 'get'
    }
    else
        options.data = q; // data is the query string for 'post'

    var $form = this, callbacks = [];
    if (options.resetForm) callbacks.push(function() { $form.resetForm(); });
    if (options.clearForm) callbacks.push(function() { $form.clearForm(); });

    // perform a load on the target only if dataType is not provided
    if (!options.dataType && options.target) {
        var oldSuccess = options.success || function(){};
        callbacks.push(function(data, status) {
            jQuery(options.target).attr("innerHTML", data).evalScripts().each(oldSuccess, [data, status]);
        });
    }
    else if (options.success)
        callbacks.push(options.success);

    options.success = function(data, status) {
        for (var i=0, max=callbacks.length; i < max; i++)
            callbacks[i](data, status);
    };

    // are there files to upload?
    var files = jQuery('input:file', this).fieldValue();
    var found = false;
    for (var j=0; j < files.length; j++)
        if (files[j]) 
            found = true;

    if (options.iframe || found) // options.iframe allows user to force iframe mode
        fileUpload();
    else
        jQuery.ajax(options);

    // fire 'notify' event
    jQuery.event.trigger('form.submit.notify', [this, options]);
    return this;


    // private function for handling file uploads (hat tip to YAHOO!)
    function fileUpload() {
        var form = $form[0];
        var opts = jQuery.extend({}, jQuery.ajaxSettings, options);
        
        var id = 'jqFormIO' + jQuery.fn.ajaxSubmit.counter++;
        var $io = jQuery('<iframe id="' + id + '" name="' + id + '" />');
        var io = $io[0];
        var op8 = jQuery.browser.opera && window.opera.version() < 9;
        if (jQuery.browser.msie || op8) io.src = 'javascript:false;document.write("");';
        $io.css({ position: 'absolute', top: '-1000px', left: '-1000px' });

        // make sure form attrs are set
        form.method = 'POST';
        form.encoding ? form.encoding = 'multipart/form-data' : form.enctype = 'multipart/form-data';

        var xhr = { // mock object
            responseText: null,
            responseXML: null,
            status: 0,
            statusText: 'n/a',
            getAllResponseHeaders: function() {},
            getResponseHeader: function() {},
            setRequestHeader: function() {}
        };
        
        var g = opts.global;
        // trigger ajax global events so that activity/block indicators work like normal
        if (g && ! jQuery.active++) jQuery.event.trigger("ajaxStart");
        if (g) jQuery.event.trigger("ajaxSend", [xhr, opts]);
        
        var cbInvoked = 0;
        var timedOut = 0;
        
        // take a breath so that pending repaints get some cpu time before the upload starts
        setTimeout(function() {
            $io.appendTo('body');
            // jQuery's event binding doesn't work for iframe events in IE
            io.attachEvent ? io.attachEvent('onload', cb) : io.addEventListener('load', cb, false);
            form.action = opts.url;
            var t = form.target;
            form.target = id;

            // support timout
            if (opts.timeout)
                setTimeout(function() { timedOut = true; cb(); }, opts.timeout);

            form.submit();
            form.target = t; // reset
        }, 10);
        
        function cb() {
            if (cbInvoked++) return;
            
            io.detachEvent ? io.detachEvent('onload', cb) : io.removeEventListener('load', cb, false);

            var ok = true;
            try {
                if (timedOut) throw 'timeout';
                // extract the server response from the iframe
                var data, doc;
                doc = io.contentWindow ? io.contentWindow.document : io.contentDocument ? io.contentDocument : io.document;
                xhr.responseText = doc.body ? doc.body.innerHTML : null;
                xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc;
                
                if (opts.dataType == 'json' || opts.dataType == 'script') {
                    var ta = doc.getElementsByTagName('textarea')[0];
                    data = ta ? ta.value : xhr.responseText;
                    if (opts.dataType == 'json')
                        eval("data = " + data);
                    else
                        jQuery.globalEval(data);
                }
                else if (opts.dataType == 'xml') {
                    data = xhr.responseXML;
                    if (!data && xhr.responseText != null)
                        data = toXml(xhr.responseText);
                }
                else {
                    data = xhr.responseText;
                }
            }
            catch(e){
                ok = false;
                jQuery.handleError(opts, xhr, 'error', e);
            }

            // ordering of these callbacks/triggers is odd, but that's how $.ajax does it
            if (ok) {
                opts.success(data, 'success');
                if (g) jQuery.event.trigger("ajaxSuccess", [xhr, opts]);
            }
            if (g) jQuery.event.trigger("ajaxComplete", [xhr, opts]);
            if (g && ! --jQuery.active) jQuery.event.trigger("ajaxStop");
            if (opts.complete) opts.complete(xhr, ok ? 'success' : 'error');

            // clean up
            setTimeout(function() { 
                $io.remove(); 
                xhr.responseXML = null;
            }, 100);
        };
        
        function toXml(s, doc) {
            if (window.ActiveXObject) {
                doc = new ActiveXObject('Microsoft.XMLDOM');
                doc.async = 'false';
                doc.loadXML(s);
            }
            else
                doc = (new DOMParser()).parseFromString(s, 'text/xml');
            return (doc && doc.documentElement && doc.documentElement.tagName != 'parsererror') ? doc : null;
        }
    };
};
jQuery.fn.ajaxSubmit.counter = 0; // used to create unique iframe ids

/**
 * ajaxForm() provides a mechanism for fully automating form submission.
 *
 * The advantages of using this method instead of ajaxSubmit() are:
 *
 * 1: This method will include coordinates for <input type="image" /> elements (if the element
 *    is used to submit the form).
 * 2. This method will include the submit element's name/value data (for the element that was
 *    used to submit the form).
 * 3. This method binds the submit() method to the form for you.
 *
 * Note that for accurate x/y coordinates of image submit elements in all browsers
 * you need to also use the "dimensions" plugin (this method will auto-detect its presence).
 *
 * The options argument for ajaxForm works exactly as it does for ajaxSubmit.  ajaxForm merely
 * passes the options argument along after properly binding events for submit elements and
 * the form itself.  See ajaxSubmit for a full description of the options argument.
 *
 *
 * @example
 * var options = {
 *     target: '#myTargetDiv'
 * };
 * $('#myForm').ajaxSForm(options);
 * @desc Bind form's submit event so that 'myTargetDiv' is updated with the server response
 *       when the form is submitted.
 *
 *
 * @example
 * var options = {
 *     success: function(responseText) {
 *         alert(responseText);
 *     }
 * };
 * $('#myForm').ajaxSubmit(options);
 * @desc Bind form's submit event so that server response is alerted after the form is submitted.
 *
 *
 * @example
 * var options = {
 *     beforeSubmit: function(formArray, jqForm) {
 *         if (formArray.length == 0) {
 *             alert('Please enter data.');
 *             return false;
 *         }
 *     }
 * };
 * $('#myForm').ajaxSubmit(options);
 * @desc Bind form's submit event so that pre-submit callback is invoked before the form
 *       is submitted.
 *
 *
 * @name   ajaxForm
 * @param  options  object literal containing options which control the form submission process
 * @return jQuery
 * @cat    Plugins/Form
 * @type   jQuery
 * @see    ajaxSubmit
 * @author jQuery Community
 */
jQuery.fn.ajaxForm = function(options) {
    return this.each(function() {
        jQuery("input:submit,input:image,button:submit", this).click(function(ev) {
            var $form = this.form;
            $form.clk = this;
            if (this.type == 'image') {
                if (ev.offsetX != undefined) {
                    $form.clk_x = ev.offsetX;
                    $form.clk_y = ev.offsetY;
                } else if (typeof jQuery.fn.offset == 'function') { // try to use dimensions plugin
                    var offset = jQuery(this).offset();
                    $form.clk_x = ev.pageX - offset.left;
                    $form.clk_y = ev.pageY - offset.top;
                } else {
                    $form.clk_x = ev.pageX - this.offsetLeft;
                    $form.clk_y = ev.pageY - this.offsetTop;
                }
            }
            // clear form vars
            setTimeout(function() {
                $form.clk = $form.clk_x = $form.clk_y = null;
                }, 10);
        })
    }).submit(function(e) {
        jQuery(this).ajaxSubmit(options);
        return false;
    });
};


/**
 * formToArray() gathers form element data into an array of objects that can
 * be passed to any of the following ajax functions: $.get, $.post, or load.
 * Each object in the array has both a 'name' and 'value' property.  An example of
 * an array for a simple login form might be:
 *
 * [ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ]
 *
 * It is this array that is passed to pre-submit callback functions provided to the
 * ajaxSubmit() and ajaxForm() methods.
 *
 * The semantic argument can be used to force form serialization in semantic order.
 * This is normally true anyway, unless the form contains input elements of type='image'.
 * If your form must be submitted with name/value pairs in semantic order and your form
 * contains an input of type='image" then pass true for this arg, otherwise pass false
 * (or nothing) to avoid the overhead for this logic.
 *
 * @example var data = $("#myForm").formToArray();
 * $.post( "myscript.cgi", data );
 * @desc Collect all the data from a form and submit it to the server.
 *
 * @name formToArray
 * @param semantic true if serialization must maintain strict semantic ordering of elements (slower)
 * @type Array<Object>
 * @cat Plugins/Form
 * @see ajaxForm
 * @see ajaxSubmit
 * @author jQuery Community
 */
jQuery.fn.formToArray = function(semantic) {
    var a = [];
    if (this.length == 0) return a;

    var form = this[0];
    var els = semantic ? form.getElementsByTagName('*') : form.elements;
    if (!els) return a;
    for(var i=0, max=els.length; i < max; i++) {
        var el = els[i];
        var n = el.name;
        if (!n) continue;

        if (semantic && form.clk && el.type == "image") {
            // handle image inputs on the fly when semantic == true
            if(!el.disabled && form.clk == el)
                a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
            continue;
        }
        var v = jQuery.fieldValue(el, true);
        if (v === null) continue;
        if (v.constructor == Array) {
            for(var j=0, jmax=v.length; j < jmax; j++)
                a.push({name: n, value: v[j]});
        }
        else
            a.push({name: n, value: v});
    }

    if (!semantic && form.clk) {
        // input type=='image' are not found in elements array! handle them here
        var inputs = form.getElementsByTagName("input");
        for(var i=0, max=inputs.length; i < max; i++) {
            var input = inputs[i];
            var n = input.name;
            if(n && !input.disabled && input.type == "image" && form.clk == input)
                a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
        }
    }
    return a;
};


/**
 * Serializes form data into a 'submittable' string. This method will return a string
 * in the format: name1=value1&amp;name2=value2
 *
 * The semantic argument can be used to force form serialization in semantic order.
 * If your form must be submitted with name/value pairs in semantic order then pass
 * true for this arg, otherwise pass false (or nothing) to avoid the overhead for
 * this logic (which can be significant for very large forms).
 *
 * @example var data = $("#myForm").formSerialize();
 * $.ajax('POST', "myscript.cgi", data);
 * @desc Collect all the data from a form into a single string
 *
 * @name formSerialize
 * @param semantic true if serialization must maintain strict semantic ordering of elements (slower)
 * @type String
 * @cat Plugins/Form
 * @see formToArray
 * @author jQuery Community
 */
jQuery.fn.formSerialize = function(semantic) {
    //hand off to jQuery.param for proper encoding
    return jQuery.param(this.formToArray(semantic));
};


/**
 * Serializes all field elements in the jQuery object into a query string.
 * This method will return a string in the format: name1=value1&amp;name2=value2
 *
 * The successful argument controls whether or not serialization is limited to
 * 'successful' controls (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls).
 * The default value of the successful argument is true.
 *
 * @example var data = $("input").formSerialize();
 * @desc Collect the data from all successful input elements into a query string
 *
 * @example var data = $(":radio").formSerialize();
 * @desc Collect the data from all successful radio input elements into a query string
 *
 * @example var data = $("#myForm :checkbox").formSerialize();
 * @desc Collect the data from all successful checkbox input elements in myForm into a query string
 *
 * @example var data = $("#myForm :checkbox").formSerialize(false);
 * @desc Collect the data from all checkbox elements in myForm (even the unchecked ones) into a query string
 *
 * @example var data = $(":input").formSerialize();
 * @desc Collect the data from all successful input, select, textarea and button elements into a query string
 *
 * @name fieldSerialize
 * @param successful true if only successful controls should be serialized (default is true)
 * @type String
 * @cat Plugins/Form
 */
jQuery.fn.fieldSerialize = function(successful) {
    var a = [];
    this.each(function() {
        var n = this.name;
        if (!n) return;
        var v = jQuery.fieldValue(this, successful);
        if (v && v.constructor == Array) {
            for (var i=0,max=v.length; i < max; i++)
                a.push({name: n, value: v[i]});
        }
        else if (v !== null && typeof v != 'undefined')
            a.push({name: this.name, value: v});
    });
    //hand off to jQuery.param for proper encoding
    return jQuery.param(a);
};


/**
 * Returns the value(s) of the element in the matched set.  For example, consider the following form:
 *
 *  <form><fieldset>
 *      <input name="A" type="text" />
 *      <input name="A" type="text" />
 *      <input name="B" type="checkbox" value="B1" />
 *      <input name="B" type="checkbox" value="B2"/>
 *      <input name="C" type="radio" value="C1" />
 *      <input name="C" type="radio" value="C2" />
 *  </fieldset></form>
 *
 *  var v = $(':text').fieldValue();
 *  // if no values are entered into the text inputs
 *  v == ['','']
 *  // if values entered into the text inputs are 'foo' and 'bar'
 *  v == ['foo','bar']
 *
 *  var v = $(':checkbox').fieldValue();
 *  // if neither checkbox is checked
 *  v === undefined
 *  // if both checkboxes are checked
 *  v == ['B1', 'B2']
 *
 *  var v = $(':radio').fieldValue();
 *  // if neither radio is checked
 *  v === undefined
 *  // if first radio is checked
 *  v == ['C1']
 *
 * The successful argument controls whether or not the field element must be 'successful'
 * (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls).
 * The default value of the successful argument is true.  If this value is false the value(s)
 * for each element is returned.
 *
 * Note: This method *always* returns an array.  If no valid value can be determined the
 *       array will be empty, otherwise it will contain one or more values.
 *
 * @example var data = $("#myPasswordElement").fieldValue();
 * alert(data[0]);
 * @desc Alerts the current value of the myPasswordElement element
 *
 * @example var data = $("#myForm :input").fieldValue();
 * @desc Get the value(s) of the form elements in myForm
 *
 * @example var data = $("#myForm :checkbox").fieldValue();
 * @desc Get the value(s) for the successful checkbox element(s) in the jQuery object.
 *
 * @example var data = $("#mySingleSelect").fieldValue();
 * @desc Get the value(s) of the select control
 *
 * @example var data = $(':text').fieldValue();
 * @desc Get the value(s) of the text input or textarea elements
 *
 * @example var data = $("#myMultiSelect").fieldValue();
 * @desc Get the values for the select-multiple control
 *
 * @name fieldValue
 * @param Boolean successful true if only the values for successful controls should be returned (default is true)
 * @type Array<String>
 * @cat Plugins/Form
 */
jQuery.fn.fieldValue = function(successful) {
    for (var val=[], i=0, max=this.length; i < max; i++) {
        var el = this[i];
        var v = jQuery.fieldValue(el, successful);
        if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length))
            continue;
        v.constructor == Array ? jQuery.merge(val, v) : val.push(v);
    }
    return val;
};

/**
 * Returns the value of the field element.
 *
 * The successful argument controls whether or not the field element must be 'successful'
 * (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls).
 * The default value of the successful argument is true.  If the given element is not
 * successful and the successful arg is not false then the returned value will be null.
 *
 * Note: If the successful flag is true (default) but the element is not successful, the return will be null
 * Note: The value returned for a successful select-multiple element will always be an array.
 * Note: If the element has no value the return value will be undefined.
 *
 * @example var data = jQuery.fieldValue($("#myPasswordElement")[0]);
 * @desc Gets the current value of the myPasswordElement element
 *
 * @name fieldValue
 * @param Element el The DOM element for which the value will be returned
 * @param Boolean successful true if value returned must be for a successful controls (default is true)
 * @type String or Array<String> or null or undefined
 * @cat Plugins/Form
 */
jQuery.fieldValue = function(el, successful) {
    var n = el.name, t = el.type, tag = el.tagName.toLowerCase();
    if (typeof successful == 'undefined') successful = true;

    if (successful && (!n || el.disabled || t == 'reset' || t == 'button' ||
        (t == 'checkbox' || t == 'radio') && !el.checked ||
        (t == 'submit' || t == 'image') && el.form && el.form.clk != el ||
        tag == 'select' && el.selectedIndex == -1))
            return null;

    if (tag == 'select') {
        var index = el.selectedIndex;
        if (index < 0) return null;
        var a = [], ops = el.options;
        var one = (t == 'select-one');
        var max = (one ? index+1 : ops.length);
        for(var i=(one ? index : 0); i < max; i++) {
            var op = ops[i];
            if (op.selected) {
                // extra pain for IE...
                var v = jQuery.browser.msie && !(op.attributes['value'].specified) ? op.text : op.value;
                if (one) return v;
                a.push(v);
            }
        }
        return a;
    }
    return el.value;
};


/**
 * Clears the form data.  Takes the following actions on the form's input fields:
 *  - input text fields will have their 'value' property set to the empty string
 *  - select elements will have their 'selectedIndex' property set to -1
 *  - checkbox and radio inputs will have their 'checked' property set to false
 *  - inputs of type submit, button, reset, and hidden will *not* be effected
 *  - button elements will *not* be effected
 *
 * @example $('form').clearForm();
 * @desc Clears all forms on the page.
 *
 * @name clearForm
 * @type jQuery
 * @cat Plugins/Form
 * @see resetForm
 */
jQuery.fn.clearForm = function() {
    return this.each(function() {
        jQuery('input,select,textarea', this).clearFields();
    });
};

/**
 * Clears the selected form elements.  Takes the following actions on the matched elements:
 *  - input text fields will have their 'value' property set to the empty string
 *  - select elements will have their 'selectedIndex' property set to -1
 *  - checkbox and radio inputs will have their 'checked' property set to false
 *  - inputs of type submit, button, reset, and hidden will *not* be effected
 *  - button elements will *not* be effected
 *
 * @example $('.myInputs').clearFields();
 * @desc Clears all inputs with class myInputs
 *
 * @name clearFields
 * @type jQuery
 * @cat Plugins/Form
 * @see clearForm
 */
jQuery.fn.clearFields = jQuery.fn.clearInputs = function() {
    return this.each(function() {
        var t = this.type, tag = this.tagName.toLowerCase();
        if (t == 'text' || t == 'password' || tag == 'textarea')
            this.value = '';
        else if (t == 'checkbox' || t == 'radio')
            this.checked = false;
        else if (tag == 'select')
            this.selectedIndex = -1;
    });
};


/**
 * Resets the form data.  Causes all form elements to be reset to their original value.
 *
 * @example $('form').resetForm();
 * @desc Resets all forms on the page.
 *
 * @name resetForm
 * @type jQuery
 * @cat Plugins/Form
 * @see clearForm
 */
jQuery.fn.resetForm = function() {
    return this.each(function() {
        // guard against an input with the name of 'reset'
        // note that IE reports the reset function as an 'object'
        if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType))
            this.reset();
    });
};
/**
 * Cookie plugin
 *
 * Copyright (c) 2006 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
 *
 */

/**
 * Create a cookie with the given name and value and other optional parameters.
 *
 * @example $.cookie('the_cookie', 'the_value');
 * @desc Set the value of a cookie.
 * @example $.cookie('the_cookie', 'the_value', {expires: 7, path: '/', domain: 'jquery.com', secure: true});
 * @desc Create a cookie with all available options.
 * @example $.cookie('the_cookie', 'the_value');
 * @desc Create a session cookie.
 * @example $.cookie('the_cookie', null);
 * @desc Delete a cookie by passing null as value.
 *
 * @param String name The name of the cookie.
 * @param String value The value of the cookie.
 * @param Object options An object literal containing key/value pairs to provide optional cookie attributes.
 * @option Number|Date expires Either an integer specifying the expiration date from now on in days or a Date object.
 *                             If a negative value is specified (e.g. a date in the past), the cookie will be deleted.
 *                             If set to null or omitted, the cookie will be a session cookie and will not be retained
 *                             when the the browser exits.
 * @option String path The value of the path atribute of the cookie (default: path of page that created the cookie).
 * @option String domain The value of the domain attribute of the cookie (default: domain of page that created the cookie).
 * @option Boolean secure If true, the secure attribute of the cookie will be set and the cookie transmission will
 *                        require a secure protocol (like HTTPS).
 * @type undefined
 *
 * @name $.cookie
 * @cat Plugins/Cookie
 * @author Klaus Hartl/klaus.hartl@stilbuero.de
 */

/**
 * Get the value of a cookie with the given name.
 *
 * @example $.cookie('the_cookie');
 * @desc Get the value of a cookie.
 *
 * @param String name The name of the cookie.
 * @return The value of the cookie.
 * @type String
 *
 * @name $.cookie
 * @cat Plugins/Cookie
 * @author Klaus Hartl/klaus.hartl@stilbuero.de
 */
jQuery.cookie = function(name, value, options) {
    if (typeof value != 'undefined') { // name and value given, set cookie
        options = options || {};
        if (value === null) {
            value = '';
            options.expires = -1;
        }
        var expires = '';
        if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) {
            var date;
            if (typeof options.expires == 'number') {
                date = new Date();
                date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000));
            } else {
                date = options.expires;
            }
            expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE
        }
        var path = options.path ? '; path=' + options.path : '';
        var domain = options.domain ? '; domain=' + options.domain : '';
        var secure = options.secure ? '; secure' : '';
        document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join('');
    } else { // only name given, get cookie
        var cookieValue = null;
        if (document.cookie && document.cookie != '') {
            var cookies = document.cookie.split(';');
            for (var i = 0; i < cookies.length; i++) {
                var cookie = jQuery.trim(cookies[i]);
                // Does this cookie string begin with the name we want?
                if (cookie.substring(0, name.length + 1) == (name + '=')) {
                    cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                    break;
                }
            }
        }
        return cookieValue;
    }
};/**
 * Tabs - jQuery plugin for accessible, unobtrusive tabs
 * @requires jQuery v1.1.1
 *
 * http://stilbuero.de/tabs/
 *
 * Copyright (c) 2006 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
 *
 * Version: 2.7.4
 */

(function($) { // block scope

$.extend({
    tabs: {
        remoteCount: 0 // TODO in Tabs 3 this is going to be more cleanly in one single namespace
    }
});

/**
 * Create an accessible, unobtrusive tab interface based on a particular HTML structure.
 *
 * The underlying HTML has to look like this:
 *
 * <div id="container">
 *     <ul>
 *         <li><a href="#fragment-1">Section 1</a></li>
 *         <li><a href="#fragment-2">Section 2</a></li>
 *         <li><a href="#fragment-3">Section 3</a></li>
 *     </ul>
 *     <div id="fragment-1">
 *
 *     </div>
 *     <div id="fragment-2">
 *
 *     </div>
 *     <div id="fragment-3">
 *
 *     </div>
 * </div>
 *
 * Each anchor in the unordered list points directly to a section below represented by one of the
 * divs (the URI in the anchor's href attribute refers to the fragment with the corresponding id).
 * Because such HTML structure is fully functional on its own, e.g. without JavaScript, the tab
 * interface is accessible and unobtrusive.
 *
 * A tab is also bookmarkable via hash in the URL. Use the History/Remote plugin (Tabs will
 * auto-detect its presence) to fix the back (and forward) button.
 *
 * @example $('#container').tabs();
 * @desc Create a basic tab interface.
 * @example $('#container').tabs(2);
 * @desc Create a basic tab interface with the second tab initially activated.
 * @example $('#container').tabs({disabled: [3, 4]});
 * @desc Create a tab interface with the third and fourth tab being disabled.
 * @example $('#container').tabs({fxSlide: true});
 * @desc Create a tab interface that uses slide down/up animations for showing/hiding tab
 *       content upon tab switching.
 *
 * @param Number initial An integer specifying the position of the tab (no zero-based index) that
 *                       gets activated at first (on page load). Two alternative ways to specify
 *                       the active tab will overrule this argument. First a li element
 *                       (representing one single tab) belonging to the selected tab class, e.g.
 *                       set the selected tab class (default: "tabs-selected", see option
 *                       selectedClass) for one of the unordered li elements in the HTML source.
 *                       In addition if a fragment identifier/hash in the URL of the page refers
 *                       to the id of a tab container of a tab interface the corresponding tab will
 *                       be activated and both the initial argument as well as an eventually
 *                       declared class attribute will be overruled. Defaults to 1 if omitted.
 * @param Object settings An object literal containing key/value pairs to provide optional settings.
 * @option Array<Number> disabled An array containing the position of the tabs (no zero-based index)
 *                                that should be disabled on initialization. Default value: null.
 *                                A tab can also be disabled by simply adding the disabling class
 *                                (default: "tabs-disabled", see option disabledClass) to the li
 *                                element representing that particular tab.
 * @option Boolean bookmarkable Boolean flag indicating if support for bookmarking and history (via
 *                              changing hash in the URL of the browser) is enabled. Default value:
 *                              false, unless the History/Remote plugin is included. In that case the
 *                              default value becomes true. @see $.ajaxHistory.initialize
 * @option Boolean remote Boolean flag indicating that tab content has to be loaded remotely from
 *                        the url given in the href attribute of the tab menu anchor elements.
 * @option String spinner The content of this string is shown in a tab while remote content is loading.
 *                        Insert plain text as well as an img here. To turn off this notification
 *                        pass an empty string or null. Default: "Loading&#8230;".
 * @option String hashPrefix A String that is used for constructing the hash the link's href attribute
 *                           of a remote tab gets altered to, such as "#remote-1".
 *                           Default value: "remote-tab-".
 * @option Boolean fxFade Boolean flag indicating whether fade in/out animations are used for tab
 *                        switching. Can be combined with fxSlide. Will overrule fxShow/fxHide.
 *                        Default value: false.
 * @option Boolean fxSlide Boolean flag indicating whether slide down/up animations are used for tab
 *                         switching. Can be combined with fxFade. Will overrule fxShow/fxHide.
 *                         Default value: false.
 * @option String|Number fxSpeed A string representing one of the three predefined speeds ("slow",
 *                               "normal", or "fast") or the number of milliseconds (e.g. 1000) to
 *                               run an animation. Default value: "normal".
 * @option Object fxShow An object literal of the form jQuery's animate function expects for making
 *                       your own, custom animation to reveal a tab upon tab switch. Unlike fxFade
 *                       or fxSlide this animation is independent from an optional hide animation.
 *                       Default value: null. @see animate
 * @option Object fxHide An object literal of the form jQuery's animate function expects for making
 *                       your own, custom animation to hide a tab upon tab switch. Unlike fxFade
 *                       or fxSlide this animation is independent from an optional show animation.
 *                       Default value: null. @see animate
 * @option String|Number fxShowSpeed A string representing one of the three predefined speeds
 *                                   ("slow", "normal", or "fast") or the number of milliseconds
 *                                   (e.g. 1000) to run the animation specified in fxShow.
 *                                   Default value: fxSpeed.
 * @option String|Number fxHideSpeed A string representing one of the three predefined speeds
 *                                   ("slow", "normal", or "fast") or the number of milliseconds
 *                                   (e.g. 1000) to run the animation specified in fxHide.
 *                                   Default value: fxSpeed.
 * @option Boolean fxAutoHeight Boolean flag that if set to true causes all tab heights
 *                              to be constant (being the height of the tallest tab).
 *                              Default value: false.
 * @option Function onClick A function to be invoked upon tab switch, immediatly after a tab has
 *                          been clicked, e.g. before the other's tab content gets hidden. The
 *                          function gets passed three arguments: the first one is the clicked
 *                          tab (e.g. an anchor element), the second one is the DOM element
 *                          containing the content of the clicked tab (e.g. the div), the third
 *                          argument is the one of the tab that gets hidden. If this callback
 *                          returns false, the tab switch is canceled (use to disallow tab
 *                          switching for the reason of a failed form validation for example).
 *                          Default value: null.
 * @option Function onHide A function to be invoked upon tab switch, immediatly after one tab's
 *                         content got hidden (with or without an animation) and right before the
 *                         next tab is revealed. The function gets passed three arguments: the
 *                         first one is the clicked tab (e.g. an anchor element), the second one
 *                         is the DOM element containing the content of the clicked tab, (e.g. the
 *                         div), the third argument is the one of the tab that gets hidden.
 *                         Default value: null.
 * @option Function onShow A function to be invoked upon tab switch. This function is invoked
 *                         after the new tab has been revealed, e.g. after the switch is completed.
 *                         The function gets passed three arguments: the first one is the clicked
 *                         tab (e.g. an anchor element), the second one is the DOM element
 *                         containing the content of the clicked tab, (e.g. the div), the third
 *                         argument is the one of the tab that gets hidden. Default value: null.
 * @option String navClass A CSS class that is used to identify the tabs unordered list by class if
 *                         the required HTML structure differs from the default one.
 *                         Default value: "tabs-nav".
 * @option String selectedClass The CSS class attached to the li element representing the
 *                              currently selected (active) tab. Default value: "tabs-selected".
 * @option String disabledClass The CSS class attached to the li element representing a disabled
 *                              tab. Default value: "tabs-disabled".
 * @option String containerClass A CSS class that is used to identify tab containers by class if
 *                               the required HTML structure differs from the default one.
 *                               Default value: "tabs-container".
 * @option String hideClass The CSS class used for hiding inactive tabs. A class is used instead
 *                          of "display: none" in the style attribute to maintain control over
 *                          visibility in other media types than screen, most notably print.
 *                          Default value: "tabs-hide".
 * @option String loadingClass The CSS class used for indicating that an Ajax tab is currently
 *                             loading, for example by showing a spinner.
 *                             Default value: "tabs-loading".
 * @option String tabStruct @deprecated A CSS selector or basic XPath expression reflecting a
 *                          nested HTML structure that is different from the default single div
 *                          structure (one div with an id inside the overall container holds one
 *                          tab's content). If for instance an additional div is required to wrap
 *                          up the several tab containers such a structure is expressed by "div>div".
 *                          Default value: "div".
 * @type jQuery
 *
 * @name tabs
 * @cat Plugins/Tabs
 * @author Klaus Hartl/klaus.hartl@stilbuero.de
 */
$.fn.tabs = function(initial, settings) {

    // settings
    if (typeof initial == 'object') settings = initial; // no initial tab given but a settings object
    settings = $.extend({
        initial: (initial && typeof initial == 'number' && initial > 0) ? --initial : 0,
        disabled: null,
        bookmarkable: $.ajaxHistory ? true : false,
        remote: false,
        spinner: 'Loading&#8230;',
        hashPrefix: 'remote-tab-',
        fxFade: null,
        fxSlide: null,
        fxShow: null,
        fxHide: null,
        fxSpeed: 'normal',
        fxShowSpeed: null,
        fxHideSpeed: null,
        fxAutoHeight: false,
        onClick: null,
        onHide: null,
        onShow: null,
        navClass: 'tabs-nav',
        selectedClass: 'tabs-selected',
        disabledClass: 'tabs-disabled',
        containerClass: 'tabs-container',
        hideClass: 'tabs-hide',
        loadingClass: 'tabs-loading',
        tabStruct: 'div'
    }, settings || {});

    $.browser.msie6 = $.browser.msie && ($.browser.version && $.browser.version < 7 || /MSIE 6.0/.test(navigator.userAgent)); // do not check for 6.0 alone, userAgent in Windows Vista has "Windows NT 6.0"

    // helper to prevent scroll to fragment
    function unFocus() {
        scrollTo(0, 0);
    }

    // initialize tabs
    return this.each(function() {

        // remember wrapper for later
        var container = this;

        // setup nav
        var nav = $('ul.' + settings.navClass, container);
        nav = nav.size() && nav || $('>ul:eq(0)', container); // fallback to default structure
        var tabs = $('a', nav);

        // prepare remote tabs
        if (settings.remote) {
            tabs.each(function() {
                var id = settings.hashPrefix + (++$.tabs.remoteCount), hash = '#' + id, url = this.href;
                this.href = hash;
                $('<div id="' + id + '" class="' + settings.containerClass + '"></div>').appendTo(container);

                $(this).bind('loadRemoteTab', function(e, callback) {
                    var $$ = $(this).addClass(settings.loadingClass), span = $('span', this)[0], tabTitle = span.innerHTML;
                    if (settings.spinner) {
                        // TODO if spinner is image
                        span.innerHTML = '<em>' + settings.spinner + '</em>'; // WARNING: html(...) crashes Safari with jQuery 1.1.2
                    }
                    setTimeout(function() { // Timeout is again required in IE, "wait" for id being restored
                        $(hash).load(url, function() {
                            if (settings.spinner) {
                                span.innerHTML = tabTitle; // WARNING: html(...) crashes Safari with jQuery 1.1.2
                            }
                            $$.removeClass(settings.loadingClass);
                            callback && callback();
                        });
                    }, 0);
                });

            });
        }

        // set up containers
        var containers = $('div.' + settings.containerClass, container);
        containers = containers.size() && containers || $('>' + settings.tabStruct, container); // fallback to default structure

        // attach classes for styling if not present
        nav.is('.' + settings.navClass) || nav.addClass(settings.navClass);
        containers.each(function() {
            var $$ = $(this);
            $$.is('.' + settings.containerClass) || $$.addClass(settings.containerClass);
        });

        // try to retrieve active tab from class in HTML
        var hasSelectedClass = $('li', nav).index( $('li.' + settings.selectedClass, nav)[0] );
        if (hasSelectedClass >= 0) {
           settings.initial = hasSelectedClass;
        }

        // try to retrieve active tab from hash in url, will override class in HTML
        if (location.hash) {
            tabs.each(function(i) {
                if (this.hash == location.hash) {
                    settings.initial = i;
                    // prevent page scroll to fragment
                    if (($.browser.msie || $.browser.opera) && !settings.remote) {
                        var toShow = $(location.hash);
                        var toShowId = toShow.attr('id');
                        toShow.attr('id', '');
                        setTimeout(function() {
                            toShow.attr('id', toShowId); // restore id
                        }, 500);
                    }
                    unFocus();
                    return false; // break
                }
            });
        }
        if ($.browser.msie) {
            unFocus(); // fix IE focussing bottom of the page for some unknown reason
        }

        // highlight tab accordingly
        containers.filter(':eq(' + settings.initial + ')').show().end().not(':eq(' + settings.initial + ')').addClass(settings.hideClass);
        $('li', nav).removeClass(settings.selectedClass).eq(settings.initial).addClass(settings.selectedClass); // we need to remove classes eventually if hash takes precedence over class
        // trigger load of initial tab
        tabs.eq(settings.initial).trigger('loadRemoteTab').end();

        // setup auto height
        if (settings.fxAutoHeight) {
            // helper
            var _setAutoHeight = function(reset) {
                // get tab heights in top to bottom ordered array
                var heights = $.map(containers.get(), function(el) {
                    var h, jq = $(el);
                    if (reset) {
                        if ($.browser.msie6) {
                            el.style.removeExpression('behaviour');
                            el.style.height = '';
                            el.minHeight = null;
                        }
                        h = jq.css({'min-height': ''}).height(); // use jQuery's height() to get hidden element values
                    } else {
                        h = jq.height(); // use jQuery's height() to get hidden element values
                    }
                    return h;
                }).sort(function(a, b) {
                    return b - a;
                });
                if ($.browser.msie6) {
                    containers.each(function() {
                        this.minHeight = heights[0] + 'px';
                        this.style.setExpression('behaviour', 'this.style.height = this.minHeight ? this.minHeight : "1px"'); // using an expression to not make print styles useless
                    });
                } else {
                    containers.css({'min-height': heights[0] + 'px'});
                }
            };
            // call once for initialization
            _setAutoHeight();
            // trigger auto height adjustment if needed
            var cachedWidth = container.offsetWidth;
            var cachedHeight = container.offsetHeight;
            var watchFontSize = $('#tabs-watch-font-size').get(0) || $('<span id="tabs-watch-font-size">M</span>').css({display: 'block', position: 'absolute', visibility: 'hidden'}).appendTo(document.body).get(0);
            var cachedFontSize = watchFontSize.offsetHeight;
            setInterval(function() {
                var currentWidth = container.offsetWidth;
                var currentHeight = container.offsetHeight;
                var currentFontSize = watchFontSize.offsetHeight;
                if (currentHeight > cachedHeight || currentWidth != cachedWidth || currentFontSize != cachedFontSize) {
                    _setAutoHeight((currentWidth > cachedWidth || currentFontSize < cachedFontSize)); // if heights gets smaller reset min-height
                    cachedWidth = currentWidth;
                    cachedHeight = currentHeight;
                    cachedFontSize = currentFontSize;
                }
            }, 50);
        }

        // setup animations
        var showAnim = {}, hideAnim = {}, showSpeed = settings.fxShowSpeed || settings.fxSpeed, hideSpeed = settings.fxHideSpeed || settings.fxSpeed;
        if (settings.fxSlide || settings.fxFade) {
            if (settings.fxSlide) {
                showAnim['height'] = 'show';
                hideAnim['height'] = 'hide';
            }
            if (settings.fxFade) {
                showAnim['opacity'] = 'show';
                hideAnim['opacity'] = 'hide';
            }
        } else {
            if (settings.fxShow) {
                showAnim = settings.fxShow;
            } else { // use some kind of animation to prevent browser scrolling to the tab
                showAnim['min-width'] = 0; // avoid opacity, causes flicker in Firefox
                showSpeed = 1; // as little as 1 is sufficient
            }
            if (settings.fxHide) {
                hideAnim = settings.fxHide;
            } else { // use some kind of animation to prevent browser scrolling to the tab
                hideAnim['min-width'] = 0; // avoid opacity, causes flicker in Firefox
                hideSpeed = 1; // as little as 1 is sufficient
            }
        }

        // callbacks
        var onClick = settings.onClick, onHide = settings.onHide, onShow = settings.onShow;

        // attach activateTab event, required for activating a tab programmatically
        tabs.bind('triggerTab', function() {

            // if the tab is already selected or disabled or animation is still running stop here
            var li = $(this).parents('li:eq(0)');
            if (container.locked || li.is('.' + settings.selectedClass) || li.is('.' + settings.disabledClass)) {
                return false;
            }

            var hash = this.hash;

            if ($.browser.msie) {

                $(this).trigger('click');
                if (settings.bookmarkable) {
                    $.ajaxHistory.update(hash);
                    location.hash = hash.replace('#', '');
                }

            } else if ($.browser.safari) {

                // Simply setting location.hash puts Safari into the eternal load state... ugh! Submit a form instead.
                var tempForm = $('<form action="' + hash + '"><div><input type="submit" value="h" /></div></form>').get(0); // no need to append it to the body
                tempForm.submit(); // does not trigger the form's submit event...
                $(this).trigger('click'); // ...thus do stuff here
                if (settings.bookmarkable) {
                    $.ajaxHistory.update(hash);
                }

            } else {

                if (settings.bookmarkable) {
                    location.hash = hash.replace('#', '');
                } else {
                    $(this).trigger('click');
                }

            }

        });

        // attach disable event, required for disabling a tab
        tabs.bind('disableTab', function() {
            var li = $(this).parents('li:eq(0)');
            if ($.browser.safari) { /* fix opacity of tab after disabling in Safari... */
                li.animate({ opacity: 0 }, 1, function() {
                   li.css({opacity: ''});
                });
            }
            li.addClass(settings.disabledClass);

        });

        // disabled from settings
        if (settings.disabled && settings.disabled.length) {
            for (var i = 0, k = settings.disabled.length; i < k; i++) {
                tabs.eq(--settings.disabled[i]).trigger('disableTab').end();
            }
        };

        // attach enable event, required for reenabling a tab
        tabs.bind('enableTab', function() {
            var li = $(this).parents('li:eq(0)');
            li.removeClass(settings.disabledClass);
            if ($.browser.safari) { /* fix disappearing tab after enabling in Safari... */
                li.animate({ opacity: 1 }, 1, function() {
                    li.css({opacity: ''});
                });
            }
        });

        // attach click event
        tabs.bind('click', function(e) {

            var trueClick = e.clientX; // add to history only if true click occured, not a triggered click
            var clicked = this, li = $(this).parents('li:eq(0)'), toShow = $(this.hash), toHide = containers.filter(':visible');

            // if animation is still running, tab is selected or disabled or onClick callback returns false stop here
            // check if onClick returns false last so that it is not executed for a disabled tab
            if (container['locked'] || li.is('.' + settings.selectedClass) || li.is('.' + settings.disabledClass) || typeof onClick == 'function' && onClick(this, toShow[0], toHide[0]) === false) {
                this.blur();
                return false;
            }

            container['locked'] = true;

            // show new tab
            if (toShow.size()) {

                // prevent scrollbar scrolling to 0 and than back in IE7, happens only if bookmarking/history is enabled
                if ($.browser.msie && settings.bookmarkable) {
                    var toShowId = this.hash.replace('#', '');
                    toShow.attr('id', '');
                    setTimeout(function() {
                        toShow.attr('id', toShowId); // restore id
                    }, 0);
                }

                var resetCSS = { display: '', overflow: '', height: '' };
                if (!$.browser.msie) { // not in IE to prevent ClearType font issue
                    resetCSS['opacity'] = '';
                }
                
                // switch tab, animation prevents browser scrolling to the fragment
                function switchTab() {
                    if (settings.bookmarkable && trueClick) { // add to history only if true click occured, not a triggered click
                        $.ajaxHistory.update(clicked.hash);
                    }
                    toHide.animate(hideAnim, hideSpeed, function() { //
                        $(clicked).parents('li:eq(0)').addClass(settings.selectedClass).siblings().removeClass(settings.selectedClass);
                        toHide.addClass(settings.hideClass).css(resetCSS); // maintain flexible height and accessibility in print etc.                        
                        if (typeof onHide == 'function') {
                            onHide(clicked, toShow[0], toHide[0]);
                        }
                        if (!(settings.fxSlide || settings.fxFade || settings.fxShow)) {
                            toShow.css('display', 'block'); // prevent occasionally occuring flicker in Firefox cause by gap between showing and hiding the tab containers
                        }
                        toShow.animate(showAnim, showSpeed, function() {
                            toShow.removeClass(settings.hideClass).css(resetCSS); // maintain flexible height and accessibility in print etc.
                            if ($.browser.msie) {
                                toHide[0].style.filter = '';
                                toShow[0].style.filter = '';
                            }
                            if (typeof onShow == 'function') {
                                onShow(clicked, toShow[0], toHide[0]);
                            }
                            container['locked'] = null;
                        });
                    });
                }

                if (!settings.remote) {
                    switchTab();
                } else {
                    $(clicked).trigger('loadRemoteTab', [switchTab]);
                }

            } else {
                alert('There is no such container.');
            }

            // Set scrollbar to saved position - need to use timeout with 0 to prevent browser scroll to target of hash
            var scrollX = window.pageXOffset || document.documentElement && document.documentElement.scrollLeft || document.body.scrollLeft || 0;
            var scrollY = window.pageYOffset || document.documentElement && document.documentElement.scrollTop || document.body.scrollTop || 0;
            setTimeout(function() {
                window.scrollTo(scrollX, scrollY);
            }, 0);

            this.blur(); // prevent IE from keeping other link focussed when using the back button

            return settings.bookmarkable && !!trueClick; // convert undefined to Boolean for IE

        });

        // enable history support if bookmarking and history is turned on
        if (settings.bookmarkable) {
            $.ajaxHistory.initialize(function() {
                tabs.eq(settings.initial).trigger('click').end();
            });
        }

    });

};

/**
 * Activate a tab programmatically with the given position (no zero-based index)
 * or its id, e.g. the URL's fragment identifier/hash representing a tab, as if the tab
 * itself were clicked.
 *
 * @example $('#container').triggerTab(2);
 * @desc Activate the second tab of the tab interface contained in <div id="container">.
 * @example $('#container').triggerTab(1);
 * @desc Activate the first tab of the tab interface contained in <div id="container">.
 * @example $('#container').triggerTab();
 * @desc Activate the first tab of the tab interface contained in <div id="container">.
 * @example $('#container').triggerTab('fragment-2');
 * @desc Activate a tab via its URL fragment identifier representation.
 *
 * @param String|Number tab Either a string that matches the id of the tab (the URL's
 *                          fragment identifier/hash representing a tab) or an integer
 *                          specifying the position of the tab (no zero-based index) to
 *                          be activated. If this parameter is omitted, the first tab
 *                          will be activated.
 * @type jQuery
 *
 * @name triggerTab
 * @cat Plugins/Tabs
 * @author Klaus Hartl/klaus.hartl@stilbuero.de
 */

/**
 * Disable a tab, so that clicking it has no effect.
 *
 * @example $('#container').disableTab(2);
 * @desc Disable the second tab of the tab interface contained in <div id="container">.
 *
 * @param String|Number tab Either a string that matches the id of the tab (the URL's
 *                          fragment identifier/hash representing a tab) or an integer
 *                          specifying the position of the tab (no zero-based index) to
 *                          be disabled. If this parameter is omitted, the first tab
 *                          will be disabled.
 * @type jQuery
 *
 * @name disableTab
 * @cat Plugins/Tabs
 * @author Klaus Hartl/klaus.hartl@stilbuero.de
 */

/**
 * Enable a tab that has been disabled.
 *
 * @example $('#container').enableTab(2);
 * @desc Enable the second tab of the tab interface contained in <div id="container">.
 *
 * @param String|Number tab Either a string that matches the id of the tab (the URL's
 *                          fragment identifier/hash representing a tab) or an integer
 *                          specifying the position of the tab (no zero-based index) to
 *                          be enabled. If this parameter is omitted, the first tab
 *                          will be enabled.
 * @type jQuery
 *
 * @name enableTab
 * @cat Plugins/Tabs
 * @author Klaus Hartl/klaus.hartl@stilbuero.de
 */

var tabEvents = ['triggerTab', 'disableTab', 'enableTab'];
for (var i = 0; i < tabEvents.length; i++) {
    $.fn[tabEvents[i]] = (function(tabEvent) {
        return function(tab) {
            return this.each(function() {
                var nav = $('ul.tabs-nav' , this);
                nav = nav.size() && nav || $('>ul:eq(0)', this); // fallback to default structure
                var a;
                if (!tab || typeof tab == 'number') {
                    a = $('li a', nav).eq((tab && tab > 0 && tab - 1 || 0)); // fall back to 0
                } else if (typeof tab == 'string') {
                    a = $('li a[@href$="#' + tab + '"]', nav);
                }
                a.trigger(tabEvent);
            });
        };
    })(tabEvents[i]);
}

/**
 * Get the position of the currently selected tab (no zero-based index).
 *
 * @example $('#container').activeTab();
 * @desc Get the position of the currently selected tab of an interface
 * contained in <div id="container">.
 *
 * @type Number
 *
 * @name activeTab
 * @cat Plugins/Tabs
 * @author Klaus Hartl/klaus.hartl@stilbuero.de
 */

$.fn.activeTab = function() {
    var selectedTabs = [];
    this.each(function() {
        var nav = $('ul.tabs-nav' , this);
        nav = nav.size() && nav || $('>ul:eq(0)', this); //fallback to default structure
        var lis = $('li', nav);
        selectedTabs.push(lis.index( lis.filter('.tabs-selected')[0] ) + 1);
    });
    return selectedTabs[0];
};

})(jQuery);/*
 * jQuery blockUI plugin
 * Version 1.32  (08/23/2007)
 * @requires jQuery v1.1.1
 *
 * $Id$
 *
 * Examples at: http://malsup.com/jquery/block/
 * Copyright (c) 2007 M. Alsup
 * Dual licensed under the MIT and GPL licenses:
 * http://www.opensource.org/licenses/mit-license.php
 * http://www.gnu.org/licenses/gpl.html
 */
 (function($) {
/**
 * blockUI provides a mechanism for blocking user interaction with a page (or parts of a page).
 * This can be an effective way to simulate synchronous behavior during ajax operations without
 * locking the browser.  It will prevent user operations for the current page while it is
 * active ane will return the page to normal when it is deactivate.  blockUI accepts the following
 * two optional arguments:
 *
 *   message (String|Element|jQuery): The message to be displayed while the UI is blocked. The message
 *              argument can be a plain text string like "Processing...", an HTML string like
 *              "<h1><img src="busy.gif" /> Please wait...</h1>", a DOM element, or a jQuery object.
 *              The default message is "<h1>Please wait...</h1>"
 *
 *   css (Object):  Object which contains css property/values to override the default styles of
 *              the message.  Use this argument if you wish to override the default
 *              styles.  The css Object should be in a format suitable for the jQuery.css
 *              function.  For example:
 *              $.blockUI({
 *                    backgroundColor: '#ff8',
 *                    border: '5px solid #f00,
 *                    fontWeight: 'bold'
 *              });
 *
 * The default blocking message used when blocking the entire page is "<h1>Please wait...</h1>"
 * but this can be overridden by assigning a value to $.blockUI.defaults.pageMessage in your
 * own code.  For example:
 *
 *      $.blockUI.defaults.pageMessage = "<h1>Bitte Wartezeit</h1>";
 *
 * The default message styling can also be overridden.  For example:
 *
 *      $.extend($.blockUI.defaults.pageMessageCSS, { color: '#00a', backgroundColor: '#0f0' });
 *
 * The default styles work well for simple messages like "Please wait", but for longer messages
 * style overrides may be necessary.
 *
 * @example  $.blockUI();
 * @desc prevent user interaction with the page (and show the default message of 'Please wait...')
 *
 * @example  $.blockUI( { backgroundColor: '#f00', color: '#fff'} );
 * @desc prevent user interaction and override the default styles of the message to use a white on red color scheme
 *
 * @example  $.blockUI('Processing...');
 * @desc prevent user interaction and display the message "Processing..." instead of the default message
 *
 * @name blockUI
 * @param String|jQuery|Element message Message to display while the UI is blocked
 * @param Object css Style object to control look of the message
 * @cat Plugins/blockUI
 */
$.blockUI = function(msg, css, opts) {
    $.blockUI.impl.install(window, msg, css, opts);
};

// expose version number so other plugins can interogate
$.blockUI.version = 1.32;

/**
 * unblockUI removes the UI block that was put in place by blockUI
 *
 * @example  $.unblockUI();
 * @desc unblocks the page
 *
 * @name unblockUI
 * @cat Plugins/blockUI
 */
$.unblockUI = function(opts) {
    $.blockUI.impl.remove(window, opts);
};

/**
 * Blocks user interaction with the selected elements.  (Hat tip: Much of
 * this logic comes from Brandon Aaron's bgiframe plugin.  Thanks, Brandon!)
 * By default, no message is displayed when blocking elements.
 *
 * @example  $('div.special').block();
 * @desc prevent user interaction with all div elements with the 'special' class.
 *
 * @example  $('div.special').block('Please wait');
 * @desc prevent user interaction with all div elements with the 'special' class
 * and show a message over the blocked content.
 *
 * @name block
 * @type jQuery
 * @param String|jQuery|Element message Message to display while the element is blocked
 * @param Object css Style object to control look of the message
 * @cat Plugins/blockUI
 */
$.fn.block = function(msg, css, opts) {
    return this.each(function() {
		if (!this.$pos_checked) {
            if ($.css(this,"position") == 'static')
                this.style.position = 'relative';
            if ($.browser.msie) this.style.zoom = 1; // force 'hasLayout' in IE
            this.$pos_checked = 1;
        }
        $.blockUI.impl.install(this, msg, css, opts);
    });
};

/**
 * Unblocks content that was blocked by "block()"
 *
 * @example  $('div.special').unblock();
 * @desc unblocks all div elements with the 'special' class.
 *
 * @name unblock
 * @type jQuery
 * @cat Plugins/blockUI
 */
$.fn.unblock = function(opts) {
    return this.each(function() {
        $.blockUI.impl.remove(this, opts);
    });
};

/**
 * displays the first matched element in a "display box" above a page overlay.
 *
 * @example  $('#myImage').displayBox();
 * @desc displays "myImage" element in a box
 *
 * @name displayBox
 * @type jQuery
 * @cat Plugins/blockUI
 */
$.fn.displayBox = function(css, fn, isFlash) {
    var msg = this[0];
    if (!msg) return;
    var $msg = $(msg);
    css = css || {};

    var w = $msg.width()  || $msg.attr('width')  || css.width  || $.blockUI.defaults.displayBoxCSS.width;
    var h = $msg.height() || $msg.attr('height') || css.height || $.blockUI.defaults.displayBoxCSS.height ;
    if (w[w.length-1] == '%') {
        var ww = document.documentElement.clientWidth || document.body.clientWidth;
        w = parseInt(w) || 100;
        w = (w * ww) / 100;
    }
    if (h[h.length-1] == '%') {
        var hh = document.documentElement.clientHeight || document.body.clientHeight;
        h = parseInt(h) || 100;
        h = (h * hh) / 100;
    }

    var ml = '-' + parseInt(w)/2 + 'px';
    var mt = '-' + parseInt(h)/2 + 'px';

    // supress opacity on overlay if displaying flash content on mac/ff platform
    var ua = navigator.userAgent.toLowerCase();
    var opts = {
        displayMode: fn || 1,
        noalpha: isFlash && /mac/.test(ua) && /firefox/.test(ua)
    };

    $.blockUI.impl.install(window, msg, { width: w, height: h, marginTop: mt, marginLeft: ml }, opts);
};


// override these in your code to change the default messages and styles
$.blockUI.defaults = {
    // the message displayed when blocking the entire page
    pageMessage:    '<h1>Please wait...</h1>',
    // the message displayed when blocking an element
    elementMessage: '', // none
    // styles for the overlay iframe
    overlayCSS:  { backgroundColor: '#fff', opacity: '0.5' },
    // styles for the message when blocking the entire page
    pageMessageCSS:    { width:'250px', margin:'-50px 0 0 -125px', top:'50%', left:'50%', textAlign:'center', color:'#000', backgroundColor:'#fff', border:'3px solid #aaa' },
    // styles for the message when blocking an element
    elementMessageCSS: { width:'250px', padding:'10px', textAlign:'center', backgroundColor:'#fff'},
    // styles for the displayBox
    displayBoxCSS: { width: '400px', height: '400px', top:'50%', left:'50%' },
    // allow body element to be stetched in ie6
    ie6Stretch: 1,
    // supress tab nav from leaving blocking content?
    allowTabToLeave: 0,
    // Title attribute for overlay when using displayBox
    closeMessage: 'Click to close',
    // use fadeOut effect when unblocking (can be overridden on unblock call)
    fadeOut:  1,
    // fadeOut transition time in millis
    fadeTime: 400
};

// the gory details
$.blockUI.impl = {
    box: null,
    boxCallback: null,
    pageBlock: null,
    pageBlockEls: [],
    op8: window.opera && window.opera.version() < 9,
    ie6: $.browser.msie && /MSIE 6.0/.test(navigator.userAgent),
    install: function(el, msg, css, opts) {
        opts = opts || {};
        this.boxCallback = typeof opts.displayMode == 'function' ? opts.displayMode : null;
        this.box = opts.displayMode ? msg : null;
        var full = (el == window);

        // use logical settings for opacity support based on browser but allow overrides via opts arg
        var noalpha = this.op8 || $.browser.mozilla && /Linux/.test(navigator.platform);
        if (typeof opts.alphaOverride != 'undefined')
            noalpha = opts.alphaOverride == 0 ? 1 : 0;

        if (full && this.pageBlock) this.remove(window, {fadeOut:0});
        // check to see if we were only passed the css object (a literal)
        if (msg && typeof msg == 'object' && !msg.jquery && !msg.nodeType) {
            css = msg;
            msg = null;
        }
        msg = msg ? (msg.nodeType ? $(msg) : msg) : full ? $.blockUI.defaults.pageMessage : $.blockUI.defaults.elementMessage;
        if (opts.displayMode)
            var basecss = jQuery.extend({}, $.blockUI.defaults.displayBoxCSS);
        else
            var basecss = jQuery.extend({}, full ? $.blockUI.defaults.pageMessageCSS : $.blockUI.defaults.elementMessageCSS);
        css = jQuery.extend(basecss, css || {});
        var f = ($.browser.msie) ? $('<iframe class="blockUI" style="z-index:1000;border:none;margin:0;padding:0;position:absolute;width:100%;height:100%;top:0;left:0" src="javascript:false;"></iframe>')
                                 : $('<div class="blockUI" style="display:none"></div>');
        var w = $('<div class="blockUI" style="z-index:1001;cursor:wait;border:none;margin:0;padding:0;width:100%;height:100%;top:0;left:0"></div>');
        var m = full ? $('<div class="blockUI blockMsg" style="z-index:1002;cursor:wait;padding:0;position:fixed"></div>')
                     : $('<div class="blockUI" style="display:none;z-index:1002;cursor:wait;position:absolute"></div>');
        w.css('position', full ? 'fixed' : 'absolute');
        if (msg) m.css(css);
        if (!noalpha) w.css($.blockUI.defaults.overlayCSS);
        if (this.op8) w.css({ width:''+el.clientWidth,height:''+el.clientHeight }); // lame
        if ($.browser.msie) f.css('opacity','0.0');

        $([f[0],w[0],m[0]]).appendTo(full ? 'body' : el);

        // ie7 must use absolute positioning in quirks mode and to account for activex issues (when scrolling)
        var expr = $.browser.msie && (!$.boxModel || $('object,embed', full ? null : el).length > 0);
        if (this.ie6 || expr) {
            // stretch content area if it's short
            if (full && $.blockUI.defaults.ie6Stretch && $.boxModel)
                $('html,body').css('height','100%');

            // fix ie6 problem when blocked element has a border width
            if ((this.ie6 || !$.boxModel) && !full) {
                var t = this.sz(el,'borderTopWidth'), l = this.sz(el,'borderLeftWidth');
                var fixT = t ? '(0 - '+t+')' : 0;
                var fixL = l ? '(0 - '+l+')' : 0;
            }

            // simulate fixed position
            $.each([f,w,m], function(i,o) {
                var s = o[0].style;
                s.position = 'absolute';
                if (i < 2) {
                    full ? s.setExpression('height','document.body.scrollHeight > document.body.offsetHeight ? document.body.scrollHeight : document.body.offsetHeight + "px"')
                         : s.setExpression('height','this.parentNode.offsetHeight + "px"');
                    full ? s.setExpression('width','jQuery.boxModel && document.documentElement.clientWidth || document.body.clientWidth + "px"')
                         : s.setExpression('width','this.parentNode.offsetWidth + "px"');
                    if (fixL) s.setExpression('left', fixL);
                    if (fixT) s.setExpression('top', fixT);
                }
                else {
                    if (full) s.setExpression('top','(document.documentElement.clientHeight || document.body.clientHeight) / 2 - (this.offsetHeight / 2) + (blah = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + "px"');
                    s.marginTop = 0;
                }
            });
        }
        if (opts.displayMode) {
            w.css('cursor','default').attr('title', $.blockUI.defaults.closeMessage);
            m.css('cursor','default');
            $([f[0],w[0],m[0]]).removeClass('blockUI').addClass('displayBox');
            $().click($.blockUI.impl.boxHandler).bind('keypress', $.blockUI.impl.boxHandler);
        }
        else
            this.bind(1, el);
        m.append(msg).show();
        if (msg.jquery) msg.show();
        if (opts.displayMode) return;
        if (full) {
            this.pageBlock = m[0];
            this.pageBlockEls = $(':input:enabled:visible',this.pageBlock);
            setTimeout(this.focus, 20);
        }
        else this.center(m[0]);
    },
    remove: function(el, opts) {
        var o = $.extend({}, $.blockUI.defaults, opts);
        this.bind(0, el);
        var full = el == window;
        var els = full ? $('body').children().filter('.blockUI') : $('.blockUI', el);
        if (full) this.pageBlock = this.pageBlockEls = null;

        if (o.fadeOut) {
            els.fadeOut(o.fadeTime, function() {
                if (this.parentNode) this.parentNode.removeChild(this);
            });
        }
        else els.remove();
    },
    boxRemove: function(el) {
        $().unbind('click',$.blockUI.impl.boxHandler).unbind('keypress', $.blockUI.impl.boxHandler);
        if (this.boxCallback)
            this.boxCallback(this.box);
        $('body .displayBox').hide().remove();
    },
    // event handler to suppress keyboard/mouse events when blocking
    handler: function(e) {
        if (e.keyCode && e.keyCode == 9) {
            if ($.blockUI.impl.pageBlock && !$.blockUI.defaults.allowTabToLeave) {
                var els = $.blockUI.impl.pageBlockEls;
                var fwd = !e.shiftKey && e.target == els[els.length-1];
                var back = e.shiftKey && e.target == els[0];
                if (fwd || back) {
                    setTimeout(function(){$.blockUI.impl.focus(back)},10);
                    return false;
                }
            }
        }
        if ($(e.target).parents('div.blockMsg').length > 0)
            return true;
        return $(e.target).parents().children().filter('div.blockUI').length == 0;
    },
    boxHandler: function(e) {
        if ((e.keyCode && e.keyCode == 27) || (e.type == 'click' && $(e.target).parents('div.blockMsg').length == 0))
            $.blockUI.impl.boxRemove();
        return true;
    },
    // bind/unbind the handler
    bind: function(b, el) {
        var full = el == window;
        // don't bother unbinding if there is nothing to unbind
        if (!b && (full && !this.pageBlock || !full && !el.$blocked)) return;
        if (!full) el.$blocked = b;
        var $e = full ? $() : $(el).find('a,:input');
        $.each(['mousedown','mouseup','keydown','keypress','click'], function(i,o) {
            $e[b?'bind':'unbind'](o, $.blockUI.impl.handler);
        });
    },
    focus: function(back) {
        if (!$.blockUI.impl.pageBlockEls) return;
        var e = $.blockUI.impl.pageBlockEls[back===true ? $.blockUI.impl.pageBlockEls.length-1 : 0];
        if (e) e.focus();
    },
    center: function(el) {
		var p = el.parentNode, s = el.style;
        var l = ((p.offsetWidth - el.offsetWidth)/2) - this.sz(p,'borderLeftWidth');
        var t = ((p.offsetHeight - el.offsetHeight)/2) - this.sz(p,'borderTopWidth');
        s.left = l > 0 ? (l+'px') : '0';
        s.top  = t > 0 ? (t+'px') : '0';
    },
    sz: function(el, p) { return parseInt($.css(el,p))||0; }
};

})(jQuery);
/**
 * jCarousel - Riding carousels with jQuery
 *   http://sorgalla.com/jcarousel/
 *
 * Copyright (c) 2006 Jan Sorgalla (http://sorgalla.com)
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 * Built on top of the jQuery library
 *   http://jquery.com
 *
 * Inspired by the "Carousel Component" by Bill Scott
 *   http://billwscott.com/carousel/
 */

(function($) {
    /**
     * Creates a carousel for all matched elements.
     *
     * @example $("#mycarousel").jcarousel();
     * @before <ul id="mycarousel"><li>First item</li><li>Second item</li></ul>
     * @result
     *
     * <div class="jcarousel-skin-name jcarousel-container">
     *   <div disabled="disabled" class="jcarousel-prev jcarousel-prev-disabled"></div>
     *   <div class="jcarousel-next"></div>
     *   <div class="jcarousel-clip">
     *     <ul class="jcarousel-list">
     *       <li class="jcarousel-item-1">First item</li>
     *       <li class="jcarousel-item-2">Second item</li>
     *     </ul>
     *   </div>
     * </div>
     *
     * @name jcarousel
     * @type jQuery
     * @param Hash o A set of key/value pairs to set as configuration properties.
     * @cat Plugins/jCarousel
     */
    $.fn.jcarousel = function(o) {
        return this.each(function() {
            new $jc(this, o);
        });
    };

    // Default configuration properties.
    var defaults = {
        vertical: false,
        start: 1,
        size: null,
        scroll: 3,
        visible: null,
        animation: 'fast',
        easing: null,
        auto: 0,
        wrap: null,
        initCallback: null,
        reloadCallback: null,
        itemLoadCallback: null,
        itemFirstInCallback: null,
        itemFirstOutCallback: null,
        itemLastInCallback: null,
        itemLastOutCallback: null,
        itemVisibleInCallback: null,
        itemVisibleOutCallback: null,
        buttonNextHTML: '<div></div>',
        buttonPrevHTML: '<div></div>',
        buttonNextEvent: 'click',
        buttonPrevEvent: 'click',
        buttonNextCallback: null,
        buttonPrevCallback: null
    };

    /**
     * The jCarousel object.
     *
     * @constructor
     * @name $.jcarousel
     * @param Object e The element to create the carousel for.
     * @param Hash o A set of key/value pairs to set as configuration properties.
     * @cat Plugins/jCarousel
     */
    $.jcarousel = function(e, o) {
        this.options    = $.extend({}, defaults, o || {});

        this.container  = null;
        this.clip       = null;
        this.list       = null;
        this.buttonNext = null;
        this.buttonPrev = null;

        this.wh = !this.options.vertical ? 'width' : 'height';
        this.lt = !this.options.vertical ? 'left' : 'top';

        if (e.nodeName == 'UL' || e.nodeName == 'OL') {
            this.list = $(e);
            this.container = this.list.parent();

            if ($.className.has(this.container[0].className, 'jcarousel-clip')) {
                if (!$.className.has(this.container[0].parentNode.className, 'jcarousel-container'))
                    this.container = this.container.wrap('<div></div>');

                this.container = this.container.parent();
            } else if (!$.className.has(this.container[0].className, 'jcarousel-container'))
                this.container = this.list.wrap('<div></div>').parent();

            // Move skin class over to container
            var split = e.className.split(' ');

            for (var i = 0; i < split.length; i++) {
                if (split[i].indexOf('jcarousel-skin') != -1) {
                    this.list.removeClass(split[i]);
                    this.container.addClass(split[i]);
                    break;
                }
            }
        } else {
            this.container = $(e);
            this.list = $('ul,ol', e);
        }

        this.clip = this.list.parent();

        if (!this.clip.length || !$.className.has(this.clip[0].className, 'jcarousel-clip'))
            this.clip = this.list.wrap('<div></div>').parent();

        this.buttonPrev = $('.jcarousel-prev', this.container);

        if (this.buttonPrev.size() == 0 && this.options.buttonPrevHTML != null)
            this.buttonPrev = this.clip.before(this.options.buttonPrevHTML).prev();

        this.buttonPrev.addClass(this.className('jcarousel-prev'));

        this.buttonNext = $('.jcarousel-next', this.container);

        if (this.buttonNext.size() == 0 && this.options.buttonNextHTML != null)
            this.buttonNext = this.clip.before(this.options.buttonNextHTML).prev();

        this.buttonNext.addClass(this.className('jcarousel-next'));

        this.clip.addClass(this.className('jcarousel-clip'));
        this.list.addClass(this.className('jcarousel-list'));
        this.container.addClass(this.className('jcarousel-container'));

        var di = this.options.visible != null ? Math.ceil(this.clipping() / this.options.visible) : null;
        var li = $('li', this.list);

        var self = this;

        if (li.size() > 0) {
            var wh = 0, i = this.options.start;
            li.each(function() {
                self.format(this, i++);
                wh += self.dimension(this, di);
            });

            this.list.css(this.wh, wh + 'px');

            // Only set if not explicitly passed as option
            if (!o || o.size == undefined)
                this.options.size = li.size();
        }

        // For whatever reason, .show() does not work in Safari...
        this.container.css('display', 'block');
        this.buttonNext.css('display', 'block');
        this.buttonPrev.css('display', 'block');

        this.funcNext   = function() { self.next(); };
        this.funcPrev   = function() { self.prev(); };
        this.funcStop   = function() { self.stop(); };
        this.funcResize = function() { self.reload(); };

        this.init();
    };

    // Create shortcut for internal use
    var $jc = $.jcarousel;

    $jc.fn = $jc.prototype = {
        jcarousel: '2.0.0'
    };

    $jc.fn.extend = $jc.extend = $.extend;

    $jc.fn.extend({
        /**
         * Setups the carousel.
         *
         * @name setup
         * @type undefined
         * @cat Plugins/jCarousel
         */
        setup: function() {
            this.first     = null;
            this.last      = null;
            this.prevFirst = null;
            this.prevLast  = null;
            this.animating = false;
            this.timer     = null;
            this.tail      = null;
            this.inTail    = false;
            this.locked    = false;

            this.scroll(this.options.start, false);
        },

        /**
         * Initialises the carousel.
         *
         * @name init
         * @type undefined
         * @cat Plugins/jCarousel
         */
        init: function() {
            if (this.options.initCallback != null)
                this.options.initCallback(this, 'init');

            this.setup();
            $(window).bind('resize', this.funcResize);
        },

        /**
         * Clears the list and resets the carousel.
         *
         * @name reset
         * @type undefined
         * @cat Plugins/jCarousel
         */
        reset: function() {
            this.list.empty();

            this.list.css(this.lt, '0px');
            this.list.css(this.wh, '0px');

            if (this.options.initCallback != null)
                this.options.initCallback(this, 'reset');

            this.setup();
        },

        /**
         * Reloads the carousel and adjusts positions.
         *
         * @name reload
         * @type undefined
         * @cat Plugins/jCarousel
         */
        reload: function() {
            if (this.tail != null && this.inTail)
                this.list.css(this.lt, $jc.intval(this.list.css(this.lt)) + this.tail);

            this.tail   = null;
            this.inTail = false;

            if (this.options.reloadCallback != null)
                this.options.reloadCallback(this);

            if (this.options.visible != null) {
                var self = this;
                var di = Math.ceil(this.clipping() / this.options.visible), wh = 0, lt = 0;
                $('li', this.list).each(function(i) {
                    wh += self.dimension(this, di);
                    if (i + 1 < self.first)
                        lt = wh;
                });

                this.list.css(this.wh, wh + 'px');
                this.list.css(this.lt, -lt + 'px');
            }

            this.scroll(this.first, false);
        },

        /**
         * Locks the carousel.
         *
         * @name lock
         * @type undefined
         * @cat Plugins/jCarousel
         */
        lock: function() {
            this.locked = true;
            this.buttons();
        },

        /**
         * Unlocks the carousel.
         *
         * @name unlock
         * @type undefined
         * @cat Plugins/jCarousel
         */
        unlock: function() {
            this.locked = false;
            this.buttons();
        },

        /**
         * Sets the size of the carousel.
         *
         * @name size
         * @type undefined
         * @param Number s The size of the carousel.
         * @cat Plugins/jCarousel
         */
        size: function(s) {
            if (s != undefined) {
                this.options.size = s;
                if (!this.locked)
                    this.buttons();
            }

            return this.options.size;
        },

        /**
         * Checks whether a list element exists for the given index (or index range).
         *
         * @name get
         * @type bool
         * @param Number i The index of the (first) element.
         * @param Number i2 The index of the last element.
         * @cat Plugins/jCarousel
         */
        has: function(i, i2) {
            if (i2 == undefined || !i2)
                i2 = i;

            for (var j = i; j <= i2; j++) {
                var e = this.get(j).get(0);
                if (!e || $.className.has(e, 'jcarousel-item-placeholder'))
                    return false;
            }

            return true;
        },

        /**
         * Returns a jQuery object with list element for the given index.
         *
         * @name get
         * @type jQuery
         * @param Number i The index of the element.
         * @cat Plugins/jCarousel
         */
        get: function(i) {
            return $('.jcarousel-item-' + i, this.list);
        },

        /**
         * Adds an element for the given index to the list.
         * If the element already exists, it updates the inner html.
         * Returns the created element as jQuery object.
         *
         * @name add
         * @type jQuery
         * @param Number i The index of the element.
         * @param String s The innerHTML of the element.
         * @cat Plugins/jCarousel
         */
        add: function(i, s) {
            var e = this.get(i), old = 0;

            if (e.length == 0) {
                var c, e = this.create(i), j = $jc.intval(i);
                while (c = this.get(--j)) {
                    if (j <= 0 || c.length) {
                        j <= 0 ? this.list.prepend(e) : c.after(e);
                        break;
                    }
                }
            } else
                old = this.dimension(e);

            e.removeClass(this.className('jcarousel-item-placeholder'));
            typeof s == 'string' ? e.html(s) : e.empty().append(s);

            var di = this.options.visible != null ? Math.ceil(this.clipping() / this.options.visible) : null;
            var wh = this.dimension(e, di) - old;

            if (i > 0 && i < this.first)
                this.list.css(this.lt, $jc.intval(this.list.css(this.lt)) + wh + 'px');

            this.list.css(this.wh, $jc.intval(this.list.css(this.wh)) + wh + 'px');

            return e;
        },

        /**
         * Removes an element for the given index from the list.
         *
         * @name remove
         * @type undefined
         * @param Number i The index of the element.
         * @cat Plugins/jCarousel
         */
        remove: function(i) {
            var e = this.get(i);

            // Check if item exists and is not currently visible
            if (!e.length || (i >= this.first && i <= this.last))
                return;

            var d = this.dimension(e);

            if (i < this.first)
                this.list.css(this.lt, $jc.intval(this.list.css(this.lt)) + d + 'px');

            e.remove();

            this.list.css(this.wh, $jc.intval(this.list.css(this.wh)) - d + 'px');
        },

        /**
         * Moves the carousel forwards.
         *
         * @name next
         * @type undefined
         * @cat Plugins/jCarousel
         */
        next: function() {
            this.stopAuto();

            if (this.tail != null && !this.inTail)
                this.scrollTail(false);
            else
                this.scroll(((this.options.wrap == 'both' || this.options.wrap == 'last') && this.options.size != null && this.last == this.options.size) ? 1 : this.first + this.options.scroll);
        },

        /**
         * Moves the carousel backwards.
         *
         * @name prev
         * @type undefined
         * @cat Plugins/jCarousel
         */
        prev: function() {
            this.stopAuto();

            if (this.tail != null && this.inTail)
                this.scrollTail(true);
            else
                this.scroll(((this.options.wrap == 'both' || this.options.wrap == 'first') && this.options.size != null && this.first == 1) ? this.options.size : this.first - this.options.scroll);
        },

        /**
         * Scrolls the tail of the carousel.
         *
         * @name scrollTail
         * @type undefined
         * @param Bool b Whether scroll the tail back or forward.
         * @cat Plugins/jCarousel
         */
        scrollTail: function(b) {
            if (this.locked || this.animating || !this.tail)
                return;

            var pos  = $jc.intval(this.list.css(this.lt));

            !b ? pos -= this.tail : pos += this.tail;
            this.inTail = !b;

            // Save for callbacks
            this.prevFirst = this.first;
            this.prevLast  = this.last;

            this.animate(pos);
        },

        /**
         * Scrolls the carousel to a certain position.
         *
         * @name scroll
         * @type undefined
         * @param Number i The index of the element to scoll to.
         * @param Bool a Flag indicating whether to perform animation.
         * @cat Plugins/jCarousel
         */
        scroll: function(i, a) {
            if (this.locked || this.animating)
                return;

            this.animate(this.pos(i), a);
        },

        /**
         * Prepares the carousel and return the position for a certian index.
         *
         * @name pos
         * @type Number
         * @param Number i The index of the element to scoll to.
         * @cat Plugins/jCarousel
         */
        pos: function(i) {
            if (this.locked || this.animating)
                return;

            if (this.options.wrap != 'circular')
                i = i < 1 ? 1 : (this.options.size && i > this.options.size ? this.options.size : i);

            var back = this.first > i;
            var pos  = $jc.intval(this.list.css(this.lt));

            // Create placeholders, new list width/height
            // and new list position
            var f = this.options.wrap != 'circular' && this.first <= 1 ? 1 : this.first;
            var c = back ? this.get(f) : this.get(this.last);
            var j = back ? f : f - 1;
            var e = null, l = 0, p = false, d = 0;

            while (back ? --j >= i : ++j < i) {
                e = this.get(j);
                p = !e.length;
                if (e.length == 0) {
                    e = this.create(j).addClass(this.className('jcarousel-item-placeholder'));
                    c[back ? 'before' : 'after' ](e);
                }

                c = e;
                d = this.dimension(e);

                if (p)
                    l += d;

                if (this.first != null && (this.options.wrap == 'circular' || (j >= 1 && (this.options.size == null || j <= this.options.size))))
                    pos = back ? pos + d : pos - d;
            }

            // Calculate visible items
            var clipping = this.clipping();
            var cache = [];
            var visible = 0, j = i, v = 0;
            var c = this.get(i - 1);

            while (++visible) {
                e = this.get(j);
                p = !e.length;
                if (e.length == 0) {
                    e = this.create(j).addClass(this.className('jcarousel-item-placeholder'));
                    // This should only happen on a next scroll
                    c.length == 0 ? this.list.prepend(e) : c[back ? 'before' : 'after' ](e);
                }

                c = e;
                d = this.dimension(e);

                if (d == 0) {
                    alert('jCarousel: No width/height set for items. This will cause an infinite loop. Aborting...');
                    return 0;
                }

                if (this.options.wrap != 'circular' && this.options.size !== null && j > this.options.size)
                    cache.push(e);
                else if (p)
                    l += d;

                v += d;

                if (v >= clipping)
                    break;

                j++;
            }

            // Remove out-of-range placeholders
            for (var x = 0; x < cache.length; x++)
                cache[x].remove();

            // Resize list
            if (l > 0) {
                this.list.css(this.wh, this.dimension(this.list) + l + 'px');

                if (back) {
                    pos -= l;
                    this.list.css(this.lt, $jc.intval(this.list.css(this.lt)) - l + 'px');
                }
            }

            // Calculate first and last item
            var last = i + visible - 1;
            if (this.options.wrap != 'circular' && this.options.size && last > this.options.size)
                last = this.options.size;

            var first = last - visible + 1;
            if (this.options.wrap != 'circular' && first < 1)
                first = 1;

            if (this.inTail && back) {
                pos += this.tail;
                this.inTail = false;
            }

            this.tail = null;
            if (this.options.wrap != 'circular' && last == this.options.size && (last - visible + 1) >= 1) {
                var m = $jc.margin(this.get(last), !this.options.vertical ? 'marginRight' : 'marginBottom');
                if ((v - m) > clipping)
                    this.tail = v - clipping - m;
            }

            // Adjust position
            while (i-- > first)
                pos += this.dimension(this.get(i));

            // Save visible item range
            this.prevFirst = this.first;
            this.prevLast  = this.last;
            this.first     = first;
            this.last      = last;

            return pos;
        },

        /**
         * Animates the carousel to a certain position.
         *
         * @name animate
         * @type undefined
         * @param mixed p Position to scroll to.
         * @param Bool a Flag indicating whether to perform animation.
         * @cat Plugins/jCarousel
         */
        animate: function(p, a) {
            if (this.locked || this.animating)
                return;

            this.animating = true;

            var self = this, pos = p;
            var scrolled = function() {
                self.animating = false;

                if (pos == 0)
                    self.list.css(self.lt,  0);

                if (self.options.wrap == 'both' || self.options.wrap == 'last' || self.options.size == null || self.last < self.options.size)
                    self.startAuto();

                self.buttons();
                self.notify('onAfterAnimation');
            };

            this.notify('onBeforeAnimation');

            // Animate
            if (!this.options.animation || a == false) {
                this.list.css(this.lt, p + 'px');
                scrolled();
            } else {
                var o = !this.options.vertical ? {'left': p} : {'top': p};
                this.list.animate(o, this.options.animation, this.options.easing, scrolled);
            }
        },

        /**
         * Starts autoscrolling.
         *
         * @name auto
         * @type undefined
         * @param Number s Seconds to periodically autoscroll the content.
         * @cat Plugins/jCarousel
         */
        startAuto: function(s) {
            if (s != undefined)
                this.options.auto = s;

            if (this.options.auto == 0)
                return this.stopAuto();

            if (this.timer != null)
                return;

            var self = this;
            this.timer = setTimeout(function() { self.next(); }, this.options.auto * 1000);
        },

        /**
         * Stops autoscrolling.
         *
         * @name stopAuto
         * @type undefined
         * @cat Plugins/jCarousel
         */
        stopAuto: function() {
            if (this.timer == null)
                return;

            clearTimeout(this.timer);
            this.timer = null;
        },

        /**
         * Sets the states of the prev/next buttons.
         *
         * @name buttons
         * @type undefined
         * @cat Plugins/jCarousel
         */
        buttons: function(n, p) {
            if (n == undefined || n == null) {
                var n = !this.locked && this.options.size !== 0 && ((this.options.wrap && this.options.wrap != 'first') || this.options.size == null || this.last < this.options.size);
                if (!this.locked && (!this.options.wrap || this.options.wrap == 'first') && this.options.size != null && this.last >= this.options.size)
                    n = this.tail != null && !this.inTail;
            }

            if (p == undefined || p == null) {
                var p = !this.locked && this.options.size !== 0 && ((this.options.wrap && this.options.wrap != 'last') || this.first > 1);
                if (!this.locked && (!this.options.wrap || this.options.wrap == 'last') && this.options.size != null && this.first == 1)
                    p = this.tail != null && this.inTail;
            }

            var self = this;

            this.buttonNext[n ? 'bind' : 'unbind'](this.options.buttonNextEvent, this.funcNext)[n ? 'removeClass' : 'addClass'](this.className('jcarousel-next-disabled')).attr('disabled', n ? false : true);
            this.buttonPrev[p ? 'bind' : 'unbind'](this.options.buttonPrevEvent, this.funcPrev)[p ? 'removeClass' : 'addClass'](this.className('jcarousel-prev-disabled')).attr('disabled', p ? false : true);

            if (this.buttonNext.length > 0 && (this.buttonNext[0].jcarouselstate == undefined || this.buttonNext[0].jcarouselstate != n) && this.options.buttonNextCallback != null) {
                this.buttonNext.each(function() { self.options.buttonNextCallback(self, this, n); });
                this.buttonNext[0].jcarouselstate = n;
            }

            if (this.buttonPrev.length > 0 && (this.buttonPrev[0].jcarouselstate == undefined || this.buttonPrev[0].jcarouselstate != p) && this.options.buttonPrevCallback != null) {
                this.buttonPrev.each(function() { self.options.buttonPrevCallback(self, this, p); });
                this.buttonPrev[0].jcarouselstate = p;
            }
        },

        notify: function(evt) {
            var state = this.prevFirst == null ? 'init' : (this.prevFirst < this.first ? 'next' : 'prev');

            // Load items
            this.callback('itemLoadCallback', evt, state);

            if (this.prevFirst != this.first) {
                this.callback('itemFirstInCallback', evt, state, this.first);
                this.callback('itemFirstOutCallback', evt, state, this.prevFirst);
            }

            if (this.prevLast != this.last) {
                this.callback('itemLastInCallback', evt, state, this.last);
                this.callback('itemLastOutCallback', evt, state, this.prevLast);
            }

            this.callback('itemVisibleInCallback', evt, state, this.first, this.last, this.prevFirst, this.prevLast);
            this.callback('itemVisibleOutCallback', evt, state, this.prevFirst, this.prevLast, this.first, this.last);
        },

        callback: function(cb, evt, state, i1, i2, i3, i4) {
            if (this.options[cb] == undefined || (typeof this.options[cb] != 'object' && evt != 'onAfterAnimation'))
                return;

            var callback = typeof this.options[cb] == 'object' ? this.options[cb][evt] : this.options[cb];

            if (!$.isFunction(callback))
                return;

            var self = this;

            if (i1 === undefined)
                callback(self, state, evt);
            else if (i2 === undefined)
                this.get(i1).each(function() { callback(self, this, i1, state, evt); });
            else {
                for (var i = i1; i <= i2; i++)
                    if (!(i >= i3 && i <= i4))
                        this.get(i).each(function() { callback(self, this, i, state, evt); });
            }
        },

        create: function(i) {
            return this.format('<li></li>', i);
        },

        format: function(e, i) {
            var $e = $(e).addClass(this.className('jcarousel-item')).addClass(this.className('jcarousel-item-' + i));
            $e.attr('jcarouselindex', i);
            return $e;
        },

        className: function(c) {
            return c + ' ' + c + (!this.options.vertical ? '-horizontal' : '-vertical');
        },

        dimension: function(e, d) {
            var el = e.jquery != undefined ? e[0] : e;

            var old = !this.options.vertical ?
                el.offsetWidth + $jc.margin(el, 'marginLeft') + $jc.margin(el, 'marginRight') :
                el.offsetHeight + $jc.margin(el, 'marginTop') + $jc.margin(el, 'marginBottom');

            if (d == undefined || old == d)
                return old;

            var w = !this.options.vertical ?
                d - $jc.margin(el, 'marginLeft') - $jc.margin(el, 'marginRight') :
                d - $jc.margin(el, 'marginTop') - $jc.margin(el, 'marginBottom');

            $(el).css(this.wh, w + 'px');

            return this.dimension(el);
        },

        clipping: function() {
            return !this.options.vertical ?
                this.clip[0].offsetWidth - $jc.intval(this.clip.css('borderLeftWidth')) - $jc.intval(this.clip.css('borderRightWidth')) :
                this.clip[0].offsetHeight - $jc.intval(this.clip.css('borderTopWidth')) - $jc.intval(this.clip.css('borderBottomWidth'));
        },

        index: function(i, s) {
            if (s == undefined)
                s = this.options.size;

            return Math.round((((i-1) / s) - Math.floor((i-1) / s)) * s) + 1;
        }
    });

    $jc.extend({
        /**
         * Sets the global default configuration properties.
         *
         * @name defaults
         * @descr Sets the global default configuration properties.
         * @type undefined
         * @param Hash d A set of key/value pairs to set as configuration properties.
         * @cat Plugins/jCarousel
         */
        defaults: function(d) {
            $.extend(defaults, d);
        },

        margin: function(e, p) {
            if (!e)
                return 0;

            var el = e.jquery != undefined ? e[0] : e;

            if (p == 'marginRight' && $.browser.safari) {
                var old = {'display': 'block', 'float': 'none', 'width': 'auto'}, oWidth, oWidth2;

                $.swap(el, old, function() { oWidth = el.offsetWidth; });

                old['marginRight'] = 0;
                $.swap(el, old, function() { oWidth2 = el.offsetWidth; });

                return oWidth2 - oWidth;
            }

            return $jc.intval($.css(el, p));
        },

        intval: function(v) {
            v = parseInt(v);
            return isNaN(v) ? 0 : v;
        }
    });

})(jQuery);
/*
 * n2menu 0.10 - Copyright (c) 2007 Cristian Libardo
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * Usage example:
 *
 *	<script type="text/javascript" src="/Js/jquery-1.1.3.1.pack.js"></script>
 *	<script type="text/javascript" src="/Js/n2menu.js"></script>
 * 	<script type="text/javascript">
 *		$(document).ready(function(){
 *			$("#myMenuRootId").n2menu();
 *		});
 *	</script>
 *
 *	<!-- the unordered list defines the menu structure -->
 *	
 *	<ul id='myMenuRootId'>
 *		<li>
 *			<a href="#">just a link</>
 *			<ul>
 *				<!-- this is a submenu, when expanded it's moved below the topmost ul -->
 *				<li>...</li>
 *			</ul>
 *		</li>
 *		<li><a href="#">just another link</></li>
 *	</ul>
 *
 *	<!-- expanded submenues are moved here -->
 *	
 */

(function($){
    $.fn.n2menu = function(options) {
        for(var i=0; i<this.length; ++i){
            var menuRoot = this.get(i);

            // defaults
            menuRoot.n2m = {
                delay: 333,
                container: null,
                current: null,
                expandTo: ".current"
            };
            if(options) {
                $.extend(menuRoot.n2m, options);
            }
            if(!menuRoot.n2m.container)
                menuRoot.n2m.container = $(menuRoot).wrap("<div class='n2menu'></div>").parent().get(0);


            var initBranchRecursive = function(el, trail){
	            el.container = menuRoot.n2m.container;
	            var q = $(el);
	            if(q.is("ul")){
		            trail.push(el);
		            el.level = trail.length;
		            el.excludes = trail.slice();
		            q.addClass("level" + el.level);
		            initExpansion(q);
	            }
	            q.children().each( function(){
		            initBranchRecursive(this, trail);
	            });
	            if(q.is("ul"))
		            trail.pop();
	            if(q.is(menuRoot.n2m.expandTo))
		            menuRoot.n2m.current = q.get(0);
            }


            var initExpansion = function(ulQ){
	            var liQ = ulQ.parent();
	            if(!liQ.is(".n2menu"))
	            {
		            var li = liQ.get(0);
		            var ul = ulQ.get(0);
		            li.opens = ul;
		            ul.opener = li;
		            liQ.addClass("expandable").hover(onMouseOver, onMouseOut);
	            }
            }
            
            
            var onMouseOver = function(){
	            var li = this;
	            var q = $(li);
	            q.addClass("hover");
	            if(menuRoot.n2m.delay > 0) {
		            setTimeout(function(){
			            if(q.is(".hover")){
				            removePreviouslyExpanded(q);
				            expand(q);
			            }
		            }, menuRoot.n2m.delay);
	            }
	            else {
		            removePreviouslyExpanded(q);
		            expand(q);
	            }
            }
            	    
            	    
            var onMouseOut = function(){
	            $(this).removeClass("hover");
            }
            
            
            var expand = function(q){
	            var li = q.get(0);
	            if(li.opens){
		            $(li.opens).remove().appendTo(li.container).addClass("subMenu");
		            q.addClass("expanded");
	            }
            }


            var removePreviouslyExpanded = function(q){
	            var li = q.get(0);
	            $(li.container).children(".subMenu").not(li.opens.excludes).each(function(){
		            var ul = this;
		            $(ul).removeClass("subMenu").remove().appendTo(ul.opener);
		            $(ul.opener).removeClass("expanded");
	            });
            }
            
            
            var expandToCurrentRecursive = function(q){
	            if(q.is(".n2menu"))
		            return;
	            else if (q.is("ul")) {
		            expandToCurrentRecursive(q.parent());
	            } else if (q.is("li")) {
		            expandToCurrentRecursive(q.parent());
		            expand(q);
		            q.addClass("trail");
	            } else
		            return;
            }


            var init = function(menuContainer){
	            $(menuContainer).each(function(){
		            var excludes = new Array();
    		        
		            initBranchRecursive(menuContainer, excludes);
    		        
		            if(menuRoot.n2m.expandTo != null)
			            expandToCurrentRecursive($(menuRoot.n2m.expandTo));
	            });
	            $(menuContainer).addClass("initialized");
            }

	        init(menuRoot.n2m.container);
        }
    };
})(jQuery);
// startsWith(String)
String.prototype.startsWith = function(strChar)
{
 if (!strChar) {return false;}
 strChar += '';
 var intLength = strChar.length;
 return (this.substr(0, intLength) == strChar);
}


function Set_Cookie( name, value, expires, path, domain, secure ) {
    // set time, it's in milliseconds
    var today = new Date();
    today.setTime( today.getTime() );

    /*
      if the expires variable is set, make the correct 
      expires time, the current script below will set 
      it for x number of days, to make it for hours, b
      delete * 24, for minutes, delete * 60 * 24
    */
    if ( expires )
	{
	    expires = expires * 1000 * 60 * 60 * 24;
	}
    var expires_date = new Date( today.getTime() + (expires) );

    document.cookie = name + "=" +escape( value ) +
	( ( expires ) ? ";expires=" + expires_date.toGMTString() : "" ) + 
	( ( path ) ? ";path=" + path : "" ) + 
	( ( domain ) ? ";domain=" + domain : "" ) +
	( ( secure ) ? ";secure" : "" );
}
	
// this function gets the cookie, if it exists
function Get_Cookie( name ) {
    var start = document.cookie.indexOf( name + "=" );
    var len = start + name.length + 1;
    if ( ( !start ) &&
	 ( name != document.cookie.substring( 0, name.length ) ) )
	{
	    return null;
	}
    if ( start == -1 ) return null;
    var end = document.cookie.indexOf( ";", len );
    if ( end == -1 ) end = document.cookie.length;
    return unescape( document.cookie.substring( len, end ) );
}
	
// this deletes the cookie when called
function Delete_Cookie( name, path, domain ) {
    if ( Get_Cookie( name ) ) document.cookie = name + "=" +
				  ( ( path ) ? ";path=" + path : "") +
				  ( ( domain ) ? ";domain=" + domain : "" ) +
				  ";expires=Thu, 01-Jan-1970 00:00:01 GMT";
}

function URLEncode(plaintext) {
    // The Javascript escape and unescape functions do not correspond
    // with what browsers actually do...
    var SAFECHARS = "0123456789" +					// Numeric
	"ABCDEFGHIJKLMNOPQRSTUVWXYZ" +	// Alphabetic
	"abcdefghijklmnopqrstuvwxyz" +
	"-_.!~*'()";					// RFC2396 Mark characters
    var HEX = "0123456789ABCDEF";

    var encoded = "";
    for (var i = 0; i < plaintext.length; i++ ) {
	var ch = plaintext.charAt(i);
	if (ch == " ") {
	    encoded += "+";				// x-www-urlencoded, rather than %20
	} else if (SAFECHARS.indexOf(ch) != -1) {
	    encoded += ch;
	} else {
	    var charCode = ch.charCodeAt(0);
	    if (charCode > 255) {
		/*	
		  alert( "Unicode Character '" 
		  + ch 
		  + "' cannot be encoded using standard URL encoding.\n" +
		  "(URL encoding only supports 8-bit characters.)\n" +
		  "A space (+) will be substituted." );
		*/
		encoded += "+";
	    } else {
		encoded += "%";
		encoded += HEX.charAt((charCode >> 4) & 0xF);
		encoded += HEX.charAt(charCode & 0xF);
	    }
	}
    } // for

    return encoded;
};







function organizeSelectionStart(th) {
    $(th).addClass("selectionBigItemDrag");
}

function organizeSelectionStop(th) {
    $(th).removeClass("selectionBigItemDrag");
}

function organizePlay(id) {
    $("#videoZone").empty();
    var nb = id.substr(12, id.length - 12)
    $("#videoZone").append($('<a id="organizeMedia" href="http://www.tourteaser.com/videos/fs/tourteaser_wiki' + nb + 'small.mp4"></a>'));

    $("#organizeMedia").media({width: 320,
			       height:255, 
			       autoplay: true, 
			       cls:'inlineDivOrganize',
			       params: {scale: '1.0'},
			       style:  {display:'inline'}
                              });
}

function organizeSelectionAdd(marker, absid, videoid, img, descr) {
    var myDiv = $('<div class="selectionBigItemDiv"></div>');
    
    myDiv.append($('<img class="selectionBigItemMovie" src="'+ img + '" width="125" height="105"/>'));
    myDiv.append($('<img src="imgs/draggable.png" class="selectionBigItemDrag" class="dragHandle" width="15" height="105"/>'));
    myDiv.append($('<a href="javascript:selectionRemove(\'' + absid + '\')"><img class="selectRemove" src="imgs/remove.png"/></a>'));
    myDiv.append($('<div class="selectionBigItemTitle">' + descr + ' <br/><a href="javascript:organizePlay(\'' + videoid + '\')"><img class = "organizePlayImage" src="imgs/organizePlayTr.png"/></a></div>'));
    var myLi = $('<li class="selection" id="selection_' + absid + '"></li>');
    myLi.append(myDiv);
    $('#sortable1').append(myLi).SortableAddItem(document.getElementById("selection_" + absid))

}

function organizeSelectionRemove(absid) {
    $("#selection_" + absid).remove();
}

function organizeSelectionClear() {
    $(".selection").remove();
}

function organizeSelectionLoad() {
    $('#sortable1').Sortable({
	accept : 'sortableitem',
	    activeclass : 'sortableactive',
	    hoverclass : 'sortablehover',
	    helperclass : 'sorthelper',
	    opacity: 	0.5,
	    fit :	false,
	    onStart: organizeSelectionStart,
	    onStop : organizeSelectionStop,
	    axis: 'vertically'
	    });
}
function getState() {
    serial = $.SortSerialize('sortable1');
    alert(serial);
}
/*==================================================*
 $Id: slideshow.js,v 1.16 2003/10/14 12:39:00 pat Exp $
 Copyright 2000-2003 Patrick Fitzgerald
 http://slideshow.barelyfitz.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 2 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, write to the Free Software
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *==================================================*/

// There are two objects defined in this file:
// "slide" - contains all the information for a single slide
// "slideshow" - consists of multiple slide objects and runs the slideshow

//==================================================
// slide object
//==================================================
function slide(src,link,text,target,attr) {
  // This is the constructor function for the slide object.
  // It is called automatically when you create a new slide object.
  // For example:
  // s = new slide();

  // Image URL
  this.src = src;

  // Link URL
  this.link = link;

  // Text to display
  this.text = text;

  // Name of the target window ("_blank")
  this.target = target;

  // Custom duration for the slide, in milliseconds.
  // This is an optional parameter.
  // this.timeout = 3000

  // Attributes for the target window:
  // width=n,height=n,resizable=yes or no,scrollbars=yes or no,
  // toolbar=yes or no,location=yes or no,directories=yes or no,
  // status=yes or no,menubar=yes or no,copyhistory=yes or no
  // Example: "width=200,height=300"
  this.attr = attr;

  // Create an image object for the slide
  if (document.images) {
    this.image = new Image();
  }

  // Flag to tell when load() has already been called
  this.loaded = false;

  //--------------------------------------------------
  this.load = function() {
    // This method loads the image for the slide

    if (!document.images) { return; }

    if (!this.loaded) {
      this.image.src = this.src;
      this.loaded = true;
    }
  }

  //--------------------------------------------------
  this.hotlink = function() {
    // This method jumps to the slide's link.
    // If a window was specified for the slide, then it opens a new window.

    var mywindow;

    // If this slide does not have a link, do nothing
    if (!this.link) return;

    // Open the link in a separate window?
    if (this.target) {

      // If window attributes are specified,
      // use them to open the new window
      if (this.attr) {
        mywindow = window.open(this.link, this.target, this.attr);
  
      } else {
        // If window attributes are not specified, do not use them
        // (this will copy the attributes from the originating window)
        mywindow = window.open(this.link, this.target);
      }

      // Pop the window to the front
      if (mywindow && mywindow.focus) mywindow.focus();

    } else {
      // Open the link in the current window
      location.href = this.link;
    }
  }
}

//==================================================
// slideshow object
//==================================================
function slideshow( slideshowname ) {
  // This is the constructor function for the slideshow object.
  // It is called automatically when you create a new object.
  // For example:
  // ss = new slideshow("ss");

  // Name of this object
  // (required if you want your slideshow to auto-play)
  // For example, "SLIDES1"
  this.name = slideshowname;

  // When we reach the last slide, should we loop around to start the
  // slideshow again?
  this.repeat = true;

  // Number of images to pre-fetch.
  // -1 = preload all images.
  //  0 = load each image is it is used.
  //  n = pre-fetch n images ahead of the current image.
  // I recommend preloading all images unless you have large
  // images, or a large amount of images.
  this.prefetch = -1;

  // IMAGE element on your HTML page.
  // For example, document.images.SLIDES1IMG
  this.image;

  // ID of a DIV element on your HTML page that will contain the text.
  // For example, "slides2text"
  // Note: after you set this variable, you should call
  // the update() method to update the slideshow display.
  this.textid;

  // TEXTAREA element on your HTML page.
  // For example, document.SLIDES1FORM.SLIDES1TEXT
  // This is a depracated method for displaying the text,
  // but you might want to supply it for older browsers.
  this.textarea;

  // Milliseconds to pause between slides.
  // Individual slides can override this.
  this.timeout = 3000;

  // Hook functions to be called before and after updating the slide
  // this.pre_update_hook = function() { }
  // this.post_update_hook = function() { }

  // These are private variables
  this.slides = new Array();
  this.current = 0;
  this.timeoutid = 0;

  //--------------------------------------------------
  // Public methods
  //--------------------------------------------------
  this.add_slide = function(slide) {
    // Add a slide to the slideshow.
    // For example:
    // SLIDES1.add_slide(new slide("s1.jpg", "link.html"))
  
    var i = this.slides.length;
  
    // Prefetch the slide image if necessary
    if (this.prefetch == -1) {
      slide.load();
    }

    this.slides[i] = slide;
  }

  //--------------------------------------------------
  this.play = function(timeout) {
    // This method implements the automatically running slideshow.
    // If you specify the "timeout" argument, then a new default
    // timeout will be set for the slideshow.
  
    // Make sure we're not already playing
    this.pause();
  
    // If the timeout argument was specified (optional)
    // then make it the new default
    if (timeout) {
      this.timeout = timeout;
    }
  
    // If the current slide has a custom timeout, use it;
    // otherwise use the default timeout
    if (typeof this.slides[ this.current ].timeout != 'undefined') {
      timeout = this.slides[ this.current ].timeout;
    } else {
      timeout = this.timeout;
    }

    // After the timeout, call this.loop()
    this.timeoutid = setTimeout( this.name + ".loop()", timeout);
  }

  //--------------------------------------------------
  this.pause = function() {
    // This method stops the slideshow if it is automatically running.
  
    if (this.timeoutid != 0) {

      clearTimeout(this.timeoutid);
      this.timeoutid = 0;

    }
  }

  //--------------------------------------------------
  this.update = function() {
    // This method updates the slideshow image on the page

    // Make sure the slideshow has been initialized correctly
    if (! this.valid_image()) { return; }
  
    // Call the pre-update hook function if one was specified
    if (typeof this.pre_update_hook == 'function') {
      this.pre_update_hook();
    }

    // Convenience variable for the current slide
    var slide = this.slides[ this.current ];

    // Determine if the browser supports filters
    var dofilter = false;
    if (this.image &&
        typeof this.image.filters != 'undefined' &&
        typeof this.image.filters[0] != 'undefined') {

      dofilter = true;

    }

    // Load the slide image if necessary
    slide.load();
  
    // Apply the filters for the image transition
    if (dofilter) {

      // If the user has specified a custom filter for this slide,
      // then set it now
      if (slide.filter &&
          this.image.style &&
          this.image.style.filter) {

        this.image.style.filter = slide.filter;

      }
      this.image.filters[0].Apply();
    }

    // Update the image.
    this.image.src = slide.image.src;

    // Play the image transition filters
    if (dofilter) {
      this.image.filters[0].Play();
    }

    // Update the text
    this.display_text();

    // Call the post-update hook function if one was specified
    if (typeof this.post_update_hook == 'function') {
      this.post_update_hook();
    }

    // Do we need to pre-fetch images?
    if (this.prefetch > 0) {

      var next, prev, count;

      // Pre-fetch the next slide image(s)
      next = this.current;
      prev = this.current;
      count = 0;
      do {

        // Get the next and previous slide number
        // Loop past the ends of the slideshow if necessary
        if (++next >= this.slides.length) next = 0;
        if (--prev < 0) prev = this.slides.length - 1;

        // Preload the slide image
        this.slides[next].load();
        this.slides[prev].load();

        // Keep going until we have fetched
        // the designated number of slides

      } while (++count < this.prefetch);
    }
  }

  //--------------------------------------------------
  this.goto_slide = function(n) {
    // This method jumpts to the slide number you specify.
    // If you use slide number -1, then it jumps to the last slide.
    // You can use this to make links that go to a specific slide,
    // or to go to the beginning or end of the slideshow.
    // Examples:
    // onClick="myslides.goto_slide(0)"
    // onClick="myslides.goto_slide(-1)"
    // onClick="myslides.goto_slide(5)"
  
    if (n == -1) {
      n = this.slides.length - 1;
    }
  
    if (n < this.slides.length && n >= 0) {
      this.current = n;
    }
  
    this.update();
  }


  //--------------------------------------------------
  this.goto_random_slide = function(include_current) {
    // Picks a random slide (other than the current slide) and
    // displays it.
    // If the include_current parameter is true,
    // then 
    // See also: shuffle()

    var i;

    // Make sure there is more than one slide
    if (this.slides.length > 1) {

      // Generate a random slide number,
      // but make sure it is not the current slide
      do {
        i = Math.floor(Math.random()*this.slides.length);
      } while (i == this.current);
 
      // Display the slide
      this.goto_slide(i);
    }
  }


  //--------------------------------------------------
  this.next = function() {
    // This method advances to the next slide.

    // Increment the image number
    if (this.current < this.slides.length - 1) {
      this.current++;
    } else if (this.repeat) {
      this.current = 0;
    }

    this.update();
  }


  //--------------------------------------------------
  this.previous = function() {
    // This method goes to the previous slide.
  
    // Decrement the image number
    if (this.current > 0) {
      this.current--;
    } else if (this.repeat) {
      this.current = this.slides.length - 1;
    }
  
    this.update();
  }


  //--------------------------------------------------
  this.shuffle = function() {
    // This method randomly shuffles the order of the slides.

    var i, i2, slides_copy, slides_randomized;

    // Create a copy of the array containing the slides
    // in sequential order
    slides_copy = new Array();
    for (i = 0; i < this.slides.length; i++) {
      slides_copy[i] = this.slides[i];
    }

    // Create a new array to contain the slides in random order
    slides_randomized = new Array();

    // To populate the new array of slides in random order,
    // loop through the existing slides, picking a random
    // slide, removing it from the ordered list and adding it to
    // the random list.

    do {

      // Pick a random slide from those that remain
      i = Math.floor(Math.random()*slides_copy.length);

      // Add the slide to the end of the randomized array
      slides_randomized[ slides_randomized.length ] =
        slides_copy[i];

      // Remove the slide from the sequential array,
      // so it cannot be chosen again
      for (i2 = i + 1; i2 < slides_copy.length; i2++) {
        slides_copy[i2 - 1] = slides_copy[i2];
      }
      slides_copy.length--;

      // Keep going until we have removed all the slides

    } while (slides_copy.length);

    // Now set the slides to the randomized array
    this.slides = slides_randomized;
  }


  //--------------------------------------------------
  this.get_text = function() {
    // This method returns the text of the current slide
  
    return(this.slides[ this.current ].text);
  }


  //--------------------------------------------------
  this.get_all_text = function(before_slide, after_slide) {
    // Return the text for all of the slides.
    // For the text of each slide, add "before_slide" in front of the
    // text, and "after_slide" after the text.
    // For example:
    // document.write("<ul>");
    // document.write(s.get_all_text("<li>","\n"));
    // document.write("<\/ul>");
  
    all_text = "";
  
    // Loop through all the slides in the slideshow
    for (i=0; i < this.slides.length; i++) {
  
      slide = this.slides[i];
    
      if (slide.text) {
        all_text += before_slide + slide.text + after_slide;
      }
  
    }
  
    return(all_text);
  }


  //--------------------------------------------------
  this.display_text = function(text) {
    // Display the text for the current slide
  
    // If the "text" arg was not supplied (usually it isn't),
    // get the text from the slideshow
    if (!text) {
      text = this.slides[ this.current ].text;
    }
  
    // If a textarea has been specified,
    // then change the text displayed in it
    if (this.textarea && typeof this.textarea.value != 'undefined') {
      this.textarea.value = text;
    }

    // If a text id has been specified,
    // then change the contents of the HTML element
    if (this.textid) {

      r = this.getElementById(this.textid);
      if (!r) { return false; }
      if (typeof r.innerHTML == 'undefined') { return false; }

      // Update the text
      r.innerHTML = text;
    }
  }


  //--------------------------------------------------
  this.hotlink = function() {
    // This method calls the hotlink() method for the current slide.
  
    this.slides[ this.current ].hotlink();
  }


  //--------------------------------------------------
  this.save_position = function(cookiename) {
    // Saves the position of the slideshow in a cookie,
    // so when you return to this page, the position in the slideshow
    // won't be lost.
  
    if (!cookiename) {
      cookiename = this.name + '_slideshow';
    }
  
    document.cookie = cookiename + '=' + this.current;
  }


  //--------------------------------------------------
  this.restore_position = function(cookiename) {
  // If you previously called slideshow_save_position(),
  // returns the slideshow to the previous state.
  
    //Get cookie code by Shelley Powers
  
    if (!cookiename) {
      cookiename = this.name + '_slideshow';
    }
  
    var search = cookiename + "=";
  
    if (document.cookie.length > 0) {
      offset = document.cookie.indexOf(search);
      // if cookie exists
      if (offset != -1) { 
        offset += search.length;
        // set index of beginning of value
        end = document.cookie.indexOf(";", offset);
        // set index of end of cookie value
        if (end == -1) end = document.cookie.length;
        this.current = parseInt(unescape(document.cookie.substring(offset, end)));
        }
     }
  }


  //--------------------------------------------------
  this.noscript = function() {
    // This method is not for use as part of your slideshow,
    // but you can call it to get a plain HTML version of the slideshow
    // images and text.
    // You should copy the HTML and put it within a NOSCRIPT element, to
    // give non-javascript browsers access to your slideshow information.
    // This also ensures that your slideshow text and images are indexed
    // by search engines.
  
    $html = "\n";
  
    // Loop through all the slides in the slideshow
    for (i=0; i < this.slides.length; i++) {
  
      slide = this.slides[i];
  
      $html += '<P>';
  
      if (slide.link) {
        $html += '<a href="' + slide.link + '">';
      }
  
      $html += '<img src="' + slide.src + '" ALT="slideshow image">';
  
      if (slide.link) {
        $html += "<\/a>";
      }
  
      if (slide.text) {
        $html += "<BR>\n" + slide.text;
      }
  
      $html += "<\/P>" + "\n\n";
    }
  
    // Make the HTML browser-safe
    $html = $html.replace(/\&/g, "&amp;" );
    $html = $html.replace(/</g, "&lt;" );
    $html = $html.replace(/>/g, "&gt;" );
  
    return('<pre>' + $html + '</pre>');
  }


  //==================================================
  // Private methods
  //==================================================

  //--------------------------------------------------
  this.loop = function() {
    // This method is for internal use only.
    // This method gets called automatically by a JavaScript timeout.
    // It advances to the next slide, then sets the next timeout.
    // If the next slide image has not completed loading yet,
    // then do not advance to the next slide yet.

    // Make sure the next slide image has finished loading
    if (this.current < this.slides.length - 1) {
      next_slide = this.slides[this.current + 1];
      if (next_slide.image.complete == null || next_slide.image.complete) {
        this.next();
      }
    } else { // we're at the last slide
      this.next();
    }
    
    // Keep playing the slideshow
    this.play( );
  }


  //--------------------------------------------------
  this.valid_image = function() {
    // Returns 1 if a valid image has been set for the slideshow
  
    if (!this.image)
    {
      return false;
    }
    else {
      return true;
    }
  }

  //--------------------------------------------------
  this.getElementById = function(element_id) {
    // This method returns the element corresponding to the id

    if (document.getElementById) {
      return document.getElementById(element_id);
    }
    else if (document.all) {
      return document.all[element_id];
    }
    else if (document.layers) {
      return document.layers[element_id];
    } else {
      return undefined;
    }
  }
  

  //==================================================
  // Deprecated methods
  // I don't recommend the use of the following methods,
  // but they are included for backward compatibility.
  // You can delete them if you don't need them.
  //==================================================

  //--------------------------------------------------
  this.set_image = function(imageobject) {
    // This method is deprecated; you should use
    // the following code instead:
    // s.image = document.images.myimagename;
    // s.update();

    if (!document.images)
      return;
    this.image = imageobject;
  }

  //--------------------------------------------------
  this.set_textarea = function(textareaobject) {
    // This method is deprecated; you should use
    // the following code instead:
    // s.textarea = document.form.textareaname;
    // s.update();

    this.textarea = textareaobject;
    this.display_text();
  }

  //--------------------------------------------------
  this.set_textid = function(textidstr) {
    // This method is deprecated; you should use
    // the following code instead:
    // s.textid = "mytextid";
    // s.update();

    this.textid = textidstr;
    this.display_text();
  }
}

var panIcon;
var dmIcon;
var addIcon;
var ttIcon;


panIcon = new GIcon();
panIcon.image = "imgs/mapfiles/panoramio-marker.png";
panIcon.shadow = "imgs/mapfiles/panoramio-shadow.png";
panIcon.iconSize = new GSize(18, 18);
panIcon.shadowSize = new GSize(22, 22);
panIcon.iconAnchor = new GPoint(9, 9);
panIcon.infoWindowAnchor = new GPoint(9, 0);

dmIcon = new GIcon(G_DEFAULT_ICON);
dmIcon.image = "imgs/mapfiles/dm-marker.png";
dmIcon.shadow = "imgs/mapfiles/dm-shadow.png";
dmIcon.iconSize = new GSize(16, 35);
dmIcon.shadowSize = new GSize(40, 34);
dmIcon.iconAnchor = new GPoint(8, 34);
dmIcon.infoWindowAnchor = new GPoint(8, 4);


addIcon = new GIcon(G_DEFAULT_ICON);
addIcon.image = "imgs/mapfiles/markeradd.png";


ttIcon = new GIcon();
ttIcon.image = "imgs/mapfiles/tt-marker.png";
ttIcon.shadow = "imgs/mapfiles/tt-shadow.png";
ttIcon.iconSize = new GSize(16, 35);
ttIcon.shadowSize = new GSize(40, 34);
ttIcon.iconAnchor = new GPoint(8, 34);
ttIcon.infoWindowAnchor = new GPoint(8, 4);

GNamedMarker.prototype = new GMarker(new GLatLng(0,0));

function GNamedMarker(map, point, name, id) {
    if(!point) {
	point = new GLatLng(0, 0);
    }
    var type = id.substr(0, id.indexOf("/"));
    var icon = G_DEFAULT_ICON;
    var title;
    
    if(type == "dm") {
	icon = dmIcon;
	title = "DailyMotion:" + name;
        this.prefix = "i";
    }
    if(type == "wikipedia") {
	icon = ttIcon;
	title = "Wikipedia:" + name;
        this.prefix = "i";
    }

    GMarker.call(this, point, {draggable: false, icon:icon, clickable: true, title:title});
    this.point = point;
    this.name         = name;
    this.id           = id;
    this.clickhandler = GEvent.addListener(this, 'click', this.openMyInfoWindow);
    this.clickhandler = GEvent.addListener(this, 'infowindowclose', this.closeMyInfoWindow);

    if(map) {
	this.map = map;
	map.addOverlay(this);
	if(!map.isVisible(type, this.id)) {
	    this.hide();
	}
    }
}


GPanoramioMarker.prototype = new GMarker(new GLatLng(0,0));

function GPanoramioMarker(map, point, name, id, photo) {
    GMarker.call(this, point, {draggable: false, icon:panIcon, clickable: true, title:"Panoramio:" + name});

    //	GMarker.call(this, point, {draggable: false});

    this.point        = point;
    this.name         = name;
    this.photo 	  = photo;
    this.id           = "panoramio/" + id; 
    this.prefix = "e";
    this.clickhandler = GEvent.addListener(this, 'click', this.openMyInfoWindow);
    this.map = map;

    var type = "panoramio";
    map.addOverlay(this);
    if(!map.isVisible(type, this.id)) {
	this.hide();
    }

}

function setSlides() {
    if (document.images)	{
	SLIDES.set_image(document.images.SLIDESIMG);
	SLIDES.set_textid("SLIDESTEXT"); // optional
	SLIDES.update();
	SLIDES.play(); //optional
    }
}

GNamedMarker.prototype.updateVisibility = function()  { 
    var id = this.id;
    var type = id.substr(0, id.indexOf("/"));
    if(this.map.isVisible(type, this.id)) {
	this.show();
    } else {
	this.hide();
    }
}

function itemFind(id) {
    var item = mapSelect.markerFind(id);
    if(item) {
	item.itemSelect();
    }
}

function infowindowHeader(marker, exportable) {
   var v = "<div><div id='iwtoolbar'><a href='javascript:itemFind(\"" + marker.prefix + marker.id + "\")'><img src='imgs/selectButton.png'/></a>  ";
/*   v += "<a href='javascript:exportAbout()' class='" + (exportable ? "e" : "nonE");
   v += "xportable'>(export ";
*/
/*   v += "(export ";
   v += exportable ? "" : "un";
   //v += "available)</a></div></div>";
   v += "available)</div></div>";*/
   v += "</div></div>";
   return v;
}

GNamedMarker.prototype.itemSelect = function() {
    selectionAdd(this, this.prefix, this.id, this.img, this.name, this.videoid ? this.videoid : "");
} 

GNamedMarker.prototype.wikipediaParseInfo = function(data) {
    var xmlP = GXml.parse(data);	
    var pt = xmlP.documentElement;
    var imgs = xmlP.documentElement.getElementsByTagName("image");
    
    this.loaded = true;
    this.videoid = pt.getAttribute("id");
    this.name = pt.getAttribute("title");
    var latlng = this.getLatLng();

    if(latlng.lat() == 0 && latlng.lng() == 0) {
	this.setLatLng(new GLatLng(pt.getAttribute("lat"), pt.getAttribute("lng")));
    }	       

    var maxHeight = 0;
    for (var i = 0; i < imgs.length; i++) {	
	var src = imgs[i].getAttribute("file");       
	var w = imgs[i].getAttribute("wt");
	var h = imgs[i].getAttribute("ht");
	var d = imgs[i].getAttribute("htmlDescr");
	var t = imgs[i].getAttribute("textDescr");
	var totalHeight = parseFloat(h) + 20;
	    
	if(totalHeight > maxHeight) {
	    maxHeight = totalHeight;
	}

	var f = "s" + src.substring(2,3) + "/" + src.substring(2,4) + "/" + src;
	f = "http://images.ecosystem.tourteaser.com/thumbs/" + f;
	if(i == 0) {
	    this.img = f;
	}
	this.imgs += {src:f, width:w, height:h, descr:d};
    }
    maxHeight += (this.name.length / 20) * 10 + 5;
    this.maxHeight = maxHeight;
}

GNamedMarker.prototype.wikipediaDownloadInfo = function(callback) {
    if(this.loaded) {
	callback();
	return;
    }
    
    var url = "wikiinfo.php?mode=xml&id=" + this.id;
    var th = this;
    var myfun = function(data, responseCode) {
	th.wikipediaParseInfo(data);
	callback();
    };

    GDownloadUrl(url, myfun);

}

GNamedMarker.prototype.wikipediaInfoWindow = function() {
    var maxHeight = this.maxHeight;
    var title = this.name;
 	       			
    // main table
    var iwdiv = $(infowindowHeader(this, true));
    var tb = $("<table><thead/></table>");
    var h = maxHeight + "px"
    tb.attr({width : "200px", height : h , padding: "5px", width : "205px"});				
    var tbod = $("<tbody/>");

    var titleRow =  $("<tr/>");
    var titleTDText = "<td><div><b><a target=\"_blank\" href=\"http://en.wikipedia.org/wiki/" + title +"\">" + title + "\<\/b></a><br/>";
/*    var imageText = "image" + (this.imgs.length > 1 ? "s" : "");				
    if(this.imgs.length == 0) {
	titleTDText += "(No image found)<br/></div></td>";		
    } else {
	titleTDText += "(" + this.imgs.length + "&nbsp;" + imageText + ")<br/></div></td>";		
    } 
*/
    var titleTD = $(titleTDText);
    titleTD.attr({valign:"top"});				
    titleRow.append(titleTD);
    tbod.append(titleRow);
    if(this.imgs.length != 0) {		
	var imgRow = $("<tr/>");
	var imgTD = $("<td/>");
			
	imgTD.attr({align: "center", valign :"top"});			
	/*	var imgA = $("<a/>");
	imgA.attr({href: "javascript:SLIDES.hotlink()"});
	*/
	var imgImg = $("<img/>");
	var imgSrc = this.img;
	imgImg.attr({src: imgSrc, border:"0px"});
	/*
	imgImg.attr({id:"SLIDESIMG", src: imgSrc, border:"0px"});
	imgA.append(imgImg);
	imgTD.append(imgA);
	*/
	imgTD.append(imgImg);
	imgRow.append(imgTD);
	tbod.append(imgRow);
		
	var legendRow =  $("<tr/>");
	var legendTD = $("<td/>");
	legendTD.attr({valign: "top"});

	var legendDiv = $("<div/>");
	legendDiv.attr({id: "SLIDESTEXT"});
					
	legendTD.append(legendDiv);				
	legendRow.append(legendTD);
	tbod.append($(legendRow));
    }
    tb.append(tbod);
    iwdiv.append(tb);

    this.openInfoWindow(iwdiv[0]);

    videoToolOpen(this, this.prefix, this.id, this.img, this.name, this.videoid);
}



GNamedMarker.prototype.dailymotionInfoWindow = function(data, responseCode) {
    var header = infowindowHeader(this,false);
    this.openInfoWindowHtml(header + data);
}



GNamedMarker.prototype.openMyInfoWindow = function()  {
    this.openInfoWindowHtml("Loading...");
	
    if(this.id.startsWith("wikipedia/")) {
	this.wikipediaDownloadInfo(this.wikipediaInfoWindow.bind(this));
	return;
    } 
    
    if(this.id.startsWith("dm/")) {
	var url = "dminfo.php?mode=xml&id=" + this.id;
	var th = this;
	GDownloadUrl(url, function(data, responseCode) {
	    th.dailymotionInfoWindow(data, responseCode);
	});
	return;
    }

}

GNamedMarker.prototype.closeMyInfoWindow = function()  {
  videoToolClose();
}

GPanoramioMarker.prototype.updateVisibility = function()  {
    var type = "panoramio";
    if(this.map.isVisible(type, this.id)) {
	this.show();
    } else {
	this.hide();
    }
}


GPanoramioMarker.prototype.itemSelect = function() {
    var p = this.photo;
    var img = "http://www.panoramio.com/photos/small/" + p.photo_id;
    selectionAdd(this, this.prefix, this.id, img, p.photo_title);
} 


GPanoramioMarker.prototype.openMyInfoWindow = function()  {
    var p = this.photo;
    var header = infowindowHeader(this, false);
    
    this.openInfoWindowHtml(header + 
			    "<div id='pano_infowin'>" +
			    "<p><a href='http://www.panoramio.com/' target='_blank'><img src='http://www.panoramio.com/img/logo-small.gif' width='119px' height='25px' alt='Panoramio logo' /><\/a></p>" +
			    "<a id='pano_photo_infowin'  target='_blank' href='http://www.panoramio.com/photo/" + p.photo_id + "'>" +
			    "<img width='240' height='155' src='http://www.panoramio.com/photos/small/" + p.photo_id + ".jpg'/><\/a>" +
			    "<div style='overflow: hidden; width: 240px;'>" +
			    "<p><a target='_blank' class='pano_photo_title' href='http://www.panoramio.com/photo/" + p.photo_id +
			    "'><strong>" + p.photo_title + "<\/strong><\/a></p>" +
			    "<p>Posted by <a target='_blank' href='http://www.panoramio.com/user/" + p.owner_id + "'>" +
			    p.owner_name + "<\/a></p><\/div>" +
			    "<\/div>");

};


// Creates a marker at the given point with the given number label
function createMarker(map, point, name, id) {
    return new GNamedMarker(map, point, name, id);
}


// Creates a marker at the given point with the given number label
function createPanoramioMarker(map, point, name, id, photo) {
    return new GPanoramioMarker(map, point, name, id, photo);
}

/*--------------------------------------------------------------------------*/
//From prototype library
var Class = {
  create: function() {
    return function() {
      this.initialize.apply(this, arguments);
    }
  }
}

var $A = Array.from = function(iterable) {
  if (!iterable) return [];
  if (iterable.toArray) {
    return iterable.toArray();
  } else {
    var results = [];
    for (var i = 0, length = iterable.length; i < length; i++)
      results.push(iterable[i]);
    return results;
  }
}

Function.prototype.bind = function() {
  var __method = this, args = $A(arguments), object = args.shift();
  return function() {
    return __method.apply(object, args.concat($A(arguments)));
  }
}

var PeriodicalExecuter = Class.create();
PeriodicalExecuter.prototype = {
  initialize: function(callback, frequency) {
    this.callback = callback;
    this.frequency = frequency;
    this.currentlyExecuting = false;

    this.registerCallback();
  },

  registerCallback: function() {
    this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
  },

  stop: function() {
    if (!this.timer) return;
    clearInterval(this.timer);
    this.timer = null;
  },

  onTimerEvent: function() {
    if (!this.currentlyExecuting) {
      try {
        this.currentlyExecuting = true;
        this.callback(this);
      } finally {
        this.currentlyExecuting = false;
      }
    }
  }
}

// --------------------------------------------------------------
// Icon for the red square displayed with the mouse wheel zoom
var baseIcon;

var rectIcon

if(GIcon) {
  baseIcon = new GIcon();
  baseIcon.iconSize=new GSize(100,100);
  baseIcon.iconAnchor=new GPoint(50,50);
  rectICon = new GIcon(baseIcon, "/imgs/rect.png", null);
}


// namespace placeholder
Heritage = {};

/**
 * A function used to extend one class with another
 * 
 * @param {Object} subClass
 * 		The inheriting class, or subclass
 * @param {Object} baseClass
 * 		The class from which to inherit
 */
Heritage.extend = function(subClass, baseClass) {
    function inheritance() {}
    inheritance.prototype = baseClass.prototype;

    subClass.prototype = new inheritance();
    subClass.prototype.constructor = subClass;
    subClass.baseConstructor = baseClass;
    subClass.superClass = baseClass.prototype;
}

// subclass GXMap
Heritage.extend(GXMap, GMap2);

function msSinceEpoch() {
	var date = new Date();
	return date.getTime();
}

function GXMap(container, serverUrl, center, zoom) {
    GXMap.baseConstructor.call(this, container);

    this.container = container;
    this.serverUrl = serverUrl;
    this.setCenter(center, zoom);

    this.latmin0 = 0;
    this.latmax0 = 0;
    this.lngmin0 = 0;
    this.lngmax0 = 0;
    this.markerCount = 0;
    this.markerArray = Object(); /* never use an Array as an associative array, this is broken by the prototype library */

    this.visibleLayer = Object(); /* used to store show/hide state of different point types */
	
    this.visibleLayer["dm"] = true;
    this.visibleLayer["wikipedia"] = true;
    this.visibleLayer["panoramio"] = true;
    this.visibleLayer["selection"] = true;

    this.enableContinuousZoom();
    this.enableDoubleClickZoom(); 
    this.wheelZooming = false;
    var th = this;
    GEvent.addDomListener(this.container, "DOMMouseScroll", function(event) { th.wheelZoom(event); });
    GEvent.addDomListener(this.container, "mousewheel", function(event) { th.wheelZoom(event); });

    GEvent.addListener(this, 'mousemove', this.mouseMove);
    GEvent.addListener(this, 'moveend', this.loadPoints);
    GEvent.addListener(this, 'zoomend', this.loadPoints);

    var ovcontrol = new GOverviewMapControl(new GSize(165,165));
    this.addControl(ovcontrol);
    var ov_map = ovcontrol.getOverviewMap();
    GEvent.addListener(this, 'maptypechanged', function(){
	ov_map.setMapType(G_NORMAL_MAP);
    });
    this.addControl(new GScaleControl());
    this.addControl(new GLargeMapControl());
    var pt = new GSize(70, 7);
    var controlPos = new GControlPosition(G_ANCHOR_TOP_LEFT, pt);
    this.addControl(new GMapTypeControl(), controlPos);	

    this.full = false;
    this.lastloadTime = msSinceEpoch();
    this.zoneToLoad = this.getBounds();
    this.loadDelay = 1000; // delay between load in ms 

    this.pe = new PeriodicalExecuter(function(pe) {
	var map = this.map;
	if(map && map.zoneToLoad) {
		if((msSinceEpoch() - map.lastLoadTime) > map.loadDelay) {
			map.loadPoints(true);
		}
	}
    }, 0.1); // period of the PeriodicalExecuter
    this.pe.map = this;
}

GXMap.prototype.postInit = function() {
    this.loadPoints(true);
}

GXMap.prototype.setCenter = function(center, zoom)  {
    this.zoom = zoom;
    this.center = center	
    GXMap.superClass.setCenter.call(this, center, zoom);
}


GXMap.prototype.display = function()  {
    this.checkResize();
    var center = this.getCenter();
    var zoom = this.getZoom();
    this.setCenter(center, zoom);
}

var start = msSinceEpoch();

GXMap.prototype.loadStdPoints = function(data, responseCode, latmin1, latmax1, lngmin1, lngmax1) {
    var xml = GXml.parse(data);
    var markers = xml.documentElement.getElementsByTagName("marker");
    var added = 0;
    for (var i = 0; i < markers.length; i++) {
	var latStr = markers[i].getAttribute("lat");
	var lngStr = markers[i].getAttribute("lng");
	var idStr = markers[i].getAttribute("id");
	var title = markers[i].getAttribute("title");
	/*			var title  = GXml.value(markers[i].getElementsByTagName("title")[0]);
				var article  = GXml.value(markers[i].getElementsByTagName("link")[0]);
				var myArray = article.split(/\//);
				article = myArray[myArray.length - 1];
	*/			
	var lat = parseFloat(latStr);
	var lng = parseFloat(lngStr);
	var point = new GLatLng(lat, lng);
	var id = idStr;
	idStr = "i" + idStr;
	if(!(idStr in (this.markerArray))) {
	    var marker = createMarker(this, point, title, id);
	    this.markerArray[idStr] = marker;	
	    this.markerCount++;
	}
	var file = markers[i].getAttribute("file");
	var w = markers[i].getAttribute("w");
	var h = markers[i].getAttribute("h");

	if(imageBar && file && w && h) {
	    file = "http://images.ecosystem.tourteaser.com/thumbs/s" + file.substring(2,3) + "/" + file.substring(2,4) + "/" + file;
		
	    w = parseInt(w);
	    h = parseInt(h);
	    if(imageBar.setImage(added, this.markerArray[idStr], file, w, h)) {
		added++;
	    }
	}
    }
    if(imageBar) {
	imageBar.finish(added);
    }
    imageBar.out_();
    if(latmin1) {
	this.latmin0 = latmin1;
	this.latmax0 = latmax1;
	this.lngmin0 = lngmin1;
	this.lngmax0 = lngmax1;
    }
    //	document.title = "There are " + th.markerCount + " points";	
}


GXMap.prototype.isVisible = function(type, id) {
    if(selection.isSelected(id) && this.visibleLayer["selection"]) {
	return true;
    }
    return this.visibleLayer[type];
}

GXMap.prototype.setVisible = function(type, visible) {
    this.visibleLayer[type] = visible;
}

GXMap.prototype.updateVisibility = function() {
    for(var m  in this.markerArray) {		    
	this.markerArray[m].updateVisibility();
    }
}

GXMap.prototype.markerFind = function(id) {
    return this.markerArray[id];
}

GXMap.prototype.loadPoints = function(full) {
    var lastLoadTime = this.lastLoadTime;
    var time = msSinceEpoch();
    var zoneToLoad = this.getBounds();
    this.zoneToLoad = zoneToLoad;
    if((time - lastLoadTime) < this.loadDelay) {		
	return;
    }
//    $("debugDiv").innerHTML += ("delay : " + (time - this.lastLoadTime) + "<br/>");

    this.lastLoadTime = time;
    this.zoneToLoad = null;

    full = true;
    // download the point data
    var bounds = zoneToLoad;
    var sw = bounds.getSouthWest();
    var ne = bounds.getNorthEast();
    var latmin1 = sw.lat();
    var latmax1 = ne.lat();
    var lngmin1 = sw.lng();
    var lngmax1 = ne.lng();


    this.display();// needed for ie to redraw the map when it was hidden

    if(this.latmin0 == latmin1 && this.latmax0 == latmax1 && this.lngmin0 == lngmin1 && this.lngmax0 == lngmax1) {
	return bounds;
    }
    if(lngmin1 == lngmax1 || latmin1 == latmax1) {
	return bounds;
    }

    if(full) {
	this.latmin0 = 0;
	this.latmax0 = 0;
	this.lngmin0 = 0;
	this.lngmax0 = 0;
    }
    var url = "";
    url += "?latmin0=" + this.latmin0 + "&latmax0=" + this.latmax0 + "&lngmin0=" + this.lngmin0 + "&lngmax0=" + this.lngmax0;
    url += "&latmin1=" + latmin1 + "&latmax1=" + latmax1 + "&lngmin1=" + lngmin1 + "&lngmax1=" + lngmax1 + "&nb=40";
    var th = this;

    GDownloadUrl(this.serverUrl + url, function(data, responseCode) {
	th.loadStdPoints(data, responseCode, latmin1, latmax1, lngmin1, lngmax1);
    }); // end GDownloadUrl

    if(true) {
	GDownloadUrl("panproxy.php" + url, function(data, responseCode) {
	    data = data.replace(/\\\\/g,"\\"); // temporary : fix bug at panoramio.com ?
	    var panData = eval('(' + data + ')'); 
	    var pCount = panData.photos.length;
	    var p;
	    for(p = 0; p < pCount; p++) {
		var photo = panData.photos[p];
		var point = new GLatLng(photo.latitude, photo.longitude);
		
		var idStr = "e" + photo.photo_id;
		if(!(idStr in (th.markerArray))) {		    
		    var marker = createPanoramioMarker(th, point, photo.photo_title, photo.photo_id, photo);
		    th.markerArray[idStr] = marker;	
		    th.markerCount++;
		}
	    }
	});
    }

    for(var m in this.markerArray) {
	var mp = this.markerArray[m];
	if(mp.point) {
	    if(! bounds.contains(mp.point) &&
		! selection.isSelected(mp.id)) {
		this.removeOverlay(mp);
		delete th.markerArray[m];
		this.markerCount--;					
	    }
	}
    }	
//    document.title = "There are " + th.markerCount + " points";	

    return bounds;
}


// Mouse wheel zoom - Event handler -----
GXMap.prototype.wheelZoom = function(event)   {
    if (this.wheelZooming) {
	return;
    }
    this.wheelZooming = true;

    this.zoomRect = new GMarker(this.mouseLatLng,{icon:rectIcon});
    this.addOverlay(this.zoomRect);

    if (event.cancelable) {
	event.preventDefault();
    }

    this.closeInfoWindow(); 
    var th = this;
    if((event.detail || -event.wheelDelta) < 0) {
		   
	window.setTimeout(function(){
	    th.zoomIn(th.mouseLatLng,true,true);
	    th.removeOverlay(th.zoomRect);
	    th.wheelZooming = false;
	},200);
    } 
    else {
	window.setTimeout(function(){
	    th.zoomOut(th.mouseLatLng,true);
	    th.removeOverlay(th.zoomRect);
	    th.wheelZooming = false;
	},200);
    }
    return false; 
}



// Global variables used with the mouse wheel zoom
// Defaults --------------------------------------------

GXMap.prototype.mouseMove = function(mousePt) {
    this.mouseLatLng = mousePt;
    this.zoom = this.getZoom();
}
// End event handler -----



var globalGeocoder = new GClientGeocoder();


ImageBar.prototype = new Object();




function ImageBar(id, count, dir, size) {
    this.container = $("#" + id);
    this.dir = dir;
    this.size = size;
    var i;
    this.count = count;
    for(i = 0; i < count; i++) {
	this.addEmptyImage(i);
    }
    var th = this;
    this.out_(true);
}

ImageBar.prototype.addEmptyImage = function(i) {
    var d = $("<div/>");
    var disp = this.dir == "h" ? "inline" : "block";
    d.css({ display: disp});
    var a = $("<a/>");
    a[0].href = "javascript:imagebarClick(" + i + ")"; 
    
    var im = $("<img/>");
    im[0].className = "imageBarImage";
    im[0].imageBar = this;
    im[0].id = "image" + i;
    a.append(im);
    d.append(a);
    $(this.container).append(d);
}

ImageBar.prototype.setCount = function(count) {
    if(count < this.count) {
	for(i = count; i < this.count; i++) {
	    $(this.imageNth(count)).parent().parent().remove();
	}
	this.count = count;
	this.finish(count);
    } else {
	for(i = this.count; i < count; i++) {
	    this.addEmptyImage(i);
	}
	this.count = count;
	this.finish(count);	
    }
}

ImageBar.prototype.setImage = function(index, marker, src, nWidth, nHeight) { 
    var i;
    if(index >= this.count) {
	return false;
    }

    for(i = 0; i < index; i++) {
	if(this.imageNth(i).src_ == src) {
	    return false;
	}
    }

    var im = this.imageNth(index);
    im.width = 80;
    im.height = 60;
    im.src = src;
    im.src_ = src;
    im.marker_ = marker;
    return true;
}

ImageBar.prototype.finish = function(index) {
    for(i = index; i < this.count; i++) {
	var im = this.imageNth(i);
	im.width = 80;
	im.height = 60;
	im.src = "";
	im.marker_ = "";
    }
    var ibCH = index * 64 - 3;
    $("#imagebarContainer").css("height", ibCH)
}

ImageBar.prototype.imageNth = function(index) {
    var dson = $(this.container).children()[index];
    return $($(dson).children()[0]).children()[0];
}

ImageBar.prototype.over = function(ev) {       
	this.marker_.openMyInfoWindow();

return;


    var im = this; //YAHOO.util.Event.getTarget(ev);
    var imageBar = im.imageBar;
    var dir = imageBar.dir;
    var factor = im.factor;
    var index = im.index;
    var i;
    var tot = 0;
    var tot1 = 0;

    for(i = 0 ; i < 2; i++) {
	var j;

	for(j = 0; j < imageBar.count; j++) {
	    var im1 = imageBar.imageNth(j);
	    var wSize = im1.nWidth / im1.factor;
	    var hSize = im1.nHeight / im1.factor;
	    if(j == index) {
		if(i == 0) {
		    wSize *= 1.0 + factor;	
		    hSize *= 1.0 + factor;
		    im1.wto = wSize;
		    im1.hto = hSize;
		    tot1 += (dir == "h") ? wSize : hSize;
		} else {
			if(tot1 > imageBar.size) {
				im1.wto *= imageBar.size / tot1;
	  		      im1.hto *= imageBar.size / tot1;	
			}
		}
/*	    } else if(j == (index - 1) || (j == index + 1)) {
		if(i == 0) {
		    wSize *= 0.5 + factor * 0.1;
		    hSize *= 0.5 + factor * 0.1;
		    im1.wto = wSize;
		    im1.hto = hSize;
		    tot1 += (dir == "h") ? wSize : hSize;
		} else {
			if(tot1 > imageBar.size) {
				im1.wto *= imageBar.size / tot1;
	  		      im1.hto *= imageBar.size / tot1;
			}
		}
*/
	    } else {
		if(i == 0) {
		    tot += (dir == "h") ? wSize : hSize;
		} else {
		    if(tot1 > imageBar.size) {
			tot1 = imageBar.size;
		    }
		    if(dir == "h")  {
			im1.wto = (wSize * (imageBar.size - tot1)) / tot;
			im1.hto = (hSize * (imageBar.size - tot1)) / tot;
		    } else {
			im1.wto = (wSize * (imageBar.size - tot1)) / tot;
			im1.hto = (hSize * (imageBar.size - tot1)) / tot;
		    }
		}		
	    }	
	}
    }

    //	im.style.margin = "10";
    //	im.style.border = "1";
	
}

ImageBar.prototype.out_ = function(init) {
     var i;
     var tot = 0;
     var dir = this.dir;
     for(i = 0 ; i < 2; i++) {
      var j;	
    	for(j = 0; j < this.count; j++) {
		var im1 = this.imageNth(j);
		var f = im1.nHeight / im1.nWidth;
		var r = (dir == "h") ? (1.0 / f) : f;
		
		if(i == 0){
			tot += r;
		} else {
			if(dir == "h") {
				im1.wto = r * this.size / tot;
				im1.hto = this.size / tot ;	
			} else {
				im1.wto = this.size / tot;
				im1.hto = r * this.size / tot ;	
			}
			if(init) {
				im1.width = im1.wto;
				im1.width0 = im1.width;
				im1.height = im1.hto;
				im1.height0 = im1.height;
			}
		}
    	}
    }	
}
ImageBar.prototype.out = function() {
	var im = this;
	im.imageBar.out_(false);
}


ImageBar.prototype.click = function() {
	this.marker_.openMyInfoWindow();
}

ImageBar.prototype.setSize = function() {
    var container = this.container;
    var dir = this.dir; 
    var size = this.size;
    var i;
    var tot = 0;
    var tot2 = 0;

    for(i = 0 ; i < 2; i++) {
	var j;
	for(j = 0; j < this.count; j++) {
	    var im1 = this.imageNth(j);
	    var wSize = (im1.width0 * 8.0 + im1.wto * 2.0) * 0.1;
	    var hSize = (im1.height0 * 8.0 + im1.hto * 2.0) * 0.1;
	    if(Math.abs(im1.width0 - im1.wto) < 1) {
		wSize = im1.wto;
	     } 

	    if(Math.abs(im1.height0 - im1.hto) < 1) {
		hSize = im1.hto;
	    }

	    if(i == 0) {
		tot += dir == "h" ? wSize : hSize;
	    } else {
		var lastOffset = Math.round(tot2);
		tot2 += dir == "h" ? (wSize * size) /tot : (hSize * size) / tot;
		var newOffset = Math.round(tot2);
		if(dir == "h") {
			im1.height0 = hSize;			
			im1.height = im1.height0;	
			im1.width0 = newOffset - lastOffset;
			im1.width = im1.width0;
		} else {
			im1.height0 = newOffset - lastOffset;
			im1.height = im1.height0;				
			im1.width0 = wSize;
			im1.width = im1.width0;
		}
	    }			
	}
    }
    var th = this;
//    setTimeout(function() {th.setSize();}, 125);
}


    
ItemSelection.prototype = new Object();


function ItemSelection(divClass) {
  this.divClass = divClass;
  this.selectionArray = Object();
}

ItemSelection.prototype.videoToolOpen = function(id) {
    var item = this.selectionArray[id];
    videoToolOpen(item.marker, item.prefix, item.id, item.img, item.descr, item.videoid);
}

ItemSelection.prototype.add = function(marker, prefix, id, img, descr, videoid) { 
    var item = new Object({marker:marker, prefix:prefix, id:id, img:img, descr:descr, videoid:videoid});
    var id0 = id;
    this.selectionArray[id0] = item;        
    
    id = id.replace(/\//, "_");

    if($('#' + 'smallselect_' + id).length != 0) {
	return;
    }         

    if($('.smallselect').length == 0) { 
	$("." + this.divClass).empty(); // remove initial "no selection available" content
    }

    //var node = $('<div class="smallselect" id="smallselect_' + id + '"><a href="javascript:selectionRemove(\'' + id + '\')"><img class="smallSelectRemove" src="imgs/remove.png"/></a><img class="smallthumb" src="' + img + '"/><div class="smalldescr">' + descr + '</div></div>');

    var node = $('<div class="smallselect" id="smallselect_' + id + '"/>');
    node.append($('<a href="javascript:selectionRemove(\'' + id + '\')\"><img class="smallSelectRemove" src="imgs/remove.png"/></a>'));
    node.append($('<a href="javascript:selectionVideoToolOpen(\'' + id0 + '\')"><img class="smallthumb" src="' + img + '"/><div class="smalldescr">' + descr + '</div></a>'));

    $("." + this.divClass).append(node);
	
    var url = "itpc://www.tourteaser.com/ipodexport.php?select=";
    
    var divs = $('.smallselect');
    for(var i = 0; i < divs.length; i++) {
	url += i == 0 ? "" : ",";
	var iid = divs[i].id;
        iid = iid.replace(/smallselect_/, "");
        iid = iid.replace(/_/, "/");
	url += URLEncode(iid);	
    }
    var exportAnch = $("#ipodshortanch")[0];
    if(divs.length == 0) {
	exportAnch.href = "javascript:ipodExportEmpty();";
    } else {
	exportAnch.href = url;
    }
    organizeSelectionAdd(marker, id, videoid, img, descr);
    
    /*
    var windowHeight_ = windowHeight();
    if(windowHeight_ <= 400) windowHeight_ = 400;
    
    var height = windowHeight_ - document.getElementById('selection').offsetHeight - 30;
    */

}

ItemSelection.prototype.remove = function(id) {    
    delete this.selectionArray[id];
    $('#' + 'smallselect_' + id).remove();
    organizeSelectionRemove(id)
}

ItemSelection.prototype.clear = function() {    
    this.selectionArray = Object();
    $('.smallselect').remove();
    organizeSelectionClear(id)
}

ItemSelection.prototype.isSelected = function(id) {
    return this.selectionArray[id] ? true : false;
}

function ipodExportEmpty() {
    alert("First select points !");
}
var mapSelect;
var mapOrganize;
var SLIDES = new slideshow("SLIDES");

var addMarker;

function markerRecenter() {
    addMarker.setPoint(mapSelect.getCenter());
}

var imageBar;
var selection;

function hrefFromVideoID(videoid, suffix) {
    var nb = videoid.substr(12, videoid.length - 12);
    var href = "http://www.tourteaser.com/videos/fs/tourteaser_wiki" + nb + suffix + ".mp4";
    
    return href;
}

function hrefSmallFromVideoID(videoid) {
    return hrefFromVideoID(videoid, "small");
}

function hrefBigFromVideoID(videoid) {
    return hrefFromVideoID(videoid, "");
}

function selectionAdd(marker, prefix, id, img, descr, videoid) {
    marker.selected = true;
    selection.add(marker, prefix, id, img, descr, videoid);
}

function videoToolOpen(marker, prefix, id, img, descr, videoid) {
  var hrefbig = hrefBigFromVideoID(videoid);
  var hrefsmall = hrefSmallFromVideoID(videoid);
    
  
  $("#videoToolContent").empty();

  $("#videoToolContent").append($('<a id="mb1" href="' + hrefsmall + '" class="mediabox w:640 h:495" style="margin-right: 20px"><img src="imgs/fullscreen.png"/></a>'));

  $("#videoToolContent").append($("<a href='javascript:itemFind(\"" + prefix + id + "\")' ><img src='imgs/selectButton.png'/></a>"));

  $("#videoToolContent").append($('<div class="videoPreviewTitle">' + descr + '</div>'));
  $("#videoToolContent").append($('<a id="videoToolMedia" href="' + hrefsmall + '"></a>'));

  $("#videoToolMedia").media({width: 220,
			       height:180, 
			       autoplay: true, 
			       cls:'inlineDivTool',
			       params: {scale: '0.6875'},
			       style:  {display:'inline'}
                               });

  $('#mb1').mediabox({ boxTitle: descr, params: {scale: '2.0'}}, { backgroundColor: '#000', opacity : '0.3' });

}

function videoToolClose() {
// $("#videoToolContent").empty();
 
}

function changetab(tab) {
    $('#tabs-content').triggerTab(tab);
}

function selectionRemove(id) {
    selection.remove(id);
}

function selectionVideoToolOpen(id) {
    selection.videoToolOpen(id);
}

function selectionClear() {
    selection.clear();
}

function imagebarClick(index) {
    var marker = imageBar.imageNth(index).marker_;
    if(console) {
	console.log("marker id is : " + marker.id);
    }
    marker.openMyInfoWindow();
}

function load() {

    $.blockUI.defaults.overlayCSS = { 
	backgroundColor:    '#003',
	opacity: '0.7'
    };

    $('#tabs-content').tabs({bookmarkable:false});

    createTools();

    imageBar = new ImageBar("imagebar", 15, "v", 800, 100, 70);
    selection = new ItemSelection("smallselection");
    var selectCenter = new GLatLng(48.856696,2.348843);
    var selectZoom = 13;

    if (!offline && GBrowserIsCompatible()) {
	var selectContainer = document.getElementById("map-select");
	mapSelect = new GXMap(selectContainer, "points.php", selectCenter, selectZoom - 1);
	//mapSelect = new GXMap(selectContainer, "points.php", new GLatLng(0,0), 1);    }
	mapOrganize = new GMap2(document.getElementById("map-organize"));
    }

    initGUI();	
    handleResize();    

    if (!offline && GBrowserIsCompatible()) {
       
	mapSelect.setCenter(selectCenter, selectZoom);
	addMarker = new GMarker(selectCenter, {draggable: true, icon:addIcon, clickable: false, title:"Add Marker"});
	mapSelect.addOverlay(addMarker);
	addMarker.hide();

	//	mapSelect.setMapType(G_SATELLITE_MAP);


	mapOrganize.addControl(new GSmallMapControl());
	mapOrganize.addControl(new GMapTypeControl());
		
	mapOrganize.setCenter(selectCenter, 12);
		
	//		showAddress("Paris, France");
        mapSelect.postInit();
	/*	setTimeout(function() {
	    var selectCenter = mapSelect.getCenter();
	    mapSelect.setCenter(selectCenter, 13); 
	    mapSelect.checkResize()
	 }, 100);
	*/
    }
    
} // end load


function submitGeoForm(evt) {
    var submit = false;
    if(evt) {
	var target = (evt.target) ? evt.target : evt.srcElement;
	var form = target.form;
	var charCode = (evt.charCode) ? evt.charCode :
	    ((evt.which) ? evt.which : evt.keyCode);
	if (charCode == 13) {
	    submit = true;
	}
    } else {
	submit = true;
    }
    if(submit) {
	recenter($("#geofind-form/*:text")[0].value);
	return false;
    }
    return true;
}

function recenter(address) {
    globalGeocoder.getLatLng(
			     address,
			     function(point) {
	if (!point) {
	    alert(address + " not found");
	} else {
	    mapSelect.setCenter(point, 13);
	    //      var marker = new GMarker(point, {draggable: true});
	    //        mapSelect.addOverlay(marker);
	    //        marker.openInfoWindowHtml("adress = " + address + " lat = " + point.lat() + " lng = " + point.lng());
	}
    }
			     );
}

function reset(start) {
    var wZ = $("#wizardZone");
    addMarker.hide();
    wZ.empty(); // TODO : do not remove checking box
    if(start) {
	wZ.removeClass("hidden");
    } else {
	wZ.addClass("hidden");
    }
}

function addPoint0() {
    var wZ = $("#wizardZone");
    reset(true);

    if(!wZ[0].mapClickListener) {
	wZ[0].mapClickListener = GEvent.bind(mapSelect, "click", wZ, function(overlay, point) {
	    addMarker.setPoint(point);
	    addMarker.show();
	    GEvent.removeListener($("#wizardZone")[0].mapClickListener);
	    $("#wizardZone")[0].mapClickListener = undefined;
	    addPoint1();
	});
    }
    var msg = $('<div>Click on the map to select the place.</div>');
    msg.attr({id:"clickmapselectplace"});
    msg.css({display:"none"});
    msg.addClass("wizardbox");
    msg.appendTo(wZ);
    msg.slideDown('slow');
}

var anonymousUserString = "Anonymous User";

function addPoint1(point) {
    var point = addMarker.getPoint();
    var lat = point.lat();
    var lng = point.lng();        

    var wZ = $("#wizardZone");
    wZ[0].addPointPhase = 1;
    $("#clickmapselectplace").slideUp('slow', function() {$("#clickmapselectplace").remove()});
    var str = '<div>';
    str += '<form id="pointaddform" class="pointaddform" action="#" onsubmit="return addPoint2($(this));">';
    str += '<fieldset>';
    str += '<legend>Item information </legend>';
    str += '<label for="formurl">URL:<input name="url" id="formurl" value="http://www..." type="text" onFocus="select();"/></label>';
    var userName = $.cookie("username");
    str += '<label for="formuser">User:<input name="user" id="formuser" value="' + (userName  ? userName : anonymousUserString) + '" type="text" onFocus="select();"/></label>';
    str += '<input id="formsubmit" value="add" type="submit"/>';
    str += '<input name="lat" type="hidden"/><input name="lng" type="hidden"/>';
    str += '</fieldset>';
    str += '</form>';
    str += 'Tip : you can drag the point if needed';
    str += '</div>';
 

    var msg = $(str);
    msg.attr({id:"clickmapinfoadd"});
    msg.css({display:"none"});
    msg.addClass("wizardbox");
    msg.appendTo(wZ);
    msg.slideDown('slow');		
}

function addPoint2() {
    var wZ = $("#wizardZone");
    if(wZ[0].addPointPhase != 1) {
	return false;
    }
    wZ[0].addPointPhase = 2;
    var point = addMarker.getPoint();
    var lat = point.lat();
    var lng = point.lng();  
    var inputs = $("input", $("#pointaddform"));
    var url = inputs[0].value;
    if(inputs[1].value != anonymousUserString) {
	$.cookie("username", inputs[1].value, {expires: 3650, path:'/'});  //expires in 10 years
    }
    inputs[3].value = "" + lat;
    inputs[4].value = "" + lng;

    var ajaxUrl = "dminsert.php?" + $('#pointaddform').formSerialize();

    $("#clickmapinfoadd").slideUp('slow', function() {$("#clickmapinfoadd").remove()});
    var msg = $('<div id="checking">Checking...</div>'); //lat = ' + lat + '<br/>lng = ' + lng + '<br/>url = ' + url + '</div>');
    msg.css({display:"none"});
    msg.addClass("wizardbox");
    msg.appendTo(wZ);
    msg.slideDown('slow');

    GDownloadUrl(ajaxUrl, function(data, responseCode) {
	if(data.substring(0,2)  == "OK") {
	    mapSelect.loadStdPoints(data.substring(2,data.length), responseCode);
	    $("#checking").append($("<b>OK!</b>"));
	    $("#checking").animate({opacity: 1.0}, 3000).slideUp('slow', function() {$("#checking").remove();});
	    var userName = $.cookie("username");
	    var msg = $('<div id="contrib">Thank you for your contribution' + (userName ? (", " + userName) : "") + ' !</div>'); 
	    msg.css({display:"none"});
	    msg.addClass("wizardbox");
	    msg.appendTo(wZ);
	    msg.slideDown('slow').animate({opacity: 1.0}, 6000).slideUp('slow', function() {$("#contrib").remove();reset(false);});
	}  else {
	    $("#checking").append($("<b>Failed!</b>"));
	    $("#checking").animate({opacity: 1.0}, 6000).slideUp('slow', function() {$("#checking").remove();reset(false);});
	}
    });

    
    //    msg.slideDown('slow').animate({opacity: 1.0}, 2000).slideUp('slow', function() {$("#checking").remove();reset(false);});
    return false;
}


function toolTitleClick(id) {
	var tool = $("#" + id);
	tool.slideToggle("fast");
}

function initTools(id, sections) {
    var openUpZone = $("#" + id);
    for(var i = 0; i < sections.length; i++) {
	var s = sections[i];
	var titleContent = s.titleContent ? s.titleContent : "" ;
	var titleDivStr = "<div class='toolTitle' id ='" + s.id +  "title'>" + titleContent + "<a href='javascript:toolTitleClick(\"" + s.id +"\")'>" + s.title + "</a></div>";
	var titleDiv = $(titleDivStr);
	titleDiv.index = i;

	var toolDiv = $("<div class='tool' id ='" + s.id +"'></div>");
	toolDiv.append(s.content);
	openUpZone.append(titleDiv);
	toolDiv.slideDown();
	openUpZone.append(toolDiv);
    }
  
}


/* [listing 6-10] */
function windowHeight() {
    // Standard browsers (Mozilla, Safari, etc.)
    if (self.innerHeight)
	return self.innerHeight;
    // IE 6
    if (document.documentElement && document.documentElement.clientHeight)
	return document.documentElement.clientHeight;
    // IE 5
    if (document.body)
	return document.body.clientHeight;
    // Just in case.
    return 0;
}

function windowWidth() {
    // Standard browsers (Mozilla, Safari, etc.)
    if (self.innerWidth)
	return self.innerWidth;
    // IE 6
    if (document.documentElement && document.documentElement.clientWidth)
	return document.documentElement.clientWidth;
    // IE 5
    if (document.body)
	return document.body.clientWidth;
    // Just in case.
    return 0;
}

function windowBoundedHeight() {
    var windowHeight_ = windowHeight();
    if(windowHeight_ <= 400) windowHeight_ = 400;
    return windowHeight_;
}

function windowBoundedWidth() {
    var windowWidth_ = windowWidth();
    if(windowWidth_ <= 640) windowWidth_ = 640;	
    return windowWidth_;
}

function handleResize() {
    var windowHeight_ = windowBoundedHeight();
    var windowWidth_ = windowBoundedWidth();
    var height = windowHeight_ - 60;
    var width = windowWidth_ - 22;
    
    imageBar.setCount(Math.floor((windowHeight_ - 70) / 63));
    
    $('.tabcontent').css({height : (height + 'px'), width: (width + 'px')});
    $('#sortZone').css({height: (height - 10) + "px"});
    var shift = 21;
    $('#videoZone').css({top: shift + "px"});
    $('#map-organize').css({top: (shift + 261 ) + "px"});
    $('#map-select').css({width: (windowWidth_ - 100) + "px", height : (windowHeight_ - 75) + "px"});

    var remain = (windowWidth_ - 584);
    var r = [];
    r[0] = (remain > 400) ? 400 : remain;
    r[1] = (remain > 400) ? remain - 400 : 0;
    var lft = 0;
    for(var i = 0; i < 3; i += 1) {
	var w = (i == 1) ? 584 : r[i / 2];
	var width = "" + w + 'px';
	var left = "" + lft + 'px';
	$("#headerBack" + i).css({position:'absolute', width:width, left:left});
	lft += w;
    }
    
    if(mapSelect) {
	 mapSelect.checkResize();
	 mapSelect.loadPoints();	
    }
    if(mapOrganize) {
	 mapOrganize.checkResize();
    }
}

function createTools() {
   var tools = new Array();   

   var layers = new Array();
   layers[0] = new Object({title:"Dailymotion", name:"dm", image:"dm-marker-l"});
   layers[1] = new Object({title:"Wikipedia", name:"wikipedia", image:"tt-marker-l"});
   layers[2] = new Object({title:"Panoramio", name:"panoramio", image:"pan-marker-l"});
   layers[3] = new Object({title:"My selection", name:"selection", image:"selected-marker"});

   
   var layerMenuDiv = $("<div id='layermenudiv'><img id='layerlegendimg' src='imgs/mapfiles/legend.png'/></div>")
   var layerMenuForm = $('<form id="layermenu" class="layermenu"/>');
  
   
   for(var i = 0; i < layers.length; i++) {
       var l = layers[i];
       var layerMenuLabel =  $('<label for="form' + l.name +'"/>');
       var idprefix = "layercheckbox";
       var layerMenuInput = $('<input checked="true" type="checkbox" name="select" id="' + idprefix + l.name + '"/>');
       layerMenuInput.click(function() {
	   var type = this.id;
	   type = type.substr(idprefix.length, type.length - idprefix.length);
	   mapSelect.setVisible(type, this.checked); 
	   mapSelect.updateVisibility();
       });
//       layerMenuLabel.append('<div class="layerlegend"><img class="layerlegendimg" src="imgs/mapfiles/' + l.image+ '.png"/></div>');
       layerMenuLabel.append(layerMenuInput);
       layerMenuLabel.append('<div class="layerlegendtext">' + l.title + '</div>');
       layerMenuForm.append(layerMenuLabel);
   }
   
   layerMenuDiv.append(layerMenuForm);
  
   tools[0] = new Object({title:'Video Preview', id:'videoTool', content:$('<div id="videoToolContent" ><div class ="videoPreviewTitle"> Select a point to view the video</div></div>')});
   tools[1] = new Object({title:'Layers', id:'layerSelect', content:layerMenuDiv});
   tools[2] = new Object({title:'Selection', 
			  titleContent: '<a href="javascript:selectionClear();"><img class="selectEmpty" src="imgs/remove.png"></a>',
			  id:'selection', 
                          content:$('<div class="smallselection">No current selection<br/></div><div><a href="javascript:changetab(3);">Export to IPod</a></div>')});


   initTools("openupZone", tools);
}

function initGUI() {	
    organizeSelectionLoad();
}

/* [listing 6-10] */
window.onresize = handleResize;
/* [listing 6-10 end] */

function unload() {
  if(!offline) {
	GUnload()
  }
}


function fpload() {
    $("#cartouches a").each(function() {
	var src = $(this).children()[0].attributes["src"].nodeValue;
	src = "javascript:fppointsget('data/" + src.substring(16, src.length - 4) + ".json')";
	this.href = src;
    });
    $('#fp-choix-POI').jcarousel({scroll: 3, visible: 3});

}

function fpunload() {

}

function fpVideoOpen(videoid) {
  var hrefsmall = hrefSmallFromVideoID(videoid);
  
  /*
    var nb = videoid.substr(12, videoid.length - 12);
    var hrefsmall = hrefSmallFromVideoID(videoid);
    var hrefbig = "http://www.tourteaser.com/videos/video/tourteaser_wiki" + nb + ".mp4";
    var hrefsmall = "http://www.tourteaser.com/videos/fs/tourteaser_wiki" + nb + "small.mp4";

  $("#videoToolContent").empty();

  $("#videoToolContent").append($('<a id="mb1" href="' + hrefsmall + '" class="mediabox w:640 h:495" style="margin-right: 20px"><img src="imgs/fullscreen.png"/></a>'));

  $("#videoToolContent").append($("<a href='javascript:itemFind(\"" + prefix + id + "\")' ><img src='imgs/selectButton.png'/></a>"));

  $("#videoToolContent").append($('<div class="videoPreviewTitle">' + descr + '</div>'));
  $("#videoToolContent").append($('<a id="videoToolMedia" href="' + hrefsmall + '"></a>'));

  $("#videoToolMedia").media({width: 220,
			       height:180, 
			       autoplay: true, 
			       cls:'inlineDivTool',
			       params: {scale: '0.6875'},
			       style:  {display:'inline'}
                               });

  $('#mb1').mediabox({ boxTitle: descr, params: {scale: '2.0'}}, { backgroundColor: '#000', opacity : '0.3' });
    */
}

function FPPoint(node, marker) {
  this.node = node;
  this.marker = marker;
}

FPPoint.prototype.callback = function() {
    var marker = this.marker;
    var name = marker.name;
    var img = marker.img;
    var videoid = marker.videoid;
    var id = marker.id;
    var id0 = id;
    id = id.replace(/\//, "_");
    
    this.node.append($('<a class="vignette" href="javascript:fpVideoOpen(\'' + videoid + '\')"><img class="vignette2" src="' + img + '"/><span class="caption">' + name + '</span></a>'));		
}

function fppointsget(filename) {
    GDownloadUrl(filename, function(data, responseCode) {
	var points = eval('(' + data + ')'); 
	var i;
	$("#fp-choix-POI").empty();

	for(i = 0; i < points.markers.length ; i++) {
	    var id = points.markers[i].id;
	    var node = $('<li/>');
	    var marker = new GNamedMarker(null, null, null, id);
	    var fppoint = new FPPoint(node, marker);
	    $("#fp-choix-POI").append(node);
	    marker.wikipediaDownloadInfo(fppoint.callback.bind(fppoint));
	}
	$('#fp-choix-POI').jcarousel({scroll: 3, visible: 3});
	
    });
}


/* [listing 6-10] */
function windowHeight() {
    // Standard browsers (Mozilla, Safari, etc.)
    if (self.innerHeight)
	return self.innerHeight;
    // IE 6
    if (document.documentElement && document.documentElement.clientHeight)
	return document.documentElement.clientHeight;
    // IE 5
    if (document.body)
	return document.body.clientHeight;
    // Just in case.
    return 0;
}

function windowWidth() {
    // Standard browsers (Mozilla, Safari, etc.)
    if (self.innerWidth)
	return self.innerWidth;
    // IE 6
    if (document.documentElement && document.documentElement.clientWidth)
	return document.documentElement.clientWidth;
    // IE 5
    if (document.body)
	return document.body.clientWidth;
    // Just in case.
    return 0;
}

