(function(){
/*
 * jQuery 1.2.6 - New Wave Javascript
 *
 * Copyright (c) 2008 John Resig (jquery.com)
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 * $Date: 2008-05-24 14:22:17 -0400 (Sat, 24 May 2008) $
 * $Rev: 5685 $
 */

// Map over jQuery in case of overwrite
var _jQuery = window.jQuery,
// Map over the $ in case of overwrite
	_$ = window.$;

var jQuery = window.jQuery = window.$ = function( selector, context ) {
	// The jQuery object is actually just the init constructor 'enhanced'
	return new jQuery.fn.init( selector, context );
};

// A simple way to check for HTML strings or ID strings
// (both of which we optimize for)
var quickExpr = /^[^<]*(<(.|\s)+>)[^>]*$|^#(\w+)$/,

// Is it a simple selector
	isSimple = /^.[^:#\[\.]*$/,

// Will speed up references to undefined, and allows munging its name.
	undefined;

jQuery.fn = jQuery.prototype = {
	init: function( selector, context ) {
		// Make sure that a selection was provided
		selector = selector || document;

		// Handle $(DOMElement)
		if ( selector.nodeType ) {
			this[0] = selector;
			this.length = 1;
			return this;
		}
		// Handle HTML strings
		if ( typeof selector == "string" ) {
			// Are we dealing with HTML string or an ID?
			var match = quickExpr.exec( selector );

			// Verify a match, and that no context was specified for #id
			if ( match && (match[1] || !context) ) {

				// HANDLE: $(html) -> $(array)
				if ( match[1] )
					selector = jQuery.clean( [ match[1] ], context );

				// HANDLE: $("#id")
				else {
					var elem = document.getElementById( match[3] );

					// Make sure an element was located
					if ( elem ){
						// Handle the case where IE and Opera return items
						// by name instead of ID
						if ( elem.id != match[3] )
							return jQuery().find( selector );

						// Otherwise, we inject the element directly into the jQuery object
						return jQuery( elem );
					}
					selector = [];
				}

			// HANDLE: $(expr, [context])
			// (which is just equivalent to: $(content).find(expr)
			} else
				return jQuery( context ).find( selector );

		// HANDLE: $(function)
		// Shortcut for document ready
		} else if ( jQuery.isFunction( selector ) )
			return jQuery( document )[ jQuery.fn.ready ? "ready" : "load" ]( selector );

		return this.setArray(jQuery.makeArray(selector));
	},

	// The current version of jQuery being used
	jquery: "1.2.6",

	// The number of elements contained in the matched element set
	size: function() {
		return this.length;
	},

	// The number of elements contained in the matched element set
	length: 0,

	// Get the Nth element in the matched element set OR
	// Get the whole matched element set as a clean array
	get: function( num ) {
		return num == undefined ?

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

			// Return just the object
			this[ num ];
	},

	// Take an array of elements and push it onto the stack
	// (returning the new matched element set)
	pushStack: function( elems ) {
		// Build a new jQuery matched element set
		var ret = jQuery( elems );

		// Add the old object onto the stack (as a reference)
		ret.prevObject = this;

		// Return the newly-formed element set
		return ret;
	},

	// Force the current matched set of elements to become
	// the specified array of elements (destroying the stack in the process)
	// You should use pushStack() in order to do this, but maintain the stack
	setArray: function( elems ) {
		// Resetting the length to 0, then using the native Array push
		// is a super-fast way to populate an object with array-like properties
		this.length = 0;
		Array.prototype.push.apply( this, elems );

		return this;
	},

	// Execute a callback for every element in the matched set.
	// (You can seed the arguments with an array of args, but this is
	// only used internally.)
	each: function( callback, args ) {
		return jQuery.each( this, callback, args );
	},

	// Determine the position of an element within
	// the matched set of elements
	index: function( elem ) {
		var ret = -1;

		// Locate the position of the desired element
		return jQuery.inArray(
			// If it receives a jQuery object, the first element is used
			elem && elem.jquery ? elem[0] : elem
		, this );
	},

	attr: function( name, value, type ) {
		var options = name;

		// Look for the case where we're accessing a style value
		if ( name.constructor == String )
			if ( value === undefined )
				return this[0] && jQuery[ type || "attr" ]( this[0], name );

			else {
				options = {};
				options[ name ] = value;
			}

		// Check to see if we're setting style values
		return this.each(function(i){
			// Set all the styles
			for ( name in options )
				jQuery.attr(
					type ?
						this.style :
						this,
					name, jQuery.prop( this, options[ name ], type, i, name )
				);
		});
	},

	css: function( key, value ) {
		// ignore negative width and height values
		if ( (key == 'width' || key == 'height') && parseFloat(value) < 0 )
			value = undefined;
		return this.attr( key, value, "curCSS" );
	},

	text: function( text ) {
		if ( typeof text != "object" && text != null )
			return this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode( text ) );

		var ret = "";

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

		return ret;
	},

	wrapAll: function( html ) {
		if ( this[0] )
			// The elements to wrap the target around
			jQuery( html, this[0].ownerDocument )
				.clone()
				.insertBefore( this[0] )
				.map(function(){
					var elem = this;

					while ( elem.firstChild )
						elem = elem.firstChild;

					return elem;
				})
				.append(this);

		return this;
	},

	wrapInner: function( html ) {
		return this.each(function(){
			jQuery( this ).contents().wrapAll( html );
		});
	},

	wrap: function( html ) {
		return this.each(function(){
			jQuery( this ).wrapAll( html );
		});
	},

	append: function() {
		return this.domManip(arguments, true, false, function(elem){
			if (this.nodeType == 1)
				this.appendChild( elem );
		});
	},

	prepend: function() {
		return this.domManip(arguments, true, true, function(elem){
			if (this.nodeType == 1)
				this.insertBefore( elem, this.firstChild );
		});
	},

	before: function() {
		return this.domManip(arguments, false, false, function(elem){
			this.parentNode.insertBefore( elem, this );
		});
	},

	after: function() {
		return this.domManip(arguments, false, true, function(elem){
			this.parentNode.insertBefore( elem, this.nextSibling );
		});
	},

	end: function() {
		return this.prevObject || jQuery( [] );
	},

	find: function( selector ) {
		var elems = jQuery.map(this, function(elem){
			return jQuery.find( selector, elem );
		});

		return this.pushStack( /[^+>] [^+>]/.test( selector ) || selector.indexOf("..") > -1 ?
			jQuery.unique( elems ) :
			elems );
	},

	clone: function( events ) {
		// Do the clone
		var ret = this.map(function(){
			if ( jQuery.browser.msie && !jQuery.isXMLDoc(this) ) {
				// IE copies events bound via attachEvent when
				// using cloneNode. Calling detachEvent on the
				// clone will also remove the events from the orignal
				// In order to get around this, we use innerHTML.
				// Unfortunately, this means some modifications to
				// attributes in IE that are actually only stored
				// as properties will not be copied (such as the
				// the name attribute on an input).
				var clone = this.cloneNode(true),
					container = document.createElement("div");
				container.appendChild(clone);
				return jQuery.clean([container.innerHTML])[0];
			} else
				return this.cloneNode(true);
		});

		// Need to set the expando to null on the cloned set if it exists
		// removeData doesn't work here, IE removes it from the original as well
		// this is primarily for IE but the data expando shouldn't be copied over in any browser
		var clone = ret.find("*").andSelf().each(function(){
			if ( this[ expando ] != undefined )
				this[ expando ] = null;
		});

		// Copy the events from the original to the clone
		if ( events === true )
			this.find("*").andSelf().each(function(i){
				if (this.nodeType == 3)
					return;
				var events = jQuery.data( this, "events" );

				for ( var type in events )
					for ( var handler in events[ type ] )
						jQuery.event.add( clone[ i ], type, events[ type ][ handler ], events[ type ][ handler ].data );
			});

		// Return the cloned set
		return ret;
	},

	filter: function( selector ) {
		return this.pushStack(
			jQuery.isFunction( selector ) &&
			jQuery.grep(this, function(elem, i){
				return selector.call( elem, i );
			}) ||

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

	not: function( selector ) {
		if ( selector.constructor == String )
			// test special case where just one selector is passed in
			if ( isSimple.test( selector ) )
				return this.pushStack( jQuery.multiFilter( selector, this, true ) );
			else
				selector = jQuery.multiFilter( selector, this );

		var isArrayLike = selector.length && selector[selector.length - 1] !== undefined && !selector.nodeType;
		return this.filter(function() {
			return isArrayLike ? jQuery.inArray( this, selector ) < 0 : this != selector;
		});
	},

	add: function( selector ) {
		return this.pushStack( jQuery.unique( jQuery.merge(
			this.get(),
			typeof selector == 'string' ?
				jQuery( selector ) :
				jQuery.makeArray( selector )
		)));
	},

	is: function( selector ) {
		return !!selector && jQuery.multiFilter( selector, this ).length > 0;
	},

	hasClass: function( selector ) {
		return this.is( "." + selector );
	},

	val: function( value ) {
		if ( value == undefined ) {

			if ( this.length ) {
				var elem = this[0];

				// We need to handle select boxes special
				if ( jQuery.nodeName( elem, "select" ) ) {
					var index = elem.selectedIndex,
						values = [],
						options = elem.options,
						one = elem.type == "select-one";

					// Nothing was selected
					if ( index < 0 )
						return null;

					// Loop through all the selected options
					for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) {
						var option = options[ i ];

						if ( option.selected ) {
							// Get the specifc value for the option
							value = jQuery.browser.msie && !option.attributes.value.specified ? option.text : option.value;

							// We don't need an array for one selects
							if ( one )
								return value;

							// Multi-Selects return an array
							values.push( value );
						}
					}

					return values;

				// Everything else, we just grab the value
				} else
					return (this[0].value || "").replace(/\r/g, "");

			}

			return undefined;
		}

		if( value.constructor == Number )
			value += '';

		return this.each(function(){
			if ( this.nodeType != 1 )
				return;

			if ( value.constructor == Array && /radio|checkbox/.test( this.type ) )
				this.checked = (jQuery.inArray(this.value, value) >= 0 ||
					jQuery.inArray(this.name, value) >= 0);

			else if ( jQuery.nodeName( this, "select" ) ) {
				var values = jQuery.makeArray(value);

				jQuery( "option", this ).each(function(){
					this.selected = (jQuery.inArray( this.value, values ) >= 0 ||
						jQuery.inArray( this.text, values ) >= 0);
				});

				if ( !values.length )
					this.selectedIndex = -1;

			} else
				this.value = value;
		});
	},

	html: function( value ) {
		return value == undefined ?
			(this[0] ?
				this[0].innerHTML :
				null) :
			this.empty().append( value );
	},

	replaceWith: function( value ) {
		return this.after( value ).remove();
	},

	eq: function( i ) {
		return this.slice( i, i + 1 );
	},

	slice: function() {
		return this.pushStack( Array.prototype.slice.apply( this, arguments ) );
	},

	map: function( callback ) {
		return this.pushStack( jQuery.map(this, function(elem, i){
			return callback.call( elem, i, elem );
		}));
	},

	andSelf: function() {
		return this.add( this.prevObject );
	},

	data: function( key, value ){
		var parts = key.split(".");
		parts[1] = parts[1] ? "." + parts[1] : "";

		if ( value === undefined ) {
			var data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]);

			if ( data === undefined && this.length )
				data = jQuery.data( this[0], key );

			return data === undefined && parts[1] ?
				this.data( parts[0] ) :
				data;
		} else
			return this.trigger("setData" + parts[1] + "!", [parts[0], value]).each(function(){
				jQuery.data( this, key, value );
			});
	},

	removeData: function( key ){
		return this.each(function(){
			jQuery.removeData( this, key );
		});
	},

	domManip: function( args, table, reverse, callback ) {
		var clone = this.length > 1, elems;

		return this.each(function(){
			if ( !elems ) {
				elems = jQuery.clean( args, this.ownerDocument );

				if ( reverse )
					elems.reverse();
			}

			var obj = this;

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

			var scripts = jQuery( [] );

			jQuery.each(elems, function(){
				var elem = clone ?
					jQuery( this ).clone( true )[0] :
					this;

				// execute all scripts after the elements have been injected
				if ( jQuery.nodeName( elem, "script" ) )
					scripts = scripts.add( elem );
				else {
					// Remove any inner scripts for later evaluation
					if ( elem.nodeType == 1 )
						scripts = scripts.add( jQuery( "script", elem ).remove() );

					// Inject the elements into the document
					callback.call( obj, elem );
				}
			});

			scripts.each( evalScript );
		});
	}
};

// Give the init function the jQuery prototype for later instantiation
jQuery.fn.init.prototype = jQuery.fn;

function evalScript( i, elem ) {
	if ( elem.src )
		jQuery.ajax({
			url: elem.src,
			async: false,
			dataType: "script"
		});

	else
		jQuery.globalEval( elem.text || elem.textContent || elem.innerHTML || "" );

	if ( elem.parentNode )
		elem.parentNode.removeChild( elem );
}

function now(){
	return +new Date;
}

jQuery.extend = jQuery.fn.extend = function() {
	// copy reference to target object
	var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options;

	// Handle a deep copy situation
	if ( target.constructor == Boolean ) {
		deep = target;
		target = arguments[1] || {};
		// skip the boolean and the target
		i = 2;
	}

	// Handle case when target is a string or something (possible in deep copy)
	if ( typeof target != "object" && typeof target != "function" )
		target = {};

	// extend jQuery itself if only one argument is passed
	if ( length == i ) {
		target = this;
		--i;
	}

	for ( ; i < length; i++ )
		// Only deal with non-null/undefined values
		if ( (options = arguments[ i ]) != null )
			// Extend the base object
			for ( var name in options ) {
				var src = target[ name ], copy = options[ name ];

				// Prevent never-ending loop
				if ( target === copy )
					continue;

				// Recurse if we're merging object values
				if ( deep && copy && typeof copy == "object" && !copy.nodeType )
					target[ name ] = jQuery.extend( deep, 
						// Never move original objects, clone them
						src || ( copy.length != null ? [ ] : { } )
					, copy );

				// Don't bring in undefined values
				else if ( copy !== undefined )
					target[ name ] = copy;

			}

	// Return the modified object
	return target;
};

var expando = "jQuery" + now(), uuid = 0, windowData = {},
	// exclude the following css properties to add px
	exclude = /z-?index|font-?weight|opacity|zoom|line-?height/i,
	// cache defaultView
	defaultView = document.defaultView || {};

jQuery.extend({
	noConflict: function( deep ) {
		window.$ = _$;

		if ( deep )
			window.jQuery = _jQuery;

		return jQuery;
	},

	// See test/unit/core.js for details concerning this function.
	isFunction: function( fn ) {
		return !!fn && typeof fn != "string" && !fn.nodeName &&
			fn.constructor != Array && /^[\s[]?function/.test( fn + "" );
	},

	// check if an element is in a (or is an) XML document
	isXMLDoc: function( elem ) {
		return elem.documentElement && !elem.body ||
			elem.tagName && elem.ownerDocument && !elem.ownerDocument.body;
	},

	// Evalulates a script in a global context
	globalEval: function( data ) {
		data = jQuery.trim( data );

		if ( data ) {
			// Inspired by code by Andrea Giammarchi
			// http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html
			var head = document.getElementsByTagName("head")[0] || document.documentElement,
				script = document.createElement("script");

			script.type = "text/javascript";
			if ( jQuery.browser.msie )
				script.text = data;
			else
				script.appendChild( document.createTextNode( data ) );

			// Use insertBefore instead of appendChild  to circumvent an IE6 bug.
			// This arises when a base node is used (#2709).
			head.insertBefore( script, head.firstChild );
			head.removeChild( script );
		}
	},

	nodeName: function( elem, name ) {
		return elem.nodeName && elem.nodeName.toUpperCase() == name.toUpperCase();
	},

	cache: {},

	data: function( elem, name, data ) {
		elem = elem == window ?
			windowData :
			elem;

		var id = elem[ expando ];

		// Compute a unique ID for the element
		if ( !id )
			id = elem[ expando ] = ++uuid;

		// Only generate the data cache if we're
		// trying to access or manipulate it
		if ( name && !jQuery.cache[ id ] )
			jQuery.cache[ id ] = {};

		// Prevent overriding the named cache with undefined values
		if ( data !== undefined )
			jQuery.cache[ id ][ name ] = data;

		// Return the named cache data, or the ID for the element
		return name ?
			jQuery.cache[ id ][ name ] :
			id;
	},

	removeData: function( elem, name ) {
		elem = elem == window ?
			windowData :
			elem;

		var id = elem[ expando ];

		// If we want to remove a specific section of the element's data
		if ( name ) {
			if ( jQuery.cache[ id ] ) {
				// Remove the section of cache data
				delete jQuery.cache[ id ][ name ];

				// If we've removed all the data, remove the element's cache
				name = "";

				for ( name in jQuery.cache[ id ] )
					break;

				if ( !name )
					jQuery.removeData( elem );
			}

		// Otherwise, we want to remove all of the element's data
		} else {
			// Clean up the element expando
			try {
				delete elem[ expando ];
			} catch(e){
				// IE has trouble directly removing the expando
				// but it's ok with using removeAttribute
				if ( elem.removeAttribute )
					elem.removeAttribute( expando );
			}

			// Completely remove the data cache
			delete jQuery.cache[ id ];
		}
	},

	// args is for internal usage only
	each: function( object, callback, args ) {
		var name, i = 0, length = object.length;

		if ( args ) {
			if ( length == undefined ) {
				for ( name in object )
					if ( callback.apply( object[ name ], args ) === false )
						break;
			} else
				for ( ; i < length; )
					if ( callback.apply( object[ i++ ], args ) === false )
						break;

		// A special, fast, case for the most common use of each
		} else {
			if ( length == undefined ) {
				for ( name in object )
					if ( callback.call( object[ name ], name, object[ name ] ) === false )
						break;
			} else
				for ( var value = object[0];
					i < length && callback.call( value, i, value ) !== false; value = object[++i] ){}
		}

		return object;
	},

	prop: function( elem, value, type, i, name ) {
		// Handle executable functions
		if ( jQuery.isFunction( value ) )
			value = value.call( elem, i );

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

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

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

		// internal only, use hasClass("class")
		has: function( elem, className ) {
			return jQuery.inArray( className, (elem.className || elem).toString().split(/\s+/) ) > -1;
		}
	},

	// A method for quickly swapping in/out CSS properties to get correct calculations
	swap: function( elem, options, callback ) {
		var old = {};
		// Remember the old values, and insert the new ones
		for ( var name in options ) {
			old[ name ] = elem.style[ name ];
			elem.style[ name ] = options[ name ];
		}

		callback.call( elem );

		// Revert the old values
		for ( var name in options )
			elem.style[ name ] = old[ name ];
	},

	css: function( elem, name, force ) {
		if ( name == "width" || name == "height" ) {
			var val, props = { position: "absolute", visibility: "hidden", display:"block" }, which = name == "width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ];

			function getWH() {
				val = name == "width" ? elem.offsetWidth : elem.offsetHeight;
				var padding = 0, border = 0;
				jQuery.each( which, function() {
					padding += parseFloat(jQuery.curCSS( elem, "padding" + this, true)) || 0;
					border += parseFloat(jQuery.curCSS( elem, "border" + this + "Width", true)) || 0;
				});
				val -= Math.round(padding + border);
			}

			if ( jQuery(elem).is(":visible") )
				getWH();
			else
				jQuery.swap( elem, props, getWH );

			return Math.max(0, val);
		}

		return jQuery.curCSS( elem, name, force );
	},

	curCSS: function( elem, name, force ) {
		var ret, style = elem.style;

		// A helper method for determining if an element's values are broken
		function color( elem ) {
			if ( !jQuery.browser.safari )
				return false;

			// defaultView is cached
			var ret = defaultView.getComputedStyle( elem, null );
			return !ret || ret.getPropertyValue("color") == "";
		}

		// We need to handle opacity special in IE
		if ( name == "opacity" && jQuery.browser.msie ) {
			ret = jQuery.attr( style, "opacity" );

			return ret == "" ?
				"1" :
				ret;
		}
		// Opera sometimes will give the wrong display answer, this fixes it, see #2037
		if ( jQuery.browser.opera && name == "display" ) {
			var save = style.outline;
			style.outline = "0 solid black";
			style.outline = save;
		}

		// Make sure we're using the right name for getting the float value
		if ( name.match( /float/i ) )
			name = styleFloat;

		if ( !force && style && style[ name ] )
			ret = style[ name ];

		else if ( defaultView.getComputedStyle ) {

			// Only "float" is needed here
			if ( name.match( /float/i ) )
				name = "float";

			name = name.replace( /([A-Z])/g, "-$1" ).toLowerCase();

			var computedStyle = defaultView.getComputedStyle( elem, null );

			if ( computedStyle && !color( elem ) )
				ret = computedStyle.getPropertyValue( name );

			// If the element isn't reporting its values properly in Safari
			// then some display: none elements are involved
			else {
				var swap = [], stack = [], a = elem, i = 0;

				// Locate all of the parent display: none elements
				for ( ; a && color(a); a = a.parentNode )
					stack.unshift(a);

				// Go through and make them visible, but in reverse
				// (It would be better if we knew the exact display type that they had)
				for ( ; i < stack.length; i++ )
					if ( color( stack[ i ] ) ) {
						swap[ i ] = stack[ i ].style.display;
						stack[ i ].style.display = "block";
					}

				// Since we flip the display style, we have to handle that
				// one special, otherwise get the value
				ret = name == "display" && swap[ stack.length - 1 ] != null ?
					"none" :
					( computedStyle && computedStyle.getPropertyValue( name ) ) || "";

				// Finally, revert the display styles back
				for ( i = 0; i < swap.length; i++ )
					if ( swap[ i ] != null )
						stack[ i ].style.display = swap[ i ];
			}

			// We should always get a number back from opacity
			if ( name == "opacity" && ret == "" )
				ret = "1";

		} else if ( elem.currentStyle ) {
			var camelCase = name.replace(/\-(\w)/g, function(all, letter){
				return letter.toUpperCase();
			});

			ret = elem.currentStyle[ name ] || elem.currentStyle[ camelCase ];

			// From the awesome hack by Dean Edwards
			// http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291

			// If we're not dealing with a regular pixel number
			// but a number that has a weird ending, we need to convert it to pixels
			if ( !/^\d+(px)?$/i.test( ret ) && /^\d/.test( ret ) ) {
				// Remember the original values
				var left = style.left, rsLeft = elem.runtimeStyle.left;

				// Put in the new values to get a computed value out
				elem.runtimeStyle.left = elem.currentStyle.left;
				style.left = ret || 0;
				ret = style.pixelLeft + "px";

				// Revert the changed values
				style.left = left;
				elem.runtimeStyle.left = rsLeft;
			}
		}

		return ret;
	},

	clean: function( elems, context ) {
		var ret = [];
		context = context || document;
		// !context.createElement fails in IE with an error but returns typeof 'object'
		if (typeof context.createElement == 'undefined')
			context = context.ownerDocument || context[0] && context[0].ownerDocument || document;

		jQuery.each(elems, function(i, elem){
			if ( !elem )
				return;

			if ( elem.constructor == Number )
				elem += '';

			// Convert html string into DOM nodes
			if ( typeof elem == "string" ) {
				// Fix "XHTML"-style tags in all browsers
				elem = elem.replace(/(<(\w+)[^>]*?)\/>/g, function(all, front, tag){
					return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i) ?
						all :
						front + "></" + tag + ">";
				});

				// Trim whitespace, otherwise indexOf won't work as expected
				var tags = jQuery.trim( elem ).toLowerCase(), div = context.createElement("div");

				var wrap =
					// option or optgroup
					!tags.indexOf("<opt") &&
					[ 1, "<select multiple='multiple'>", "</select>" ] ||

					!tags.indexOf("<leg") &&
					[ 1, "<fieldset>", "</fieldset>" ] ||

					tags.match(/^<(thead|tbody|tfoot|colg|cap)/) &&
					[ 1, "<table>", "</table>" ] ||

					!tags.indexOf("<tr") &&
					[ 2, "<table><tbody>", "</tbody></table>" ] ||

				 	// <thead> matched above
					(!tags.indexOf("<td") || !tags.indexOf("<th")) &&
					[ 3, "<table><tbody><tr>", "</tr></tbody></table>" ] ||

					!tags.indexOf("<col") &&
					[ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ] ||

					// IE can't serialize <link> and <script> tags normally
					jQuery.browser.msie &&
					[ 1, "div<div>", "</div>" ] ||

					[ 0, "", "" ];

				// Go to html and back, then peel off extra wrappers
				div.innerHTML = wrap[1] + elem + wrap[2];

				// Move to the right depth
				while ( wrap[0]-- )
					div = div.lastChild;

				// Remove IE's autoinserted <tbody> from table fragments
				if ( jQuery.browser.msie ) {

					// String was a <table>, *may* have spurious <tbody>
					var tbody = !tags.indexOf("<table") && tags.indexOf("<tbody") < 0 ?
						div.firstChild && div.firstChild.childNodes :

						// String was a bare <thead> or <tfoot>
						wrap[1] == "<table>" && tags.indexOf("<tbody") < 0 ?
							div.childNodes :
							[];

					for ( var j = tbody.length - 1; j >= 0 ; --j )
						if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length )
							tbody[ j ].parentNode.removeChild( tbody[ j ] );

					// IE completely kills leading whitespace when innerHTML is used
					if ( /^\s/.test( elem ) )
						div.insertBefore( context.createTextNode( elem.match(/^\s*/)[0] ), div.firstChild );

				}

				elem = jQuery.makeArray( div.childNodes );
			}

			if ( elem.length === 0 && (!jQuery.nodeName( elem, "form" ) && !jQuery.nodeName( elem, "select" )) )
				return;

			if ( elem[0] == undefined || jQuery.nodeName( elem, "form" ) || elem.options )
				ret.push( elem );

			else
				ret = jQuery.merge( ret, elem );

		});

		return ret;
	},

	attr: function( elem, name, value ) {
		// don't set attributes on text and comment nodes
		if (!elem || elem.nodeType == 3 || elem.nodeType == 8)
			return undefined;

		var notxml = !jQuery.isXMLDoc( elem ),
			// Whether we are setting (or getting)
			set = value !== undefined,
			msie = jQuery.browser.msie;

		// Try to normalize/fix the name
		name = notxml && jQuery.props[ name ] || name;

		// Only do all the following if this is a node (faster for style)
		// IE elem.getAttribute passes even for style
		if ( elem.tagName ) {

			// These attributes require special treatment
			var special = /href|src|style/.test( name );

			// Safari mis-reports the default selected property of a hidden option
			// Accessing the parent's selectedIndex property fixes it
			if ( name == "selected" && jQuery.browser.safari )
				elem.parentNode.selectedIndex;

			// If applicable, access the attribute via the DOM 0 way
			if ( name in elem && notxml && !special ) {
				if ( set ){
					// We can't allow the type property to be changed (since it causes problems in IE)
					if ( name == "type" && jQuery.nodeName( elem, "input" ) && elem.parentNode )
						throw "type property can't be changed";

					elem[ name ] = value;
				}

				// browsers index elements by id/name on forms, give priority to attributes.
				if( jQuery.nodeName( elem, "form" ) && elem.getAttributeNode(name) )
					return elem.getAttributeNode( name ).nodeValue;

				return elem[ name ];
			}

			if ( msie && notxml &&  name == "style" )
				return jQuery.attr( elem.style, "cssText", value );

			if ( set )
				// convert the value to a string (all browsers do this but IE) see #1070
				elem.setAttribute( name, "" + value );

			var attr = msie && notxml && special
					// Some attributes require a special call on IE
					? elem.getAttribute( name, 2 )
					: elem.getAttribute( name );

			// Non-existent attributes return null, we normalize to undefined
			return attr === null ? undefined : attr;
		}

		// elem is actually elem.style ... set the style

		// IE uses filters for opacity
		if ( msie && name == "opacity" ) {
			if ( set ) {
				// 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
				elem.filter = (elem.filter || "").replace( /alpha\([^)]*\)/, "" ) +
					(parseInt( value ) + '' == "NaN" ? "" : "alpha(opacity=" + value * 100 + ")");
			}

			return elem.filter && elem.filter.indexOf("opacity=") >= 0 ?
				(parseFloat( elem.filter.match(/opacity=([^)]*)/)[1] ) / 100) + '':
				"";
		}

		name = name.replace(/-([a-z])/ig, function(all, letter){
			return letter.toUpperCase();
		});

		if ( set )
			elem[ name ] = value;

		return elem[ name ];
	},

	trim: function( text ) {
		return (text || "").replace( /^\s+|\s+$/g, "" );
	},

	makeArray: function( array ) {
		var ret = [];

		if( array != null ){
			var i = array.length;
			//the window, strings and functions also have 'length'
			if( i == null || array.split || array.setInterval || array.call )
				ret[0] = array;
			else
				while( i )
					ret[--i] = array[i];
		}

		return ret;
	},

	inArray: function( elem, array ) {
		for ( var i = 0, length = array.length; i < length; i++ )
		// Use === because on IE, window == document
			if ( array[ i ] === elem )
				return i;

		return -1;
	},

	merge: function( first, second ) {
		// We have to loop this way because IE & Opera overwrite the length
		// expando of getElementsByTagName
		var i = 0, elem, pos = first.length;
		// Also, we need to make sure that the correct elements are being returned
		// (IE returns comment nodes in a '*' query)
		if ( jQuery.browser.msie ) {
			while ( elem = second[ i++ ] )
				if ( elem.nodeType != 8 )
					first[ pos++ ] = elem;

		} else
			while ( elem = second[ i++ ] )
				first[ pos++ ] = elem;

		return first;
	},

	unique: function( array ) {
		var ret = [], done = {};

		try {

			for ( var i = 0, length = array.length; i < length; i++ ) {
				var id = jQuery.data( array[ i ] );

				if ( !done[ id ] ) {
					done[ id ] = true;
					ret.push( array[ i ] );
				}
			}

		} catch( e ) {
			ret = array;
		}

		return ret;
	},

	grep: function( elems, callback, inv ) {
		var ret = [];

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

		return ret;
	},

	map: function( elems, callback ) {
		var ret = [];

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

			if ( value != null )
				ret[ ret.length ] = value;
		}

		return ret.concat.apply( [], ret );
	}
});

var userAgent = navigator.userAgent.toLowerCase();

// Figure out what browser is being used
jQuery.browser = {
	version: (userAgent.match( /.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/ ) || [])[1],
	safari: /webkit/.test( userAgent ),
	opera: /opera/.test( userAgent ),
	msie: /msie/.test( userAgent ) && !/opera/.test( userAgent ),
	mozilla: /mozilla/.test( userAgent ) && !/(compatible|webkit)/.test( userAgent )
};

var styleFloat = jQuery.browser.msie ?
	"styleFloat" :
	"cssFloat";

jQuery.extend({
	// Check to see if the W3C box model is being used
	boxModel: !jQuery.browser.msie || document.compatMode == "CSS1Compat",

	props: {
		"for": "htmlFor",
		"class": "className",
		"float": styleFloat,
		cssFloat: styleFloat,
		styleFloat: styleFloat,
		readonly: "readOnly",
		maxlength: "maxLength",
		cellspacing: "cellSpacing"
	}
});

jQuery.each({
	parent: function(elem){return elem.parentNode;},
	parents: function(elem){return jQuery.dir(elem,"parentNode");},
	next: function(elem){return jQuery.nth(elem,2,"nextSibling");},
	prev: function(elem){return jQuery.nth(elem,2,"previousSibling");},
	nextAll: function(elem){return jQuery.dir(elem,"nextSibling");},
	prevAll: function(elem){return jQuery.dir(elem,"previousSibling");},
	siblings: function(elem){return jQuery.sibling(elem.parentNode.firstChild,elem);},
	children: function(elem){return jQuery.sibling(elem.firstChild);},
	contents: function(elem){return jQuery.nodeName(elem,"iframe")?elem.contentDocument||elem.contentWindow.document:jQuery.makeArray(elem.childNodes);}
}, function(name, fn){
	jQuery.fn[ name ] = function( selector ) {
		var ret = jQuery.map( this, fn );

		if ( selector && typeof selector == "string" )
			ret = jQuery.multiFilter( selector, ret );

		return this.pushStack( jQuery.unique( ret ) );
	};
});

jQuery.each({
	appendTo: "append",
	prependTo: "prepend",
	insertBefore: "before",
	insertAfter: "after",
	replaceAll: "replaceWith"
}, function(name, original){
	jQuery.fn[ name ] = function() {
		var args = arguments;

		return this.each(function(){
			for ( var i = 0, length = args.length; i < length; i++ )
				jQuery( args[ i ] )[ original ]( this );
		});
	};
});

jQuery.each({
	removeAttr: function( name ) {
		jQuery.attr( this, name, "" );
		if (this.nodeType == 1)
			this.removeAttribute( name );
	},

	addClass: function( classNames ) {
		jQuery.className.add( this, classNames );
	},

	removeClass: function( classNames ) {
		jQuery.className.remove( this, classNames );
	},

	toggleClass: function( classNames ) {
		jQuery.className[ jQuery.className.has( this, classNames ) ? "remove" : "add" ]( this, classNames );
	},

	remove: function( selector ) {
		if ( !selector || jQuery.filter( selector, [ this ] ).r.length ) {
			// Prevent memory leaks
			jQuery( "*", this ).add(this).each(function(){
				jQuery.event.remove(this);
				jQuery.removeData(this);
			});
			if (this.parentNode)
				this.parentNode.removeChild( this );
		}
	},

	empty: function() {
		// Remove element nodes and prevent memory leaks
		jQuery( ">*", this ).remove();

		// Remove any remaining nodes
		while ( this.firstChild )
			this.removeChild( this.firstChild );
	}
}, function(name, fn){
	jQuery.fn[ name ] = function(){
		return this.each( fn, arguments );
	};
});

jQuery.each([ "Height", "Width" ], function(i, name){
	var type = name.toLowerCase();

	jQuery.fn[ type ] = function( size ) {
		// Get window width or height
		return this[0] == window ?
			// Opera reports document.body.client[Width/Height] properly in both quirks and standards
			jQuery.browser.opera && document.body[ "client" + name ] ||

			// Safari reports inner[Width/Height] just fine (Mozilla and Opera include scroll bar widths)
			jQuery.browser.safari && window[ "inner" + name ] ||

			// Everyone else use document.documentElement or document.body depending on Quirks vs Standards mode
			document.compatMode == "CSS1Compat" && document.documentElement[ "client" + name ] || document.body[ "client" + name ] :

			// Get document width or height
			this[0] == document ?
				// Either scroll[Width/Height] or offset[Width/Height], whichever is greater
				Math.max(
					Math.max(document.body["scroll" + name], document.documentElement["scroll" + name]),
					Math.max(document.body["offset" + name], document.documentElement["offset" + name])
				) :

				// Get or set width or height on the element
				size == undefined ?
					// Get width or height on the element
					(this.length ? jQuery.css( this[0], type ) : null) :

					// Set the width or height on the element (default to pixels if value is unitless)
					this.css( type, size.constructor == String ? size : size + "px" );
	};
});

// Helper function used by the dimensions and offset modules
function num(elem, prop) {
	return elem[0] && parseInt( jQuery.curCSS(elem[0], prop, true), 10 ) || 0;
}var chars = jQuery.browser.safari && parseInt(jQuery.browser.version) < 417 ?
		"(?:[\\w*_-]|\\\\.)" :
		"(?:[\\w\u0128-\uFFFF*_-]|\\\\.)",
	quickChild = new RegExp("^>\\s*(" + chars + "+)"),
	quickID = new RegExp("^(" + chars + "+)(#)(" + chars + "+)"),
	quickClass = new RegExp("^([#.]?)(" + chars + "*)");

jQuery.extend({
	expr: {
		"": function(a,i,m){return m[2]=="*"||jQuery.nodeName(a,m[2]);},
		"#": function(a,i,m){return a.getAttribute("id")==m[2];},
		":": {
			// Position Checks
			lt: function(a,i,m){return i<m[3]-0;},
			gt: function(a,i,m){return i>m[3]-0;},
			nth: function(a,i,m){return m[3]-0==i;},
			eq: function(a,i,m){return m[3]-0==i;},
			first: function(a,i){return i==0;},
			last: function(a,i,m,r){return i==r.length-1;},
			even: function(a,i){return i%2==0;},
			odd: function(a,i){return i%2;},

			// Child Checks
			"first-child": function(a){return a.parentNode.getElementsByTagName("*")[0]==a;},
			"last-child": function(a){return jQuery.nth(a.parentNode.lastChild,1,"previousSibling")==a;},
			"only-child": function(a){return !jQuery.nth(a.parentNode.lastChild,2,"previousSibling");},

			// Parent Checks
			parent: function(a){return a.firstChild;},
			empty: function(a){return !a.firstChild;},

			// Text Check
			contains: function(a,i,m){return (a.textContent||a.innerText||jQuery(a).text()||"").indexOf(m[3])>=0;},

			// Visibility
			visible: function(a){return "hidden"!=a.type&&jQuery.css(a,"display")!="none"&&jQuery.css(a,"visibility")!="hidden";},
			hidden: function(a){return "hidden"==a.type||jQuery.css(a,"display")=="none"||jQuery.css(a,"visibility")=="hidden";},

			// Form attributes
			enabled: function(a){return !a.disabled;},
			disabled: function(a){return a.disabled;},
			checked: function(a){return a.checked;},
			selected: function(a){return a.selected||jQuery.attr(a,"selected");},

			// Form elements
			text: function(a){return "text"==a.type;},
			radio: function(a){return "radio"==a.type;},
			checkbox: function(a){return "checkbox"==a.type;},
			file: function(a){return "file"==a.type;},
			password: function(a){return "password"==a.type;},
			submit: function(a){return "submit"==a.type;},
			image: function(a){return "image"==a.type;},
			reset: function(a){return "reset"==a.type;},
			button: function(a){return "button"==a.type||jQuery.nodeName(a,"button");},
			input: function(a){return /input|select|textarea|button/i.test(a.nodeName);},

			// :has()
			has: function(a,i,m){return jQuery.find(m[3],a).length;},

			// :header
			header: function(a){return /h\d/i.test(a.nodeName);},

			// :animated
			animated: function(a){return jQuery.grep(jQuery.timers,function(fn){return a==fn.elem;}).length;}
		}
	},

	// The regular expressions that power the parsing engine
	parse: [
		// Match: [@value='test'], [@foo]
		/^(\[) *@?([\w-]+) *([!*$^~=]*) *('?"?)(.*?)\4 *\]/,

		// Match: :contains('foo')
		/^(:)([\w-]+)\("?'?(.*?(\(.*?\))?[^(]*?)"?'?\)/,

		// Match: :even, :last-child, #id, .class
		new RegExp("^([:.#]*)(" + chars + "+)")
	],

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

		// check to make sure context is a DOM element or a document
		if ( context && context.nodeType != 1 && context.nodeType != 9)
			return [ ];

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

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

		// 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);

			var foundToken = false,

			// An attempt at speeding up child selectors that
			// point to a specific element tag
				re = quickChild,

				m = re.exec(t);

			if ( m ) {
				nodeName = m[1].toUpperCase();

				// Perform our own iteration and filter
				for ( var i = 0; ret[i]; i++ )
					for ( var c = ret[i].firstChild; c; c = c.nextSibling )
						if ( c.nodeType == 1 && (nodeName == "*" || c.nodeName.toUpperCase() == nodeName) )
							r.push( c );

				ret = r;
				t = t.replace( re, "" );
				if ( t.indexOf(" ") == 0 ) continue;
				foundToken = true;
			} else {
				re = /^([>+~])\s*(\w*)/i;

				if ( (m = re.exec(t)) != null ) {
					r = [];

					var merge = {};
					nodeName = m[2].toUpperCase();
					m = m[1];

					for ( var j = 0, rl = ret.length; j < rl; j++ ) {
						var n = m == "~" || m == "+" ? ret[j].nextSibling : ret[j].firstChild;
						for ( ; n; n = n.nextSibling )
							if ( n.nodeType == 1 ) {
								var id = jQuery.data(n);

								if ( m == "~" && merge[id] ) break;

								if (!nodeName || n.nodeName.toUpperCase() == nodeName ) {
									if ( m == "~" ) merge[id] = true;
									r.push( n );
								}

								if ( m == "+" ) break;
							}
					}

					ret = r;

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

			// 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 ( context == ret[0] ) ret.shift();

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

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

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

				} else {
					// Optimize for the case nodeName#idName
					var re2 = quickID;
					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 = quickClass;
						m = re2.exec(t);
					}

					m[2] = m[2].replace(/\\/g, "");

					var elem = ret[ret.length-1];

					// Try to do a global search by ID, where we can
					if ( m[1] == "#" && elem && elem.getElementById && !jQuery.isXMLDoc(elem) ) {
						// Optimization for HTML document case
						var oid = elem.getElementById(m[2]);

						// Do a quick check for the existence of the actual ID attribute
						// to avoid selecting by the name attribute in IE
						// also check to insure id is a string to avoid selecting an element with the name of 'id' inside a form
						if ( (jQuery.browser.msie||jQuery.browser.opera) && oid && typeof oid.id == "string" && oid.id != m[2] )
							oid = jQuery('[@id="'+m[2]+'"]', elem)[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 {
						// We need to find all descendant elements
						for ( var i = 0; ret[i]; i++ ) {
							// Grab the tag name being searched for
							var tag = m[1] == "#" && m[3] ? m[3] : m[1] != "" || m[0] == "" ? "*" : m[2];

							// Handle IE7 being really dumb about <object>s
							if ( tag == "*" && ret[i].nodeName.toLowerCase() == "object" )
								tag = "param";

							r = jQuery.merge( r, ret[i].getElementsByTagName( tag ));
						}

						// It's faster to filter by class and be done with it
						if ( m[1] == "." )
							r = jQuery.classFilter( r, m[2] );

						// Same with ID filtering
						if ( m[1] == "#" ) {
							var tmp = [];

							// Try to find the element with the ID
							for ( var i = 0; r[i]; i++ )
								if ( r[i].getAttribute("id") == m[2] ) {
									tmp = [ r[i] ];
									break;
								}

							r = tmp;
						}

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

		// An error occurred with the selector;
		// just return an empty set instead
		if ( t )
			ret = [];

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

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

		return done;
	},

	classFilter: function(r,m,not){
		m = " " + m + " ";
		var tmp = [];
		for ( var i = 0; r[i]; i++ ) {
			var pass = (" " + r[i].className + " ").indexOf( m ) >= 0;
			if ( !not && pass || not && !pass )
				tmp.push( r[i] );
		}
		return tmp;
	},

	filter: function(t,r,not) {
		var last;

		// Look for common filter expressions
		while ( t && t != last ) {
			last = t;

			var p = jQuery.parse, m;

			for ( var i = 0; p[i]; i++ ) {
				m = p[i].exec( t );

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

					m[2] = m[2].replace(/\\/g, "");
					break;
				}
			}

			if ( !m )
				break;

			// :not() is a special case that can be optimized by
			// keeping it out of the expression list
			if ( m[1] == ":" && m[2] == "not" )
				// optimize if only one selector found (most common case)
				r = isSimple.test( m[3] ) ?
					jQuery.filter(m[3], r, true).r :
					jQuery( r ).not( m[3] );

			// We can get a big speed boost by filtering by class here
			else if ( m[1] == "." )
				r = jQuery.classFilter(r, m[2], not);

			else if ( m[1] == "[" ) {
				var tmp = [], type = m[3];

				for ( var i = 0, rl = r.length; i < rl; i++ ) {
					var a = r[i], z = a[ jQuery.props[m[2]] || m[2] ];

					if ( z == null || /href|src|selected/.test(m[2]) )
						z = jQuery.attr(a,m[2]) || '';

					if ( (type == "" && !!z ||
						 type == "=" && z == m[5] ||
						 type == "!=" && z != m[5] ||
						 type == "^=" && z && !z.indexOf(m[5]) ||
						 type == "$=" && z.substr(z.length - m[5].length) == m[5] ||
						 (type == "*=" || type == "~=") && z.indexOf(m[5]) >= 0) ^ not )
							tmp.push( a );
				}

				r = tmp;

			// We can get a speed boost by handling nth-child here
			} else if ( m[1] == ":" && m[2] == "nth-child" ) {
				var merge = {}, tmp = [],
					// parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'
					test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec(
						m[3] == "even" && "2n" || m[3] == "odd" && "2n+1" ||
						!/\D/.test(m[3]) && "0n+" + m[3] || m[3]),
					// calculate the numbers (first)n+(last) including if they are negative
					first = (test[1] + (test[2] || 1)) - 0, last = test[3] - 0;

				// loop through all the elements left in the jQuery object
				for ( var i = 0, rl = r.length; i < rl; i++ ) {
					var node = r[i], parentNode = node.parentNode, id = jQuery.data(parentNode);

					if ( !merge[id] ) {
						var c = 1;

						for ( var n = parentNode.firstChild; n; n = n.nextSibling )
							if ( n.nodeType == 1 )
								n.nodeIndex = c++;

						merge[id] = true;
					}

					var add = false;

					if ( first == 0 ) {
						if ( node.nodeIndex == last )
							add = true;
					} else if ( (node.nodeIndex - last) % first == 0 && (node.nodeIndex - last) / first >= 0 )
						add = true;

					if ( add ^ not )
						tmp.push( node );
				}

				r = tmp;

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

				if ( typeof fn == "string" )
					fn = eval("false||function(a,i){return " + fn + ";}");

				// Execute it against the current filter
				r = jQuery.grep( r, function(elem, i){
					return fn(elem, i, m, r);
				}, not );
			}
		}

		// Return an array of filtered elements (r)
		// and the modified expression string (t)
		return { r: r, t: t };
	},

	dir: function( elem, dir ){
		var matched = [],
			cur = elem[dir];
		while ( cur && cur != document ) {
			if ( cur.nodeType == 1 )
				matched.push( cur );
			cur = cur[dir];
		}
		return matched;
	},

	nth: function(cur,result,dir,elem){
		result = result || 1;
		var num = 0;

		for ( ; cur; cur = cur[dir] )
			if ( cur.nodeType == 1 && ++num == result )
				break;

		return cur;
	},

	sibling: function( n, elem ) {
		var r = [];

		for ( ; n; n = n.nextSibling ) {
			if ( n.nodeType == 1 && 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(elem, types, handler, data) {
		if ( elem.nodeType == 3 || elem.nodeType == 8 )
			return;

		// For whatever reason, IE has trouble passing the window object
		// around, causing it to be cloned in the process
		if ( jQuery.browser.msie && elem.setInterval )
			elem = window;

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

		// if data is passed, bind to handler
		if( data != undefined ) {
			// Create temporary function pointer to original handler
			var fn = handler;

			// Create unique handler function, wrapped around original handler
			handler = this.proxy( fn, function() {
				// Pass arguments and context to original handler
				return fn.apply(this, arguments);
			});

			// Store data in unique handler
			handler.data = data;
		}

		// Init the element's event structure
		var events = jQuery.data(elem, "events") || jQuery.data(elem, "events", {}),
			handle = jQuery.data(elem, "handle") || jQuery.data(elem, "handle", function(){
				// 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 jQuery.event.handle.apply(arguments.callee.elem, arguments);
			});
		// Add elem as a property of the handle function
		// This is to prevent a memory leak with non-native
		// event in IE.
		handle.elem = elem;

		// Handle multiple events separated by a space
		// jQuery(...).bind("mouseover mouseout", fn);
		jQuery.each(types.split(/\s+/), function(index, type) {
			// Namespaced event handlers
			var parts = type.split(".");
			type = parts[0];
			handler.type = parts[1];

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

			// Init the event handler queue
			if (!handlers) {
				handlers = events[type] = {};

				// Check for a special event handler
				// Only use addEventListener/attachEvent if the special
				// events handler returns false
				if ( !jQuery.event.special[type] || jQuery.event.special[type].setup.call(elem) === false ) {
					// Bind the global event handler to the element
					if (elem.addEventListener)
						elem.addEventListener(type, handle, false);
					else if (elem.attachEvent)
						elem.attachEvent("on" + type, handle);
				}
			}

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

			// Keep track of which events have been used, for global triggering
			jQuery.event.global[type] = true;
		});

		// Nullify elem to prevent memory leaks in IE
		elem = null;
	},

	guid: 1,
	global: {},

	// Detach an event or set of events from an element
	remove: function(elem, types, handler) {
		// don't do events on text and comment nodes
		if ( elem.nodeType == 3 || elem.nodeType == 8 )
			return;

		var events = jQuery.data(elem, "events"), ret, index;

		if ( events ) {
			// Unbind all events for the element
			if ( types == undefined || (typeof types == "string" && types.charAt(0) == ".") )
				for ( var type in events )
					this.remove( elem, type + (types || "") );
			else {
				// types is actually an event object here
				if ( types.type ) {
					handler = types.handler;
					types = types.type;
				}

				// Handle multiple events seperated by a space
				// jQuery(...).unbind("mouseover mouseout", fn);
				jQuery.each(types.split(/\s+/), function(index, type){
					// Namespaced event handlers
					var parts = type.split(".");
					type = parts[0];

					if ( events[type] ) {
						// remove the given handler for the given type
						if ( handler )
							delete events[type][handler.guid];

						// remove all handlers for the given type
						else
							for ( handler in events[type] )
								// Handle the removal of namespaced events
								if ( !parts[1] || events[type][handler].type == parts[1] )
									delete events[type][handler];

						// remove generic event handler if no more handlers exist
						for ( ret in events[type] ) break;
						if ( !ret ) {
							if ( !jQuery.event.special[type] || jQuery.event.special[type].teardown.call(elem) === false ) {
								if (elem.removeEventListener)
									elem.removeEventListener(type, jQuery.data(elem, "handle"), false);
								else if (elem.detachEvent)
									elem.detachEvent("on" + type, jQuery.data(elem, "handle"));
							}
							ret = null;
							delete events[type];
						}
					}
				});
			}

			// Remove the expando if it's no longer used
			for ( ret in events ) break;
			if ( !ret ) {
				var handle = jQuery.data( elem, "handle" );
				if ( handle ) handle.elem = null;
				jQuery.removeData( elem, "events" );
				jQuery.removeData( elem, "handle" );
			}
		}
	},

	trigger: function(type, data, elem, donative, extra) {
		// Clone the incoming data, if any
		data = jQuery.makeArray(data);

		if ( type.indexOf("!") >= 0 ) {
			type = type.slice(0, -1);
			var exclusive = true;
		}

		// Handle a global trigger
		if ( !elem ) {
			// Only trigger if we've ever bound an event for it
			if ( this.global[type] )
				jQuery("*").add([window, document]).trigger(type, data);

		// Handle triggering a single element
		} else {
			// don't do events on text and comment nodes
			if ( elem.nodeType == 3 || elem.nodeType == 8 )
				return undefined;

			var val, ret, fn = jQuery.isFunction( elem[ type ] || null ),
				// Check to see if we need to provide a fake event, or not
				event = !data[0] || !data[0].preventDefault;

			// Pass along a fake event
			if ( event ) {
				data.unshift({
					type: type,
					target: elem,
					preventDefault: function(){},
					stopPropagation: function(){},
					timeStamp: now()
				});
				data[0][expando] = true; // no need to fix fake event
			}

			// Enforce the right trigger type
			data[0].type = type;
			if ( exclusive )
				data[0].exclusive = true;

			// Trigger the event, it is assumed that "handle" is a function
			var handle = jQuery.data(elem, "handle");
			if ( handle )
				val = handle.apply( elem, data );

			// Handle triggering native .onfoo handlers (and on links since we don't call .click() for links)
			if ( (!fn || (jQuery.nodeName(elem, 'a') && type == "click")) && elem["on"+type] && elem["on"+type].apply( elem, data ) === false )
				val = false;

			// Extra functions don't get the custom event object
			if ( event )
				data.shift();

			// Handle triggering of extra function
			if ( extra && jQuery.isFunction( extra ) ) {
				// call the extra function and tack the current return value on the end for possible inspection
				ret = extra.apply( elem, val == null ? data : data.concat( val ) );
				// if anything is returned, give it precedence and have it overwrite the previous value
				if (ret !== undefined)
					val = ret;
			}

			// Trigger the native events (except for clicks on links)
			if ( fn && donative !== false && val !== false && !(jQuery.nodeName(elem, 'a') && type == "click") ) {
				this.triggered = true;
				try {
					elem[ type ]();
				// prevent IE from throwing an error for some hidden elements
				} catch (e) {}
			}

			this.triggered = false;
		}

		return val;
	},

	handle: function(event) {
		// returned undefined or false
		var val, ret, namespace, all, handlers;

		event = arguments[0] = jQuery.event.fix( event || window.event );

		// Namespaced event handlers
		namespace = event.type.split(".");
		event.type = namespace[0];
		namespace = namespace[1];
		// Cache this now, all = true means, any handler
		all = !namespace && !event.exclusive;

		handlers = ( jQuery.data(this, "events") || {} )[event.type];

		for ( var j in handlers ) {
			var handler = handlers[j];

			// Filter the functions by class
			if ( all || handler.type == namespace ) {
				// Pass in a reference to the handler function itself
				// So that we can later remove it
				event.handler = handler;
				event.data = handler.data;

				ret = handler.apply( this, arguments );

				if ( val !== false )
					val = ret;

				if ( ret === false ) {
					event.preventDefault();
					event.stopPropagation();
				}
			}
		}

		return val;
	},

	fix: function(event) {
		if ( event[expando] == true )
			return event;

		// store a copy of the original event object
		// and "clone" to set read-only properties
		var originalEvent = event;
		event = { originalEvent: originalEvent };
		var props = "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target timeStamp toElement type view wheelDelta which".split(" ");
		for ( var i=props.length; i; i-- )
			event[ props[i] ] = originalEvent[ props[i] ];

		// Mark it as fixed
		event[expando] = true;

		// add preventDefault and stopPropagation since
		// they will not work on the clone
		event.preventDefault = function() {
			// if preventDefault exists run it on the original event
			if (originalEvent.preventDefault)
				originalEvent.preventDefault();
			// otherwise set the returnValue property of the original event to false (IE)
			originalEvent.returnValue = false;
		};
		event.stopPropagation = function() {
			// if stopPropagation exists run it on the original event
			if (originalEvent.stopPropagation)
				originalEvent.stopPropagation();
			// otherwise set the cancelBubble property of the original event to true (IE)
			originalEvent.cancelBubble = true;
		};

		// Fix timeStamp
		event.timeStamp = event.timeStamp || now();

		// Fix target property, if necessary
		if ( !event.target )
			event.target = event.srcElement || document; // Fixes #1925 where srcElement might not be defined either

		// check if target is a textnode (safari)
		if ( event.target.nodeType == 3 )
			event.target = event.target.parentNode;

		// Add relatedTarget, if necessary
		if ( !event.relatedTarget && event.fromElement )
			event.relatedTarget = event.fromElement == event.target ? event.toElement : event.fromElement;

		// Calculate pageX/Y if missing and clientX/Y available
		if ( event.pageX == null && event.clientX != null ) {
			var doc = document.documentElement, body = document.body;
			event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc.clientLeft || 0);
			event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc.clientTop || 0);
		}

		// Add which for key events
		if ( !event.which && ((event.charCode || event.charCode === 0) ? event.charCode : event.keyCode) )
			event.which = event.charCode || event.keyCode;

		// Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
		if ( !event.metaKey && event.ctrlKey )
			event.metaKey = event.ctrlKey;

		// Add which for click: 1 == left; 2 == middle; 3 == right
		// Note: button is not normalized, so don't use it
		if ( !event.which && event.button )
			event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));

		return event;
	},

	proxy: function( fn, proxy ){
		// Set the guid of unique handler to the same of original handler, so it can be removed
		proxy.guid = fn.guid = fn.guid || proxy.guid || this.guid++;
		// So proxy can be declared as an argument
		return proxy;
	},

	special: {
		ready: {
			setup: function() {
				// Make sure the ready event is setup
				bindReady();
				return;
			},

			teardown: function() { return; }
		},

		mouseenter: {
			setup: function() {
				if ( jQuery.browser.msie ) return false;
				jQuery(this).bind("mouseover", jQuery.event.special.mouseenter.handler);
				return true;
			},

			teardown: function() {
				if ( jQuery.browser.msie ) return false;
				jQuery(this).unbind("mouseover", jQuery.event.special.mouseenter.handler);
				return true;
			},

			handler: function(event) {
				// If we actually just moused on to a sub-element, ignore it
				if ( withinElement(event, this) ) return true;
				// Execute the right handlers by setting the event type to mouseenter
				event.type = "mouseenter";
				return jQuery.event.handle.apply(this, arguments);
			}
		},

		mouseleave: {
			setup: function() {
				if ( jQuery.browser.msie ) return false;
				jQuery(this).bind("mouseout", jQuery.event.special.mouseleave.handler);
				return true;
			},

			teardown: function() {
				if ( jQuery.browser.msie ) return false;
				jQuery(this).unbind("mouseout", jQuery.event.special.mouseleave.handler);
				return true;
			},

			handler: function(event) {
				// If we actually just moused on to a sub-element, ignore it
				if ( withinElement(event, this) ) return true;
				// Execute the right handlers by setting the event type to mouseleave
				event.type = "mouseleave";
				return jQuery.event.handle.apply(this, arguments);
			}
		}
	}
};

jQuery.fn.extend({
	bind: function( type, data, fn ) {
		return type == "unload" ? this.one(type, data, fn) : this.each(function(){
			jQuery.event.add( this, type, fn || data, fn && data );
		});
	},

	one: function( type, data, fn ) {
		var one = jQuery.event.proxy( fn || data, function(event) {
			jQuery(this).unbind(event, one);
			return (fn || data).apply( this, arguments );
		});
		return this.each(function(){
			jQuery.event.add( this, type, one, fn && data);
		});
	},

	unbind: function( type, fn ) {
		return this.each(function(){
			jQuery.event.remove( this, type, fn );
		});
	},

	trigger: function( type, data, fn ) {
		return this.each(function(){
			jQuery.event.trigger( type, data, this, true, fn );
		});
	},

	triggerHandler: function( type, data, fn ) {
		return this[0] && jQuery.event.trigger( type, data, this[0], false, fn );
	},

	toggle: function( fn ) {
		// Save reference to arguments for access in closure
		var args = arguments, i = 1;

		// link all the functions, so any of them can unbind this click handler
		while( i < args.length )
			jQuery.event.proxy( fn, args[i++] );

		return this.click( jQuery.event.proxy( fn, function(event) {
			// Figure out which function to execute
			this.lastToggle = ( this.lastToggle || 0 ) % i;

			// Make sure that clicks stop
			event.preventDefault();

			// and execute the function
			return args[ this.lastToggle++ ].apply( this, arguments ) || false;
		}));
	},

	hover: function(fnOver, fnOut) {
		return this.bind('mouseenter', fnOver).bind('mouseleave', fnOut);
	},

	ready: function(fn) {
		// Attach the listeners
		bindReady();

		// If the DOM is already ready
		if ( jQuery.isReady )
			// Execute the function immediately
			fn.call( document, jQuery );

		// Otherwise, remember the function for later
		else
			// Add the function to the wait list
			jQuery.readyList.push( function() { return fn.call(this, jQuery); } );

		return this;
	}
});

jQuery.extend({
	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.call( document );
				});

				// Reset the list of functions
				jQuery.readyList = null;
			}

			// Trigger any bound ready events
			jQuery(document).triggerHandler("ready");
		}
	}
});

var readyBound = false;

function bindReady(){
	if ( readyBound ) return;
	readyBound = true;

	// Mozilla, Opera (see further below for it) and webkit nightlies currently support this event
	if ( document.addEventListener && !jQuery.browser.opera)
		// Use the handy event callback
		document.addEventListener( "DOMContentLoaded", jQuery.ready, false );

	// If IE is used and is not in a frame
	// Continually check to see if the document is ready
	if ( jQuery.browser.msie && window == top ) (function(){
		if (jQuery.isReady) return;
		try {
			// If IE is used, use the trick by Diego Perini
			// http://javascript.nwbox.com/IEContentLoaded/
			document.documentElement.doScroll("left");
		} catch( error ) {
			setTimeout( arguments.callee, 0 );
			return;
		}
		// and execute any waiting functions
		jQuery.ready();
	})();

	if ( jQuery.browser.opera )
		document.addEventListener( "DOMContentLoaded", function () {
			if (jQuery.isReady) return;
			for (var i = 0; i < document.styleSheets.length; i++)
				if (document.styleSheets[i].disabled) {
					setTimeout( arguments.callee, 0 );
					return;
				}
			// and execute any waiting functions
			jQuery.ready();
		}, false);

	if ( jQuery.browser.safari ) {
		var numStyles;
		(function(){
			if (jQuery.isReady) return;
			if ( document.readyState != "loaded" && document.readyState != "complete" ) {
				setTimeout( arguments.callee, 0 );
				return;
			}
			if ( numStyles === undefined )
				numStyles = jQuery("style, link[rel=stylesheet]").length;
			if ( document.styleSheets.length != numStyles ) {
				setTimeout( arguments.callee, 0 );
				return;
			}
			// and execute any waiting functions
			jQuery.ready();
		})();
	}

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

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, name){

	// Handle event binding
	jQuery.fn[name] = function(fn){
		return fn ? this.bind(name, fn) : this.trigger(name);
	};
});

// Checks if an event happened on an element within another element
// Used in jQuery.event.special.mouseenter and mouseleave handlers
var withinElement = function(event, elem) {
	// Check if mouse(over|out) are still within the same parent element
	var parent = event.relatedTarget;
	// Traverse up the tree
	while ( parent && parent != elem ) try { parent = parent.parentNode; } catch(error) { parent = elem; }
	// Return true if we actually just moused on to a sub-element
	return parent == elem;
};

// Prevent memory leaks in IE
// And prevent errors on refresh with events like mouseover in other browsers
// Window isn't included so as not to unbind existing unload events
jQuery(window).bind("unload", function() {
	jQuery("*").add(document).unbind();
});
jQuery.fn.extend({
	// Keep a copy of the old load
	_load: jQuery.fn.load,

	load: function( url, params, callback ) {
		if ( typeof url != 'string' )
			return this._load( url );

		var off = url.indexOf(" ");
		if ( off >= 0 ) {
			var selector = url.slice(off, url.length);
			url = url.slice(0, off);
		}

		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,
			dataType: "html",
			data: params,
			complete: function(res, status){
				// If successful, inject the HTML into all the matched elements
				if ( status == "success" || status == "notmodified" )
					// See if a selector was specified
					self.html( selector ?
						// Create a dummy div to hold the results
						jQuery("<div/>")
							// inject the contents of the document in, removing the scripts
							// to avoid any 'Permission Denied' errors in IE
							.append(res.responseText.replace(/<script(.|\s)*?\/script>/g, ""))

							// Locate the specified elements
							.find(selector) :

						// If not, just inject the full result
						res.responseText );

				self.each( callback, [res.responseText, status, res] );
			}
		});
		return this;
	},

	serialize: function() {
		return jQuery.param(this.serializeArray());
	},
	serializeArray: function() {
		return this.map(function(){
			return jQuery.nodeName(this, "form") ?
				jQuery.makeArray(this.elements) : this;
		})
		.filter(function(){
			return this.name && !this.disabled &&
				(this.checked || /select|textarea/i.test(this.nodeName) ||
					/text|hidden|password/i.test(this.type));
		})
		.map(function(i, elem){
			var val = jQuery(this).val();
			return val == null ? null :
				val.constructor == Array ?
					jQuery.map( val, function(val, i){
						return {name: elem.name, value: val};
					}) :
					{name: elem.name, value: val};
		}).get();
	}
});

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

var jsc = now();

jQuery.extend({
	get: function( url, data, callback, type ) {
		// shift arguments if data argument was ommited
		if ( jQuery.isFunction( data ) ) {
			callback = data;
			data = null;
		}

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

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

	ajaxSetup: function( settings ) {
		jQuery.extend( jQuery.ajaxSettings, settings );
	},

	ajaxSettings: {
		url: location.href,
		global: true,
		type: "GET",
		timeout: 0,
		contentType: "application/x-www-form-urlencoded",
		processData: true,
		async: true,
		data: null,
		username: null,
		password: null,
		accepts: {
			xml: "application/xml, text/xml",
			html: "text/html",
			script: "text/javascript, application/javascript",
			json: "application/json, text/javascript",
			text: "text/plain",
			_default: "*/*"
		}
	},

	// Last-Modified header cache for next request
	lastModified: {},

	ajax: function( s ) {
		// Extend the settings, but re-extend 's' so that it can be
		// checked again later (in the test suite, specifically)
		s = jQuery.extend(true, s, jQuery.extend(true, {}, jQuery.ajaxSettings, s));

		var jsonp, jsre = /=\?(&|$)/g, status, data,
			type = s.type.toUpperCase();

		// convert data if not already a string
		if ( s.data && s.processData && typeof s.data != "string" )
			s.data = jQuery.param(s.data);

		// Handle JSONP Parameter Callbacks
		if ( s.dataType == "jsonp" ) {
			if ( type == "GET" ) {
				if ( !s.url.match(jsre) )
					s.url += (s.url.match(/\?/) ? "&" : "?") + (s.jsonp || "callback") + "=?";
			} else if ( !s.data || !s.data.match(jsre) )
				s.data = (s.data ? s.data + "&" : "") + (s.jsonp || "callback") + "=?";
			s.dataType = "json";
		}

		// Build temporary JSONP function
		if ( s.dataType == "json" && (s.data && s.data.match(jsre) || s.url.match(jsre)) ) {
			jsonp = "jsonp" + jsc++;

			// Replace the =? sequence both in the query string and the data
			if ( s.data )
				s.data = (s.data + "").replace(jsre, "=" + jsonp + "$1");
			s.url = s.url.replace(jsre, "=" + jsonp + "$1");

			// We need to make sure
			// that a JSONP style response is executed properly
			s.dataType = "script";

			// Handle JSONP-style loading
			window[ jsonp ] = function(tmp){
				data = tmp;
				success();
				complete();
				// Garbage collect
				window[ jsonp ] = undefined;
				try{ delete window[ jsonp ]; } catch(e){}
				if ( head )
					head.removeChild( script );
			};
		}

		if ( s.dataType == "script" && s.cache == null )
			s.cache = false;

		if ( s.cache === false && type == "GET" ) {
			var ts = now();
			// try replacing _= if it is there
			var ret = s.url.replace(/(\?|&)_=.*?(&|$)/, "$1_=" + ts + "$2");
			// if nothing was replaced, add timestamp to the end
			s.url = ret + ((ret == s.url) ? (s.url.match(/\?/) ? "&" : "?") + "_=" + ts : "");
		}

		// If data is available, append data to url for get requests
		if ( s.data && type == "GET" ) {
			s.url += (s.url.match(/\?/) ? "&" : "?") + 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" );

		// Matches an absolute URL, and saves the domain
		var remote = /^(?:\w+:)?\/\/([^\/?#]+)/;

		// If we're requesting a remote document
		// and trying to load JSON or Script with a GET
		if ( s.dataType == "script" && type == "GET"
				&& remote.test(s.url) && remote.exec(s.url)[1] != location.host ){
			var head = document.getElementsByTagName("head")[0];
			var script = document.createElement("script");
			script.src = s.url;
			if (s.scriptCharset)
				script.charset = s.scriptCharset;

			// Handle Script loading
			if ( !jsonp ) {
				var done = false;

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

			head.appendChild(script);

			// We handle everything using the script element injection
			return undefined;
		}

		var requestDone = false;

		// Create the request object; Microsoft failed to properly
		// implement the XMLHttpRequest in IE7, so we use the ActiveXObject when it is available
		var xhr = window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : new XMLHttpRequest();

		// Open the socket
		// Passing null username, generates a login popup on Opera (#2865)
		if( s.username )
			xhr.open(type, s.url, s.async, s.username, s.password);
		else
			xhr.open(type, s.url, s.async);

		// Need an extra try/catch for cross domain requests in Firefox 3
		try {
			// Set the correct header, if data is being sent
			if ( s.data )
				xhr.setRequestHeader("Content-Type", s.contentType);

			// Set the If-Modified-Since header, if ifModified mode.
			if ( s.ifModified )
				xhr.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
			xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");

			// Set the Accepts header for the server, depending on the dataType
			xhr.setRequestHeader("Accept", s.dataType && s.accepts[ s.dataType ] ?
				s.accepts[ s.dataType ] + ", */*" :
				s.accepts._default );
		} catch(e){}

		// Allow custom headers/mimetypes
		if ( s.beforeSend && s.beforeSend(xhr, s) === false ) {
			// cleanup active request counter
			s.global && jQuery.active--;
			// close opended socket
			xhr.abort();
			return false;
		}

		if ( s.global )
			jQuery.event.trigger("ajaxSend", [xhr, 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 ( !requestDone && xhr && (xhr.readyState == 4 || isTimeout == "timeout") ) {
				requestDone = true;

				// clear poll interval
				if (ival) {
					clearInterval(ival);
					ival = null;
				}

				status = isTimeout == "timeout" && "timeout" ||
					!jQuery.httpSuccess( xhr ) && "error" ||
					s.ifModified && jQuery.httpNotModified( xhr, s.url ) && "notmodified" ||
					"success";

				if ( status == "success" ) {
					// Watch for, and catch, XML document parse errors
					try {
						// process the data (runs the xml through httpData regardless of callback)
						data = jQuery.httpData( xhr, s.dataType, s.dataFilter );
					} catch(e) {
						status = "parsererror";
					}
				}

				// Make sure that the request was successful or notmodified
				if ( status == "success" ) {
					// Cache Last-Modified header, if ifModified mode.
					var modRes;
					try {
						modRes = xhr.getResponseHeader("Last-Modified");
					} catch(e) {} // swallow exception thrown by FF if header is not available

					if ( s.ifModified && modRes )
						jQuery.lastModified[s.url] = modRes;

					// JSONP handles its own success callback
					if ( !jsonp )
						success();
				} else
					jQuery.handleError(s, xhr, status);

				// Fire the complete handlers
				complete();

				// Stop memory leaks
				if ( s.async )
					xhr = null;
			}
		};

		if ( s.async ) {
			// 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 ( xhr ) {
						// Cancel the request
						xhr.abort();

						if( !requestDone )
							onreadystatechange( "timeout" );
					}
				}, s.timeout);
		}

		// Send the data
		try {
			xhr.send(s.data);
		} catch(e) {
			jQuery.handleError(s, xhr, null, e);
		}

		// firefox 1.5 doesn't fire statechange for sync requests
		if ( !s.async )
			onreadystatechange();

		function success(){
			// 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", [xhr, s] );
		}

		function complete(){
			// Process result
			if ( s.complete )
				s.complete(xhr, status);

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

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

		// return XMLHttpRequest to allow aborting the request etc.
		return xhr;
	},

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

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

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

	// Determines if an XMLHttpRequest was successful or not
	httpSuccess: function( xhr ) {
		try {
			// IE error sometimes returns 1223 when it should be 204 so treat it as success, see #1450
			return !xhr.status && location.protocol == "file:" ||
				( xhr.status >= 200 && xhr.status < 300 ) || xhr.status == 304 || xhr.status == 1223 ||
				jQuery.browser.safari && xhr.status == undefined;
		} catch(e){}
		return false;
	},

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

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

	httpData: function( xhr, type, filter ) {
		var ct = xhr.getResponseHeader("content-type"),
			xml = type == "xml" || !type && ct && ct.indexOf("xml") >= 0,
			data = xml ? xhr.responseXML : xhr.responseText;

		if ( xml && data.documentElement.tagName == "parsererror" )
			throw "parsererror";
			
		// Allow a pre-filtering function to sanitize the response
		if( filter )
			data = filter( data, type );

		// 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" )
			data = eval("(" + data + ")");

		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( jQuery.isFunction(a[j]) ? a[j]() : a[j] ) );

		// Return the resulting serialization
		return s.join("&").replace(/%20/g, "+");
	}

});
jQuery.fn.extend({
	show: function(speed,callback){
		return speed ?
			this.animate({
				height: "show", width: "show", opacity: "show"
			}, speed, callback) :

			this.filter(":hidden").each(function(){
				this.style.display = this.oldblock || "";
				if ( jQuery.css(this,"display") == "none" ) {
					var elem = jQuery("<" + this.tagName + " />").appendTo("body");
					this.style.display = elem.css("display");
					// handle an edge condition where css is - div { display:none; } or similar
					if (this.style.display == "none")
						this.style.display = "block";
					elem.remove();
				}
			}).end();
	},

	hide: function(speed,callback){
		return speed ?
			this.animate({
				height: "hide", width: "hide", opacity: "hide"
			}, speed, callback) :

			this.filter(":visible").each(function(){
				this.oldblock = this.oldblock || jQuery.css(this,"display");
				this.style.display = "none";
			}).end();
	},

	// Save the old toggle function
	_toggle: jQuery.fn.toggle,

	toggle: function( fn, fn2 ){
		return jQuery.isFunction(fn) && jQuery.isFunction(fn2) ?
			this._toggle.apply( this, arguments ) :
			fn ?
				this.animate({
					height: "toggle", width: "toggle", opacity: "toggle"
				}, fn, fn2) :
				this.each(function(){
					jQuery(this)[ jQuery(this).is(":hidden") ? "show" : "hide" ]();
				});
	},

	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.animate({height: "toggle"}, 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 ) {
		var optall = jQuery.speed(speed, easing, callback);

		return this[ optall.queue === false ? "each" : "queue" ](function(){
			if ( this.nodeType != 1)
				return false;

			var opt = jQuery.extend({}, optall), p,
				hidden = jQuery(this).is(":hidden"), self = this;

			for ( p in prop ) {
				if ( prop[p] == "hide" && hidden || prop[p] == "show" && !hidden )
					return opt.complete.call(this);

				if ( p == "height" || p == "width" ) {
					// Store display property
					opt.display = jQuery.css(this, "display");

					// Make sure that nothing sneaks out
					opt.overflow = this.style.overflow;
				}
			}

			if ( opt.overflow != null )
				this.style.overflow = "hidden";

			opt.curAnim = jQuery.extend({}, prop);

			jQuery.each( prop, function(name, val){
				var e = new jQuery.fx( self, opt, name );

				if ( /toggle|show|hide/.test(val) )
					e[ val == "toggle" ? hidden ? "show" : "hide" : val ]( prop );
				else {
					var parts = val.toString().match(/^([+-]=)?([\d+-.]+)(.*)$/),
						start = e.cur(true) || 0;

					if ( parts ) {
						var end = parseFloat(parts[2]),
							unit = parts[3] || "px";

						// We need to compute starting value
						if ( unit != "px" ) {
							self.style[ name ] = (end || 1) + unit;
							start = ((end || 1) / e.cur(true)) * start;
							self.style[ name ] = start + unit;
						}

						// If a +=/-= token was provided, we're doing a relative animation
						if ( parts[1] )
							end = ((parts[1] == "-=" ? -1 : 1) * end) + start;

						e.custom( start, end, unit );
					} else
						e.custom( start, val, "" );
				}
			});

			// For JS strict compliance
			return true;
		});
	},

	queue: function(type, fn){
		if ( jQuery.isFunction(type) || ( type && type.constructor == Array )) {
			fn = type;
			type = "fx";
		}

		if ( !type || (typeof type == "string" && !fn) )
			return queue( this[0], type );

		return this.each(function(){
			if ( fn.constructor == Array )
				queue(this, type, fn);
			else {
				queue(this, type).push( fn );

				if ( queue(this, type).length == 1 )
					fn.call(this);
			}
		});
	},

	stop: function(clearQueue, gotoEnd){
		var timers = jQuery.timers;

		if (clearQueue)
			this.queue([]);

		this.each(function(){
			// go in reverse order so anything added to the queue during the loop is ignored
			for ( var i = timers.length - 1; i >= 0; i-- )
				if ( timers[i].elem == this ) {
					if (gotoEnd)
						// force the next step to be the last
						timers[i](true);
					timers.splice(i, 1);
				}
		});

		// start the next in the queue if the last step wasn't forced
		if (!gotoEnd)
			this.dequeue();

		return this;
	}

});

var queue = function( elem, type, array ) {
	if ( elem ){

		type = type || "fx";

		var q = jQuery.data( elem, type + "queue" );

		if ( !q || array )
			q = jQuery.data( elem, type + "queue", jQuery.makeArray(array) );

	}
	return q;
};

jQuery.fn.dequeue = function(type){
	type = type || "fx";

	return this.each(function(){
		var q = queue(this, type);

		q.shift();

		if ( q.length )
			q[0].call( 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 :
			jQuery.fx.speeds[opt.duration]) || jQuery.fx.speeds.def;

		// Queueing
		opt.old = opt.complete;
		opt.complete = function(){
			if ( opt.queue !== false )
				jQuery(this).dequeue();
			if ( jQuery.isFunction( opt.old ) )
				opt.old.call( this );
		};

		return opt;
	},

	easing: {
		linear: function( p, n, firstNum, diff ) {
			return firstNum + diff * p;
		},
		swing: function( p, n, firstNum, diff ) {
			return ((-Math.cos(p*Math.PI)/2) + 0.5) * diff + firstNum;
		}
	},

	timers: [],
	timerId: null,

	fx: function( elem, options, prop ){
		this.options = options;
		this.elem = elem;
		this.prop = prop;

		if ( !options.orig )
			options.orig = {};
	}

});

jQuery.fx.prototype = {

	// Simple function for setting a style value
	update: function(){
		if ( this.options.step )
			this.options.step.call( this.elem, this.now, this );

		(jQuery.fx.step[this.prop] || jQuery.fx.step._default)( this );

		// Set display property to block for height/width animations
		if ( this.prop == "height" || this.prop == "width" )
			this.elem.style.display = "block";
	},

	// Get the current size
	cur: function(force){
		if ( this.elem[this.prop] != null && this.elem.style[this.prop] == null )
			return this.elem[ this.prop ];

		var r = parseFloat(jQuery.css(this.elem, this.prop, force));
		return r && r > -10000 ? r : parseFloat(jQuery.curCSS(this.elem, this.prop)) || 0;
	},

	// Start an animation from one number to another
	custom: function(from, to, unit){
		this.startTime = now();
		this.start = from;
		this.end = to;
		this.unit = unit || this.unit || "px";
		this.now = this.start;
		this.pos = this.state = 0;
		this.update();

		var self = this;
		function t(gotoEnd){
			return self.step(gotoEnd);
		}

		t.elem = this.elem;

		jQuery.timers.push(t);

		if ( jQuery.timerId == null ) {
			jQuery.timerId = setInterval(function(){
				var timers = jQuery.timers;

				for ( var i = 0; i < timers.length; i++ )
					if ( !timers[i]() )
						timers.splice(i--, 1);

				if ( !timers.length ) {
					clearInterval( jQuery.timerId );
					jQuery.timerId = null;
				}
			}, 13);
		}
	},

	// Simple 'show' function
	show: function(){
		// Remember where we started, so that we can go back to it later
		this.options.orig[this.prop] = jQuery.attr( this.elem.style, this.prop );
		this.options.show = true;

		// Begin the animation
		this.custom(0, this.cur());

		// Make sure that we start at a small width/height to avoid any
		// flash of content
		if ( this.prop == "width" || this.prop == "height" )
			this.elem.style[this.prop] = "1px";

		// Start by showing the element
		jQuery(this.elem).show();
	},

	// Simple 'hide' function
	hide: function(){
		// Remember where we started, so that we can go back to it later
		this.options.orig[this.prop] = jQuery.attr( this.elem.style, this.prop );
		this.options.hide = true;

		// Begin the animation
		this.custom(this.cur(), 0);
	},

	// Each step of an animation
	step: function(gotoEnd){
		var t = now();

		if ( gotoEnd || t > this.options.duration + this.startTime ) {
			this.now = this.end;
			this.pos = this.state = 1;
			this.update();

			this.options.curAnim[ this.prop ] = true;

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

			if ( done ) {
				if ( this.options.display != null ) {
					// Reset the overflow
					this.elem.style.overflow = this.options.overflow;

					// Reset the display
					this.elem.style.display = this.options.display;
					if ( jQuery.css(this.elem, "display") == "none" )
						this.elem.style.display = "block";
				}

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

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

			if ( done )
				// Execute the complete function
				this.options.complete.call( this.elem );

			return false;
		} else {
			var n = t - this.startTime;
			this.state = n / this.options.duration;

			// Perform the easing function, defaults to swing
			this.pos = jQuery.easing[this.options.easing || (jQuery.easing.swing ? "swing" : "linear")](this.state, n, 0, 1, this.options.duration);
			this.now = this.start + ((this.end - this.start) * this.pos);

			// Perform the next step of the animation
			this.update();
		}

		return true;
	}

};

jQuery.extend( jQuery.fx, {
	speeds:{
		slow: 600,
 		fast: 200,
 		// Default speed
 		def: 400
	},
	step: {
		scrollLeft: function(fx){
			fx.elem.scrollLeft = fx.now;
		},

		scrollTop: function(fx){
			fx.elem.scrollTop = fx.now;
		},

		opacity: function(fx){
			jQuery.attr(fx.elem.style, "opacity", fx.now);
		},

		_default: function(fx){
			fx.elem.style[ fx.prop ] = fx.now + fx.unit;
		}
	}
});
// The Offset Method
// Originally By Brandon Aaron, part of the Dimension Plugin
// http://jquery.com/plugins/project/dimensions
jQuery.fn.offset = function() {
	var left = 0, top = 0, elem = this[0], results;

	if ( elem ) with ( jQuery.browser ) {
		var parent       = elem.parentNode,
		    offsetChild  = elem,
		    offsetParent = elem.offsetParent,
		    doc          = elem.ownerDocument,
		    safari2      = safari && parseInt(version) < 522 && !/adobeair/i.test(userAgent),
		    css          = jQuery.curCSS,
		    fixed        = css(elem, "position") == "fixed";

		// Use getBoundingClientRect if available
		if ( elem.getBoundingClientRect ) {
			var box = elem.getBoundingClientRect();

			// Add the document scroll offsets
			add(box.left + Math.max(doc.documentElement.scrollLeft, doc.body.scrollLeft),
				box.top  + Math.max(doc.documentElement.scrollTop,  doc.body.scrollTop));

			// IE adds the HTML element's border, by default it is medium which is 2px
			// IE 6 and 7 quirks mode the border width is overwritable by the following css html { border: 0; }
			// IE 7 standards mode, the border is always 2px
			// This border/offset is typically represented by the clientLeft and clientTop properties
			// However, in IE6 and 7 quirks mode the clientLeft and clientTop properties are not updated when overwriting it via CSS
			// Therefore this method will be off by 2px in IE while in quirksmode
			add( -doc.documentElement.clientLeft, -doc.documentElement.clientTop );

		// Otherwise loop through the offsetParents and parentNodes
		} else {

			// Initial element offsets
			add( elem.offsetLeft, elem.offsetTop );

			// Get parent offsets
			while ( offsetParent ) {
				// Add offsetParent offsets
				add( offsetParent.offsetLeft, offsetParent.offsetTop );

				// Mozilla and Safari > 2 does not include the border on offset parents
				// However Mozilla adds the border for table or table cells
				if ( mozilla && !/^t(able|d|h)$/i.test(offsetParent.tagName) || safari && !safari2 )
					border( offsetParent );

				// Add the document scroll offsets if position is fixed on any offsetParent
				if ( !fixed && css(offsetParent, "position") == "fixed" )
					fixed = true;

				// Set offsetChild to previous offsetParent unless it is the body element
				offsetChild  = /^body$/i.test(offsetParent.tagName) ? offsetChild : offsetParent;
				// Get next offsetParent
				offsetParent = offsetParent.offsetParent;
			}

			// Get parent scroll offsets
			while ( parent && parent.tagName && !/^body|html$/i.test(parent.tagName) ) {
				// Remove parent scroll UNLESS that parent is inline or a table to work around Opera inline/table scrollLeft/Top bug
				if ( !/^inline|table.*$/i.test(css(parent, "display")) )
					// Subtract parent scroll offsets
					add( -parent.scrollLeft, -parent.scrollTop );

				// Mozilla does not add the border for a parent that has overflow != visible
				if ( mozilla && css(parent, "overflow") != "visible" )
					border( parent );

				// Get next parent
				parent = parent.parentNode;
			}

			// Safari <= 2 doubles body offsets with a fixed position element/offsetParent or absolutely positioned offsetChild
			// Mozilla doubles body offsets with a non-absolutely positioned offsetChild
			if ( (safari2 && (fixed || css(offsetChild, "position") == "absolute")) ||
				(mozilla && css(offsetChild, "position") != "absolute") )
					add( -doc.body.offsetLeft, -doc.body.offsetTop );

			// Add the document scroll offsets if position is fixed
			if ( fixed )
				add(Math.max(doc.documentElement.scrollLeft, doc.body.scrollLeft),
					Math.max(doc.documentElement.scrollTop,  doc.body.scrollTop));
		}

		// Return an object with top and left properties
		results = { top: top, left: left };
	}

	function border(elem) {
		add( jQuery.curCSS(elem, "borderLeftWidth", true), jQuery.curCSS(elem, "borderTopWidth", true) );
	}

	function add(l, t) {
		left += parseInt(l, 10) || 0;
		top += parseInt(t, 10) || 0;
	}

	return results;
};


jQuery.fn.extend({
	position: function() {
		var left = 0, top = 0, results;

		if ( this[0] ) {
			// Get *real* offsetParent
			var offsetParent = this.offsetParent(),

			// Get correct offsets
			offset       = this.offset(),
			parentOffset = /^body|html$/i.test(offsetParent[0].tagName) ? { top: 0, left: 0 } : offsetParent.offset();

			// Subtract element margins
			// note: when an element has margin: auto the offsetLeft and marginLeft 
			// are the same in Safari causing offset.left to incorrectly be 0
			offset.top  -= num( this, 'marginTop' );
			offset.left -= num( this, 'marginLeft' );

			// Add offsetParent borders
			parentOffset.top  += num( offsetParent, 'borderTopWidth' );
			parentOffset.left += num( offsetParent, 'borderLeftWidth' );

			// Subtract the two offsets
			results = {
				top:  offset.top  - parentOffset.top,
				left: offset.left - parentOffset.left
			};
		}

		return results;
	},

	offsetParent: function() {
		var offsetParent = this[0].offsetParent;
		while ( offsetParent && (!/^body|html$/i.test(offsetParent.tagName) && jQuery.css(offsetParent, 'position') == 'static') )
			offsetParent = offsetParent.offsetParent;
		return jQuery(offsetParent);
	}
});


// Create scrollLeft and scrollTop methods
jQuery.each( ['Left', 'Top'], function(i, name) {
	var method = 'scroll' + name;
	
	jQuery.fn[ method ] = function(val) {
		if (!this[0]) return;

		return val != undefined ?

			// Set the scroll offset
			this.each(function() {
				this == window || this == document ?
					window.scrollTo(
						!i ? val : jQuery(window).scrollLeft(),
						 i ? val : jQuery(window).scrollTop()
					) :
					this[ method ] = val;
			}) :

			// Return the scroll offset
			this[0] == window || this[0] == document ?
				self[ i ? 'pageYOffset' : 'pageXOffset' ] ||
					jQuery.boxModel && document.documentElement[ method ] ||
					document.body[ method ] :
				this[0][ method ];
	};
});
// Create innerHeight, innerWidth, outerHeight and outerWidth methods
jQuery.each([ "Height", "Width" ], function(i, name){

	var tl = i ? "Left"  : "Top",  // top or left
		br = i ? "Right" : "Bottom"; // bottom or right

	// innerHeight and innerWidth
	jQuery.fn["inner" + name] = function(){
		return this[ name.toLowerCase() ]() +
			num(this, "padding" + tl) +
			num(this, "padding" + br);
	};

	// outerHeight and outerWidth
	jQuery.fn["outer" + name] = function(margin) {
		return this["inner" + name]() +
			num(this, "border" + tl + "Width") +
			num(this, "border" + br + "Width") +
			(margin ?
				num(this, "margin" + tl) + num(this, "margin" + br) : 0);
	};

});})();
/*  
===============================================================================
WResize is the jQuery plugin for fixing the IE window resize bug
...............................................................................
                                               Copyright 2007 / Andrea Ercolino
-------------------------------------------------------------------------------
LICENSE: http://www.opensource.org/licenses/mit-license.php
WEBSITE: http://noteslog.com/
===============================================================================
*/

( function( $ ) 
{
	$.fn.wresize = function( f ) 
	{
		version = '1.1';
		wresize = {fired: false, width: 0};

		function resizeOnce() 
		{
			if ( $.browser.msie )
			{
				if ( ! wresize.fired )
				{
					wresize.fired = true;
				}
				else 
				{
					var version = parseInt( $.browser.version, 10 );
					wresize.fired = false;
					if ( version < 7 )
					{
						return false;
					}
					else if ( version == 7 )
					{
						//a vertical resize is fired once, an horizontal resize twice
						var width = $( window ).width();
						if ( width != wresize.width )
						{
							wresize.width = width;
							return false;
						}
					}
				}
			}

			return true;
		}

		function handleWResize( e ) 
		{
			if ( resizeOnce() )
			{
				return f.apply(this, [e]);
			}
		}

		this.each( function() 
		{
			if ( this == window )
			{
				$( this ).resize( handleWResize );
			}
			else
			{
				$( this ).resize( f );
			}
		} );

		return this;
	};

} ) ( 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" class="jcarousel-skin-name"><li>First item</li><li>Second item</li></ul>
     * @result
     *
     * <div class="jcarousel-skin-name">
     *   <div class="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>
     * </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,
        offset: 1,
        size: null,
        scroll: 3,
        visible: null,
        animation: 'normal',
        easing: 'swing',
        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.locked     = false;

        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';

        // Extract skin class
        var skin = '', split = e.className.split(' ');

        for (var i = 0; i < split.length; i++) {
            if (split[i].indexOf('jcarousel-skin') != -1) {
                $(e).removeClass(split[i]);
                var skin = split[i];
                break;
            }
        }

        if (e.nodeName == 'UL' || e.nodeName == 'OL') {
            this.list = $(e);
            this.container = this.list.parent();

            if (this.container.hasClass('jcarousel-clip')) {
                if (!this.container.parent().hasClass('jcarousel-container'))
                    this.container = this.container.wrap('<div></div>');

                this.container = this.container.parent();
            } else if (!this.container.hasClass('jcarousel-container'))
                this.container = this.list.wrap('<div></div>').parent();
        } else {
            this.container = $(e);
            this.list = $(e).find('>ul,>ol,div>ul,div>ol');
        }

        if (skin != '' && this.container.parent()[0].className.indexOf('jcarousel-skin') == -1)
        	this.container.wrap('<div class=" '+ skin + '"></div>');

        this.clip = this.list.parent();

        if (!this.clip.length || !this.clip.hasClass('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 = this.list.children('li');

        var self = this;

        if (li.size() > 0) {
            var wh = 0, i = this.options.offset;
            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.funcResize = function() { self.reload(); };

        if (this.options.initCallback != null)
            this.options.initCallback(this, 'init');

        if ($.browser.safari) {
            this.buttons(false, false);
            $(window).bind('load', function() { self.setup(); });
        } else
            this.setup();
    };

    // Create shortcut for internal use
    var $jc = $.jcarousel;

    $jc.fn = $jc.prototype = {
        jcarousel: '0.2.3'
    };

    $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;

            if (this.locked)
                return;

            this.list.css(this.lt, this.pos(this.options.offset) + 'px');
            var p = this.pos(this.options.start);
            this.prevFirst = this.prevLast = null;
            this.animate(p, false);

            $(window).unbind('resize', this.funcResize).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, '10px');

            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;

            if (this.options.size !== null && i2 > this.options.size)
            	i2 = this.options.size;

            for (var j = i; j <= i2; j++) {
                var e = this.get(j);
                if (!e.length || e.hasClass('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, add = 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;
                var 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;

            if (j > last) {
                visible = 0, j = last, v = 0;
                while (++visible) {
                    var e = this.get(j--);
                    if (!e.length)
                        break;
                    v += this.dimension(e);
                    if (v >= clipping)
                        break;
                }
            }

            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;
            var scrolled = function() {
                self.animating = false;

                if (p == 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 !== null && !(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({
        /**
         * Gets/Sets the global default configuration properties.
         *
         * @name defaults
         * @descr Gets/Sets the global default configuration properties.
         * @type Hash
         * @param Hash d A set of key/value pairs to set as configuration properties.
         * @cat Plugins/jCarousel
         */
        defaults: function(d) {
            return $.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);
// *** ACTIONS FOR EVERY PAGE ON LOAD *** //
jQuery(document).ready(function() {
    appendBg();
    animateShopNav();
	watchInterfaces(); // permet d'empêcher le footer d'aller trop haut suivant la hauteur de page
});

$(window).wresize(watchInterfaces); // ecoute le resize du browser

var minWidth = 750; // largeur après laquelle le module e-shop (en haut à droite) n'est plus déplacé sur le resize

// *** PREPARATION *** //

// Set the page-bg area's height = entire document's height
function containersSetSize() {
	var validHeight = 700;
	if($(window).height() > 700)
		validHeight = $(window).height();

  jQuery('#page-bg').height(validHeight+'px');
  jQuery('#page').width('1200px')
  jQuery('#page').height(validHeight+'px');
  jQuery('#content').width('1200px')
  jQuery('#content').height(validHeight+'px');

  $("#mainmenu").height(validHeight+"px");
}

// Pseudo flash menu
function internalMenu() {
  jQuery('ul.cartridge-menu > li > span').fadeTo(1, 0.1);
  jQuery('ul[id^=creations] > li').mouseover( function(){ 
  	jQuery(this).children("span").fadeTo(1, 0.1);
  	jQuery(this).children("span").animate({'opacity' : 1}, 150) .animate({'opacity': 0.5 }, 200);
  	jQuery(this).children("a").addClass("over");
  });
  jQuery('ul[id^=creations] > li').mouseout( function(){ 
		jQuery(this).children("span").fadeTo(0.2,0.1, function() {
			jQuery(this).parent().children("a").removeClass("over");
		});
	});

  jQuery('ul#exclusive > li > span')
    .fadeTo(1, 0.3)
    .bind('mouseenter', function(){ jQuery(this).animate({'opacity' : 0.8}, 150) .animate({'opacity': 0.3 }, 200); });
};


// *** LOADING CONTENT *** //

// Insert the background image/flash
function appendBg() {
  containersSetSize();
};

// *** EFFECTS *** //

// Shop navbar animation
function animateShopNav() {
  jQuery('#shop-navigation > li > a')
    .fadeTo(1, 0.5)
    .bind('mouseenter', function(){ jQuery(this).animate({opacity: 1.0}, 250); })
    .bind('mouseleave', function(){ jQuery(this).animate({opacity: 0.5}, 250); });
};
// Tab menu
function tabMenu() {
	// :not seems not working for now
	jQuery('ul#tab-menu > li:not(.active)')
		.fadeTo(1, 0.5)
	    .bind('mouseenter', function(){
	    	//console.log('over');
	    	jQuery(this).animate({'opacity' : 0.9}, 150);
	    })
	    .bind('mouseleave', function(){
	    	//console.log('out');
	    	jQuery(this).animate({'opacity' : 0.5}, 150);
	    })
	    .bind('click', function(){
	    	//console.log('click');
			jQuery(this).parent().children().removeClass('active').fadeTo(1, 0.5);
			jQuery(this).addClass('active').fadeTo(0.5, 0.9)
				.bind('mouseleave', function(){
					jQuery(this).animate({'opacity' : 0.9}, 150);
				});
	    });
	jQuery('ul#tab-menu > li.active').fadeTo(0.5, 0.9);
};


// *** JCarousel *** //


// List of products handled by jCarousel
function buildCarouselProducts(iNbProduit) {
	if(iNbProduit < 7)
		jQuery('#line-items').jcarousel({ scroll: 1, animation: 'slow', buttonNextHTML: null, buttonPrevHTML: null});
	else
		jQuery('#line-items').jcarousel({ scroll: 1, animation: 'slow'});
  // Selon le ticket #239, il n'y a pas d'opacit� � mettre.
  // pour enclencher les effets d'apparition unitaire des elements, ajouter :  ,initCallback: initJcarrouselCallback 
  // dans content.css, ajouter "visibility:hidden;" � #content.product-line #line-items ul.items
  //jQuery('#line-items').jcarousel({ scroll: 1, animation: 'slow', initCallback: initJcarrouselRollOver});
}
function initJcarrouselRollOver() {
	var item = $('#line-items ul li.jcarousel-item ul li');
  $(item).animate({opacity: 0.6}, 500);
	// rollover sur les produits
  jQuery('#line-items ul li.jcarousel-item ul li')
    .bind('mouseenter', function(){ jQuery(this).animate({'opacity' : 1}, 500); })
    .bind('mouseleave', function(){ jQuery(this).animate({'opacity' : 0.5}, 500); });
}
function initJcarrouselCallback() {
	// declencher les effets d'apparition element par element seulement quand le carrousel est construit
	
	// les items sont masqu�s dans la css pour eviter l'apparition par defaut de la liste 
	$("#line-items ul.items").css('visibility','visible');
	
	// apparition des boutons suivants/precedents avec un delai ?
	jQuery('#line-items > .jcarousel-prev, #line-items > .jcarousel-next')
    .hide()
    .animate({opacity: 1.0}, 2000)
    .fadeIn(2000);

  // masquer tous les produits
  jQuery('#line-items ul li.jcarousel-item ul li').hide();
	// afficher les produits masqu�s un par un
  showProductsList();

	// rollover sur les produits
  jQuery('#line-items ul li.jcarousel-item ul li')
    .bind('mouseenter', function(){ jQuery(this).animate({'opacity' : 1}, 500); })
    .bind('mouseleave', function(){ jQuery(this).animate({'opacity' : 0.5}, 500); });
  // gestionnaires rollover et apparition des boutons suivants/precedents du carrousel
  jQuery('#line-items > .jcarousel-prev, #line-items > .jcarousel-next')
    .fadeTo(1000, 0.6)
    .bind('mouseenter', function(){ jQuery(this).animate({'opacity' : 1}, 300); })
    .bind('mouseleave', function(){ jQuery(this).animate({'opacity' : 0.6}, 300); });

}
// afficher les produits du carrousel un par un
function showProductsList() {
  var j = 6;
  var item = $('#line-items ul li.jcarousel-item ul li');
  $(item).animate({opacity: 0.6}, 500)
  //$(item).hide();
  function outer(){
    var a = 0;
    function inner(){
      if (a>=j)
      {
        $(item).show();
      }
      a++;
      $(item).eq(a-1).fadeIn(500,function(){fader();});
    }
    return inner;
  }
  var fader = outer();
  fader();
};

// Widget menu
function widgetMenu() {
  jQuery('ul#widget-menu > li ')
    .fadeTo(1, 0.5)
    .bind('mouseenter', function(){ jQuery(this).animate({'opacity' : 1}, 150) .animate({'opacity': 0.6 }, 200); });
};

// Change points to gifts list
function pointsToGifts() {
 jQuery('ul#points-to-gifts > li > p').fadeTo(1, 0.0);
 jQuery('ul#points-to-gifts > li')
  .bind('mouseenter', function() {
    jQuery(this).children('img')
      .animate({'opacity' : 0.5}, 500);
    jQuery(this).children('p')
      .animate({'opacity' : 1.0}, 1000);
  })
  .bind('mouseleave', function(){
    jQuery(this).children('p')
      .animate({'opacity' : 0.0}, 200);
    jQuery(this).children('img')
      .animate({'opacity' : 1.0}, 300);
  })
};

// Show / hide descriptions list
function showMe() {
  jQuery('li.item > .container').hide();
  jQuery('li.item.active > .container').show();
  jQuery('li.item > h4 > a')
   .bind('click', function() {
     jQuery('li.item').removeClass('active').children('.container')
       .animate({opacity: 0.0}, 300)
       .slideUp(400);
     $(this).parent().parent().addClass('active').children('.container')
       .animate({opacity: 1.0}, 1000)
       .slideDown(300);
   });
};

// Show / hide address list
function openList() {
  jQuery('li.element > .contener').hide();
  jQuery('li.element.active > .contener').show();
  jQuery('li.element > h4 > a')
   .bind('click', function() {
      $('li.element').children('.contener')
      .animate({opacity: 0.0}, 300)
      .slideUp(200);
      $('li.element').removeClass('active');
     $(this).parent().parent().children('.contener')
      .animate({opacity: 1.0}, 1000)
      .slideDown(200);
     $(this).parent().parent().addClass('active');
   });
};

// jScrollPane plugin handling - if there is more content in description-list - change class
function scrollHandling() {
 jQuery('.jScrollPaneTrack').siblings('.list-content')
   .addClass('scroll');
};


function runScrollPane(element) {
  $(element)
    .jScrollPane({
      scrollbarWidth:5,
      dragMinHeight:0,
      dragMaxHeight:0,
      showArrows:true,
      wheelSpeed:10,
      maintainPosition:true
    });
 };

function runCheckbox(element) {
  	$(element).checkbox();
};

function runCheckbox(element, src) {
  	$(element).checkbox({empty: src});
 };

function runSelectbox(element) {
	//console.log("entring normal runSelectbox function for:"+element)
	$(element).selectbox();
 };

function runAjaxSelectbox(element) {
	//console.log("entring runAjaxSelectbox function for:"+element)
	$(element).ajaxSelectbox();
};

/**
 * Add behaviour to "quantity" lists (those used to choose product variant value)
 * @param idUl Id of the list
 * The id of the items will be passed to the callback function. The callback
 * function is called each times an element is selected
 */
 function changeValue(idUl, moveUpId, moveDownId, callbackFunc) {

	// TODO : use a constant for 13
	
  // search the active element (specified by the class "active") and focus on it
  var nbPrevInactiveElements = jQuery(idUl + ' > li[class=active]').prevAll().length;
  var topMargin = jQuery(idUl).css('margin-top');
  var topOffsetToDo = parseInt(topMargin) - (nbPrevInactiveElements*13);
  jQuery(idUl).css('margin-top', topOffsetToDo + 'px');
  
  jQuery(moveDownId)
    .bind('click', function(){
      var listHeight = jQuery(idUl).height();
      var maxOffset = listHeight - 13;
      var topMargin = parseInt(jQuery(idUl).css('margin-top'));
	  if(topMargin%13 == 0) {
        var topOffsetToDo = topMargin - 13;
        if (topOffsetToDo >= -maxOffset)
        {
    	  jQuery(idUl).animate({marginTop: topOffsetToDo+'px'}, 150);
        
          // change active element
          var oldActive = jQuery(idUl + ' > li[class=active]');
	      oldActive.removeClass('active');
	      var newActiveNumber = Math.abs(parseInt(topOffsetToDo / 13)) + 1;
	      var newActive = jQuery(idUl + ' > li:nth-child(' + newActiveNumber + ')');
	      newActive.addClass('active');
	      callbackFunc(newActive.attr('id'));
        }
	  }
    });
  jQuery(moveUpId)
    .bind('click', function(){
      var listHeight = jQuery(idUl).height();
      var maxOffset = 0;
      var topMargin = parseInt(jQuery(idUl).css('margin-top'));
	  if(topMargin%13 == 0) {
        var topOffsetToDo = topMargin + 13;
        if (topOffsetToDo <= maxOffset)
        {
      	  jQuery(idUl).animate({marginTop: topOffsetToDo+'px'}, 150);
        
          // change active element
          var oldActive = jQuery(idUl + ' > li[class=active]');
	      oldActive.removeClass('active');
	      var newActiveNumber = Math.abs(parseInt(topOffsetToDo / 13)) + 1;
	      var newActive = jQuery(idUl + ' > li:nth-child(' + newActiveNumber + ')');
	      newActive.addClass('active');
	      callbackFunc(newActive.attr('id'));
        }
	  }
    });
};

// show fake popup and hide content under it
// Fade in content (when page is loaded)
function popupHandle(urlToLoad, idTrigger, idContainer){
	idTrigger = '#'+idTrigger;
	idContainer = '#'+idContainer;
	
	var fadeOutDuration = 100;
	var fadeInDuration = 100;
	
	jQuery(idContainer).hide();
  
	//Pour le lien "envoie � un ami/une amie"
	jQuery(idTrigger).bind('click',function(){
		//Maybe usefull for IE
		//$('#tab-menu, .products, #description-list, form#order').animate({opacity: 0.0}, fadeOutDuration).fadeOut(fadeOutDuration);
		$(idContainer).load(urlToLoad,function(){
			$(".popupBox").not(idContainer).hide();
			$(idContainer).animate({opacity: 1.0}, fadeInDuration).fadeIn(fadeInDuration, function() {
				// For IE6 transparency fix.
				if($.browser.msie && $.browser.version == "6.0"){
					$('img[@src$=.png]').ifixpng();
				}
				$(idContainer).animate({opacity: 1.0}, fadeInDuration).fadeIn(fadeInDuration);
				jQuery(idContainer + ' a.close').bind('click',function(){
					$(idContainer).animate({opacity: 0.0}, fadeOutDuration).fadeOut(fadeOutDuration);
					//Maybe usefull for IE
					//$('#tab-menu, .products, #description-list, form#order').animate({opacity: 1.0}, fadeInDuration).fadeIn(fadeInDuration);
				});
			});
		});
	});
};

function lostPass(){
 jQuery('#forgotten-pass').click(function(){
	 $('#lostpassword').animate({opacity: 1.0}, 600).fadeIn(700);
   	  return false;
   });
 };

function passSucces(){
 };

function inscrConfirm(){
 jQuery('#inscr-add').click(function(){
   $('#inscr-confirm')
     .animate({opacity: 1.0}, 600)
     .fadeIn(700);
   });
 };

function popupInit(){
   jQuery('.popup').hide();
   lostPass();
   inscrConfirm();
   //close button
   jQuery('.popup > a.close').bind('click',function(){
	   //$('.popup').animate({opacity: 0.0}, 1000).fadeOut(1000);
	   $('.popup').hide();
    });
 };
 
 /**
 * permet de gerer les affichages ou non du footer et du menu e-shop
 */
 function watchInterfaces() {
 	// gestion du positionnement du footer en fonction de la hauteur du menu et de la page
 	if ($(window).height() < $("#mainmenu").height()) {
 		$("#footer").css({position:"relative",top:"0px"});
 	} else {
 		if($(window).height() < 700) {
 			$("#footer").css({position:"absolute",top:"700px"});
 		} else {
 			$("#footer").css({position:"absolute",top: ( $(window).height() - $("#footer").height())+"px"});	
 		}
 	}
 	if($(window).width()>1200){
 		
	 	$("#footer").width($(window).width()+"px");
	 	// gestion du body
	 	$("#page").width($(window).width()+"px");
	 	$("#content").width($(window).width()+"px");
	 	
 	}else{
 		$("#footer").width("1200px");
	 	// gestion du body
	 	$("#page").width("1200px");
	 	$("#page-bg").width("1200px");
	 	$("#content").width("1200px");

	 	
 	}
 	
 	// gestion du module e-shop
	 if ( ($(window).width() - $("#shop-navigation").width()) < minWidth ) {// on va trop loin avec le module
	 	if ($.browser.msie) {
		 	$("#shop-navigation").css({right: "-"+$("#shop-navigation").width()+"px"});
		} else {
			$("#shop-navigation").animate({top: "-"+$("#shop-navigation").height()+"px"});
		}
	 } else {
	 	if ($.browser.msie) {
	 		$("#shop-navigation").css({right: "0px"});
	 	} else {
	 		$("#shop-navigation").animate({top: "0px"});
	 	}
	 }
 }

function setPopupContent(urlToLoad, idDiv) {
	$.get(
		urlToLoad,
	    "",
	    function(data, textStatus) {
			$("#"+idDiv).append($(data).find("#legality"));
    });
	/*
	var contextToRemove = appContext.replace(/\//g, "\\/");
	var url = location.protocol + "//" + location.host + appContext + "/layout-https" + urlToLoad.replace(new RegExp(contextToRemove),"");

	$.get(
		url,
	    "",
	    function(data, textStatus) {
			var trueUrl = location.protocol + "//" + location.host + appContext + urlToLoad.replace(new RegExp(contextToRemove),"");
			if(data != "null") {
				trueUrl = data.replace("/layout-https","");
			}
			$.get(
				trueUrl,
				"",
				function(trueData, textStatus) {
					$("#"+idDiv).append($(trueData).find("#legality"));
				});
    });
    */
}

function showLegalMention() {
	$("#legalityPopup").show();
	$("#legalityPopup div.terms-content").jScrollPane({scrollbarWidth:5, dragMinHeight:10, dragMaxHeight:10, showArrows:true, wheelSpeed:10});
	$("#legality a.close").click(function() {$("#legalityPopup").hide();});
}

function hideLegalMention() {
	$("#legalityPopup").hide();
}

/* waitLoaderShow */
function waitLoaderSimpleShow(idDivContainer) {
	waitLoaderShow(idDivContainer, $("#"+idDivContainer).height()/2, $("#"+idDivContainer).width()/2);
}

function waitLoaderShow(idDivContainer, topPos, leftPos) {
	$("#"+idDivContainer).append("<div id='waitingLoader'><img src='"+tb_pathToImage+"' /></div>");
	$("#waitingLoader").css("top", topPos+"px");
	$("#waitingLoader").css("left", leftPos+"px");
}

/* waitLoaderHide */
function waitLoaderHide(idDivContainer) {
	$("#"+idDivContainer+" #waitingLoader").remove();
}
// Do a nice page reload after clicking on internal link
function loadPage(address) {

  $('#content').fadeOut(1500, function(){
    jQuery(this).parent().load(address+' #content', function(){

      // Apply loaded page's content to the current page
      jQuery(this).show(1, function () {
        // If #points-vente is found, run scrollpane on it
        runScrollPane('#points-vente ul.places');
        runScrollPane('#points-vente div.address-content');
        jQuery('#content-inside > *')
          .hide();
        jQuery('#shop-navigation')
          .hide();
      });

      appendBg();

      // Load new content (only if it hasn't been loaded in appendBg() yet)
      loadContentDelay();

      // Apply effects
      animateShopNav();
      internalMenu();
      tabMenu();
      buildVenteContent();

    });
  });
  return false;

};


function reloadTo(address) {

  $('#content').fadeOut(1500, function(){
    document.location = address;
    $('#content').hide();

  });
  return false;

};


function initHorizontalMenu(){
	var menuWrapper = $("#horizontal-navigation");
	// vars pour les placements de menus
	var autorizedWidth = 600;//menuWrapper.width() +  menuWrapper.offset().left;
	var link; // référence au lien survolé
	var linkWidth; // pour récupérer la largeur du lien survolé (car prise en compte des padding droits et gauche)
	var linkXoffest; // position en X du lien que l'on va survoler
	var childWidth; // largeur du sous-menu qu'on va afficher
	var child = null; // référence au sous-menbu
	
	var divTop = parseInt(menuWrapper.css("top").split("px")[0]);
	var currentLink; // stocker le lien en cours de survol (il est mis à jour à chaque nouveau survol)
	
	///////////////////////////////////////  gestionnaires d'événements pour les liens de nieau 1 :::::::::::::::::::::::::::::::::::::::::::::::
	// rollover sur un lien de la navigation horizontale
	$("li[class='lvl_1'] > a").mouseover(function() {
		link = $(this);
		// masquer le menu précédent s'il est différent du menu en cours
		if (currentLink != undefined && currentLink != link) {
			hideMenu_forNav();
		}
		currentLink = link;
		showMenu_forNav();
	});
	// si on quitte le lien par le haut ou qu'il n'a pas d'enfant, le 
	$("li[class='lvl_1'] > a").bind("mouseleave", function(e) { 
		if (e.pageY < divTop || child == null ) {
			hideMenu_forNav();
		}
	});
	// gestionnaire de clicks
	$("li[class='lvl_1'] > a").mouseup(function() {
		clickOnMenu_forNav($(this));
	});
	///////////////////////////////////////  gestionnaires d'événements pour les liens de nieau 2 :::::::::::::::::::::::::::::::::::::::::::::::
	// quitter les sous menus
	menuWrapper.children("ul").children("li").children("ul").bind("mouseleave",function() {  // le bind est mieux gérer que le mouseout
		hideMenu_forNav();
	});
	// click sur les liens des sous-menus
	menuWrapper.children("ul").children("li").children("ul").children("li").children("a").mouseup(function() {
		clickOnMenu_forNav($(this));
	});


	///////////////////////////////////////	fonctions de gestions ::::::::::::::::::::::::::::::::::::::::::	
	// affiche un menu + sous-menu s'il existe
	function showMenu_forNav() {
		 if ( hasChild(link) ) { // this = <a>
				link.addClass("activeDown");
				child = link.parent().children("ul");		
				child.show();
				
				// obtenir la largeur du sous-menu qu'on va afficher
				childWidth = 0;
				child.children("li").each(function() {
					childWidth += $(this).width();
				});
				child.width(childWidth); // important de réaffecter la largeur de la liste en question pour IE6
				
				// repositionner le menu s'il dépasse à droite, en le calant sous le bord droit du lien actif
				linkXoffest = link.offset().left;
				linkWidth = link.width() + parseInt(link.css("padding-left").split("px")[0]) + parseInt(link.css("padding-right").split("px")[0]);
				if ( childWidth + linkXoffest > autorizedWidth) {
					l = (linkWidth-childWidth) + "px";
					child.css({"margin-left":l});
				}
		} else { // le lien n'a pas d'enfants
			link.addClass("activeRight");
			child = null;
		}
	}
	// efface les sous-menus et met à jour les styles de lien
	function hideMenu_forNav() {
		if ( child != null) {
			currentLink.removeClass("activeDown");
			child.fadeOut('fast');
		} else {
			$(link).removeClass("activeRight");
		}		
	}
	// un menu a-t-il un sous menu ?
	function hasChild(link) {
		if (link.parent().children("ul").length > 0) {
			return true;
		}
		return false;
	}
	// gestionnaire pour les clicls sur les liens
	function clickOnMenu_forNav(link) {
		if (hasChild(link)) {
			//alert("ce lien ne doit pas être cliquable car il a un enfant");
		} else {
			//alert("Gestionnaire pour les liens du menu // version DEV \n Url trouvée : " + link.html() + " \n Aucun traitement pour le moment.");
		}
	}
}
/**
 * Called by the flash menu when it opens itself
 * @return
 */
function openDiv()
{
	$('.main-menu').css("width", "100%");
	$('.main-menu').css("z-index", 100);
}

/**
 * Called by the flash menu when it closes itself
 * @return
 */
function closeDiv()
{
	$('.main-menu').css("width", "234px");
	$('.main-menu').css("z-index", 10);
}

/**
 * Retrieve flash object.
 * @param movie_name name of the flash object.
 * @return
 */
function getApplicationReference(movie_name)
{
	if	( navigator.appName.indexOf('Microsoft') != -1 )
	{
		return window[movie_name];
	}
    else
    {
		return document[movie_name];
    }
}

/**
 * Send the url to the flash menu.
 * The menu uses this url as the current one.
 * @param value full url
 * @return
 */
function sendUrlToMenu(value) {
	if (typeof getApplicationReference("mainmenu").getUrl != 'function')
	{
		setTimeout(function(){sendUrlToMenu(value);}, 500);
	}
	else
	{
		getApplicationReference("mainmenu").getUrl(value);
	}
}

/**
 * Send the login status to the flash menu.
 * It is used by the flash menu to show itself with login or registration sub-menu.
 * @param value
 * @return
 */
function sendLoginStatusToMenu(value) {
	if (typeof getApplicationReference("mainmenu").getLoginStatus != 'function')
	{
		setTimeout(function(){sendLoginStatusToMenu(value);}, 500);
	}
	else
	{
		getApplicationReference("mainmenu").getLoginStatus(value);
	}
}

function sendLink(tabLink) {
	var indexPopup = tabLink.indexOf(' POPUP');
	var url = tabLink;
	
	if (tabLink == 'back' || tabLink == 'BACK') {
	  history.back();
	} else {
	
	  if (indexPopup > -1) {
	    var indexLang = tabLink.indexOf("/" + lang + "/");
	url = tabLink.substr(0,indexPopup);
	
	// thickbox
	if (tabLink.indexOf(' SMALL') > -1) {
	  url = url.substr(0, indexLang) + "/layout-shutter" + url.substr(indexLang, url.length);
	  tb_show('', url + '?height=270&width=430&inlineId=caddieMessage&modal=true&fromId=' + nfrontActiveObjectID + '&fromType=' + nfrontActiveObjectType);
	  $("#TB_window").addClass("TB_dioruniverse_window");
	  $("#TB_ajaxContent").addClass("TB_dioruniverse_ajaxContent");
	// normal popup
	    } else{
	      showPopupPage(url, 440, 480);
	    }
	  } else if (tabLink.indexOf("http") == 0 ) {
	    showPopup(tabLink, screen.availHeight, screen.availWidth);
	  }
	  else {
	    loadPageWithHistory(url);
	  }
	  var hash = url.substr(url.lastIndexOf("/" + lang + "/"),url.length);
	  /* 1093: D�sactivation de l'envoi des informations au clic vers Smart Profile */
	  /* sp_clic('N', document.title, location.hash.replace(/#/,''), hash); */
	
	}
}

function playVideo(url) {
	if (typeof getApplicationReference("video_player").playMovie != 'function')
	{
		setTimeout(function(){playVideo(url);}, 500);
	}
	else
	{
		getApplicationReference("video_player").playMovie(url);
	}
}

function refreshNav() {
	var nav = getNavObject();
	if (nav != null) {
      // when there are more than one flash on the site, nav is an array
      if (typeof(nav.length) == "undefined") {
        if (nav.connect) {
          nav.connect(sendID());
        }
      } else {
        //looping on all flash, trying to find updateArticle
        for(i=0;i<nav.length;i++) {
          try {
            if (nav.connect) {
              nav.connect(sendID());
            }
          } catch(e) {
            //alert(e);
          }
        }
      }
    }
  }
  
function getNavObject(){
	 if($.browser.msie) {
	    return window.navFlash;
	 } else {
	    return window.document.navFlash;
	 }  
  }

/* --- Constantes / Variables globales --- */

/* id de la div contenant les shutter */
var mainFrame = "#mainframe";

/* id de la div pour un shutter */
var shutter = "#shutter";

/* chemin de l'option 'preview' */
var preview = "/preview";

/* constantes */
var INIT_LEFT = 200;
var TOTAL_MARGIN = 80;

/* shutterIndex : represente l'id du dernier volet et le nombre de volets */
var shutterIndex = 1;

/* minLevel : represente le niveau du volet ayant le niveau le plus bas */
var minLevel = 1;

/* valeur de vitesse et de type d'animation */
var fadeDuration = 200;
var effectDuration = 1500;
var slideEffect = "easeout";

/* constante : nombre max de niveau */
var MAX_LEVEL = 8;

var currentContext = "";

/* valeur fixe de la marge d'un shutter (utilis� pour les flashs) */
var customLeftMargin = "";

var shutterTargeted;

var myUrl;
var myUrlLevel;

var INITIAL_SHUTTER_WIDTH = 710;
var _generatedWidth = document.documentElement.clientWidth;

var controllerDebug = false;

/* used for pane only */
var replaceId = null;

/* ------------------------ */
/* -private- writeDebug --- */
/* ------------------------ */
function writeDebug(msg) {
    if (controllerDebug) {
      console.debug(msg);
    }
}

/* -------------------------- */
/* -private-- JSController --- */
/* -------------------------- */

/**
 * url : url de la page demand�e
 * addToLeft : useless
 * isShutter : useless
 * alignLeft : useless
 */
function JSController(url, isShutter, isPopup) {
	//-- On construit l'url de la page requetee
	var sharpPosition = url.indexOf('#/' + lang ,0) + ('#/' + lang).length;
	var myUrl = url.substring(sharpPosition, url.length).replace(/\.html/,'/');
	
	var beginUrl = location.protocol + "//" + location.host + appContext;
	var endUrl = appSite + "/" + lang + myUrl.replace(/_/,"?");
	var ajaxUrl = beginUrl + "/layout-https" + endUrl;
	if(isPopup)
		ajaxUrl = beginUrl + "/layout-text" + endUrl;
	//--
	
	if(isPopup) {
		if(isPopup == "show") {
			$(".popup-flash").load(ajaxUrl, null, function() {
				$(".popup-flash").show();
			});
		} else if(isPopup == "hide") {
			$(".popup-flash").hide();
		}
	} else {
		 $.get(
		    ajaxUrl,
		    "",
		    function(data, textStatus) {
		      // no redirect 
		      if (data == "null") {
		        var ajaxUrlFinal = beginUrl + "/layout-shutter" + endUrl;
		         $.ajax({
		          type: "GET",
		          url: ajaxUrlFinal,
		          dataType: "html",
		          success: function(dataFinal, textStatus) {
		             $('#shutter1').html(dataFinal);
		             
		             // timeToWait is retrieve from the shutter.jsp and is related to the category.
		             if(timeToWait > 0) {
			             $('#content-inside').hide();
			             setTimeout(function(){
			             	$('#content-inside').show();
			             	}, timeToWait);
		             }
			        }
		        });
		      // redirect 
		      } else {
		        redirectHash(data.replace('/layout-https',''));
		      }
		    });
		    
	}
	
	/* Mise a jour du contexte */
	context = myUrl;
	shutterIndex = shutterTargeted;
}

/* ----------------------------- */
/* -private- compareLevelUrl --- */
/* ----------------------------- */
function compareLevelUrl(old_url, new_url) {
   /* suppression des eventuels parametres en fin d'URL (_...) */
   oldUrl = old_url.replace(/_.*$/, '').replace(/\/$/,'');
   newUrl = new_url.replace(/_.*$/, '').replace(/\/$/,'');

   var commonLevel = 0;
   var continueLoop = true;
   var returnVal = "";
   var nl = returnLevel(newUrl);
   var ol = returnLevel(oldUrl);
   var nbPlaceNeeded;
   var tOldUrl = oldUrl.split("/");
   var tNewUrl = newUrl.split("/");

   /* suppression du premier element (vide) */
   tOldUrl.shift();
   tNewUrl.shift();

   /* calcul du nombre de niveaux communs entre les 2 URL */
   while (commonLevel < tOldUrl.length && continueLoop) {
     if (tOldUrl[commonLevel] == tNewUrl[commonLevel]) {
       commonLevel++;
     } else {
       continueLoop = false;
     }
   }

   /* implicite: !(commonLevel>0) si les 2 URL sont completement diff�rentes -> on supprime tout les volets (NEW) */
   returnVal = "NEW";
   if (commonLevel > 0) {
      /* (max(ol,nl)-commonLevel <= 1) la diff�rence entre le niveau courant et le nombre de niveau en commun entre les 2 URL doit etre egal ou inf�rieur a 1
         (ie. /a/a1/a11 et /a/b1/b11 -> 3 - 1 = 2 NOK)
         (ie. /a/a1/a11 et /a/a1/a12 -> 3 - 2 = 1  OK)
         (ie. /a/a1/a11 et /a/b1/    -> 3 - 1 = 2 NOK)
         (ie. /a/a1/a11 et /a/a1/    -> 3 - 2 = 1  OK)
         (ie. /a/a1/    et /a/b1/b12 -> 3 - 1 = 2 NOK)
         (ie. /a/a1/    et /a/a1/a12 -> 3 - 2 = 1  OK) */
      if (Math.max(ol,nl) - commonLevel <= 1) {

        /* les niveaux sont equivalents, on remplace le contenu du volet */
        if (ol == nl) {
          if (shutterExist(newUrl)) {
            returnVal = "REPLACE";
          } else {
            returnVal = "NEW";
          }
        } else {

          /* calcul du nombre de places n�cessaires : 0 si le volet existe deja sinon 1 */
          nbPlaceNeeded = 1;
          if (shutterExist(newUrl)) {
            nbPlaceNeeded = 0;
          }

          /* il doit toujours rester une place libre (ou 0 si le volet existe deja) : le nombre de place libre est determin� en fonction du niveau le plus bas
          ie. a niveau min 4 et de nombre de shutter 2, on a 2 places pour les volets disponibles */
          if (minLevel - shutterIndex >= nbPlaceNeeded) {
            /* le niveau de l'ancienne URL est inf�rieur � la nouvelle (ie. /a/a1 -> /a) */
            if (ol == nl + 1) {
              if (getShutterIndexForLevel(nl) != 0 && !shutterExist(new_url)) {
                returnVal = "REPLACE_LEFT";
              } else {
                returnVal = "ADD_LEFT";
              }
            }
            /* le niveau de l'ancienne URL est sup�rieur � la nouvelle (ie. /a -> /a/a1) */
            else if (ol == nl - 1) {
              if (getShutterIndexForLevel(nl) != 0 && !shutterExist(new_url)) {
                returnVal = "REPLACE_RIGHT";
              } else {
                returnVal = "ADD_RIGHT";
              }
            }
          }
        }
      }
   }

   return returnVal;
}

/* ------------------------- */
/* -private- returnLevel --- */
/* ------------------------- */
function returnLevel(url) {
  /* suppression des parametres de l'url (_...) et du dernier */
  var _url = url.replace(/_.*$/, '').replace(/\/$/,'');
  return _url.split("/").length - 1;
}

/* ------------------------ */
/* -private- addShutter --- */
/* ------------------------ */
function addShutter(url, add_to_left, align_to_left) {
  // #1801 : special case for tint page
  var tintSpecialCase = context.lastIndexOf("_pane=tint") == context.length - "_pane=tint".length;
  tintSpecialCase = tintSpecialCase && returnLevel(context) == returnLevel(url);

  if (!shutterExist(url) && !tintSpecialCase ) {

    /* le shutter n'existe pas, on en cr�e un nouveau */
    var emptyShutter = getNewShutter(++shutterIndex);
    shutterTargeted = shutterIndex;
    if (add_to_left) {
      $(mainFrame).prepend(emptyShutter);
      $(mainFrame).css({left: INIT_LEFT - TOTAL_MARGIN - INITIAL_SHUTTER_WIDTH});
      /*insertion a gauche : suppression du volet a droite */
      ajaxCall(url, shutterIndex, "moveShutter()");
    } else {
      $(mainFrame).append(emptyShutter);
      /* insertion a droite on doit lancer l'animation de d�calage la div "mainframe" vers la gauche */
      ajaxCall(url, shutterIndex, "addShutterAnimation(1," + align_to_left + ")");
    }

  } else {

    if (add_to_left) {
      if (tintSpecialCase) {
        var shutterList = getShutterList();
        shutterTargeted = parseInt($(shutterList[shutterList.length-2]).find(".shutter-url").attr("title"));
      } else {
        shutterTargeted = shutterId(url);
      }
      addShutterAnimation(-1, align_to_left);
    } else {
      shutterTargeted = shutterIndex;
      addShutterAnimation(1, align_to_left);
    }

  }
}

/* --------------------------------- */
/* -private- addShutterAnimation --- */
/* --------------------------------- */
function addShutterAnimation(aDirection, alignToLeft) {
  customLeftMargin = getMargin(shutterTargeted);

  /* alignement du volet courant sur la gauche du navigateur */
  if (alignToLeft) {
    moveShutter();
  } else {
    var documentWidth = _generatedWidth;
    var shutterList = getShutterList();
    var widthNextToLastShutter = $(shutterList[shutterList.length-2]).width() + getShutterPadding(shutterList[shutterList.length-2]);
    var widthLastShutter = $(shutterList[shutterList.length-1]).width() + getShutterPadding(shutterList[shutterList.length-1]);

    /* alignement du volet courant sur la droite du naviagteur ou sinon � la droite du dernir volet  */
    if (INIT_LEFT + widthNextToLastShutter + widthLastShutter > documentWidth) {
      if (aDirection == 1) {
        moveShutter(documentWidth - getTotalWidth(), false);
      } else {
        moveShutter();
      }
    }
  }
}

/* -------------------------- */
/* -private- cleanShutter --- */
/* -------------------------- */
function cleanShutter(url) {
  shutterIndex = 1;
  shutterTargeted = 1;
  minLevel = returnLevel(url);
  ajaxCall(url, shutterIndex, "cleanShutterAnimation()", true);
}

/* ----------------------------------- */
/* -private- cleanShutterAnimation --- */
/* ----------------------------------- */
function cleanShutterAnimation() {
  $(mainFrame).css({left: getMargin(shutterIndex)});
}

/* ---------------------------- */
/* -private- replaceShutter --- */
/* ---------------------------- */
/* direction: 0 - REPLACE
             -1 - REPLACE_LEFT
              1 - REPLACE_RIGHT */
function replaceShutter(url, urlLevel, direction, noAnimation, index, alignLeft) {
  writeDebug("replaceShutter: " + url + " noAnimation: " + noAnimation);

  /* idx can be set manually (used in tint page) */
  var idx = index;
  if (idx == null) {
    idx = getShutterIndexForLevel(urlLevel + direction);
    if (idx == 0) {
      idx = 1;
    }
  }

  shutterTargeted = idx;

  if (noAnimation) {
    ajaxCall(url, idx, "");
  } else {
    if (alignLeft == null || alignLeft == true) {
      ajaxCall(url, idx, "replaceShutterAnimation()");
    } else {
      ajaxCall(url, idx, "addShutterAnimation(1, " + alignLeft + ")");
    }

  }
}

/* ------------------------------------- */
/* -private- replaceShutterAnimation --- */
/* ------------------------------------- */
function replaceShutterAnimation() {
  moveShutter();
}

/* -------------------------------- */
/* -public- closeCurrentShutter --- */
/* -------------------------------- */
function closeCurrentShutter() {
  history.back();
}

/* ------------------------- */
/* -private- moveShutter --- */
/* ------------------------- */
function moveShutter() {
  var mainFrameShift = 0;
  var mainFrameLeft = parseInt($(mainFrame).css("left").replace(/px/,''));

  if(arguments.length == 0) {
    /* pas d'argument : mode align� � gauche */
    var currentId = 0;
    getShutterList().each( function() {
      currentId = parseInt($(this).attr("id").replace(/shutter/,''));
      /* on additionne les marges et les tailles des shutters pr�cedant le shutter courant, pour obtenir le deplacement total */
      if (currentId != shutterTargeted) {
        mainFrameShift -= parseInt($(this).width());
        mainFrameShift -= getShutterPadding(this);
      } else {
        /* on additionne la marge de gauche du shutter courant et on met fin � la boucle */
        mainFrameShift += getMargin(shutterTargeted);
        return false;
      }
    });

    writeDebug("mainFrameLeft: " + mainFrameLeft);
    writeDebug("mainFrameShift: " + mainFrameShift);
    if(mainFrameLeft <= mainFrameShift) {
      removeShutter();
    }
  } else {
    /* argument 1 (taille) : mode libre */
    mainFrameShift = parseInt(arguments[0]);
    if(parseInt(arguments[0]) > 0) {
      /* argument 1 (boolean) : bloquage de la suppression */
      remove = true;
      if (arguments.length > 1) {
        if (arguments[1] == false) {
          remove = false;
        }
      }
      if (remove) {
        removeShutter();
      }
    }
  }

  if (mainFrameLeft != mainFrameShift) {
    $(mainFrame).animate({left: mainFrameShift}, effectDuration, slideEffect);
  }
}

/* ---------------------- */
/* -private- ajaxCall --- */
/* ---------------------- */
function ajaxCall(url, sIndex, aFunction, cleanBeforeInsert) {
  var isPreview = preview;
  var previewIndex = url.indexOf(preview);
  if (previewIndex > -1) {
    /* removing keyword preview from url */
    url = url.substr(0,previewIndex) + url.substr(previewIndex + preview.length, url.length);
  } else {
    isPreview = "";
  }

  /* moving jsessionid at first call */
  var jSessionID = "";
  if (appContext.indexOf(";jsessionid=") > -1) {
    jSessionID = appContext.substr(appContext.indexOf(";jsessionid="), appContext.length);
    appContext = appContext.substr(0, appContext.indexOf(";jsessionid="));
  }

  var beginUrl = location.protocol + "//" + location.host + appContext + isPreview;
  var endUrl = appSite + "/" + lang + url.replace(/_/,"?") + jSessionID;
  var ajaxHttpsUrl = beginUrl + "/layout-https" + endUrl;
  $.get(
    ajaxHttpsUrl,
    "",
    function(data, textStatus) {
      var ajaxUrl;
      /* no redirect */
      if (data == "null") {
        var ajaxUrl = beginUrl + "/layout-shutter" + endUrl;
         $.ajax({
          type: "GET",
          url: ajaxUrl,
          dataType: "html",
          success: function(data, textStatus) {
            if (cleanBeforeInsert != null && cleanBeforeInsert) {
              $(mainFrame).html(getNewShutter(shutterIndex));
            }
            $(shutter + sIndex).toggleClass("setBackground");
            var divInfos = "<div class='shutter-url' title='" + sIndex + "'>" + url + "</div>";
            if(jQuery.browser.mozilla) {
              $(shutter + sIndex).html(data + divInfos);
            } else {
              $(shutter + sIndex).html(data + divInfos).evalScripts();
            }
            eval(aFunction + ";");
          }
        });
      /* redirect */
      } else {
        redirectHash(data.replace('/layout-https',''));
      }
    }
  );

}

/* -------------------------- */
/* -private- shutterExist --- */
/* -------------------------- */
function shutterExist(text) {
  return shutterId(text) != 0;
}

/* ----------------------- */
/* -private- shutterId --- */
/* ----------------------- */
function shutterId(text) {
  var id = 0;
  $(".shutter-url").each( function () {
    if($(this).text() == text) {
      id = parseInt($(this).attr("title"));
    }
  });
  writeDebug("shutterId(" + text + "): " + id);
  return id;
}

/* --------------------------- */
/* -private- getNewShutter --- */
/* --------------------------- */
function getNewShutter(index) {
  return '<div id="shutter' + index + '" class="shutter"></div>';
}

/* ----------------------- */
/* -private- getMargin --- */
/* ----------------------- */
function getMargin(index) {
  var margin = INIT_LEFT;
  var customMargin = $("#shutter" + index + " input[@name=customLeftMargin]").val();
  if (customMargin != null) {
    margin = customMargin;
  }
  return parseInt(margin);
}

/* --------------------------- */
/* -private- removeShutter --- */
/* --------------------------- */

function removeShutter() {
  writeDebug("removeShutter: removing shutter number " + shutterTargeted);

  /* removing the shutter from the last to the one after the shutter with id index */
  var shutterList = getShutterList();
  var i;
  var currentId = 0;
  var remove = true;
  for (i=shutterList.length-1; i>=0; i--) {
    currentId = parseInt($(shutterList[i]).attr("id").replace(/shutter/,''));
    if (currentId == shutterTargeted) {
      remove = false;
    }
    if (remove) {
      /* suppression du volet avec effet de fadeOut */
      $(shutter + currentId).fadeOut(effectDuration, function() {
        $(this).remove();
      });
    }
  }
}

/* ------------------------------------ */
/* -public-- loadPageWithoutHistory --- */
/* ------------------------------------ */

function loadPageWithoutHistory(url) {
  loadPage(url, false);
}

/* --------------------------------- */
/* -public-- loadPageWithHistory --- */
/* --------------------------------- */

function loadPageWithHistory(url) {
  loadPage(url, true)
}

/* ----------------------- */
/* -private-- loadPage --- */
/* ----------------------- */

function loadPage(url, withHistory) {
  try {
    var brandPath = appContext + appSite + "/";
    var strRedirect = url.substring(url.indexOf(brandPath) + brandPath.length - 1);
    /* replacing the ? by _ (if exists) */
    strRedirect = strRedirect.replace(/\?/, '_');

    hideLegalMention();
    if(url.indexOf(sLegalInfoPath) != -1) {
    	showLegalMention();
    } else if (withHistory && ('#'+strRedirect) != location.hash) {
      writeDebug("loadPage: currentRel " + currentRel);
      writeDebug("loadPage: strRedirect " + strRedirect);

      if (currentRel == '') {
        currentRel = "align.left shutter.true";
      }

      /* 1498 */
      if (currentRel.indexOf("position.right") > -1) {
        if (strRedirect.indexOf('_ispanel=true') > -1 || strRedirect.indexOf('_pane=') > -1) {
          if (context.indexOf('_ispanel=true') > -1 || context.indexOf('_pane=') > -1) {

            history.back();
          }
        }
      }

      if(!jQuery.browser.mozilla) {
        $.historyLoad(strRedirect);
      } else {
        location.hash = "#" + strRedirect;
      }
    } else {
      JSController("#" + strRedirect, null, true, true);
    }
  } catch(e) {
	  logError("Error in loadPage(" + url + "," + withHistory + "): " + e);
  }
}

/* ---------------------------- */
/* -private-- getTotalWidth --- */
/* ---------------------------- */
function getTotalWidth() {
  var totalWidth = 0;

  getShutterList().each( function () {
    totalWidth += parseInt($(this).width());
    totalWidth += getShutterPadding(this);
  });

  writeDebug("getTotalWidth: " + totalWidth)
  return totalWidth;
}

/* ----------------------------- */
/* -private-- getShutterList --- */
/* ----------------------------- */
function getShutterList() {
  return $(mainFrame + " .shutter");
}

/* -------------------------------------- */
/* -private-- getShutterIndexForLevel --- */
/* -------------------------------------- */
function getShutterIndexForLevel(level) {
  var index = 0;
   $(".shutter-url").each( function() {
    writeDebug("getShutterIndexForLevel: " + $(this).text());
    if ( returnLevel($(this).text()) == level) {
      index = parseInt($(this).attr("title"));
    }
  });
  return index;
}

/* -------------------------------- */
/* -private-- getShutterPadding --- */
/* -------------------------------- */
function getShutterPadding(shutter) {
  var padding = TOTAL_MARGIN;
  try {
    padding = parseInt($(shutter).css("padding-left").replace(/px/,'')) + parseInt($(shutter).css("padding-right").replace(/px/,''));
  } catch (e) {
    /* nothing */
  }
  return padding;

}

function refreshPage() {
  var url = "/" + lang + $("#shutter" + shutterIndex + " .shutter-url").text();
  JSController("#" + url, null, true, true);
}

function logError(error){
	if (jQuery.browser.mozilla) {
		try{
			console.error(error);
		}
		catch(e){}
	}
}/*
 * jQuery form plugin
 * @requires jQuery v1.1 or later
 *
 * Examples at: http://malsup.com/jquery/form/
 * 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: 1.0.2  Jul-18-2007
 */
 (function($) {
/**
 * 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 'success'
 *                   callback method, if specified, will be passed the responseXML value
 *      'json':   if dataType == 'json' the server response will be evaluted and passed to
 *                   the 'success' 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
 */
$.fn.ajaxSubmit = function(options) {
    if (typeof options == 'function')
        options = { success: options };

    options = $.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 = {};
    $.event.trigger('form.submit.validate', [a, this, options, veto]);
    if (veto.veto)
        return this;

    var q = $.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) {
            $(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 = $('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 {
      /* #1285 (Espace perso authentification) */
      if (jQuery.browser.msie && navigator.appVersion.indexOf("MSIE 6.0") > -1 && location.protocol == 'https:') {
        $.ajax({async: false, url: baseXmlUrl, type: "POST"});
        $.ajax(options);
      } else {
        $.ajax(options);
      }
    }

    // fire 'notify' event
    $.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 = $.extend({}, $.ajaxSettings, options);

        var id = 'jqFormIO' + $.fn.ajaxSubmit.counter++;
        var $io = $('<iframe id="' + id + '" src="' + blankPage + '" name="' + id + '" />');
        var io = $io[0];
        var op8 = $.browser.opera && window.opera.version() < 9;
        if ($.browser.msie || op8) io.src = 'javascript:false;document.write("");';
        $io.css({ position: 'absolute', top: '-1000px', left: '-1000px' });

        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 && ! $.active++) $.event.trigger("ajaxStart");
        if (g) $.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);

            // make sure form attrs are set
            var encAttr = form.encoding ? 'encoding' : 'enctype';
            var t = $form.attr('target');
            $form.attr({
                target:   id,
                method:  'POST',
                encAttr: 'multipart/form-data',
                action:   opts.url
            });

            // support timout
            if (opts.timeout)
                setTimeout(function() { timedOut = true; cb(); }, opts.timeout);

            form.submit();
            $form.attr('target', t); // reset target
        }, 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
                        $.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;
                $.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) $.event.trigger("ajaxSuccess", [xhr, opts]);
            }
            if (g) $.event.trigger("ajaxComplete", [xhr, opts]);
            if (g && ! --$.active) $.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;
        };
    };
};
$.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
 */
$.fn.ajaxForm = function(options) {
    return this.ajaxFormUnbind().submit(submitHandler).each(function() {
        // store options in hash
        this.formPluginId = $.fn.ajaxForm.counter++;
        $.fn.ajaxForm.optionHash[this.formPluginId] = options;
        $(":submit,input:image", this).click(clickHandler);
    });
};

$.fn.ajaxForm.counter = 1;
$.fn.ajaxForm.optionHash = {};

function clickHandler(e) {
    var $form = this.form;
    $form.clk = this;
    if (this.type == 'image') {
        if (e.offsetX != undefined) {
            $form.clk_x = e.offsetX;
            $form.clk_y = e.offsetY;
        } else if (typeof $.fn.offset == 'function') { // try to use dimensions plugin
            var offset = $(this).offset();
            $form.clk_x = e.pageX - offset.left;
            $form.clk_y = e.pageY - offset.top;
        } else {
            $form.clk_x = e.pageX - this.offsetLeft;
            $form.clk_y = e.pageY - this.offsetTop;
        }
    }
    // clear form vars
    setTimeout(function() { $form.clk = $form.clk_x = $form.clk_y = null; }, 10);
};

function submitHandler() {
    // retrieve options from hash
    var id = this.formPluginId;
    var options = $.fn.ajaxForm.optionHash[id];
    $(this).ajaxSubmit(options);
    return false;
};

/**
 * ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm
 *
 * @name   ajaxFormUnbind
 * @return jQuery
 * @cat    Plugins/Form
 * @type   jQuery
 */
$.fn.ajaxFormUnbind = function() {
    this.unbind('submit', submitHandler);
    return this.each(function() {
        $(":submit,input:image", this).unbind('click', clickHandler);
    });

};

/**
 * 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
 */
$.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 = $.fieldValue(el, true);
        if (v && v.constructor == Array) {
            for(var j=0, jmax=v.length; j < jmax; j++)
                a.push({name: n, value: v[j]});
        }
        else if (v !== null && typeof v != 'undefined')
            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
 */
$.fn.formSerialize = function(semantic) {
    //hand off to jQuery.param for proper encoding
    return $.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
 */
$.fn.fieldSerialize = function(successful) {
    var a = [];
    this.each(function() {
        var n = this.name;
        if (!n) return;
        var v = $.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 $.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
 */
$.fn.fieldValue = function(successful) {
    for (var val=[], i=0, max=this.length; i < max; i++) {
        var el = this[i];
        var v = $.fieldValue(el, successful);
        if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length))
            continue;
        v.constructor == Array ? $.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
 */
$.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 = $.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
 */
$.fn.clearForm = function() {
    return this.each(function() {
        $('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
 */
$.fn.clearFields = $.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
 */
$.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();
    });
};

})(jQuery);

/**
 * Loops over all forms in document and prepare them for being AJAX submited
 * if they can be. A form can be AJAX submited if it has the css class "ajaxForm".
 * this method is to be invoked when
 *   - document is ready
 *   - ajax is complete
 */
function bindForms() {

  // For each form in document
  $("form").each( function() {
    // gets class attribute of form tag
    var currClass = $(this).attr("class");
    // if class attribute exists
    if(currClass) {
      if( currClass.indexOf("ajaxForm") > -1 ) {

        // removes ajaxForm class for not binding anymore
        $(this).toggleClass("ajaxForm");


        // Inits var callback to false
        var callBack = false;
        if(this.elements["callBack"]) {           // If form has input named callBack
          callBack = this.elements["callBack"].value;
        }

        // retrieves form action
        var formAction = $(this).attr("action");
        if (formAction) {
          // adding parameter ajax=true
          formAction = formAction + ((formAction.indexOf("?") > -1) ? "&" : "?") + "ajax=true";
          // changes form action
          $(this).attr("action", formAction);

          // overriding form submit event
          $(this).submit( function() {
            try {
              var thisForm = $(this);

              toggleFormInput(thisForm, false);

              // submits in AJAX
              var options = {
                  success:    function(xmlReturn) {
                      eval(callBack + "(xmlReturn)" );
                      toggleFormInput(thisForm, true);
                  }
              };

              $(this).ajaxSubmit(options);
            } catch(e) {
              // if error occurs
              logError("[submit] " + e.description);
            }
            // return false to prevent standard submit
            return false;
          } );
        }
      }
    }
  } );
}

/**
 * Activate/deactivate the submission input.
 */
function toggleFormInput(el, show) {
  /* #1557: only for login form */
  if (el.attr("id") == "loginForm" || el.attr("id") == "contactForm" || el.attr("id") == "newsletterForm") {
    if (show) {
      el.find("input[@type=submit]").removeAttr("disabled");
    } else {
      el.find("input[@type=submit]").attr("disabled", true);
    }
  }
}



/**
 * To keep compatibility with old way
 */
function ajaxFormSubmit(form, callBack) {
  $(form).ajaxSubmit(eval(callBack));
}


/**
 * Login form call back
 */
function callBackLogin(xmlReturn) {
   try {
     var goOn = true;
     
 	$("#loginError div.modal p").remove();
 	var errors = $("#loginError div.modal").html();
        $("error", xmlReturn).each(function() {
          goOn = false;
          errors = errors + "<p>" + $(this).text() + "</p>" ;
        });
        if(goOn) {
          /* refreshing the menu */
          refreshNav();
           $("redirect", xmlReturn).each(function() {
            loadPageWithHistory($(this).text());
           });
        } else {
          //errors = "<a href='#' class='modal-close' onclick='tb_remove();return false'>" + common_close_link + "</a>" + errors;
          $("#loginError div.modal").html(errors);
          var url = '#TB_inline?height=200&width=250&inlineId=loginError&modal=true';
          tb_show('Error',url);
        }
     } catch(e) {
        logError("[account-login]" + e);
     }
}

/**
 * Login form call back
 */
function callBackReserve(xmlReturn) {

  $("redirect", xmlReturn).each(function() {
    var strRedirect = $(this).text();
    strRedirect = strRedirect + "?DISPLAY=RESERVE";
    $("PRODUCTS", xmlReturn).each(function() {
        strRedirect = strRedirect + "&PRODUCTS="+$(this).text();
      });
    loadPageWithHistory(strRedirect);
  });
}

function callBackSendReserve(xmlReturn) {

  $("redirect", xmlReturn).each(function() {
      loadPageWithoutHistory($(this).text() + "?DISPLAY=SENDRESERVE");
  });
}



/**
 *
 */
function submitServicesForm() {
  ajaxFormSubmit($("#tunnel-save-services"), callBackTunnelServices);
  return false;
}

/**
 * Services call back function
 */
function callBackTunnelServices(xmlReturn) {
  try {
    var goOn = true;

    if ($("refresh", xmlReturn).text().replace(/\n/g,"") == "true") {
      refreshPage();
    }

    $("#errorframe p").remove();
    if (typeof($("address", xmlReturn).attr('code')) == 'undefined') {
      $("error", xmlReturn).each(function() {
        goOn = false;
        $("<p>" + $(this).text() + "</p>").appendTo($("#errorframe div.modal"));
      });
    }

    if ($("address", xmlReturn).attr('code') == 'notadded') {
      goOn = false;
      $("<p>" + error_creatingAddress + "</p>").appendTo($("#errorframe div.modal"));
    }

    if (goOn) {
      $("redirect", xmlReturn).each(function() {
        currentRel = "align.left shutter.true position.right";
        loadPageWithHistory($(this).text());
      });
      $("input[@name=redirect]").val($("input[@name=redirectForReview]").val());
    } else {
      tb_show('Error', '#TB_inline?height=320&width=300&inlineId=errorframe&modal=true');
    }
  } catch(e) {
    logError("[shipping-service]" + e);
  }
}

function submitCheckSamplesForm() {
  ajaxFormSubmit($("#tunnel-check-samples"), callBackCheckSamplesForm);
  return false;
}

/**
 * Services call back function
 */
function callBackCheckSamplesForm(xmlReturn) {
  try {
	if($("issamples", xmlReturn).text().replace(/\n/g,"") == 0) {
		tb_show('','#TB_inline?height=150&width=235&inlineId=samplesMessage&modal=true');
        
		$("#TB_ajaxContent .message a").click( function () {
	        $("#TB_ajaxContent").hide();
	        setTimeout('$("#TB_ajaxContent").show();', 1000);
        });
		
		$("#TB_ajaxContent .message a").each( function () {
	        tb_init($(this));
        });
	} else {
		$("redirect", xmlReturn).each(function() {
		      	currentRel = "align.left shutter.true position.right";
		      	loadPageWithHistory($(this).text());
		});
	}
  } catch(e) {
    logError("[check-samples]" + e);
  }
}



/**
 * Basket call back
 */
function returnFromBasket(xmlReturn) {
      try {
        var str="";
        $("#caddieMessage p").remove();

        $("error", xmlReturn).each(function() {
          $("<p>" + $(this).text() + "</p>").appendTo($("#caddieMessage div.modal"));
        });

        $("message", xmlReturn).each(function() {
          $("<p>" + $(this).text() + "</p>").appendTo($("#caddieMessage div.modal"));
        });

        $("nbItemsInCart", xmlReturn).each(function() {
          updateArticle($(this).text().replace(/\n/g,""));
        });

        loadSmartProfile({sp_id: $("#spStat input[@name=catId]").val(), sp_type: $("#spStat input[@name=catType]").val(), sp_added: $("#spStat input[@name=catId]").val(), sp_quantity: $("#quantity").val()});
        tb_show('', '#TB_inline?height=200&width=300&inlineId=caddieMessage&modal=true');
      } catch(e) {
        logError("[returnFromBasket]" + e);
      }
}

function bindThickbox() {
  //pass where to apply thickbox
  $('a.thickbox, area.thickbox, input.thickbox').each(
    function() {
      if(($(this).attr("href"))) {
        if($(this).attr("href").indexOf("/layout-shutter") < 0 ) {
          var brandPath = appContext + appSite + "/";
          var idx = $(this).attr("href").indexOf(brandPath);
          if( idx >= 0) {
            var newHref = $(this).attr("href").substr(0, idx + brandPath.length - 1);
            newHref += "/layout-shutter" + $(this).attr("href").substr(idx + brandPath.length - 1);
            $(this).attr("href", newHref);
          }
        }
      }
      if ($(this).attr("class").indexOf("TBbinded") == -1) {
        tb_init($(this));
        $(this).toggleClass("TBbinded");
      }
    }
  );
}

/* JS Functions for tunnel-modify-caddie-product */
function resultProductModified(xmlReturn) {
  try {
    var hasErrors=false;
    $("error ", xmlReturn).each(function() {
      logError($(this).text());
      hasErrors = true;
    });
    if (!hasErrors) {
		/* rechargement de la page */
	    refreshPage();
		refreshNav();
		setTimeout("tb_remove()", 200);
    }
  } catch(e) {
    logError("resultProductModified: " + e.description);
  }
}

/* JS Functions for caddie-list */
function resultProductDeleted(xmlReturn) {
  try {
    var goOn=true;

    $("formId", xmlReturn).each(function() {
      formId = $(this).text().replace(/\n/g,'');
    });
    
    $("#errorframe p").remove();
    $("error", xmlReturn).each(function() {
      goOn = false;
      $("<p>" + $(this).text() + "</p>").appendTo($("#errorframe div.modal"));
    });
    
    if (goOn) {
	    refreshNav();
	    refreshPage();
	} else {
		tb_show('Error', '#TB_inline?height=200&width=300&inlineId=errorframe&modal=true');
	}
  } catch(e) {
    logError("[resultProductDeleted]" + e);
  }
}

/**
 *
 */
function submitDeleteProduct(productId) {
  var selected = '';
  var selected_price = 0;
  var newTotalTTC = 0;
  var text = '';
  var selected_price = $('input[@name=discard_price_'+productId+']').val();
  var totalTTC = document.forms.frm_discard_selection.elements['totalTTC'];
  var freeShippingThreshold = document.forms.frm_discard_selection.elements['freeShippingThreshold'];
  var realShippingPrice = document.forms.frm_discard_selection.elements['realShippingPrice'];
  var shippingPrice = document.forms.frm_discard_selection.elements['shippingPrice'];
  var shippingPage = document.forms.frm_discard_selection.elements['shippingPage'];
  
  newTotalTTC = parseFloat(totalTTC.value) - selected_price;
  if(newTotalTTC <= parseFloat(freeShippingThreshold.value)
      && parseFloat(freeShippingThreshold.value) != -1
      && parseFloat(totalTTC.value) > 0
      && parseFloat(shippingPrice.value) == 0) {
    text = "removefromcartfreeshippinglost";
  } else {
    text = "removefromcart";
  }
  //If there is no  product select, displays an alert, otherwise submit the form
    tb_show('', $("#confirmUrl").val() + "?height=160&width=235&text=" + text + "&modal=true&formID=frm_discard_selection&callback=resultProductDeleted");
}

function callBackTunnelDisplayVariant(xmlReturn) {
	var price = $("price", xmlReturn).text().replace(/\n/g,'');
	$("#priceTTC").text(price);
	var img = new Image();
		var l = $("#packshot img").attr("width");
		var h = $("#packshot img").attr("height");
	$("#packshot").empty();
 
	$(img).load(function () {
		$("#packshot").append(this);
		$("#imgLoading").fadeOut("fast", function() {
			$("#packshot").fadeIn();
		});
		//$(this).attr("width",200);
		//$(this).attr("height",240);
	}).attr({
		width: "200",
		height : "244",
          src: $("packshot", xmlReturn).text().replace(/\n/g,''),
          title: $("productTitle", xmlReturn).text().replace(/\n/g,'')+" "+$("productSubTitle", xmlReturn).text().replace(/\n/g,''),
          alt: $("productTitle", xmlReturn).text().replace(/\n/g,'')+" "+$("productSubTitle", xmlReturn).text().replace(/\n/g,'')
    }).error(function () {
      // notify the user that the image could not be loaded
		$("#packshot").append(this);
		$("#imgLoading").fadeOut("fast", function() {
			$("#packshot").fadeIn();
		});
    });
    $("input[@name=pcid]").val($("pcid", xmlReturn).text().replace(/\n/g,''));
    $("#description").text($("description", xmlReturn).text().replace(/\n/g,''));
    $("#title").text($("title", xmlReturn).text().replace(/\n/g,''));
    
    // re-initialiser le scroll
    $(".highlights p").css("margin-top","0px");
    var id= $(".highlights").attr("id").split("hLights")[1];
    initScroll(id);
}

function callBackTunnelDisplayAddress(xmlReturn) {
	var addressId = $("addressId", xmlReturn).text().replace(/\n/g,'');
	var addressType = $("addressType", xmlReturn).text().replace(/\n/g,'');
	$("#addressFullname-"+addressType).text($("addressFullName", xmlReturn).text().replace(/\n/g,''));
	$("#addressLine1-"+addressType).text($("addressLine1", xmlReturn).text().replace(/\n/g,''));
	$("#addressLine2-"+addressType).text($("addressLine2", xmlReturn).text().replace(/\n/g,''));
	$("#addressZipCity-"+addressType).text($("addressZipcode", xmlReturn).text().replace(/\n/g,'')+" "+$("addressCity", xmlReturn).text().replace(/\n/g,''));
	$("#addressCountry-"+addressType).text($("addressCountry", xmlReturn).text().replace(/\n/g,''));
	if(addressType == 1) {
		$("input[@name=shippingAddressId]").val(addressId);
	}
	if(addressType == 2) {
		$("input[@name=billingAddressId]").val(addressId);
	}
}

/**
 * Order review call back
 */
function callBackRecHistory(xmlReturn) {

  try {
    var goOn = true;
    $("error", xmlReturn).each(function() {
      goOn = false;
    });

    if (goOn) {

    $("redirect", xmlReturn).each(function() {
      loadPageWithHistory($(this).text());
    });

    }
  }
  catch(e) {
    logError(e);
  }
}

/**
 * Order review call back
 */
function callBackForm(xmlReturn) {

  try {
    var goOn = true;
    var error = "";
    $("#errorframe p").remove();
    $("error", xmlReturn).each(function() {
      goOn = false;
      $("<p>" + $(this).text() + "</p>").appendTo($("#errorframe div.modal"));
    });

    if (goOn) {

      $("redirect", xmlReturn).each(function() {
        loadPageWithHistory($(this).text());
      });

    } else {
      tb_show('Error', '#TB_inline?height=200&width=300&inlineId=errorframe&modal=true');
    }
  }
  catch(e) {
    logError(e);
  }
}

function submitPaymentByPhone() {
  $("#acceptLegalTerms").val("false");
  $("#isClickToCall").val("true");
  ajaxFormSubmit($("#tunnel-recap-payment"), callBackPaymentByPhone);
}

function submitInPaymentByPhone() {
  $("#acceptLegalTerms").val("false");
  $("#isClickToCall").val("true");
  webVoicePop("Template=" + $("input[@name=estara_id]").val());
}

function callBackPaymentByPhone(xmlReturn) {
  try {
    var goOn = true;
    var error = "";
    $("#errorframe p").remove();
    $("error", xmlReturn).each(function() {
      $("<p>" + $(this).text() + "</p>").appendTo($("#errorframe div.modal"));
      goOn = false;
    });

    if (goOn) {
      $("form#tunnel-recap-payment input[@type=submit]").css("visibility", "hidden");
      webVoicePop("Template=" + $("input[@name=estara_id]").val());
    } else {
      tb_show('Error', '#TB_inline?height=200&width=300&inlineId=errorframe&modal=true');
    }
  }
  catch(e) {
    logError("[callBackPaymentByPhone] " + e);
  }
}

/**
 * Order payment call back
 */
function callBackPaymentForm(xmlReturn) {

  try {
    var goOn = true;
    var error = "";;
    $("#paymentMessage p").remove("");
    $("error", xmlReturn).each(function() {
      goOn = false;
      error += "<p>" + $(this).text() + "</p>";
    });

    if (goOn) {
      tb_remove();

      /* refreshing the menu */
      refreshNav();

      $("redirect", xmlReturn).each(function() {
        loadPageWithoutHistory($(this).text());
      });

    } else {
      $("#paymentMessage").append(error);
      tb_show('Error', '#TB_inline?height=200&width=300&inlineId=paymentMessage&modal=true');
    }
  }
  catch(e) {
    logError(e);
  }
}

/**
 * Order payment call back
 */
function callBackContactForm(xmlReturn) {

  try {
    var goOn = true;
    var message = "";;
    $("#contactMessage p").remove();
    $("#errorcontactMessage p").remove();

    $("error", xmlReturn).each(function() {
      goOn = false;
      message += "<p>" + $(this).text() + "</p>";
    });

    $("message", xmlReturn).each(function() {
      message += "<p>" + $(this).text() + "</p>";
    });


    if (goOn) {
      $("#contactMessage").append(message);
      tb_show('', '#TB_inline?height=200&width=300&inlineId=contactMessage&modal=true');
      $("redirect", xmlReturn).each(function() {
        loadPageWithoutHistory($(this).text());
      });
    } else {
      $("#errorcontactMessage").append(message);
      tb_show('', '#TB_inline?height=200&width=300&inlineId=errorcontactMessage&modal=true');
    }
  }
  catch(e) {
    logError(e);
  }
}

function returnFromWl(xmlReturn) {
  try {
    $("#wishlistMessage p").remove();
    $("error", xmlReturn).each(function() {
      $("<p>" + $(this).text() + "</p>").appendTo($("#wishlistMessage div.modal"));
    });
    $("message", xmlReturn).each(function() {
      $("<p>" + $(this).text() + "</p>").appendTo($("#wishlistMessage div.modal"));
    });
    tb_show('', '#TB_inline?height=200&width=300&inlineId=wishlistMessage&modal=true');
  } catch(e) {
    logError("[returnFromWl]" + e);
  }
}

function returnFromCaddieWl(xmlReturn) {
  try {
    $("#wishlistMessage p").remove();
    $("error", xmlReturn).each(function() {
      $("<p>" + $(this).text() + "</p>").appendTo($("#wishlistMessage div.modal"));
    });
    $("message", xmlReturn).each(function() {
      $("<p>" + $(this).text() + "</p>").appendTo($("#wishlistMessage div.modal"));
    });
    tb_show('', '#TB_inline?height=200&width=300&inlineId=wishlistMessage&modal=true');
  } catch(e) {
    logError("[returnFromCaddieWl]" + e);
  }
}

/*
 * account-registration.jsp
 */
function callBackRegister(xmlReturn) {
   try {
    var goOn = true;
    var errors = "";
    $("#registerError p").remove();
    $("error", xmlReturn).each(function() {
      goOn = false;
      errors = errors + "<p>" + $(this).text() + "</p>";
    });
    
    if(goOn) {
      /* refreshing the menu */
      refreshNav();
       $("redirect", xmlReturn).each(function() {
        loadPageWithoutHistory($(this).text());
       });
    } else {
      $("#registerError").append(errors);
      tb_show('Error','#TB_inline?height=400&width=250&inlineId=registerError&modal=true');
    }
  } catch(e) {
    logError("[account-login]" + e);
  }
}

/*
 * profile.jsp
 */

  function activateFields(name, mode) {
    try {
      var fieldName = "fieldset." + name;

      /* disabling input hidden and putting input in read only */
      if (mode == 'readonly') {
        $(fieldName + " input").attr("readonly", "readonly");
      } else {
        /* showing/hiding address */
        if ($(fieldName).attr("class").indexOf("isFirstAddress") == -1 && $(fieldName).attr("class").indexOf("address") > -1) {
          if ($("fieldset.isFirstAddress").html()) {
            $("fieldset.isFirstAddress ol").hide();
            /* if selectedAdress has been modified, we have to hide cancel button and show modify button */
            if($("fieldset.isFirstAddress").attr("class").indexOf("resume") == -1) {
              $("fieldset.isFirstAddress a.link").each( function() {
                showHideLink($(this));
              });
              $("fieldset.isFirstAddress").toggleClass("resume");
            }
          }
          $("fieldset.isFirstAddress").toggleClass("isFirstAddress");
          $(fieldName + " ol").show();
          $(fieldName).toggleClass("isFirstAddress");
        }
        $(fieldName + " input").removeAttr("readonly");
      }

      showHideSelect(name, mode);
      $(fieldName).toggleClass("resume");
      $(fieldName + " a.link").each(
        function() { showHideLink($(this)); }
      );
    } catch(e) {
      logError("[activateFields]" + e);
    }
  }

  function showHideLink(link) {
    if(link.attr("class") && link.attr("class").indexOf("hidden") == -1) {
      link.hide();
    } else {
      link.show();
    }
    link.toggleClass("hidden");
  }

  function showHideSelect(name, mode) {
    /* hiding select only in readonly mode */
    /* showing select not in readonly mode */
    /* showing / hiding input-select */
    $("fieldset." + name + " input").each(
      function() {
        if ($(this).attr("class")) {
          if ($(this).attr("class").indexOf("unused") > -1 || $(this).attr("class").indexOf("selectbox") > -1) {
            $(this).toggle();
          }
        }
      }
    );
  }


  function resultProfileModified(xmlReturn) {
    try {
      var hasErrors=false;
      var height = "";
      var width = "";
      var divId = "";
      $("#error div.modal p").remove();
      $("error", xmlReturn).each(function() {
        hasErrors = true;
        $("#error div.modal").append("<p>" + $(this).text() + "</p>");
      });
      if (!hasErrors) {
        var addressIdDeleted = $("input[@name=address_to_delete]").val();
        $("fieldset.address" + addressIdDeleted).remove();
        height = "150";
        width = "235";
        divId = "profil";
        refreshNav();
        var oldLogin = $("oldLogin", xmlReturn).text().replace(/\n/g,'');
        var newLogin = $("newLogin", xmlReturn).text().replace(/\n/g,'');
        $("redirect", xmlReturn).each(function() {
          loadPageWithoutHistory($(this).text() + "?oldLogin=" + oldLogin + "&newLogin=" + newLogin);
        });
      } else {
        height = "200";
        width = "300";
        divId = "error";
      }
      var url = '#TB_inline?height=' + height + '&width=' + width + '&inlineId=' + divId + '&modal=true';
      tb_show('',url);
    } catch(e) {
      logError("[resultProfileModified]" + e);
    }
  }

  function submitDeleteAddress(id) {
    try {
      $("input[@name=address_to_delete]").val(id);
      ajaxFormSubmit($("#profile-informations"), resultProfileModified);
    } catch(e) {
      logError("[submitDeleteAddress]" + e);
    }
  }

  function closePopup(redirect) {
    //close pop up
    tb_remove();
    loadPageWithoutHistory(redirect);
  }


/*
 * wishlist.jsp
 */

    function callBackSendWl(xmlResponse) {
      var msg = "";
      var hasErrors = false;
      $("#backFromWlError p").remove();
      $("#backFromWlMessage p").remove();

      $("error", xmlResponse).each(function() {
        hasErrors = true;
        $("<p>" + $(this).text() + "</p>").appendTo($("#backFromWlError div.modal"));
      });

      $("message", xmlResponse).each(function() {
        $("<p>" + $(this).text() + "</p>").appendTo($("#backFromWlMessage div.modal"));
      });

      if (!hasErrors) {
        tb_show('','#TB_inline?height=200&amp;width=250&amp;inlineId=backFromWlMessage&amp;modal=true');
        $("#messageSendWl").val("");
        $("#friendEmail").val("");
      } else {
        tb_show('','#TB_inline?height=200&amp;width=250&amp;inlineId=backFromWlError&amp;modal=true');
      }
    }

    function returnFromWlToCart(xmlResponse) {
      var msg = "";
      var hasErrors = false;

      $("#caddieMessage p").remove();

      $("error", xmlResponse).each(function() {
        hasErrors = true;
        $("<p>" + $(this).text() + "</p>").appendTo($("#caddieMessage div.modal"));
      });

      if (hasErrors) {
        tb_show('', '#TB_inline?height=200&width=300&inlineId=caddieMessage&modal=true');
      } else {
        $("caddie", xmlResponse).each(function() {
          updateArticle($(this).text().replace(/\n/g,""));
        });
        $("#addWlToCartButton").hide();
        $("#buyAllList, #addWlToCartDisabledButton").show();
        $("#buyList_" + $("result", xmlResponse).text().replace(/\n/g,'')).show();
      }
    }

    function returnFromOrderHistory(xmlResponse) {
      var msg = "";
      var hasErrors = false;

      $("error", xmlResponse).each(function() {
        hasErrors = true;
        $("<p>" + $(this).text() + "</p>").appendTo($("#caddieMessage div.modal"));
      });

      if (hasErrors) {
        tb_show('', '#TB_inline?height=470&width=500&inlineId=caddieMessage&modal=true');
      } else {

      }
    }

  function clearListCallBack(xmlReturn) {
    var goOn = true;
    var errors = "";
    $("#error div.modal p").remove();
    $("error", xmlReturn).each(function() {
      goOn = false;
      errors = errors + "<p>" + $(this).text() + "</p>";
    });
    if(goOn) {
      var redirect = $("redirect", xmlReturn).text();
      closePopup(redirect);
    } else {
      $("#error div.modal").append(errors);
      //tb_remove();
      var url = '#TB_inline?height=200&width=300&inlineId=error&modal=true';
      tb_show('',url);
    }
  }

  function writeCommentCallBack(xmlReturn) {
    var goOn = true;
    var errors = "";
    $("#error div.modal p").remove();
    $("error", xmlReturn).each(function() {
      goOn = false;
      errors = errors + "<p>" + $(this).text() + "</p>";
    });
    if(goOn) {
      closePopup($("redirect", xmlReturn).text());
    } else {
      $("#error div.modal").append(errors);
      //tb_remove();
      var url = '#TB_inline?height=200&width=300&inlineId=error&modal=true';
      tb_show('',url);
    }
  }


/*
 *
 */
    function bookmarkThis(actionUrl, objectType, id) {
      if (id != null) {
        $.post(
          actionUrl,
          { objectType: objectType, id: id},
          function(xmlReturn) {
            var goOn = true;
            var error = "";
            $("error", xmlReturn).each(function() {
              goOn = false;
              error += "<p>" + $(this).text().replace(/\n/g,'') + "</p>";
            });
            if (!goOn) {
              $("#errorframe").html(error);
              tb_show('Error', '#TB_inline?height=200&width=300&inlineId=errorframe');
            } else {
              $("#notBookmarked").hide();
              $("#bookmarked").show();
            }
          }
        );
      }
    }

/*
 * extranet : orderdetails.jsp
 */
  function callBackForm(xmlReturn) {

    try {
      var goOn = true;
      var error = "";
      $("#errorframe p").remove();
      $("error", xmlReturn).each(function() {
        goOn = false;
        $("<p>" + $(this).text() + "</p>").appendTo($("#errorframe div.modal"));
      });

      if (goOn) {
        tb_remove();
        $("redirect", xmlReturn).each(function() {
          loadPageWithHistory($(this).text() + "&user=" + $("user", xmlReturn).text().replace(/\n/g,'') + "&document=" + $("document", xmlReturn).text().replace(/\n/g,''));
        });

      } else {
        tb_show('Error', '#TB_inline?height=200&width=300&inlineId=errorframe&modal=true');
      }
    }
    catch(e) {
      logError(e);
    }
  }

  /*
   * extranet : customer.jsp
   */
  function listUserCallBack(xmlReturn) {
    try {
      var goOn = true;
      var errors = "";
      var j = 1;
      /* #1309 */
      if (jQuery.browser.msie) {
        $("#searchUserResult tr").hide();
      } else {
        $("#searchUserResult tr").remove();
      }
      $("#errorframe p").remove();
      $("error", xmlReturn).each(function() {
        goOn = false;
        errors = errors + "<p>" + $(this).text().replace(/\n/g,'') + "</p>";
      });
      if(goOn) {
        $("user", xmlReturn).each(function() {
          var result = $(this).text().split("|");
          var i;
          var row;
          if (j%2 == 1) {
            row = "<tr class='exOdd'>";
          } else {
            row = "<tr>";
          }
          for(i=1; i<result.length; i++) {
            if (i == 1) {
              row += "<td><a href='javascript:loginUser(" + result[0] + ")'>" + result[i] + "</a></td>";
            } else {
              row += "<td>" + result[i] + "</td>";
            }
          }

          row += "</tr>";
          $("#searchUserResult").append(row);
          j++;
        });
      } else {
        $("#searchUserResult").append("<tr><td>" + extranet_customer_no_result + "</td></tr>");
        $("#errorframe").append(errors);
        tb_show('', '#TB_inline?height=200&width=300&inlineId=errorframe&modal=true');
      }
    } catch(e) {
      logError("listUserCallBack: " + e.description);
    }
  }

  function loginUser(id) {
    if (id != null && $("#setSwitchUserAction").val() != null) {
      $.post(
        $("#setSwitchUserAction").val(),
        { id: id},
        function(xmlReturn) {
          var goOn = true;
          var error = "";
          $("#error p").remove();
          $("error", xmlReturn).each(function() {
            goOn = false;
            error += "<p>" + $(this).text().replace(/\n/g,'') + "</p>";
          });
          if (!goOn) {
            $("#error").html(error);
            tb_show('Error', '#TB_inline?height=200&width=300&inlineId=error');
          } else {
            if (id == 0) {
              $("#customerName").html($("message", xmlReturn).text());
              $("#disconnectCustomer").hide();
            } else {
              $("#customerName").html($("name", xmlReturn).text());
              $("#disconnectCustomer").show();
            }
          }
        }
      );
    }
  }

/*
 * extranet : update-document-note-popup.jsp
 */

  function UpdateDocumentNoteCallBack(xmlReturn) {
    var goOn = true;
    var errors = "";
    $("#errorDocumentNote p").remove();
    $("error", xmlReturn).each(function() {
      goOn = false;
      errors = errors + "<p>" + $(this).text().replace(/\n/g,'') + "</p>";
    });
    if(goOn) {
      var row = "<tr>";
      row += "<td>" + $("date", xmlReturn).text() + "</td>";
      row += "<td>" + $("operatorName", xmlReturn).text() + "</td>";
      row += "<td><textarea rows='2' cols='20' readonly='readonly'>" + $("description", xmlReturn).text() + "</textarea></td>";
      row += "</tr>";
      //alert(row);
      $("#listNotes").append(row);
      $("#noteCount" + $("documentID", xmlReturn).text().replace(/\n/g,'')).text($("documentCount", xmlReturn).text());
    } else {
      $("#errorDocumentNote").append(errors);
      //tb_remove();
      var url = '#TB_inline?height=200&width=300&inlineId=error';
      tb_show('',url);
    }
  }

  /*
   * extranet : cancel-order-popup.jsp
   */

  function cancelDocumentPopupCallBack(xmlReturn) {
    var goOn = true;
    var errors = "";
    $("#errorCancelDocument p").remove();
    $("error", xmlReturn).each(function() {
      tb_remove();
      goOn = false;
      logError($(this).text().replace(/\n/g,''));
      //errors = errors + "<p>" + $(this).text().replace(/\n/g,'') + "</p>";
    });
    if(goOn) {
     $("redirect", xmlReturn).each(function() {
      tb_remove();
      loadPageWithoutHistory($(this).text());
     });
    } /*else {
      $("#errorDocumentNote").append(errors);
      var url = '#TB_inline?height=200&width=300&inlineId=error';
      tb_show('',url);
    }*/
  }

  /*
   * store-locator: search.jsp
   */


  function submitStoreSearch() {
    var countryVal = $("#ac-country").val();
    var cityVal = $("#ac-city").val();
    var strRedirect = $("#storeForm").attr("action") + "_country=" + countryVal + "&city=" + cityVal;
    loadPageWithHistory(strRedirect);
    return false;
  }

  /*
   * store-locator: result.jsp
   */


  function showStores(id, way) {
    var i = 1;
    if (way == "previous") {
      i = -1;
    }
    showStorePane(id, i);
  }

  function showStorePane(id, i) {
    $("#paneright" + id).fadeOut("slow");
    $("#previous" + id).fadeOut("slow");
    $("#next" + id).fadeOut("slow");
    $("#paneleft" + id).fadeOut("slow",
      function() {
        $("#paneleft" + (id + i)).fadeIn("slow");
        $("#paneright" + (id + i)).fadeIn("slow");
        $("#previous" + (id + i)).fadeIn("slow");
        $("#next" + (id + i)).fadeIn("slow");
      }
    );
  }

  function showStoreForm(id) {
    /* hiding links */
    $("table#links").hide();
    /* hiding previous data */
    $("#store-content table").hide();
    $("#store-content div.divbg").hide();
    $("form#" + id).show();
    $("p#foottext").show();
  }

  /*
   * very dior/espace perso : home.jsp
   */

  function showBoudoir() {
    if ($("#boudoir").css("display") == "none") {
      $("#boudoir").show();
    }
    $("#boudoir").css("visibility", "visible");
    $("#boudoir").css("z-index", "1000");
  }
  function hideBoudoir() {
    $("#boudoir").css("visibility", "hidden");
    $("#boudoir").css("z-index", "1");
  }

  /*
   * common
   */

   function disableInput(button) {
     $(button).attr('disabled',true);
   }

   /*
    * tunnel
    */
  function showCaddie(show) {
    /* #1391 le parametre show n'est plus n�cessaire */
    $("div.jScrollPaneContainer div").css("overflow", "hidden");
  }

  /*
   *  forgotton password (tunnel et espace perso)
   */

  function callBackRetrievePassword(xmlReturn) {
    try {
      $("#loginError p").remove();
      $("error", xmlReturn).each(function() {
        $("<p>" + $(this).text() + "</p>").appendTo($("#loginError div.modal"));
      });
      $("message", xmlReturn).each(function() {
        $("<p>" + $(this).text() + "</p>").appendTo($("#loginError div.modal"));
      });
      tb_show('Error','#TB_inline?height=200&amp;width=250&amp;inlineId=loginError&amp;modal=true');
    } catch(e) {
      logError("[retrieve-password]" + e);
    }
  }

  /**
   * Prepares the returned message and display it in the 'message' div...
   */
  function callBackSendEmail(xmlReturn) {

    var msg = "";
    $("error", xmlReturn).each( function() {
      msg += $(this).text() + '<br/>';
    });

    $("message", xmlReturn).each( function() {
      msg += $(this).text() + '<br/>';
    });

    $("#message").html("<p>" + msg + "</p>");
    $("#message").show();

  }

  /*
   * product-tints.jsp
   */
  var tintArray = new Array();
  function addTint(img, label, color){
      tintArray.push({swatch: img, name: label, color: color});
  }

  function showTint(index){
      $("img#texture").attr("src", tintArray[index].swatch);
      $("span#label").html(tintArray[index].name);
      $("span#color").html(tintArray[index].color);
  }

  function replace_shutter_left(aUrl) {
      var url = aUrl.substr(aUrl.lastIndexOf("/" + lang + "/"),aUrl.length);
      var sharpPosition = url.indexOf('#/' + lang ,0) + ('#/' + lang).length;
      var myUrl = url.substring(sharpPosition, url.length).replace(/\.html/,'/');
      var myUrlLevel = returnLevel(myUrl.replace(/_.*$/, '').replace(/\/$/,''));

      // getting next to last shutter (product page, tint page is the last)
      var shutters = getShutterList();
      var index = 1;
      if (shutters.length > 1) {
        index = $(shutters[shutters.length-2]).attr("id").replace(/shutter/,'');
      }

      replaceShutter(myUrl, myUrlLevel, -1, true, index);
      return false;
  }

  /*
   * newsletter.jsp
   */

   function callBackNewsletterForm(xmlReturn) {
      var msg = "";
      var refresh = false;
      $("#backFromNewsletterMessage p").remove();

      $("error", xmlReturn).each(function() {
        msg += "<p>" + $(this).text()  + '</p>' ;
      });

      $("message", xmlReturn).each(function() {
        msg += "<p>" + $(this).text()  + '</p>' ;
        refresh = true;
      });

     if (refresh) {
       history.go(-1);
     }

      $("#backFromNewsletterMessage").append("<p>" + msg + "</p>");
      tb_show('','#TB_inline?height=200&amp;width=250&amp;inlineId=backFromNewsletterMessage&amp;modal=true');
  }


  function callBackPersoLogin(xmlReturn) {
    try {
      var goOn = true;
      $("#error div.modal p").remove();
      $("error", xmlReturn).each(function() {
        goOn = false;
        $("#error div.modal").append("<p>" + $(this).text() + "</p>");
      });
      if (goOn) {
        /* refreshing the menu */
        refreshNav();
        $("redirect", xmlReturn).each(function() {
          /* #1470 : probl�me de refresh apr�s login */
          var redirect = $(this).text();
          if (redirect.indexOf("?") == -1) {
            redirect += "?refresh=true";
          } else {
            redirect += "&refresh=true";
          }
          loadPageWithoutHistory(redirect);
        });
      } else {
        var url = '#TB_inline?height=200&width=300&inlineId=error&modal=true';
        tb_show('',url);
        $("redirectPerso", xmlReturn).each(function() {
          loadPageWithHistory($(this).text().replace(/\n/g,''));
        });
      }
    } catch(e) {
      logError("[callBackPersoLogin]" + e);
    }
  }

  function callBackPopupLogin(xmlReturn) {
    try {
      var goOn = true;
      $("#TB_ajaxContent div.modal p.error").remove();
      $("error", xmlReturn).each(function() {
        goOn = false;
        $("#TB_ajaxContent div.modal").append("<p class='error'>" + $(this).text() + "</p>");
      });
      if (goOn) {
        /* refreshing the menu */
        refreshNav();
        /* adding to wishlist */
        $('#addToWl').submit();
      } else {
        var url = '#TB_inline?height=390&width=500&inlineId=error&modal=true';
        tb_show('',url);
      }
    } catch(e) {
      logError("[callBackPersoLogin]" + e);
    }
  }

  /* extranet */

  function callBackExtranet(xmlReturn) {
    try {
      var goOn = true;
      $("#errorframe div.modal p").remove();
      $("error", xmlReturn).each(function() {
        goOn = false;
        $("#errorframe div.modal").append("<p>" + $(this).text() + "</p>");
      });
      if (goOn) {
        location.reload(true);
      } else {
        var url = '#TB_inline?height=200&width=300&inlineId=errorframe&modal=true';
        tb_show('',url);
      }
    } catch(e) {
      logError("[callBackExtranet]" + e);
    }
  }


  /* print functions */
  function printPage(url) {
    showPopup(url, 500, 500);
  }

  function showPopupPage(aUrl, height, width) {
    var indexLang = aUrl.indexOf("/" + lang + "/");
    var layout = "/layout-popup";
    var url = aUrl.substr(0, indexLang) + layout + aUrl.substr(indexLang, aUrl.length);
    showPopup(url, height, width);
  }

  function showPopup(url, height, width) {
    var top=(screen.availHeight-height)/2;
    var left=(screen.availWidth-width)/2;
    window.open(url, "" ,"width=" + width + ",height=" + height + ",left=" + left + ",top=" + top);
  }



/* product-page */
  var isScrolling = false;

  function initScroll(timeStamp) {
    var highlightsID  = 'hLights' + timeStamp;
    var cursorID      = 'cId' + timeStamp;
    var scrollTop     = $('#sTop' + timeStamp);
    var scrollBottom  = $('#sBottom' + timeStamp);
    var highlights    = $('#hLights' + timeStamp);

    if (scrollTop.attr("class") && scrollTop.attr("class").indexOf("binded") == -1) {
      var heightText     = parseInt($('#' + highlightsID + ' p').height());
      var heightVisible  = parseInt(highlights.height());
      var heightToScroll = parseInt(heightVisible * 3 / 4);

      if ( heightText > heightVisible ) {
        scrollTop.mouseover( function(event) { myFunctionToAdd(event, "up", cursorID, highlightsID, heightToScroll, heightText);} )
                       .mousemove( function(event) { myFunctionToShow(event, cursorID)} )
                       .mouseout ( function(event) { myFunctionToHide(cursorID)} )
                       .toggleClass("binded");

        scrollBottom.mouseover( function(event) { myFunctionToAdd(event, "down", cursorID, highlightsID, heightToScroll, heightText);} )
                          .mousemove( function(event) { myFunctionToShow(event, cursorID)} )
                          .mouseout ( function(event) { myFunctionToHide(cursorID)} );

        highlights.mouseover( function(event) { myFunctionToAdd(event, null, cursorID) } )
                        .mousemove( function(event) { myFunctionToShow(event, cursorID)} )
                        .mouseout ( function(event) { myFunctionToHide(cursorID)} );
      }
    }
  }

  function scrollMe(way, highlightsID, heightToScroll, heightText) {
    var text = $('#' + highlightsID + ' p');

    if (!isScrolling) {
      var margin = parseInt(text.css("margin-top").replace("px", ""));

      if (way == 'up') {
        if (margin + heightToScroll < 15) {
          isScrolling = true;
          text.animate({marginTop: margin + heightToScroll}, 500, function() {isScrolling = false;});
        }
      } else if (way == 'down') {
        if (margin - heightToScroll > - heightText - 15) {
          isScrolling = true;
          text.animate({marginTop: margin - heightToScroll}, 500, function() {isScrolling = false;});
        }
      }

    }
  }

  function myFunctionToAdd(event, way, cursorID, highlightsID, heightToScroll, heightText) {
    if($('#' + cursorID).size() == 0){
      $("body").append("<div id='" + cursorID + "' class='cursor_scroll' alt='scroll' />");
      $('#' + cursorID).css({
        top: (event.pageY + 11) + 'px',
        left: (event.pageX + 16) + 'px',
        position: 'absolute'
      });
    }
    $('#' + cursorID).show();

    if (way) {
      scrollMe(way, highlightsID, heightToScroll, heightText);
    }
  }

  function myFunctionToHide(cursorID) {
    $('#' + cursorID).hide();
  }

  function myFunctionToShow(event, cursorID) {
    $('#' + cursorID).css({
        top: (event.pageY + 11) + 'px',
        left: (event.pageX + 16) + 'px'
    });
    $('#' + cursorID).show();
  }


  function addToWl(sku) {
    $('#addToWl input').val(sku);
    $('#addToWl').submit();
    $('#addToWl input').val('');
  }

  function limite(zone) {
    var max = 500;
    if(zone.value.length>=max){
      zone.value=zone.value.substring(0,max);
    }
  }

  /* --- SmartProfile --- */

  function loadSmartProfile(parameters) {
    $.get(
      smart_profile_path,
      parameters,
      function(JSReturn) {
        eval(JSReturn);
      }
    );
  }
  
  
  function callBackGuerlainLogin(xmlReturn) {
	try {
		var goOn = true;
		$("error", xmlReturn).each( function() {
			goOn = false;
			$("#" + $(this).text()).show();
		});
		if (goOn) {
			sendLoginStatusToMenu(true);
			/* refreshing the menu */
			refreshNav();
			$("redirect", xmlReturn).each( function() {
				loadPageWithHistory($(this).text());
				location.reload();
			});
		}
	} catch (e) {
		logError("[account-login]" + e);
	}
  }

  function callBackGuerlainSendPassword(xmlReturn) {
		if (GuerlainHighlightErrors(xmlReturn, true)){
			$('#lostpassword').animate({opacity: 0.0}, 300).fadeOut(300);
			$('#send-success').animate({opacity: 1.0}, 400).fadeIn(600);
		}
	  }
  
  function callBackGuerlainRegister(xmlReturn) {
	  if (GuerlainHighlightErrors(xmlReturn, true))
	  {
		  $('#inscr-confirm').animate({opacity: 1.0}, 600).fadeIn(700);
			var redirect;
			$("redirect", xmlReturn).each( function() {
				redirect = $(this).text();
			});
			$('#inscr-confirm a.close').click( function(){
				$('#inscr-confirm').hide();
				refreshNav();
				loadPageWithHistory(redirect);				
			});
	  }else{
		  updateCaptcha();
	  	  $("#captcha").val("");
	  }
  }
// On utlise ici la fonction GuerlainHighlightErrorsNewsletter qui permet de gerer l'erreur du mail deja existant
  function callBackGuerlainContact(xmlReturn) {
	  var xmlresult=GuerlainHighlightErrorsNewsletter(xmlReturn, true)
	  var redirect;
		$("redirect", xmlReturn).each( function() {
			redirect = $(this).text();
		});
	  if (xmlresult==0||xmlresult==2) {
			$("select").hide();
			$('#send-success').show();	
			 $('#send-success a.close').click( function(){
					$('#send-success').hide();
					refreshNav();
					loadPageWithHistory(redirect);				
				});
	  }
	  else {
		  var count = 0;
		  $("error", xmlReturn).each( function() {
			  count++;
			  var namesAr = $(this).attr("name").split(",");
			  var codesAr = $(this).attr("code").split(",");
			  if (namesAr[0] == "email" && codesAr[0] == "registerEmailUse") {
				 count--;
			  }
		 });
		  if (count == 0) {
			  $('#send-success').show();	
			  $('#send-success a.close').click( function(){
					$('#send-success').hide();
					refreshNav();
					loadPageWithHistory(redirect);				
				});
		  }
	  }
	}
	  
    function callBackGuerlainEditAccount(xmlReturn) {
    	if (GuerlainHighlightErrors(xmlReturn, true)) {
    		refreshNav();
    		refreshPage();
    		toggleEditMode();
    		copySubmittableValueToLabel(".cssform .edit");
    	}
	}
    // Cette fonction est differente des autres  car elle appelleun fonction differente.
    // Cella � �t� fait pour g�rer la popup prevenant l'existance d'un compte possedant le m�me mail.
    function callbackGuerlainNewsletter (xmlReturn){
    	var resxml=GuerlainHighlightErrorsNewsletter(xmlReturn,true);
    	if (resxml==0){
    		$('#inscr-confirm').show();
    	} else if(resxml==2){
    		$('#inscr-confirm-ko').show();
    	}
	}
    
    function callBackGuerlainSendToAFriend (xmlReturn){
 	   if (GuerlainHighlightErrors(xmlReturn,true)) {
 		   $('#send-success-send-to-a-friend').animate({opacity: 1.0}, 400).fadeIn(600);
   		}else{
   		  updateCaptcha();
  	  	  $("#captcha").val("");
   		}
    }
    
  var htmlTemplate = null;
  function GuerlainHighlightErrors (xmlReturn, appendMessage){
	  try {
		var goOn = true;
		
		$("#mandatory").removeClass("error");
		$("input[@name='email'").addClass("required");
		$(".required").removeClass("required");
		
		if (htmlTemplate == null)
			htmlTemplate = $("#errorBlock").html();
		
		var htmlTemplateCopy = htmlTemplate;
		
		$("#errorBlock").empty();
		$("#errorBlock-right").empty();
		var k = 2;
		var container;
		$("error", xmlReturn).each( function() {
			goOn = false;
			var namesArray = $(this).attr("name").split(",");
			for (var i=0;i<namesArray.length;i++){
				$("[@name='" + namesArray[i] + "']").addClass("required");
				$("select[@name='" + namesArray[i] + "']").siblings("input[@type='text']").addClass("required");
				$("input[@name='" + namesArray[i] + "'][@type='checkbox']").parent().addClass("required");
			}
			
			if ($(this).attr("type") == "mandatory"){
				$("#mandatory").addClass("error");
			}
			if (appendMessage)
			{
				container = "#errorBlock";
					
				if($("#errorBlock-right").length > 0 && k > ($("error", xmlReturn).size() + 1) / 2){
					
					container = "#errorBlock-right";
				}
				
				$(container).append(htmlTemplate.replace("<!-- #MSG -->",$(this).text()));
			}
			k++;
		});
		k = 1;
		htmlTemplate = htmlTemplateCopy;
		return goOn;
	   }catch (e){
		   logError("[GuerlainHighlightErrors : ]"+e);
	   }
   }

  function GuerlainHighlightErrorsNewsletter (xmlReturn, appendMessage){
	  try {
		var goOn = 0;
		
		$("#mandatory").removeClass("error");
		$("input[@name='email'").addClass("required");
		$(".required").removeClass("required");
		
		if (htmlTemplate == null)
			htmlTemplate = $("#errorBlock").html();
		
		var htmlTemplateCopy = htmlTemplate;
		
		$("#errorBlock").empty();
		$("#errorBlock-right").empty();
		var k = 2;
		var container;
		$("error", xmlReturn).each( function() {
			goOn = 1;
			
			var namesArray = $(this).attr("name").split(",");
			for (var i=0;i<namesArray.length;i++){
				$("[@name='" + namesArray[i] + "']").addClass("required");
				$("select[@name='" + namesArray[i] + "']").siblings("input[@type='text']").addClass("required");
				$("input[@name='" + namesArray[i] + "'][@type='checkbox']").parent().addClass("required");
			}
			
			if ($(this).attr("type") == "mandatory"){
				$("#mandatory").addClass("error");
			}
			if (appendMessage)
			{
				container = "#errorBlock";
					
				if($("#errorBlock-right").length > 0 && k > ($("error", xmlReturn).size() + 1) / 2){
					
					container = "#errorBlock-right";
				}
				
				$(container).append(htmlTemplate.replace("<!-- #MSG -->",$(this).text()));
			}
			k++;
		});
		$("errorMail", xmlReturn).each( function() {
			goOn = 2;
		});
		k = 1;
		htmlTemplate = htmlTemplateCopy;
		return goOn;
	   }catch (e){
		   logError("[GuerlainHighlightErrorsNewsletter : ]"+e);
	   }
   }  
  
    function callBackGuerlainWishlistAdd(xmlReturn) {
		try {
		    var goOn = true;
		    $(".registerError").hide();
			$("error", xmlReturn).each( function() {
				goOn = false;
				
				if ($(this).text() == "mandatoryError")
			{
				$("#mandatory").addClass("error");
			}
			$("#" + $(this).text()).show();
		});
			if (goOn) {
				/* refreshing the menu */
					 $('#send-success-wishlist-add').animate({opacity: 1.0}, 400).fadeIn(600);

			}
		} catch (e) {
			logError("[wishlist-add]" + e);
		}
	  }
    
    function toggleEditMode(){
    	$('form#change_contact .label').toggle();
    	$('form#change_contact .edit, #mandatory').toggle();
    }
    
    function setFieldValue(url , fieldMappingParam){
    	var result = new Array();
		$.ajax({
			async : false,
			cache: false,
			type: "GET",
			url: url,
			dataType	: "json",
			success: function(data){
				var fieldName;
				for (var i = 0; i < data.length; i++) {
					fieldName = (fieldMappingParam != null && fieldMappingParam[data[i].fieldName] != null) ? fieldMappingParam[data[i].fieldName] : data[i].fieldName;
					$('[@name=' + fieldName + ']').val(data[i].fieldValue);
					result[fieldName] = data[i].fieldValue;
				}
			}
		});
		return result;
	}
    
    
    function selectBoxOnChange(id, idRegion, ajaxUrl, asyncParam, removeSelectIfEmpty){
    	
			$.ajax({
				async : asyncParam,
				cache: false,
				data : "id=" + id, 
				type: "GET",
				url: ajaxUrl,
				dataType	: "json",
				success: function(j){
				
					var options = '';
					var selectedValue = "";
					for (var i = 0; i < j.length; i++) {
					   if (j[i].optionValue == idRegion){
						   selectedValue = " selected='selected' ";
					   }
					  options += '<option ' + selectedValue + ' value="' + j[i].optionValue + '">' + j[i].optionDisplay + '</option>';
					  selectedValue = "";
					}
					//virer le select region generer par runSelectbox 
					$("input").remove("#regionSelect_input");
					$("div").remove("#regionSelect_container");
					$("div").remove("#selectbox-wrapper");
					$("ul").remove;
					$("li").remove;
					
					// repeupler le bon select
					$("select#regionSelect").html(options);
					var sorted = $.makeArray($('select#regionSelect option')).sort(function(a,b){	
						if($(a).val() == ''){
							return -1;
						}
						if($(b).val() == ''){
							return 1;
						}
						return $(a).text() > $(b).text();
					});
					$("select#regionSelect").html(sorted);


					
					// le montrer si des regions sont présentes sinon, (dans le cas contraire, seul l'item sélectionner est renvoyé)  
					if(j.length > 1 || !removeSelectIfEmpty){
						$("select#regionSelect").show();
						$("#regionLablel").show();
						$("select#regionSelect option").each(function (){	
							if($(this).val()==''){
								$(this).attr("selected",true);
							}
						});						
						//puis faire dessus un runSelectbox
						runSelectbox("select#regionSelect");
					}else{
						//le hide de regionSelect étant déja fait il reste a supprimer le label "REGION:" 
						$("#regionLablel").hide();
					}
					
				}
			});
			
	}
    
    function copySubmittableValueToLabel(submittableSelector){
    	$(submittableSelector).each(function(){
	    	var input = $(this).children("input");
	    	var value;
	    	if (input.attr("type") == "password"){
	    		value ="*****";
	    	}
	    	else{
	    		value = input.val();
	    	}
	    	
	    	$(this).siblings("span").html("");
	    	
	    	//Usefull if "Sélectionner" is the selectioned option
	    	if ($(this).children("select").val() != "")
	    	{
	    		$(this).siblings("span").html(value);
	    	}
	    	
    	});
    }/* value of the attribute 'rel' of the last clicked link */
var currentRel = "";

/* array containing the historic of parameters for the function JSController */
var controllerParam = new Array();

/* idxCP : index for controllerParam */
var idxCP = 0;

function pageload(hash) {
  writeDebug("pageload(" + hash + ")");

  var add_left = null;
  var align_left = true;
  var is_shutter = true;
  var popupToManage = null;
  var nav = "";

  if (hash && hash.indexOf("TB_inline") == -1) {
    if (currentRel != "") {
      /* 1. currentRel is not empty : user has clicked on a link */
      if (currentRel.indexOf("position.left") > -1) {
        add_left = true;
      }
      if (currentRel.indexOf("position.right") > -1) {
        add_left = false;
      }
      if (currentRel.indexOf("position.new") > -1) {
        add_left = "new";
      }
      if (currentRel.indexOf("position.replace_left") > -1) {
        add_left = "replace_left";
      }
      if (currentRel.indexOf("position.replace_right") > -1) {
        add_left = "replace_right";
      }
      if (currentRel.indexOf("align.left") > -1) {
        align_left = true;
      }
      if (currentRel.indexOf("align.right") > -1) {
        align_left = false;
      }
      if (currentRel.indexOf("shutter.false") > -1) {
        is_shutter = false;
      }
      if (currentRel.indexOf("popup") > -1) {
    	  popupToManage = "show";
      }
      
      //Check if we simply have a back link from the popup shown
      if((popupToHide(hash)==true) && (popupToManage != "show"))
    	  popupToManage = "hide";
      
      controllerParam[idxCP] = new Array(add_left, align_left, is_shutter, hash, popupToManage);

      idxCP++;

    } else if (idxCP > 0) {

      /* 2. user has pressed back or following button, detecting which buttons has been pressed */
      nav = detectNavigationButton(hash, idxCP);

      if (nav == "back") {
        idxCP--;
      }

      if (nav == "new") {
          add_left = "new";
          align_left = true;
          is_shutter = true;
      } else {
        if (controllerParam[idxCP][0] == null) {
          add_left = null;
        } else {
          /* if user has clicked on "back" */
          /* add_left can be a boolean or a string */
          if (typeof(controllerParam[idxCP][0]) == 'boolean') {
            if (nav == "back") {
              add_left = !controllerParam[idxCP][0];
            } else {
              add_left = controllerParam[idxCP][0];
            }
          } else {
            add_left = null;
          }
        }
        align_left = controllerParam[idxCP][1];
        is_shutter = controllerParam[idxCP][2];
      }

      if (nav == "forward") {
        idxCP++;
      }

      /* Resetting the parameters */
      if (nav == "new") {
        idxCP = 0;
        controllerParam = new Array();
      }
    } else {
      /* 3. No history yet, this is the first user come */
      controllerParam[idxCP] = new Array(add_left, align_left, is_shutter, hash, popupToManage);

      /*alert("Autre: [add,align,shutter,hash] " + controllerParam[idxCP]);*/

      idxCP++;
    }
    JSController("#" + hash, is_shutter, popupToManage);
    /* cleaning the current rel */
    currentRel = "";
  }
}

function detectNavigationButton(hash,position) {
  var idx;
  var buttonClicked = "";
  for(idx=0; idx<controllerParam.length && buttonClicked == ""; idx++) {
    if (controllerParam[idx][3] == hash) {
      if (idx < position) {
        buttonClicked = "back";
      } else {
        buttonClicked = "forward";
      }
    }
  }
  /* the URL entered is not in the history : emptying the shutters and creating new one */
  if (buttonClicked == "") {
    buttonClicked = "new"
  }

  return buttonClicked;
}

function bindLinks() {
  /* set onlick event for buttons */
  $("a").each(function(){
    if (this.rel.indexOf("controller") > -1 && (($(this).attr("class")) ? $(this).attr("class") : "").indexOf("thickbox") < 0) {
      /* remove the keyword 'controller' from rel */
      this.rel = this.rel.replace(/controller/, '');
      $(this).bind("click",function(){
        currentRel = this.rel;
        loadPageWithHistory(this.href);
        return false;
      });
    }
  });
}


/* Used to redirect the url when there are no hash (#) */
/* splitting the url with the home url */
function redirectHash(url) {
  if (rootUrl != '' && rootUrl != '#') {
	  var href = getHref(url);
	  
	  if (href != null){
		  if (href.indexOf(location.href) == 0 && $.browser.msie) {
		      //special case for IE when base Url called
		      currentRel = "align.left shutter.true";
		      $.historyLoad(href.split("#")[1]);
		    } else {
		      location.href = href;
		  }
	  }
  }
}

function getHref(url) {
	  var hash;
	  var currentUrl;
	  if (url == null) {
	    hash = location.hash;
	    
	    currentUrl = document.location.href.replace(/#/, '');
	  } else {
	    hash = '';
	    currentUrl = url;
	  }
	  
	  if (hash.length <= 1) {
	    var href = currentUrl.substr(0, currentUrl.indexOf(appContext + appSite + "/") ) + baseUrl.substr(0, baseUrl.length - 1) + ".html#";

	    if (currentUrl.indexOf(baseUrl.substr(0,baseUrl.length - 1) + ".html") > -1 || currentUrl.indexOf(baseUrl) > -1) {
	      currentUrl = rootUrl;
	    }

	    var indexLang = currentUrl.lastIndexOf("/" + lang + "/");
	    if (isPreview == "true" && currentUrl.substr(indexLang,currentUrl.length).indexOf(codePreview) == -1 ) {
	      href += "/" + lang + codePreview + currentUrl.substr(indexLang+lang.length+1 ,currentUrl.length);
	    } else {
	      href += currentUrl.substr(indexLang,currentUrl.length);
	    }
	    return href.replace(/\?/, '_');
	  }  
}

/**
 * Verify if the previous url called was the one included the popup
 * @param hash
 * @return
 */
function popupToHide(hash) {
	var bHide = false;
	
	if(controllerParam.length > 1) {
		// Looking for the hash before the previous one
		var previousHash = controllerParam[controllerParam.length-2][3];
		// Looking for the previous action
		var previousPopup = controllerParam[controllerParam.length-1][4];
		if((previousHash==hash) && (previousPopup=="show"))
			bHide = true;
	}
	
	return bHide;
}
/*
 * 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;" src="' + blankPage + '"></iframe>'); /* GSR */
      var ihistory = $("#jQuery_history")[0];
      if (typeof(ihistory) != 'undefined') { /* GSR */
        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) {
        // enter when back button is pushed

        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];
      if(typeof(ihistory) != 'undefined') { /* SPR */
	      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);
    }
  }
});


/*! SWFObject v2.1 <http://code.google.com/p/swfobject/>
	Copyright (c) 2007-2008 Geoff Stearns, Michael Williams, and Bobby van der Sluis
	This software is released under the MIT License <http://www.opensource.org/licenses/mit-license.php>
*/

var swfobject = function() {
	
	var UNDEF = "undefined",
		OBJECT = "object",
		SHOCKWAVE_FLASH = "Shockwave Flash",
		SHOCKWAVE_FLASH_AX = "ShockwaveFlash.ShockwaveFlash",
		FLASH_MIME_TYPE = "application/x-shockwave-flash",
		EXPRESS_INSTALL_ID = "SWFObjectExprInst",
		
		win = window,
		doc = document,
		nav = navigator,
		
		domLoadFnArr = [],
		regObjArr = [],
		objIdArr = [],
		listenersArr = [],
		script,
		timer = null,
		storedAltContent = null,
		storedAltContentId = null,
		isDomLoaded = false,
		isExpressInstallActive = false;
	
	/* Centralized function for browser feature detection
		- Proprietary feature detection (conditional compiling) is used to detect Internet Explorer's features
		- User agent string detection is only used when no alternative is possible
		- Is executed directly for optimal performance
	*/	
	var ua = function() {
		var w3cdom = typeof doc.getElementById != UNDEF && typeof doc.getElementsByTagName != UNDEF && typeof doc.createElement != UNDEF,
			playerVersion = [0,0,0],
			d = null;
		if (typeof nav.plugins != UNDEF && typeof nav.plugins[SHOCKWAVE_FLASH] == OBJECT) {
			d = nav.plugins[SHOCKWAVE_FLASH].description;
			if (d && !(typeof nav.mimeTypes != UNDEF && nav.mimeTypes[FLASH_MIME_TYPE] && !nav.mimeTypes[FLASH_MIME_TYPE].enabledPlugin)) { // navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin indicates whether plug-ins are enabled or disabled in Safari 3+
				d = d.replace(/^.*\s+(\S+\s+\S+$)/, "$1");
				playerVersion[0] = parseInt(d.replace(/^(.*)\..*$/, "$1"), 10);
				playerVersion[1] = parseInt(d.replace(/^.*\.(.*)\s.*$/, "$1"), 10);
				playerVersion[2] = /r/.test(d) ? parseInt(d.replace(/^.*r(.*)$/, "$1"), 10) : 0;
			}
		}
		else if (typeof win.ActiveXObject != UNDEF) {
			var a = null, fp6Crash = false;
			try {
				a = new ActiveXObject(SHOCKWAVE_FLASH_AX + ".7");
			}
			catch(e) {
				try { 
					a = new ActiveXObject(SHOCKWAVE_FLASH_AX + ".6");
					playerVersion = [6,0,21];
					a.AllowScriptAccess = "always";	 // Introduced in fp6.0.47
				}
				catch(e) {
					if (playerVersion[0] == 6) {
						fp6Crash = true;
					}
				}
				if (!fp6Crash) {
					try {
						a = new ActiveXObject(SHOCKWAVE_FLASH_AX);
					}
					catch(e) {}
				}
			}
			if (!fp6Crash && a) { // a will return null when ActiveX is disabled
				try {
					d = a.GetVariable("$version");	// Will crash fp6.0.21/23/29
					if (d) {
						d = d.split(" ")[1].split(",");
						playerVersion = [parseInt(d[0], 10), parseInt(d[1], 10), parseInt(d[2], 10)];
					}
				}
				catch(e) {}
			}
		}
		var u = nav.userAgent.toLowerCase(),
			p = nav.platform.toLowerCase(),
			webkit = /webkit/.test(u) ? parseFloat(u.replace(/^.*webkit\/(\d+(\.\d+)?).*$/, "$1")) : false, // returns either the webkit version or false if not webkit
			ie = false,
			windows = p ? /win/.test(p) : /win/.test(u),
			mac = p ? /mac/.test(p) : /mac/.test(u);
		/*@cc_on
			ie = true;
			@if (@_win32)
				windows = true;
			@elif (@_mac)
				mac = true;
			@end
		@*/
		return { w3cdom:w3cdom, pv:playerVersion, webkit:webkit, ie:ie, win:windows, mac:mac };
	}();

	/* Cross-browser onDomLoad
		- Based on Dean Edwards' solution: http://dean.edwards.name/weblog/2006/06/again/
		- Will fire an event as soon as the DOM of a page is loaded (supported by Gecko based browsers - like Firefox -, IE, Opera9+, Safari)
	*/ 
	var onDomLoad = function() {
		if (!ua.w3cdom) {
			return;
		}
		addDomLoadEvent(main);
		if (ua.ie && ua.win) {
			try {	 // Avoid a possible Operation Aborted error
				doc.write("<scr" + "ipt id=__ie_ondomload defer=true src=//:></scr" + "ipt>"); // String is split into pieces to avoid Norton AV to add code that can cause errors 
				script = getElementById("__ie_ondomload");
				if (script) {
					addListener(script, "onreadystatechange", checkReadyState);
				}
			}
			catch(e) {}
		}
		if (ua.webkit && typeof doc.readyState != UNDEF) {
			timer = setInterval(function() { if (/loaded|complete/.test(doc.readyState)) { callDomLoadFunctions(); }}, 10);
		}
		if (typeof doc.addEventListener != UNDEF) {
			doc.addEventListener("DOMContentLoaded", callDomLoadFunctions, null);
		}
		addLoadEvent(callDomLoadFunctions);
	}();
	
	function checkReadyState() {
		if (script.readyState == "complete") {
			script.parentNode.removeChild(script);
			callDomLoadFunctions();
		}
	}
	
	function callDomLoadFunctions() {
		if (isDomLoaded) {
			return;
		}
		if (ua.ie && ua.win) { // Test if we can really add elements to the DOM; we don't want to fire it too early
			var s = createElement("span");
			try { // Avoid a possible Operation Aborted error
				var t = doc.getElementsByTagName("body")[0].appendChild(s);
				t.parentNode.removeChild(t);
			}
			catch (e) {
				return;
			}
		}
		isDomLoaded = true;
		if (timer) {
			clearInterval(timer);
			timer = null;
		}
		var dl = domLoadFnArr.length;
		for (var i = 0; i < dl; i++) {
			domLoadFnArr[i]();
		}
	}
	
	function addDomLoadEvent(fn) {
		if (isDomLoaded) {
			fn();
		}
		else { 
			domLoadFnArr[domLoadFnArr.length] = fn; // Array.push() is only available in IE5.5+
		}
	}
	
	/* Cross-browser onload
		- Based on James Edwards' solution: http://brothercake.com/site/resources/scripts/onload/
		- Will fire an event as soon as a web page including all of its assets are loaded 
	 */
	function addLoadEvent(fn) {
		if (typeof win.addEventListener != UNDEF) {
			win.addEventListener("load", fn, false);
		}
		else if (typeof doc.addEventListener != UNDEF) {
			doc.addEventListener("load", fn, false);
		}
		else if (typeof win.attachEvent != UNDEF) {
			addListener(win, "onload", fn);
		}
		else if (typeof win.onload == "function") {
			var fnOld = win.onload;
			win.onload = function() {
				fnOld();
				fn();
			};
		}
		else {
			win.onload = fn;
		}
	}
	
	/* Main function
		- Will preferably execute onDomLoad, otherwise onload (as a fallback)
	*/
	function main() { // Static publishing only
		var rl = regObjArr.length;
		for (var i = 0; i < rl; i++) { // For each registered object element
			var id = regObjArr[i].id;
			if (ua.pv[0] > 0) {
				var obj = getElementById(id);
				if (obj) {
					regObjArr[i].width = obj.getAttribute("width") ? obj.getAttribute("width") : "0";
					regObjArr[i].height = obj.getAttribute("height") ? obj.getAttribute("height") : "0";
					if (hasPlayerVersion(regObjArr[i].swfVersion)) { // Flash plug-in version >= Flash content version: Houston, we have a match!
						if (ua.webkit && ua.webkit < 312) { // Older webkit engines ignore the object element's nested param elements
							fixParams(obj);
						}
						setVisibility(id, true);
					}
					else if (regObjArr[i].expressInstall && !isExpressInstallActive && hasPlayerVersion("6.0.65") && (ua.win || ua.mac)) { // Show the Adobe Express Install dialog if set by the web page author and if supported (fp6.0.65+ on Win/Mac OS only)
						showExpressInstall(regObjArr[i]);
					}
					else { // Flash plug-in and Flash content version mismatch: display alternative content instead of Flash content
						displayAltContent(obj);
					}
				}
			}
			else {	// If no fp is installed, we let the object element do its job (show alternative content)
				setVisibility(id, true);
			}
		}
	}
	
	/* Fix nested param elements, which are ignored by older webkit engines
		- This includes Safari up to and including version 1.2.2 on Mac OS 10.3
		- Fall back to the proprietary embed element
	*/
	function fixParams(obj) {
		var nestedObj = obj.getElementsByTagName(OBJECT)[0];
		if (nestedObj) {
			var e = createElement("embed"), a = nestedObj.attributes;
			if (a) {
				var al = a.length;
				for (var i = 0; i < al; i++) {
					if (a[i].nodeName == "DATA") {
						e.setAttribute("src", a[i].nodeValue);
					}
					else {
						e.setAttribute(a[i].nodeName, a[i].nodeValue);
					}
				}
			}
			var c = nestedObj.childNodes;
			if (c) {
				var cl = c.length;
				for (var j = 0; j < cl; j++) {
					if (c[j].nodeType == 1 && c[j].nodeName == "PARAM") {
						e.setAttribute(c[j].getAttribute("name"), c[j].getAttribute("value"));
					}
				}
			}
			obj.parentNode.replaceChild(e, obj);
		}
	}
	
	/* Show the Adobe Express Install dialog
		- Reference: http://www.adobe.com/cfusion/knowledgebase/index.cfm?id=6a253b75
	*/
	function showExpressInstall(regObj) {
		isExpressInstallActive = true;
		var obj = getElementById(regObj.id);
		if (obj) {
			if (regObj.altContentId) {
				var ac = getElementById(regObj.altContentId);
				if (ac) {
					storedAltContent = ac;
					storedAltContentId = regObj.altContentId;
				}
			}
			else {
				storedAltContent = abstractAltContent(obj);
			}
			if (!(/%$/.test(regObj.width)) && parseInt(regObj.width, 10) < 310) {
				regObj.width = "310";
			}
			if (!(/%$/.test(regObj.height)) && parseInt(regObj.height, 10) < 137) {
				regObj.height = "137";
			}
			doc.title = doc.title.slice(0, 47) + " - Flash Player Installation";
			var pt = ua.ie && ua.win ? "ActiveX" : "PlugIn",
				dt = doc.title,
				fv = "MMredirectURL=" + win.location + "&MMplayerType=" + pt + "&MMdoctitle=" + dt,
				replaceId = regObj.id;
			// For IE when a SWF is loading (AND: not available in cache) wait for the onload event to fire to remove the original object element
			// In IE you cannot properly cancel a loading SWF file without breaking browser load references, also obj.onreadystatechange doesn't work
			if (ua.ie && ua.win && obj.readyState != 4) {
				var newObj = createElement("div");
				replaceId += "SWFObjectNew";
				newObj.setAttribute("id", replaceId);
				obj.parentNode.insertBefore(newObj, obj); // Insert placeholder div that will be replaced by the object element that loads expressinstall.swf
				obj.style.display = "none";
				var fn = function() {
					obj.parentNode.removeChild(obj);
				};
				addListener(win, "onload", fn);
			}
			createSWF({ data:regObj.expressInstall, id:EXPRESS_INSTALL_ID, width:regObj.width, height:regObj.height }, { flashvars:fv }, replaceId);
		}
	}
	
	/* Functions to abstract and display alternative content
	*/
	function displayAltContent(obj) {
		if (ua.ie && ua.win && obj.readyState != 4) {
			// For IE when a SWF is loading (AND: not available in cache) wait for the onload event to fire to remove the original object element
			// In IE you cannot properly cancel a loading SWF file without breaking browser load references, also obj.onreadystatechange doesn't work
			var el = createElement("div");
			obj.parentNode.insertBefore(el, obj); // Insert placeholder div that will be replaced by the alternative content
			el.parentNode.replaceChild(abstractAltContent(obj), el);
			obj.style.display = "none";
			var fn = function() {
				obj.parentNode.removeChild(obj);
			};
			addListener(win, "onload", fn);
		}
		else {
			obj.parentNode.replaceChild(abstractAltContent(obj), obj);
		}
	} 

	function abstractAltContent(obj) {
		var ac = createElement("div");
		if (ua.win && ua.ie) {
			ac.innerHTML = obj.innerHTML;
		}
		else {
			var nestedObj = obj.getElementsByTagName(OBJECT)[0];
			if (nestedObj) {
				var c = nestedObj.childNodes;
				if (c) {
					var cl = c.length;
					for (var i = 0; i < cl; i++) {
						if (!(c[i].nodeType == 1 && c[i].nodeName == "PARAM") && !(c[i].nodeType == 8)) {
							ac.appendChild(c[i].cloneNode(true));
						}
					}
				}
			}
		}
		return ac;
	}
	
	/* Cross-browser dynamic SWF creation
	*/
	function createSWF(attObj, parObj, id) {
		var r, el = getElementById(id);
		if (el) {
			if (typeof attObj.id == UNDEF) { // if no 'id' is defined for the object element, it will inherit the 'id' from the alternative content
				attObj.id = id;
			}
			if (ua.ie && ua.win) { // IE, the object element and W3C DOM methods do not combine: fall back to outerHTML
				var att = "";
				for (var i in attObj) {
					if (attObj[i] != Object.prototype[i]) { // Filter out prototype additions from other potential libraries, like Object.prototype.toJSONString = function() {}
						if (i.toLowerCase() == "data") {
							parObj.movie = attObj[i];
						}
						else if (i.toLowerCase() == "styleclass") { // 'class' is an ECMA4 reserved keyword
							att += ' class="' + attObj[i] + '"';
						}
						else if (i.toLowerCase() != "classid") {
							att += ' ' + i + '="' + attObj[i] + '"';
						}
					}
				}
				var par = "";
				for (var j in parObj) {
					if (parObj[j] != Object.prototype[j]) { // Filter out prototype additions from other potential libraries
						par += '<param name="' + j + '" value="' + parObj[j] + '" />';
					}
				}
				el.outerHTML = '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"' + att + '>' + par + '</object>';
				objIdArr[objIdArr.length] = attObj.id; // Stored to fix object 'leaks' on unload (dynamic publishing only)
				r = getElementById(attObj.id);	
			}
			else if (ua.webkit && ua.webkit < 312) { // Older webkit engines ignore the object element's nested param elements: fall back to the proprietary embed element
				var e = createElement("embed");
				e.setAttribute("type", FLASH_MIME_TYPE);
				for (var k in attObj) {
					if (attObj[k] != Object.prototype[k]) { // Filter out prototype additions from other potential libraries
						if (k.toLowerCase() == "data") {
							e.setAttribute("src", attObj[k]);
						}
						else if (k.toLowerCase() == "styleclass") { // 'class' is an ECMA4 reserved keyword
							e.setAttribute("class", attObj[k]);
						}
						else if (k.toLowerCase() != "classid") { // Filter out IE specific attribute
							e.setAttribute(k, attObj[k]);
						}
					}
				}
				for (var l in parObj) {
					if (parObj[l] != Object.prototype[l]) { // Filter out prototype additions from other potential libraries
						if (l.toLowerCase() != "movie") { // Filter out IE specific param element
							e.setAttribute(l, parObj[l]);
						}
					}
				}
				el.parentNode.replaceChild(e, el);
				r = e;
			}
			else { // Well-behaving browsers
				var o = createElement(OBJECT);
				o.setAttribute("type", FLASH_MIME_TYPE);
				for (var m in attObj) {
					if (attObj[m] != Object.prototype[m]) { // Filter out prototype additions from other potential libraries
						if (m.toLowerCase() == "styleclass") { // 'class' is an ECMA4 reserved keyword
							o.setAttribute("class", attObj[m]);
						}
						else if (m.toLowerCase() != "classid") { // Filter out IE specific attribute
							o.setAttribute(m, attObj[m]);
						}
					}
				}
				for (var n in parObj) {
					if (parObj[n] != Object.prototype[n] && n.toLowerCase() != "movie") { // Filter out prototype additions from other potential libraries and IE specific param element
						createObjParam(o, n, parObj[n]);
					}
				}
				el.parentNode.replaceChild(o, el);
				r = o;
			}
		}
		return r;
	}
	
	function createObjParam(el, pName, pValue) {
		var p = createElement("param");
		p.setAttribute("name", pName);	
		p.setAttribute("value", pValue);
		el.appendChild(p);
	}
	
	/* Cross-browser SWF removal
		- Especially needed to safely and completely remove a SWF in Internet Explorer
	*/
	function removeSWF(id) {
		var obj = getElementById(id);
		if (obj && (obj.nodeName == "OBJECT" || obj.nodeName == "EMBED")) {
			if (ua.ie && ua.win) {
				if (obj.readyState == 4) {
					removeObjectInIE(id);
				}
				else {
					win.attachEvent("onload", function() {
						removeObjectInIE(id);
					});
				}
			}
			else {
				obj.parentNode.removeChild(obj);
			}
		}
	}
	
	function removeObjectInIE(id) {
		var obj = getElementById(id);
		if (obj) {
			for (var i in obj) {
				if (typeof obj[i] == "function") {
					obj[i] = null;
				}
			}
			obj.parentNode.removeChild(obj);
		}
	}
	
	/* Functions to optimize JavaScript compression
	*/
	function getElementById(id) {
		var el = null;
		try {
			el = doc.getElementById(id);
		}
		catch (e) {}
		return el;
	}
	
	function createElement(el) {
		return doc.createElement(el);
	}
	
	/* Updated attachEvent function for Internet Explorer
		- Stores attachEvent information in an Array, so on unload the detachEvent functions can be called to avoid memory leaks
	*/	
	function addListener(target, eventType, fn) {
		target.attachEvent(eventType, fn);
		listenersArr[listenersArr.length] = [target, eventType, fn];
	}
	
	/* Flash Player and SWF content version matching
	*/
	function hasPlayerVersion(rv) {
		var pv = ua.pv, v = rv.split(".");
		v[0] = parseInt(v[0], 10);
		v[1] = parseInt(v[1], 10) || 0; // supports short notation, e.g. "9" instead of "9.0.0"
		v[2] = parseInt(v[2], 10) || 0;
		return (pv[0] > v[0] || (pv[0] == v[0] && pv[1] > v[1]) || (pv[0] == v[0] && pv[1] == v[1] && pv[2] >= v[2])) ? true : false;
	}
	
	/* Cross-browser dynamic CSS creation
		- Based on Bobby van der Sluis' solution: http://www.bobbyvandersluis.com/articles/dynamicCSS.php
	*/	
	function createCSS(sel, decl) {
		if (ua.ie && ua.mac) {
			return;
		}
		var h = doc.getElementsByTagName("head")[0], s = createElement("style");
		s.setAttribute("type", "text/css");
		s.setAttribute("media", "screen");
		if (!(ua.ie && ua.win) && typeof doc.createTextNode != UNDEF) {
			s.appendChild(doc.createTextNode(sel + " {" + decl + "}"));
		}
		h.appendChild(s);
		if (ua.ie && ua.win && typeof doc.styleSheets != UNDEF && doc.styleSheets.length > 0) {
			var ls = doc.styleSheets[doc.styleSheets.length - 1];
			if (typeof ls.addRule == OBJECT) {
				ls.addRule(sel, decl);
			}
		}
	}
	
	function setVisibility(id, isVisible) {
		var v = isVisible ? "visible" : "hidden";
		if (isDomLoaded && getElementById(id)) {
			getElementById(id).style.visibility = v;
		}
		else {
			createCSS("#" + id, "visibility:" + v);
		}
	}

	/* Filter to avoid XSS attacks 
	*/
	function urlEncodeIfNecessary(s) {
		var regex = /[\\\"<>\.;]/;
		var hasBadChars = regex.exec(s) != null;
		return hasBadChars ? encodeURIComponent(s) : s;
	}
	
	/* Release memory to avoid memory leaks caused by closures, fix hanging audio/video threads and force open sockets/NetConnections to disconnect (Internet Explorer only)
	*/
	var cleanup = function() {
		if (ua.ie && ua.win) {
			window.attachEvent("onunload", function() {
				// remove listeners to avoid memory leaks
				var ll = listenersArr.length;
				for (var i = 0; i < ll; i++) {
					listenersArr[i][0].detachEvent(listenersArr[i][1], listenersArr[i][2]);
				}
				// cleanup dynamically embedded objects to fix audio/video threads and force open sockets and NetConnections to disconnect
				var il = objIdArr.length;
				for (var j = 0; j < il; j++) {
					removeSWF(objIdArr[j]);
				}
				// cleanup library's main closures to avoid memory leaks
				for (var k in ua) {
					ua[k] = null;
				}
				ua = null;
				for (var l in swfobject) {
					swfobject[l] = null;
				}
				swfobject = null;
			});
		}
	}();
	
	
	return {
		/* Public API
			- Reference: http://code.google.com/p/swfobject/wiki/SWFObject_2_0_documentation
		*/ 
		registerObject: function(objectIdStr, swfVersionStr, xiSwfUrlStr) {
			if (!ua.w3cdom || !objectIdStr || !swfVersionStr) {
				return;
			}
			var regObj = {};
			regObj.id = objectIdStr;
			regObj.swfVersion = swfVersionStr;
			regObj.expressInstall = xiSwfUrlStr ? xiSwfUrlStr : false;
			regObjArr[regObjArr.length] = regObj;
			setVisibility(objectIdStr, false);
		},
		
		getObjectById: function(objectIdStr) {
			var r = null;
			if (ua.w3cdom) {
				var o = getElementById(objectIdStr);
				if (o) {
					var n = o.getElementsByTagName(OBJECT)[0];
					if (!n || (n && typeof o.SetVariable != UNDEF)) {
							r = o;
					}
					else if (typeof n.SetVariable != UNDEF) {
						r = n;
					}
				}
			}
			return r;
		},
		
		embedSWF: function(swfUrlStr, replaceElemIdStr, widthStr, heightStr, swfVersionStr, xiSwfUrlStr, flashvarsObj, parObj, attObj) {
			if (!ua.w3cdom || !swfUrlStr || !replaceElemIdStr || !widthStr || !heightStr || !swfVersionStr) {
				return;
			}
			widthStr += ""; // Auto-convert to string
			heightStr += "";
			if (hasPlayerVersion(swfVersionStr)) {
				setVisibility(replaceElemIdStr, false);
				var att = {};
				if (attObj && typeof attObj === OBJECT) {
					for (var i in attObj) {
						if (attObj[i] != Object.prototype[i]) { // Filter out prototype additions from other potential libraries
							att[i] = attObj[i];
						}
					}
				}
				att.data = swfUrlStr;
				att.width = widthStr;
				att.height = heightStr;
				var par = {}; 
				if (parObj && typeof parObj === OBJECT) {
					for (var j in parObj) {
						if (parObj[j] != Object.prototype[j]) { // Filter out prototype additions from other potential libraries
							par[j] = parObj[j];
						}
					}
				}
				if (flashvarsObj && typeof flashvarsObj === OBJECT) {
					for (var k in flashvarsObj) {
						if (flashvarsObj[k] != Object.prototype[k]) { // Filter out prototype additions from other potential libraries
							if (typeof par.flashvars != UNDEF) {
								par.flashvars += "&" + k + "=" + flashvarsObj[k];
							}
							else {
								par.flashvars = k + "=" + flashvarsObj[k];
							}
						}
					}
				}
				addDomLoadEvent(function() {
					createSWF(att, par, replaceElemIdStr);
					if (att.id == replaceElemIdStr) {
						setVisibility(replaceElemIdStr, true);
					}
				});
			}
			else if (xiSwfUrlStr && !isExpressInstallActive && hasPlayerVersion("6.0.65") && (ua.win || ua.mac)) {
				isExpressInstallActive = true; // deferred execution
				setVisibility(replaceElemIdStr, false);
				addDomLoadEvent(function() {
					var regObj = {};
					regObj.id = regObj.altContentId = replaceElemIdStr;
					regObj.width = widthStr;
					regObj.height = heightStr;
					regObj.expressInstall = xiSwfUrlStr;
					showExpressInstall(regObj);
				});
			}
		},
		
		getFlashPlayerVersion: function() {
			return { major:ua.pv[0], minor:ua.pv[1], release:ua.pv[2] };
		},
		
		hasFlashPlayerVersion: hasPlayerVersion,
		
		createSWF: function(attObj, parObj, replaceElemIdStr) {
			if (ua.w3cdom) {
				return createSWF(attObj, parObj, replaceElemIdStr);
			}
			else {
				return undefined;
			}
		},
		
		removeSWF: function(objElemIdStr) {
			if (ua.w3cdom) {
				removeSWF(objElemIdStr);
			}
		},
		
		createCSS: function(sel, decl) {
			if (ua.w3cdom) {
				createCSS(sel, decl);
			}
		},
		
		addDomLoadEvent: addDomLoadEvent,
		
		addLoadEvent: addLoadEvent,
		
		getQueryParamValue: function(param) {
			var q = doc.location.search || doc.location.hash;
			if (param == null) {
				return urlEncodeIfNecessary(q);
			}
			if (q) {
				var pairs = q.substring(1).split("&");
				for (var i = 0; i < pairs.length; i++) {
					if (pairs[i].substring(0, pairs[i].indexOf("=")) == param) {
						return urlEncodeIfNecessary(pairs[i].substring((pairs[i].indexOf("=") + 1)));
					}
				}
			}
			return "";
		},
		
		// For internal usage only
		expressInstallCallback: function() {
			if (isExpressInstallActive && storedAltContent) {
				var obj = getElementById(EXPRESS_INSTALL_ID);
				if (obj) {
					obj.parentNode.replaceChild(storedAltContent, obj);
					if (storedAltContentId) {
						setVisibility(storedAltContentId, true);
						if (ua.ie && ua.win) {
							storedAltContent.style.display = "block";
						}
					}
					storedAltContent = null;
					storedAltContentId = null;
					isExpressInstallActive = false;
				}
			} 
		}
	};
}();
var trace_tags = false;

if(typeof deconcept=="undefined"){var deconcept=new Object();}if(typeof deconcept.util=="undefined"){deconcept.util=new Object();}if(typeof deconcept.SWFObjectUtil=="undefined"){deconcept.SWFObjectUtil=new Object();}deconcept.SWFObject=function(_1,id,w,h,_5,c,_7,_8,_9,_a){if(!document.getElementById){return;}this.DETECT_KEY=_a?_a:"detectflash";this.skipDetect=deconcept.util.getRequestParameter(this.DETECT_KEY);this.params=new Object();this.variables=new Object();this.attributes=new Array();if(_1){this.setAttribute("swf",_1);}if(id){this.setAttribute("id",id);}if(w){this.setAttribute("width",w);}if(h){this.setAttribute("height",h);}if(_5){this.setAttribute("version",new deconcept.PlayerVersion(_5.toString().split(".")));}this.installedVer=deconcept.SWFObjectUtil.getPlayerVersion();if(!window.opera&&document.all&&this.installedVer.major>7){deconcept.SWFObject.doPrepUnload=true;}if(c){this.addParam("bgcolor",c);}var q=_7?_7:"high";this.addParam("quality",q);this.setAttribute("useExpressInstall",false);this.setAttribute("doExpressInstall",false);var _c=(_8)?_8:window.location;this.setAttribute("xiRedirectUrl",_c);this.setAttribute("redirectUrl","");if(_9){this.setAttribute("redirectUrl",_9);}};deconcept.SWFObject.prototype={useExpressInstall:function(_d){this.xiSWFPath=!_d?"expressinstall.swf":_d;this.setAttribute("useExpressInstall",true);},setAttribute:function(_e,_f){this.attributes[_e]=_f;},getAttribute:function(_10){return this.attributes[_10];},addParam:function(_11,_12){this.params[_11]=_12;},getParams:function(){return this.params;},addVariable:function(_13,_14){this.variables[_13]=_14;},getVariable:function(_15){return this.variables[_15];},getVariables:function(){return this.variables;},getVariablePairs:function(){var _16=new Array();var key;var _18=this.getVariables();for(key in _18){_16[_16.length]=key+"="+_18[key];}return _16;},getSWFHTML:function(){var _19="";if(navigator.plugins&&navigator.mimeTypes&&navigator.mimeTypes.length){if(this.getAttribute("doExpressInstall")){this.addVariable("MMplayerType","PlugIn");this.setAttribute("swf",this.xiSWFPath);}_19="<embed type=\"application/x-shockwave-flash\" src=\""+this.getAttribute("swf")+"\" width=\""+this.getAttribute("width")+"\" height=\""+this.getAttribute("height")+"\" style=\""+this.getAttribute("style")+"\"";_19+=" id=\""+this.getAttribute("id")+"\" name=\""+this.getAttribute("id")+"\" ";var _1a=this.getParams();for(var key in _1a){_19+=[key]+"=\""+_1a[key]+"\" ";}var _1c=this.getVariablePairs().join("&");if(_1c.length>0){_19+="flashvars=\""+_1c+"\"";}_19+="/>";}else{if(this.getAttribute("doExpressInstall")){this.addVariable("MMplayerType","ActiveX");this.setAttribute("swf",this.xiSWFPath);}_19="<object id=\""+this.getAttribute("id")+"\" classid=\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\" width=\""+this.getAttribute("width")+"\" height=\""+this.getAttribute("height")+"\" style=\""+this.getAttribute("style")+"\">";_19+="<param name=\"movie\" value=\""+this.getAttribute("swf")+"\" />";var _1d=this.getParams();for(var key in _1d){_19+="<param name=\""+key+"\" value=\""+_1d[key]+"\" />";}var _1f=this.getVariablePairs().join("&");if(_1f.length>0){_19+="<param name=\"flashvars\" value=\""+_1f+"\" />";}_19+="</object>";}return _19;},write:function(_20){if(this.getAttribute("useExpressInstall")){var _21=new deconcept.PlayerVersion([6,0,65]);if(this.installedVer.versionIsValid(_21)&&!this.installedVer.versionIsValid(this.getAttribute("version"))){this.setAttribute("doExpressInstall",true);this.addVariable("MMredirectURL",escape(this.getAttribute("xiRedirectUrl")));document.title=document.title.slice(0,47)+" - Flash Player Installation";this.addVariable("MMdoctitle",document.title);}}if(this.skipDetect||this.getAttribute("doExpressInstall")||this.installedVer.versionIsValid(this.getAttribute("version"))){var n=(typeof _20=="string")?document.getElementById(_20):_20;n.innerHTML=this.getSWFHTML();return true;}else{if(this.getAttribute("redirectUrl")!=""){document.location.replace(this.getAttribute("redirectUrl"));}}return false;}};deconcept.SWFObjectUtil.getPlayerVersion=function(){var _23=new deconcept.PlayerVersion([0,0,0]);if(navigator.plugins&&navigator.mimeTypes.length){var x=navigator.plugins["Shockwave Flash"];if(x&&x.description){_23=new deconcept.PlayerVersion(x.description.replace(/([a-zA-Z]|\s)+/,"").replace(/(\s+r|\s+b[0-9]+)/,".").split("."));}}else{if(navigator.userAgent&&navigator.userAgent.indexOf("Windows CE")>=0){var axo=1;var _26=3;while(axo){try{_26++;axo=new ActiveXObject("ShockwaveFlash.ShockwaveFlash."+_26);_23=new deconcept.PlayerVersion([_26,0,0]);}catch(e){axo=null;}}}else{try{var axo=new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7");}catch(e){try{var axo=new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6");_23=new deconcept.PlayerVersion([6,0,21]);axo.AllowScriptAccess="always";}catch(e){if(_23.major==6){return _23;}}try{axo=new ActiveXObject("ShockwaveFlash.ShockwaveFlash");}catch(e){}}if(axo!=null){_23=new deconcept.PlayerVersion(axo.GetVariable("$version").split(" ")[1].split(","));}}}return _23;};deconcept.PlayerVersion=function(_29){this.major=_29[0]!=null?parseInt(_29[0]):0;this.minor=_29[1]!=null?parseInt(_29[1]):0;this.rev=_29[2]!=null?parseInt(_29[2]):0;};deconcept.PlayerVersion.prototype.versionIsValid=function(fv){if(this.major<fv.major){return false;}if(this.major>fv.major){return true;}if(this.minor<fv.minor){return false;}if(this.minor>fv.minor){return true;}if(this.rev<fv.rev){return false;}return true;};deconcept.util={getRequestParameter:function(_2b){var q=document.location.search||document.location.hash;if(_2b==null){return q;}if(q){var _2d=q.substring(1).split("&");for(var i=0;i<_2d.length;i++){if(_2d[i].substring(0,_2d[i].indexOf("="))==_2b){return _2d[i].substring((_2d[i].indexOf("=")+1));}}}return "";}};deconcept.SWFObjectUtil.cleanupSWFs=function(){var _2f=document.getElementsByTagName("OBJECT");for(var i=_2f.length-1;i>=0;i--){_2f[i].style.display="none";for(var x in _2f[i]){if(typeof _2f[i][x]=="function"){_2f[i][x]=function(){};}}}};if(deconcept.SWFObject.doPrepUnload){if(!deconcept.unloadSet){deconcept.SWFObjectUtil.prepUnload=function(){__flash_unloadHandler=function(){};__flash_savedUnloadHandler=function(){};window.attachEvent("onunload",deconcept.SWFObjectUtil.cleanupSWFs);};window.attachEvent("onbeforeunload",deconcept.SWFObjectUtil.prepUnload);deconcept.unloadSet=true;}}if(!document.getElementById&&document.all){document.getElementById=function(id){return document.all[id];};}var getQueryParamValue=deconcept.util.getRequestParameter;var FlashObject=deconcept.SWFObject;var SWFObject=deconcept.SWFObject;

function sp_tracker(sp,ci)
{
	if (trace_tags) {
		var titre = (sp.length > 5) ? "TAG DECLARATIF\n" : "TAG STATISTIQUE\n";
		logTags(titre + sp.join("\n"));
	}
	
	var smartParam = "";
	for(var i=0;i<sp.length;i++) smartParam += sp[i];
	document.cookie = 'sp=1; expires=Sunday, 02-Feb-2020 20:20:20 GMT';
	if (ci!="") smartParam += "&_ci=" +ci;
	if (window.screen) {
		res = screen.width + "x" + screen.height;
		col = screen.colorDepth;
	} else {
		res ="n/a"; col="n/a";
	}
	ctz=(new Date()).getTimezoneOffset();smartParam += "&_cr=" + Math.round (Math.random()*1000000000000000);
	var flashversion = deconcept.SWFObjectUtil.getPlayerVersion();
	if (flashversion["major"] > 0) _fv=flashversion["major"]; else _fv=-1;
	smartParam += "&_fv=" + escape(_fv);
	smartParam += "&_dom=" + escape(window.location.protocol+"//"+window.location.hostname);
	smartParam += "&_ref=" + escape(document.referrer.substring(0,254));
	smartParam += "&_res=" + escape(res) + "&_col=" + escape(col);
	smartParam += "&_tz=" + Math.round(((ctz==(new Date(20010101)).getTimezoneOffset())?ctz:(ctz+60))/-60);
	smartParam += "&_ck=" + (document.cookie.indexOf('sp=1') >= 0);
	//deja mis en place precedement en place --> doublon
	//smartParam += "&_event=" + escape(getParamValue('event'));
	smartImageF=new Image();
	smartImageF.src=location.protocol+"//ws2.smartp.com/sp_tracker.cfm"+smartParam;
}
var sp_t=1;


function sp_send(sp) {
	var clicParam = "";for(var i=0;i<sp.length;i++) clicParam += sp[i];document.cookie = 'spc=1; expires=Sunday, 02-Feb-2020 20:20:20 GMT';
	clicParam += "&_cr=" + Math.round (Math.random()*1000000000000000);clicParam += "&_ck=" + (document.cookie.indexOf('spc=1') >= 0);
	clicParam += "&_dom=" + escape(window.location.protocol+"//"+window.location.hostname);clicImage=new Image();clicImage.src=location.protocol+"//ws2.smartp.com/sp_tracker.cfm"+clicParam;
}

/***********************************************************************/

/**
* Gestion du HID en fonction du pays
**/
var HIDs = [];

HIDs['fr'] = [];
HIDs['fr']['stat'] = '182FA6C3A9AB0A026DCF87E7E726CB22';
HIDs['fr']['clic'] = '854D9FCA60B4BD07F9BB215D59EF5561';

HIDs['us'] = [];
HIDs['us']['stat'] = '812A75AC973C44B3DA97D5E9CEA3872B';
HIDs['us']['clic'] = '559CB990C9DFFD8675F6BC2186971DC2';

HIDs['es'] = [];
HIDs['es']['stat'] = '71B8442D27FE06D174CA676D0423A073';
HIDs['es']['clic'] = 'B534BA68236BA543AE44B22BD110A1D6';

HIDs['jp'] = [];
HIDs['jp']['stat'] = '602D1394A8D431AB0D20A74118C3454D';
HIDs['jp']['clic'] = '51043C580A94C49CB2189CDD8AB26E7D';

HIDs['cn'] = [];
HIDs['cn']['stat'] = 'EADB5CC71FC413736977A6A1C6885031';
HIDs['cn']['clic'] = '7380AD8A673226AE47FCE7BFF88E9C33';

HIDs['ph'] = [];
HIDs['ph']['stat'] = '31D2FA2664FEE010A650D75D3284A281';
HIDs['ph']['clic'] = 'B6EB6E5F7FB4D3E01842907FCBC531E6';

HIDs['ko'] = [];
HIDs['ko']['stat'] = '0B3A773ECEA97BFFE949B5A1BE46004B';
HIDs['ko']['clic'] = '2C62AB51C2EE625B618D68B2D1D79CEB';


/**
* Appel d'un tag event
*/
function callEventTag(pTitle, pEvent, pCntry) {
	if (!pCntry) {
		var pathTab = location.pathname.split("\\").join("/").split("/");
		var lang = pathTab[pathTab.length-2];
	} else lang = pCntry;
	var sp = new Array();
	sp[0]="?_hid=" + HIDs[lang]['stat'];
	sp[1]="&_title="+pTitle;
	sp[2]="&_event=" + pEvent;
	if (typeof sp_t != 'undefined') sp_tracker(sp,"");
}

/**
* Appel d'un tag statistique
*/
function callStatsTagMiniSite(pLogin, pTitle, pCntry) {
	var sp_ref=sp_getCookie('sp_ref',1);
	var sp = new Array();
	var ci = "";
	sp[0]="?_hid=" + HIDs[pCntry]['stat'];
	sp[1]= "&Login="+ ( (pLogin != 'null' && pLogin != 'undefined' && pLogin != undefined) ? pLogin : "");
	sp[2]="&_title="+ ( (pTitle != 'null' && pTitle != 'undefined' && pTitle != undefined) ? pTitle : "");
	sp[3]="&_class="+ ( (pTitle != 'null' && pTitle != 'undefined' && pTitle != undefined) ? pTitle : "");
	sp[4]="&_refredir="+sp_ref;
	if (typeof sp_t != 'undefined') sp_tracker(sp,ci);
}

/**
* Appel d'un tag d'informations dclaratives
*/
function callDataTag(pPanier, pPr_ach, pPr_in, pPr_out, pPr_vu, pCntry) {
	var sp = new Array();
	var ci = "";
	sp[0]="?_hid=" + HIDs[pCntry]['data'];
	sp[1]="&panier="+ ( (pPanier != 'null' && pPanier != 'undefined' && pPanier != undefined) ? pPanier : "");
	sp[2]="&pr_ach="+ ( (pPr_ach != 'null' && pPr_ach != 'undefined' && pPr_ach != undefined) ? pPr_ach : "");
	sp[3]="&pr_in="+ ( (pPr_in != 'null' && pPr_in != 'undefined' && pPr_in != undefined) ? pPr_in : "");
	sp[4]="&pr_out="+ ( (pPr_out != 'null' && pPr_out != 'undefined' && pPr_out != undefined) ? pPr_out : "");
	sp[5]="&pr_vu="+ ( (pPr_vu != 'null' && pPr_vu != 'undefined' && pPr_vu != undefined) ? pPr_vu : "");
	if (typeof sp_t != 'undefined') sp_tracker(sp,ci);
}

/**
* Appel d'un tag de clic
*/
function sp_clicMiniSite(ctyp, clab, cfrom, cto, pCntry) {
	var sp_ref=sp_getCookie('sp_ref',1);
	sp = new Array();
	sp[0]="?_hid=" + HIDs[pCntry]['clic'];
	sp[1]="&_ctyp="+ ( (ctyp != 'null' && ctyp != 'undefined' && ctyp != undefined) ? ctyp : "");
	sp[2]="&_clab="+ ( (clab != 'null' && clab != 'undefined' && clab != undefined) ? clab : "");
	sp[3]="&_cfrom="+ ( (cfrom != 'null' && cfrom != 'undefined' && cfrom != undefined) ? cfrom : "");
	sp[4]="&_cto="+ ( (cto != 'null' && cto != 'undefined' && cto != undefined) ? cto : "");
	sp[5]="&_refredir="+sp_ref;
	if (trace_tags) logTags("TAG CLIC\nhid:"+ sp[0] + "\nctype : "+ ctyp +"\nclab : "+ clab + "\ncfrom : "+ cfrom + "\ncto : "+ cto);
	sp_send(sp);
}

/***********************************************************************/
/*************************  GESTION DES TRACE  *************************/
/***********************************************************************/
if (trace_tags) {
	var msg = "Voulez-vous afficher les appels de tags ?";
	trace_tags = confirm(msg);
}

function logTags(pTxt) {
	var logger = window.open("", "tags_logger", "width=600,height=700,scrollbars=yes");
	logger.document.write("<p style='font-family:verdana;font-size:11px'>");
	pTxt = pTxt.split("\n").join("<br />\n");
	logger.document.write(pTxt+"<br />\n");
	logger.document.write("</p><hr />\n");
	logger.focus();
}


function getParamValue(param) {
	
var qs = window.location.href;
var startIndex=qs.indexOf("?"); 
var longueur=qs.length;
if (startIndex<longueur && startIndex != -1){
	var params = qs.split("?")
	var vars = params[1].split("&");
	for (var i=0;i<vars.length;i++) {
		var pair = vars[i].split("=");
		if (pair[0] == param) {return pair[1];}
	}
}
return "";
}

/* Ecrit un cookie 1st part */
function sp_setCookie(name, value, chemin,domaine){
	     document.cookie = name + '=' + escape(value) + '; path=' + chemin + '; domain='+ domaine;
}

/* Supprime un cookie */
function sp_delCookie(name) {
	document.cookie=name+"=;expires=Thu, 01-Jan-1970 00:00:01 GMT";
}

/* R�cup�re la valeur d'un cookie 1st part */
function sp_getCookie(name,reset) {
	var a_all_cookies = document.cookie.split( ';' );
	var a_temp_cookie = '';
	var cookie_name = '';
	var cookie_value = '';
	var b_cookie_found = false; 
	
	for (i=0; i<a_all_cookies.length; i++)
	{
		a_temp_cookie = a_all_cookies[i].split('=');
		cookie_name = a_temp_cookie[0].replace(/^\s+|\s+$/g,'');
		
		if ((cookie_name==name) && (a_temp_cookie[1]))
		{
			b_cookie_found = true;
			cookie_value = unescape(a_temp_cookie[1].replace(/^\s+|\s+$/g,''));
			if (reset) {
				sp_delCookie(name);
			}
			return cookie_value;
			break;
		}
		a_temp_cookie = null;
		cookie_name = '';
	}
	if (!b_cookie_found)
	{
		return '';
	}
}


